@@ -586,6 +586,43 @@ void AfterOpenFileHandle(uv_fs_t* req) {
586
586
}
587
587
}
588
588
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
+
589
626
void AfterStringPath (uv_fs_t * req) {
590
627
FSReqBase* req_wrap = FSReqBase::from_req (req);
591
628
FSReqAfterScope after (req_wrap, req);
@@ -1213,18 +1250,25 @@ int MKDirpSync(uv_loop_t* loop,
1213
1250
const std::string& path,
1214
1251
int mode,
1215
1252
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
+ }
1218
1261
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 ();
1221
1264
int err = uv_fs_mkdir (loop, req, next_path.c_str (), mode, nullptr );
1222
1265
while (true ) {
1223
1266
switch (err) {
1224
1267
// Note: uv_fs_req_cleanup in terminal paths will be called by
1225
1268
// ~FSReqWrapSync():
1226
1269
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 ) {
1228
1272
return 0 ;
1229
1273
}
1230
1274
break ;
@@ -1237,9 +1281,9 @@ int MKDirpSync(uv_loop_t* loop,
1237
1281
std::string dirname = next_path.substr (0 ,
1238
1282
next_path.find_last_of (kPathSeparator ));
1239
1283
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 ) {
1243
1287
err = UV_EEXIST;
1244
1288
continue ;
1245
1289
}
@@ -1251,7 +1295,8 @@ int MKDirpSync(uv_loop_t* loop,
1251
1295
err = uv_fs_stat (loop, req, next_path.c_str (), nullptr );
1252
1296
if (err == 0 && !S_ISDIR (req->statbuf .st_mode )) {
1253
1297
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 ) {
1255
1300
return UV_ENOTDIR;
1256
1301
}
1257
1302
return UV_EEXIST;
@@ -1296,8 +1341,10 @@ int MKDirpAsync(uv_loop_t* loop,
1296
1341
// FSReqAfterScope::~FSReqAfterScope()
1297
1342
case 0 : {
1298
1343
if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
1344
+ req_wrap->continuation_data ()->MaybeSetFirstPath (path);
1299
1345
req_wrap->continuation_data ()->Done (0 );
1300
1346
} else {
1347
+ req_wrap->continuation_data ()->MaybeSetFirstPath (path);
1301
1348
uv_fs_req_cleanup (req);
1302
1349
MKDirpAsync (loop, req, path.c_str (),
1303
1350
req_wrap->continuation_data ()->mode (), nullptr );
@@ -1360,6 +1407,25 @@ int MKDirpAsync(uv_loop_t* loop,
1360
1407
return err;
1361
1408
}
1362
1409
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
+
1363
1429
static void MKDir (const FunctionCallbackInfo<Value>& args) {
1364
1430
Environment* env = Environment::GetCurrent (args);
1365
1431
@@ -1378,14 +1444,29 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
1378
1444
FSReqBase* req_wrap_async = GetReqWrap (env, args[3 ]);
1379
1445
if (req_wrap_async != nullptr ) { // mkdir(path, mode, req)
1380
1446
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);
1382
1449
} else { // mkdir(path, mode, undefined, ctx)
1383
1450
CHECK_EQ (argc, 5 );
1384
1451
FSReqWrapSync req_wrap_sync;
1385
1452
FS_SYNC_TRACE_BEGIN (mkdir);
1386
1453
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
+ }
1389
1470
} else {
1390
1471
SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
1391
1472
uv_fs_mkdir, *path, mode);
0 commit comments