fs: return first folder made by mkdir recursive · nodejs/node@ff58854

@@ -586,6 +586,43 @@ void AfterOpenFileHandle(uv_fs_t* req) {

586586

}

587587

}

588588589+

// 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+589626

void 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+

}

121812611219-

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

}

136214091410+

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+13631429

static 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);