@@ -590,6 +590,43 @@ void AfterOpenFileHandle(uv_fs_t* req) {
590590 }
591591}
592592
593+ // Reverse the logic applied by path.toNamespacedPath() to create a
594+ // namespace-prefixed path.
595+ void FromNamespacedPath (std::string* path) {
596+ #ifdef _WIN32
597+ if (path->compare (0 , 8 , " \\\\ ?\\ UNC\\ " , 8 ) == 0 ) {
598+ *path = path->substr (8 );
599+ path->insert (0 , " \\\\ " );
600+ } else if (path->compare (0 , 4 , " \\\\ ?\\ " , 4 ) == 0 ) {
601+ *path = path->substr (4 );
602+ }
603+ #endif
604+ }
605+
606+ void AfterMkdirp (uv_fs_t * req) {
607+ FSReqBase* req_wrap = FSReqBase::from_req (req);
608+ FSReqAfterScope after (req_wrap, req);
609+
610+ MaybeLocal<Value> path;
611+ Local<Value> error;
612+
613+ if (after.Proceed ()) {
614+ if (!req_wrap->continuation_data ()->first_path ().empty ()) {
615+ std::string first_path (req_wrap->continuation_data ()->first_path ());
616+ FromNamespacedPath (&first_path);
617+ path = StringBytes::Encode (req_wrap->env ()->isolate (), first_path.c_str (),
618+ req_wrap->encoding (),
619+ &error);
620+ if (path.IsEmpty ())
621+ req_wrap->Reject (error);
622+ else
623+ req_wrap->Resolve (path.ToLocalChecked ());
624+ } else {
625+ req_wrap->Resolve (Undefined (req_wrap->env ()->isolate ()));
626+ }
627+ }
628+ }
629+
593630void AfterStringPath (uv_fs_t * req) {
594631 FSReqBase* req_wrap = FSReqBase::from_req (req);
595632 FSReqAfterScope after (req_wrap, req);
@@ -1215,18 +1252,25 @@ int MKDirpSync(uv_loop_t* loop,
12151252 const std::string& path,
12161253 int mode,
12171254 uv_fs_cb cb) {
1218- FSContinuationData continuation_data (req, mode, cb);
1219- continuation_data.PushPath (std::move (path));
1255+ FSReqWrapSync* req_wrap = ContainerOf (&FSReqWrapSync::req, req);
1256+
1257+ // on the first iteration of algorithm, stash state information.
1258+ if (req_wrap->continuation_data () == nullptr ) {
1259+ req_wrap->set_continuation_data (
1260+ std::make_unique<FSContinuationData>(req, mode, cb));
1261+ req_wrap->continuation_data ()->PushPath (std::move (path));
1262+ }
12201263
1221- while (continuation_data. paths ().size () > 0 ) {
1222- std::string next_path = continuation_data. PopPath ();
1264+ while (req_wrap-> continuation_data ()-> paths ().size () > 0 ) {
1265+ std::string next_path = req_wrap-> continuation_data ()-> PopPath ();
12231266 int err = uv_fs_mkdir (loop, req, next_path.c_str (), mode, nullptr );
12241267 while (true ) {
12251268 switch (err) {
12261269 // Note: uv_fs_req_cleanup in terminal paths will be called by
12271270 // ~FSReqWrapSync():
12281271 case 0 :
1229- if (continuation_data.paths ().size () == 0 ) {
1272+ req_wrap->continuation_data ()->MaybeSetFirstPath (next_path);
1273+ if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
12301274 return 0 ;
12311275 }
12321276 break ;
@@ -1239,9 +1283,9 @@ int MKDirpSync(uv_loop_t* loop,
12391283 std::string dirname = next_path.substr (0 ,
12401284 next_path.find_last_of (kPathSeparator ));
12411285 if (dirname != next_path) {
1242- continuation_data. PushPath (std::move (next_path));
1243- continuation_data. PushPath (std::move (dirname));
1244- } else if (continuation_data. paths ().size () == 0 ) {
1286+ req_wrap-> continuation_data ()-> PushPath (std::move (next_path));
1287+ req_wrap-> continuation_data ()-> PushPath (std::move (dirname));
1288+ } else if (req_wrap-> continuation_data ()-> paths ().size () == 0 ) {
12451289 err = UV_EEXIST;
12461290 continue ;
12471291 }
@@ -1253,7 +1297,8 @@ int MKDirpSync(uv_loop_t* loop,
12531297 err = uv_fs_stat (loop, req, next_path.c_str (), nullptr );
12541298 if (err == 0 && !S_ISDIR (req->statbuf .st_mode )) {
12551299 uv_fs_req_cleanup (req);
1256- if (orig_err == UV_EEXIST && continuation_data.paths ().size () > 0 ) {
1300+ if (orig_err == UV_EEXIST &&
1301+ req_wrap->continuation_data ()->paths ().size () > 0 ) {
12571302 return UV_ENOTDIR;
12581303 }
12591304 return UV_EEXIST;
@@ -1298,8 +1343,10 @@ int MKDirpAsync(uv_loop_t* loop,
12981343 // FSReqAfterScope::~FSReqAfterScope()
12991344 case 0 : {
13001345 if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
1346+ req_wrap->continuation_data ()->MaybeSetFirstPath (path);
13011347 req_wrap->continuation_data ()->Done (0 );
13021348 } else {
1349+ req_wrap->continuation_data ()->MaybeSetFirstPath (path);
13031350 uv_fs_req_cleanup (req);
13041351 MKDirpAsync (loop, req, path.c_str (),
13051352 req_wrap->continuation_data ()->mode (), nullptr );
@@ -1362,6 +1409,25 @@ int MKDirpAsync(uv_loop_t* loop,
13621409 return err;
13631410}
13641411
1412+ int CallMKDirpSync (Environment* env, const FunctionCallbackInfo<Value>& args,
1413+ FSReqWrapSync* req_wrap, const char * path, int mode) {
1414+ env->PrintSyncTrace ();
1415+ int err = MKDirpSync (env->event_loop (), &req_wrap->req , path, mode,
1416+ nullptr );
1417+ if (err < 0 ) {
1418+ v8::Local<v8::Context> context = env->context ();
1419+ v8::Local<v8::Object> ctx_obj = args[4 ].As <v8::Object>();
1420+ v8::Isolate* isolate = env->isolate ();
1421+ ctx_obj->Set (context,
1422+ env->errno_string (),
1423+ v8::Integer::New (isolate, err)).Check ();
1424+ ctx_obj->Set (context,
1425+ env->syscall_string (),
1426+ OneByteString (isolate, " mkdir" )).Check ();
1427+ }
1428+ return err;
1429+ }
1430+
13651431static void MKDir (const FunctionCallbackInfo<Value>& args) {
13661432 Environment* env = Environment::GetCurrent (args);
13671433
@@ -1380,14 +1446,29 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
13801446 FSReqBase* req_wrap_async = GetReqWrap (env, args[3 ]);
13811447 if (req_wrap_async != nullptr ) { // mkdir(path, mode, req)
13821448 AsyncCall (env, req_wrap_async, args, " mkdir" , UTF8,
1383- AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1449+ mkdirp ? AfterMkdirp : AfterNoArgs,
1450+ mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
13841451 } else { // mkdir(path, mode, undefined, ctx)
13851452 CHECK_EQ (argc, 5 );
13861453 FSReqWrapSync req_wrap_sync;
13871454 FS_SYNC_TRACE_BEGIN (mkdir);
13881455 if (mkdirp) {
1389- SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
1390- MKDirpSync, *path, mode);
1456+ int err = CallMKDirpSync (env, args, &req_wrap_sync, *path, mode);
1457+ if (err == 0 &&
1458+ !req_wrap_sync.continuation_data ()->first_path ().empty ()) {
1459+ Local<Value> error;
1460+ std::string first_path (req_wrap_sync.continuation_data ()->first_path ());
1461+ FromNamespacedPath (&first_path);
1462+ MaybeLocal<Value> path = StringBytes::Encode (env->isolate (),
1463+ first_path.c_str (),
1464+ UTF8, &error);
1465+ if (path.IsEmpty ()) {
1466+ Local<Object> ctx = args[4 ].As <Object>();
1467+ ctx->Set (env->context (), env->error_string (), error).Check ();
1468+ return ;
1469+ }
1470+ args.GetReturnValue ().Set (path.ToLocalChecked ());
1471+ }
13911472 } else {
13921473 SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
13931474 uv_fs_mkdir, *path, mode);
0 commit comments