@@ -586,6 +586,43 @@ void AfterOpenFileHandle(uv_fs_t* req) {
}
}
// Reverse the logic applied by path.toNamespacedPath() to create a
// namespace-prefixed path.
void FromNamespacedPath (std::string* path) {
#ifdef _WIN32
if (path->compare (0 , 8 , " \\\\ ?\\ UNC\\ " , 8 ) == 0 ) {
*path = path->substr (8 );
path->insert (0 , " \\\\ " );
} else if (path->compare (0 , 4 , " \\\\ ?\\ " , 4 ) == 0 ) {
*path = path->substr (4 );
}
#endif
}
void AfterMkdirp (uv_fs_t * req) {
FSReqBase* req_wrap = FSReqBase::from_req (req);
FSReqAfterScope after (req_wrap, req);
MaybeLocal<Value> path;
Local<Value> error;
if (after.Proceed ()) {
if (!req_wrap->continuation_data ()->first_path ().empty ()) {
std::string first_path (req_wrap->continuation_data ()->first_path ());
FromNamespacedPath (&first_path);
path = StringBytes::Encode (req_wrap->env ()->isolate (), first_path.c_str (),
req_wrap->encoding (),
&error);
if (path.IsEmpty ())
req_wrap->Reject (error);
else
req_wrap->Resolve (path.ToLocalChecked ());
} else {
req_wrap->Resolve (Undefined (req_wrap->env ()->isolate ()));
}
}
}
void AfterStringPath (uv_fs_t * req) {
FSReqBase* req_wrap = FSReqBase::from_req (req);
FSReqAfterScope after (req_wrap, req);
@@ -1218,18 +1255,25 @@ int MKDirpSync(uv_loop_t* loop,
const std::string& path,
int mode,
uv_fs_cb cb) {
FSContinuationData continuation_data (req, mode, cb);
continuation_data.PushPath (std::move (path));
FSReqWrapSync* req_wrap = ContainerOf (&FSReqWrapSync::req, req);
// on the first iteration of algorithm, stash state information.
if (req_wrap->continuation_data () == nullptr ) {
req_wrap->set_continuation_data (
std::make_unique<FSContinuationData>(req, mode, cb));
req_wrap->continuation_data ()->PushPath (std::move (path));
}
while (continuation_data. paths ().size () > 0 ) {
std::string next_path = continuation_data. PopPath ();
while (req_wrap-> continuation_data ()-> paths ().size () > 0 ) {
std::string next_path = req_wrap-> continuation_data ()-> PopPath ();
int err = uv_fs_mkdir (loop, req, next_path.c_str (), mode, nullptr );
while (true ) {
switch (err) {
// Note: uv_fs_req_cleanup in terminal paths will be called by
// ~FSReqWrapSync():
case 0 :
if (continuation_data.paths ().size () == 0 ) {
req_wrap->continuation_data ()->MaybeSetFirstPath (next_path);
if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
return 0 ;
}
break ;
@@ -1241,9 +1285,9 @@ int MKDirpSync(uv_loop_t* loop,
std::string dirname = next_path.substr (0 ,
next_path.find_last_of (kPathSeparator ));
if (dirname != next_path) {
continuation_data. PushPath (std::move (next_path));
continuation_data. PushPath (std::move (dirname));
} else if (continuation_data. paths ().size () == 0 ) {
req_wrap-> continuation_data ()-> PushPath (std::move (next_path));
req_wrap-> continuation_data ()-> PushPath (std::move (dirname));
} else if (req_wrap-> continuation_data ()-> paths ().size () == 0 ) {
err = UV_EEXIST;
continue ;
}
@@ -1255,7 +1299,8 @@ int MKDirpSync(uv_loop_t* loop,
err = uv_fs_stat (loop, req, next_path.c_str (), nullptr );
if (err == 0 && !S_ISDIR (req->statbuf .st_mode )) {
uv_fs_req_cleanup (req);
if (orig_err == UV_EEXIST && continuation_data.paths ().size () > 0 ) {
if (orig_err == UV_EEXIST &&
req_wrap->continuation_data ()->paths ().size () > 0 ) {
return UV_ENOTDIR;
}
return UV_EEXIST;
@@ -1300,8 +1345,10 @@ int MKDirpAsync(uv_loop_t* loop,
// FSReqAfterScope::~FSReqAfterScope()
case 0 : {
if (req_wrap->continuation_data ()->paths ().size () == 0 ) {
req_wrap->continuation_data ()->MaybeSetFirstPath (path);
req_wrap->continuation_data ()->Done (0 );
} else {
req_wrap->continuation_data ()->MaybeSetFirstPath (path);
uv_fs_req_cleanup (req);
MKDirpAsync (loop, req, path.c_str (),
req_wrap->continuation_data ()->mode (), nullptr );
@@ -1364,6 +1411,25 @@ int MKDirpAsync(uv_loop_t* loop,
return err;
}
int CallMKDirpSync (Environment* env, const FunctionCallbackInfo<Value>& args,
FSReqWrapSync* req_wrap, const char * path, int mode) {
env->PrintSyncTrace ();
int err = MKDirpSync (env->event_loop (), &req_wrap->req , path, mode,
nullptr );
if (err < 0 ) {
v8::Local<v8::Context> context = env->context ();
v8::Local<v8::Object> ctx_obj = args[4 ].As <v8::Object>();
v8::Isolate* isolate = env->isolate ();
ctx_obj->Set (context,
env->errno_string (),
v8::Integer::New (isolate, err)).Check ();
ctx_obj->Set (context,
env->syscall_string (),
OneByteString (isolate, " mkdir" )).Check ();
}
return err;
}
static void MKDir (const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent (args);
@@ -1382,14 +1448,29 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
FSReqBase* req_wrap_async = GetReqWrap (env, args[3 ]);
if (req_wrap_async != nullptr ) { // mkdir(path, mode, req)
AsyncCall (env, req_wrap_async, args, " mkdir" , UTF8,
AfterNoArgs, mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
mkdirp ? AfterMkdirp : AfterNoArgs,
mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
} else { // mkdir(path, mode, undefined, ctx)
CHECK_EQ (argc, 5 );
FSReqWrapSync req_wrap_sync;
FS_SYNC_TRACE_BEGIN (mkdir);
if (mkdirp) {
SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
MKDirpSync, *path, mode);
int err = CallMKDirpSync (env, args, &req_wrap_sync, *path, mode);
if (err == 0 &&
!req_wrap_sync.continuation_data ()->first_path ().empty ()) {
Local<Value> error;
std::string first_path (req_wrap_sync.continuation_data ()->first_path ());
FromNamespacedPath (&first_path);
MaybeLocal<Value> path = StringBytes::Encode (env->isolate (),
first_path.c_str (),
UTF8, &error);
if (path.IsEmpty ()) {
Local<Object> ctx = args[4 ].As <Object>();
ctx->Set (env->context (), env->error_string (), error).Check ();
return ;
}
args.GetReturnValue ().Set (path.ToLocalChecked ());
}
} else {
SyncCall (env, args[4 ], &req_wrap_sync, " mkdir" ,
uv_fs_mkdir, *path, mode);
0 comments on commit
13fe56b