@@ -586,6 +586,43 @@ void AfterOpenFileHandle(uv_fs_t* req) {
586586 }
587587}
588588
589+ // Reverse the logic applied by path.toNamespacedPath() to create a
590+ // namespace-prefixed path.
591+ void FromNamespacedPath (std::string* path) {
592+ #ifdef _WIN32
593+ if (path->compare (0 , 8 , " \\\\ ?\\ UNC\\ " , 8 ) == 0 ) {
594+ *path = path->substr (8 );
595+ path->insert (0 , " \\\\ " );
596+ } else if (path->compare (0 , 4 , " \\\\ ?\\ " , 4 ) == 0 ) {
597+ *path = path->substr (4 );
598+ }
599+ #endif
600+ }
601+
602+ void AfterMkdirp (uv_fs_t * req) {
603+ FSReqBase* req_wrap = FSReqBase::from_req (req);
604+ FSReqAfterScope after (req_wrap, req);
605+
606+ MaybeLocal<Value> path;
607+ Local<Value> error;
608+
609+ if (after.Proceed ()) {
610+ if (!req_wrap->continuation_data ()->first_path ().empty ()) {
611+ std::string first_path (req_wrap->continuation_data ()->first_path ());
612+ FromNamespacedPath (&first_path);
613+ path = StringBytes::Encode (req_wrap->env ()->isolate (), first_path.c_str (),
614+ req_wrap->encoding (),
615+ &error);
616+ if (path.IsEmpty ())
617+ req_wrap->Reject (error);
618+ else
619+ req_wrap->Resolve (path.ToLocalChecked ());
620+ } else {
621+ req_wrap->Resolve (Undefined (req_wrap->env ()->isolate ()));
622+ }
623+ }
624+ }
625+
589626void AfterStringPath (uv_fs_t * req) {
590627 FSReqBase* req_wrap = FSReqBase::from_req (req);
591628 FSReqAfterScope after (req_wrap, req);
@@ -1218,18 +1255,25 @@ int MKDirpSync(uv_loop_t* loop,
12181255 const std::string& path,
12191256 int mode,
12201257 uv_fs_cb cb) {
1221- FSContinuationData continuation_data (req, mode, cb);
1222- continuation_data.PushPath (std::move (path));
1258+ FSReqWrapSync* req_wrap = ContainerOf (&FSReqWrapSync::req, req);
1259+
1260+ // on the first iteration of algorithm, stash state information.
1261+ if (req_wrap->continuation_data () == nullptr ) {
1262+ req_wrap->set_continuation_data (
1263+ std::make_unique<FSContinuationData>(req, mode, cb));
1264+ req_wrap->continuation_data ()->PushPath (std::move (path));
1265+ }
12231266
1224- while (continuation_data. paths ().size () > 0 ) {
1225- std::string next_path = continuation_data. PopPath ();
1267+ while (req_wrap-> continuation_data ()-> paths ().size () > 0 ) {
1268+ std::string next_path = req_wrap-> continuation_data ()-> PopPath ();
12261269 int err = uv_fs_mkdir (loop, req, next_path.c_str (), mode, nullptr );
12271270 while (true ) {
12281271 switch (err) {
12291272 // Note: uv_fs_req_cleanup in terminal paths will be called by
12301273 // ~FSReqWrapSync():
12311274 case 0 :
1232- if (continuation_data.paths ().size () == 0 ) {
1275+ req_wrap->continuation_data ()->MaybeSetFirstPath (next_path);
1276+ if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
12331277 return 0 ;
12341278 }
12351279 break ;
@@ -1241,9 +1285,9 @@ int MKDirpSync(uv_loop_t* loop,
12411285 std::string dirname = next_path.substr (0 ,
12421286 next_path.find_last_of (kPathSeparator ));
12431287 if (dirname != next_path) {
1244- continuation_data. PushPath (std::move (next_path));
1245- continuation_data. PushPath (std::move (dirname));
1246- } else if (continuation_data. paths ().size () == 0 ) {
1288+ req_wrap-> continuation_data ()-> PushPath (std::move (next_path));
1289+ req_wrap-> continuation_data ()-> PushPath (std::move (dirname));
1290+ } else if (req_wrap-> continuation_data ()-> paths ().size () == 0 ) {
12471291 err = UV_EEXIST;
12481292 continue ;
12491293 }
@@ -1255,7 +1299,8 @@ int MKDirpSync(uv_loop_t* loop,
12551299 err = uv_fs_stat (loop, req, next_path.c_str (), nullptr );
12561300 if (err == 0 && !S_ISDIR (req->statbuf .st_mode )) {
12571301 uv_fs_req_cleanup (req);
1258- if (orig_err == UV_EEXIST && continuation_data.paths ().size () > 0 ) {
1302+ if (orig_err == UV_EEXIST &&
1303+ req_wrap->continuation_data ()->paths ().size () > 0 ) {
12591304 return UV_ENOTDIR;
12601305 }
12611306 return UV_EEXIST;
@@ -1300,8 +1345,10 @@ int MKDirpAsync(uv_loop_t* loop,
13001345 // FSReqAfterScope::~FSReqAfterScope()
13011346 case 0 : {
13021347 if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
1348+ req_wrap->continuation_data ()->MaybeSetFirstPath (path);
13031349 req_wrap->continuation_data ()->Done (0 );
13041350 } else {
1351+ req_wrap->continuation_data ()->MaybeSetFirstPath (path);
13051352 uv_fs_req_cleanup (req);
13061353 MKDirpAsync (loop, req, path.c_str (),
13071354 req_wrap->continuation_data ()->mode (), nullptr );
@@ -1364,6 +1411,25 @@ int MKDirpAsync(uv_loop_t* loop,
13641411 return err;
13651412}
13661413
1414+ int CallMKDirpSync (Environment* env, const FunctionCallbackInfo<Value>& args,
1415+ FSReqWrapSync* req_wrap, const char * path, int mode) {
1416+ env->PrintSyncTrace ();
1417+ int err = MKDirpSync (env->event_loop (), &req_wrap->req , path, mode,
1418+ nullptr );
1419+ if (err < 0 ) {
1420+ v8::Local<v8::Context> context = env->context ();
1421+ v8::Local<v8::Object> ctx_obj = args[4 ].As <v8::Object>();
1422+ v8::Isolate* isolate = env->isolate ();
1423+ ctx_obj->Set (context,
1424+ env->errno_string (),
1425+ v8::Integer::New (isolate, err)).Check ();
1426+ ctx_obj->Set (context,
1427+ env->syscall_string (),
1428+ OneByteString (isolate, " mkdir" )).Check ();
1429+ }
1430+ return err;
1431+ }
1432+
13671433static void MKDir (const FunctionCallbackInfo<Value>& args) {
13681434 Environment* env = Environment::GetCurrent (args);
13691435
@@ -1382,14 +1448,29 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
13821448 FSReqBase* req_wrap_async = GetReqWrap (env, args[3 ]);
13831449 if (req_wrap_async != nullptr ) { // mkdir(path, mode, req)
13841450 AsyncCall (env, req_wrap_async, args, " mkdir" , UTF8,
1385- AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1451+ mkdirp ? AfterMkdirp : AfterNoArgs,
1452+ mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
13861453 } else { // mkdir(path, mode, undefined, ctx)
13871454 CHECK_EQ (argc, 5 );
13881455 FSReqWrapSync req_wrap_sync;
13891456 FS_SYNC_TRACE_BEGIN (mkdir);
13901457 if (mkdirp) {
1391- SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
1392- MKDirpSync, *path, mode);
1458+ int err = CallMKDirpSync (env, args, &req_wrap_sync, *path, mode);
1459+ if (err == 0 &&
1460+ !req_wrap_sync.continuation_data ()->first_path ().empty ()) {
1461+ Local<Value> error;
1462+ std::string first_path (req_wrap_sync.continuation_data ()->first_path ());
1463+ FromNamespacedPath (&first_path);
1464+ MaybeLocal<Value> path = StringBytes::Encode (env->isolate (),
1465+ first_path.c_str (),
1466+ UTF8, &error);
1467+ if (path.IsEmpty ()) {
1468+ Local<Object> ctx = args[4 ].As <Object>();
1469+ ctx->Set (env->context (), env->error_string (), error).Check ();
1470+ return ;
1471+ }
1472+ args.GetReturnValue ().Set (path.ToLocalChecked ());
1473+ }
13931474 } else {
13941475 SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
13951476 uv_fs_mkdir, *path, mode);
0 commit comments