summaryrefslogtreecommitdiff
path: root/src/node_file.cc
diff options
context:
space:
mode:
authorRichard Lau <riclau@uk.ibm.com>2019-04-13 02:29:01 +0100
committerRichard Lau <riclau@uk.ibm.com>2019-04-16 13:59:43 -0400
commit2400cbcf7c6b3c35c96b199676cb8a577f6e701a (patch)
tree514e71b8c1328aedd3c9e8e6a2307786344e149d /src/node_file.cc
parent96e46d37c458ab3d6cf1148a471cfd1aac7aafe6 (diff)
downloadandroid-node-v8-2400cbcf7c6b3c35c96b199676cb8a577f6e701a.tar.gz
android-node-v8-2400cbcf7c6b3c35c96b199676cb8a577f6e701a.tar.bz2
android-node-v8-2400cbcf7c6b3c35c96b199676cb8a577f6e701a.zip
fs: fix infinite loop with async recursive mkdir on Windows
If `file` is a file then on Windows `mkdir` on `file/a` returns an `ENOENT` error while on POSIX the equivalent returns `ENOTDIR`. On the POSIX systems `ENOTDIR` would break out of the loop but on Windows the `ENOENT` would strip off the `a` and attempt to make `file` as a directory. This would return `EEXIST` but the code wasn't detecting that the existing path was a file and attempted to make `file/a` again. PR-URL: https://github.com/nodejs/node/pull/27207 Fixes: https://github.com/nodejs/node/issues/27198 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com> Reviewed-By: Ben Coe <bencoe@gmail.com>
Diffstat (limited to 'src/node_file.cc')
-rw-r--r--src/node_file.cc48
1 files changed, 32 insertions, 16 deletions
diff --git a/src/node_file.cc b/src/node_file.cc
index e1acf82408..5d3b48cfa4 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -1270,8 +1270,15 @@ int MKDirpSync(uv_loop_t* loop,
}
default:
uv_fs_req_cleanup(req);
+ int orig_err = err;
err = uv_fs_stat(loop, req, next_path.c_str(), nullptr);
- if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) return UV_EEXIST;
+ if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) {
+ uv_fs_req_cleanup(req);
+ if (orig_err == UV_EEXIST && continuation_data.paths.size() > 0) {
+ return UV_ENOTDIR;
+ }
+ return UV_EEXIST;
+ }
if (err < 0) return err;
break;
}
@@ -1338,23 +1345,32 @@ int MKDirpAsync(uv_loop_t* loop,
break;
}
default:
- if (err == UV_EEXIST &&
- req_wrap->continuation_data->paths.size() > 0) {
- uv_fs_req_cleanup(req);
- MKDirpAsync(loop, req, path.c_str(),
- req_wrap->continuation_data->mode, nullptr);
- } else {
+ uv_fs_req_cleanup(req);
+ // Stash err for use in the callback.
+ req->data = reinterpret_cast<void*>(static_cast<intptr_t>(err));
+ int err = uv_fs_stat(loop, req, path.c_str(),
+ uv_fs_callback_t{[](uv_fs_t* req) {
+ FSReqBase* req_wrap = FSReqBase::from_req(req);
+ int err = req->result;
+ if (reinterpret_cast<intptr_t>(req->data) == UV_EEXIST &&
+ req_wrap->continuation_data->paths.size() > 0) {
+ if (err == 0 && S_ISDIR(req->statbuf.st_mode)) {
+ Environment* env = req_wrap->env();
+ uv_loop_t* loop = env->event_loop();
+ std::string path = req->path;
+ uv_fs_req_cleanup(req);
+ MKDirpAsync(loop, req, path.c_str(),
+ req_wrap->continuation_data->mode, nullptr);
+ return;
+ }
+ err = UV_ENOTDIR;
+ }
// verify that the path pointed to is actually a directory.
+ if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
uv_fs_req_cleanup(req);
- int err = uv_fs_stat(loop, req, path.c_str(),
- uv_fs_callback_t{[](uv_fs_t* req) {
- FSReqBase* req_wrap = FSReqBase::from_req(req);
- int err = req->result;
- if (err == 0 && !S_ISDIR(req->statbuf.st_mode)) err = UV_EEXIST;
- req_wrap->continuation_data->Done(err);
- }});
- if (err < 0) req_wrap->continuation_data->Done(err);
- }
+ req_wrap->continuation_data->Done(err);
+ }});
+ if (err < 0) req_wrap->continuation_data->Done(err);
break;
}
break;