-
-
Save drsm/38714fecb523293d70296741cb62eb02 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User Artem S. Povalyukhin <artem.povaluhin@gmail.com> | |
# Date 1595681343 -10800 | |
# Sat Jul 25 15:49:03 2020 +0300 | |
# Node ID 4c7f4fe1136d7961ac242277e8ab23bc4c8d1c9c | |
# Parent cb2ff67e595dcb885d53f41879f13dcdc511a59e | |
Improved fs.rmdir() to support recursive directory removal. | |
diff -r cb2ff67e595d -r 4c7f4fe1136d src/njs_fs.c | |
--- a/src/njs_fs.c Wed Jul 15 15:51:06 2020 +0300 | |
+++ b/src/njs_fs.c Sat Jul 25 15:49:03 2020 +0300 | |
@@ -8,6 +8,7 @@ | |
#include <njs_main.h> | |
#include <dirent.h> | |
+#include <ftw.h> | |
#if (NJS_SOLARIS) | |
@@ -73,6 +74,9 @@ static njs_int_t njs_fs_result(njs_vm_t | |
static njs_int_t njs_fs_make_path(njs_vm_t *vm, const char *path, mode_t md, | |
njs_bool_t recursive, njs_value_t *retval); | |
+static njs_int_t njs_fs_rmtree(njs_vm_t *vm, const char *path, | |
+ njs_bool_t recursive, njs_value_t *retval); | |
+ | |
static int njs_fs_flags(njs_vm_t *vm, njs_value_t *value, int default_flags); | |
static mode_t njs_fs_mode(njs_vm_t *vm, njs_value_t *value, | |
mode_t default_mode); | |
@@ -893,18 +897,7 @@ njs_fs_rmdir(njs_vm_t *vm, njs_value_t * | |
} | |
} | |
- if (njs_is_true(&recursive)) { | |
- njs_type_error(vm, "\"options.recursive\" is not supported"); | |
- return NJS_ERROR; | |
- } | |
- | |
- njs_set_undefined(&retval); | |
- | |
- ret = rmdir(file_path); | |
- if (njs_slow_path(ret != 0)) { | |
- ret = njs_fs_error(vm, "rmdir", strerror(errno), path, errno, | |
- &retval); | |
- } | |
+ ret = njs_fs_rmtree(vm, file_path, njs_is_true(&recursive), &retval); | |
if (ret == NJS_OK) { | |
return njs_fs_result(vm, &retval, calltype, callback, 1); | |
@@ -1229,6 +1222,62 @@ failed: | |
static int | |
+njs_fs_rmtree_cb(const char *path, const struct stat *sb, int flag, | |
+ struct FTW *ftwbuf) | |
+{ | |
+ njs_int_t ret; | |
+ | |
+ ret = remove(path); | |
+ if (ret != 0) { | |
+ return -1; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+ | |
+static njs_int_t | |
+njs_fs_rmtree(njs_vm_t *vm, const char *path, njs_bool_t recursive, | |
+ njs_value_t *retval) | |
+{ | |
+ size_t size; | |
+ ssize_t length; | |
+ njs_int_t ret; | |
+ njs_value_t value; | |
+ | |
+ njs_set_undefined(retval); | |
+ | |
+ ret = rmdir(path); | |
+ if (ret == 0) { | |
+ return NJS_OK; | |
+ } | |
+ | |
+ if (recursive && errno == ENOTEMPTY) { | |
+ ret = nftw(path, njs_fs_rmtree_cb, 16, | |
+ FTW_DEPTH | FTW_PHYS | FTW_MOUNT); | |
+ | |
+ if (ret == 0) { | |
+ return NJS_OK; | |
+ } | |
+ } | |
+ | |
+ size = njs_strlen(path); | |
+ length = njs_utf8_length((u_char *) path, size); | |
+ if (njs_slow_path(length < 0)) { | |
+ length = 0; | |
+ } | |
+ | |
+ ret = njs_string_new(vm, &value, (u_char *) path, size, length); | |
+ if (ret != NJS_OK) { | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ return njs_fs_error(vm, "rmdir", strerror(errno), &value, errno, | |
+ retval); | |
+} | |
+ | |
+ | |
+static int | |
njs_fs_flags(njs_vm_t *vm, njs_value_t *value, int default_flags) | |
{ | |
njs_str_t flags; | |
diff -r cb2ff67e595d -r 4c7f4fe1136d test/js/fs_promises_009.js | |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 | |
+++ b/test/js/fs_promises_009.js Sat Jul 25 15:49:03 2020 +0300 | |
@@ -0,0 +1,106 @@ | |
+var fs = require('fs'); | |
+var fsp = fs.promises; | |
+var root = './build/test/'; | |
+var dname = 'fs_promises_αβγ_009/'; | |
+var lname = 'fs_promises_αβγ_009_lnk'; | |
+var path = 'one/two/three/αβγ'; | |
+ | |
+ | |
+var setContent = (root, path) => { | |
+ fs.mkdirSync(root + path, { recursive: true }); | |
+ path | |
+ .split('/') | |
+ .forEach((x, i, a) => { | |
+ for (var j = 1; j < 10; ++j) { | |
+ var path = root + a.slice(0, i + 1).join('/') + '_file' + j; | |
+ fs.writeFileSync(path, path); | |
+ } | |
+ }); | |
+}; | |
+ | |
+ | |
+var isNode = () => process.argv[0].includes('node'); | |
+ | |
+ | |
+var testSync = () => new Promise((resolve, reject) => { | |
+ try { | |
+ fs.unlinkSync(root + lname); | |
+ } catch (e) { | |
+ } | |
+ try { | |
+ fs.rmdirSync(root + dname, { recursive: true }); | |
+ } catch (e) { | |
+ } | |
+ | |
+ try { | |
+ | |
+ fs.mkdirSync(root + dname); | |
+ fs.symlinkSync(dname, root + lname); | |
+ try { | |
+ fs.rmdirSync(root + lname); | |
+ throw new Error('fs.rmdirSync() - error 0'); | |
+ } catch (e) { | |
+ if (e.code != "ENOTDIR") { | |
+ throw e; | |
+ } | |
+ } | |
+ fs.rmdirSync(root + dname); | |
+ fs.unlinkSync(root + lname); | |
+ | |
+ if (!isNode()) { | |
+ fs.mkdirSync(root + dname); | |
+ fs.symlinkSync(dname, root + lname); | |
+ try { | |
+ fs.rmdirSync(root + lname, { recursive: true }); | |
+ throw new Error('fs.rmdirSync() - error 1'); | |
+ } catch (e) { | |
+ if (e.code != "ENOTDIR") { | |
+ throw e; | |
+ } | |
+ } | |
+ fs.rmdirSync(root + dname); | |
+ fs.unlinkSync(root + lname); | |
+ } | |
+ | |
+ fs.mkdirSync(root + dname, { mode: 0 }); | |
+ fs.rmdirSync(root + dname, { recursive: true }); | |
+ | |
+ setContent(root + dname, path); | |
+ fs.rmdirSync(root + dname, { recursive: true }); | |
+ | |
+ try { | |
+ fs.accessSync(root + dname); | |
+ throw new Error('fs.rmdirSync() - error 2'); | |
+ } catch (e) { | |
+ if (e.code != "ENOENT") { | |
+ throw e; | |
+ } | |
+ } | |
+ | |
+ if (!isNode()) { | |
+ try { | |
+ fs.rmdirSync(root + dname, { recursive: true }); | |
+ throw new Error('fs.rmdirSync() - error 3'); | |
+ } catch (e) { | |
+ if (e.code != "ENOENT") { | |
+ throw e; | |
+ } | |
+ } | |
+ } | |
+ | |
+ resolve(); | |
+ | |
+ } catch (e) { | |
+ reject(e); | |
+ } | |
+}); | |
+ | |
+ | |
+Promise.resolve() | |
+.then(testSync) | |
+.then(() => { | |
+ console.log('test recursive fs.rmdirSync()'); | |
+}) | |
+.catch((e) => { | |
+ console.log('test failed recursive fs.rmdirSync()', e.message, JSON.stringify(e)); | |
+}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment