Skip to content

Instantly share code, notes, and snippets.

@drsm
Last active July 25, 2020 16:58
Show Gist options
  • Save drsm/38714fecb523293d70296741cb62eb02 to your computer and use it in GitHub Desktop.
Save drsm/38714fecb523293d70296741cb62eb02 to your computer and use it in GitHub Desktop.
# 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