@@ -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);
@@ -1213,18 +1250,25 @@ int MKDirpSync(uv_loop_t* loop,
12131250 const std::string& path,
12141251 int mode,
12151252 uv_fs_cb cb) {
1216- FSContinuationData continuation_data (req, mode, cb);
1217- continuation_data.PushPath (std::move (path));
1253+ FSReqWrapSync* req_wrap = ContainerOf (&FSReqWrapSync::req, req);
1254+
1255+ // on the first iteration of algorithm, stash state information.
1256+ if (req_wrap->continuation_data () == nullptr ) {
1257+ req_wrap->set_continuation_data (
1258+ std::make_unique<FSContinuationData>(req, mode, cb));
1259+ req_wrap->continuation_data ()->PushPath (std::move (path));
1260+ }
12181261
1219- while (continuation_data. paths ().size () > 0 ) {
1220- std::string next_path = continuation_data. PopPath ();
1262+ while (req_wrap-> continuation_data ()-> paths ().size () > 0 ) {
1263+ std::string next_path = req_wrap-> continuation_data ()-> PopPath ();
12211264 int err = uv_fs_mkdir (loop, req, next_path.c_str (), mode, nullptr );
12221265 while (true ) {
12231266 switch (err) {
12241267 // Note: uv_fs_req_cleanup in terminal paths will be called by
12251268 // ~FSReqWrapSync():
12261269 case 0 :
1227- if (continuation_data.paths ().size () == 0 ) {
1270+ req_wrap->continuation_data ()->MaybeSetFirstPath (next_path);
1271+ if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
12281272 return 0 ;
12291273 }
12301274 break ;
@@ -1237,9 +1281,9 @@ int MKDirpSync(uv_loop_t* loop,
12371281 std::string dirname = next_path.substr (0 ,
12381282 next_path.find_last_of (kPathSeparator ));
12391283 if (dirname != next_path) {
1240- continuation_data. PushPath (std::move (next_path));
1241- continuation_data. PushPath (std::move (dirname));
1242- } else if (continuation_data. paths ().size () == 0 ) {
1284+ req_wrap-> continuation_data ()-> PushPath (std::move (next_path));
1285+ req_wrap-> continuation_data ()-> PushPath (std::move (dirname));
1286+ } else if (req_wrap-> continuation_data ()-> paths ().size () == 0 ) {
12431287 err = UV_EEXIST;
12441288 continue ;
12451289 }
@@ -1251,7 +1295,8 @@ int MKDirpSync(uv_loop_t* loop,
12511295 err = uv_fs_stat (loop, req, next_path.c_str (), nullptr );
12521296 if (err == 0 && !S_ISDIR (req->statbuf .st_mode )) {
12531297 uv_fs_req_cleanup (req);
1254- if (orig_err == UV_EEXIST && continuation_data.paths ().size () > 0 ) {
1298+ if (orig_err == UV_EEXIST &&
1299+ req_wrap->continuation_data ()->paths ().size () > 0 ) {
12551300 return UV_ENOTDIR;
12561301 }
12571302 return UV_EEXIST;
@@ -1296,8 +1341,10 @@ int MKDirpAsync(uv_loop_t* loop,
12961341 // FSReqAfterScope::~FSReqAfterScope()
12971342 case 0 : {
12981343 if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
1344+ req_wrap->continuation_data ()->MaybeSetFirstPath (path);
12991345 req_wrap->continuation_data ()->Done (0 );
13001346 } else {
1347+ req_wrap->continuation_data ()->MaybeSetFirstPath (path);
13011348 uv_fs_req_cleanup (req);
13021349 MKDirpAsync (loop, req, path.c_str (),
13031350 req_wrap->continuation_data ()->mode (), nullptr );
@@ -1360,6 +1407,25 @@ int MKDirpAsync(uv_loop_t* loop,
13601407 return err;
13611408}
13621409
1410+ int CallMKDirpSync (Environment* env, const FunctionCallbackInfo<Value>& args,
1411+ FSReqWrapSync* req_wrap, const char * path, int mode) {
1412+ env->PrintSyncTrace ();
1413+ int err = MKDirpSync (env->event_loop (), &req_wrap->req , path, mode,
1414+ nullptr );
1415+ if (err < 0 ) {
1416+ v8::Local<v8::Context> context = env->context ();
1417+ v8::Local<v8::Object> ctx_obj = args[4 ].As <v8::Object>();
1418+ v8::Isolate* isolate = env->isolate ();
1419+ ctx_obj->Set (context,
1420+ env->errno_string (),
1421+ v8::Integer::New (isolate, err)).Check ();
1422+ ctx_obj->Set (context,
1423+ env->syscall_string (),
1424+ OneByteString (isolate, " mkdir" )).Check ();
1425+ }
1426+ return err;
1427+ }
1428+
13631429static void MKDir (const FunctionCallbackInfo<Value>& args) {
13641430 Environment* env = Environment::GetCurrent (args);
13651431
@@ -1378,14 +1444,29 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
13781444 FSReqBase* req_wrap_async = GetReqWrap (env, args[3 ]);
13791445 if (req_wrap_async != nullptr ) { // mkdir(path, mode, req)
13801446 AsyncCall (env, req_wrap_async, args, " mkdir" , UTF8,
1381- AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1447+ mkdirp ? AfterMkdirp : AfterNoArgs,
1448+ mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
13821449 } else { // mkdir(path, mode, undefined, ctx)
13831450 CHECK_EQ (argc, 5 );
13841451 FSReqWrapSync req_wrap_sync;
13851452 FS_SYNC_TRACE_BEGIN (mkdir);
13861453 if (mkdirp) {
1387- SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
1388- MKDirpSync, *path, mode);
1454+ int err = CallMKDirpSync (env, args, &req_wrap_sync, *path, mode);
1455+ if (err == 0 &&
1456+ !req_wrap_sync.continuation_data ()->first_path ().empty ()) {
1457+ Local<Value> error;
1458+ std::string first_path (req_wrap_sync.continuation_data ()->first_path ());
1459+ FromNamespacedPath (&first_path);
1460+ MaybeLocal<Value> path = StringBytes::Encode (env->isolate (),
1461+ first_path.c_str (),
1462+ UTF8, &error);
1463+ if (path.IsEmpty ()) {
1464+ Local<Object> ctx = args[4 ].As <Object>();
1465+ ctx->Set (env->context (), env->error_string (), error).Check ();
1466+ return ;
1467+ }
1468+ args.GetReturnValue ().Set (path.ToLocalChecked ());
1469+ }
13891470 } else {
13901471 SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
13911472 uv_fs_mkdir, *path, mode);
0 commit comments