简体   繁体   中英

Error: "EPERM: operation not permitted" while remove directory not emty


I'm trying to remove folder which is not empty in Nodejs file system. All folder inside root folder was removed, but the root folder was not removed. I try again with empty folder, it success!

const rmDir =  (dirPath) => {
  try { var files = fs.readdirSync(dirPath); }
  catch(e) { return; }
  if (files.length > 0)
    for (var i = 0; i < files.length; i++) {
      var filePath = dirPath + '/' + files[i];
      if (fs.statSync(filePath).isFile())
        fs.unlinkSync(filePath);
      else
        rmDir(filePath);
    }
  fs.rmdirSync(dirPath);
  return true;
}


Here is the error:

(node:16108) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: ENOTEMPTY: directory not empty, rmdir '{dir}'
(node:16108) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

You can make it work recursively. Like this:

var fs = require('fs');
var deleteFolderRecursive = function(path) {
  if (fs.existsSync(path)) {
    fs.readdirSync(path).forEach(function(file, index){
      var curPath = path + "/" + file;
      if (fs.lstatSync(curPath).isDirectory()) { // recurse
        deleteFolderRecursive(curPath);
      } else { // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
};

Or you could try with this package (rimraf) .

fs use shell commands. To remove a folder fs use rm without -rf so you can't force it. Hope it helped.

Preamble

This is a supplementary answer. EPERM (see comments ) error code may also be caused by a file under the path being unlinked still being in use. I encountered this issue while setting up a cleanup process after unit testing with Mocha.

Problem

Unlinking files with unlink() or unlinkSync() may not work as expected on Windows, because files aren't actually deleted, but basically marked to be deleted once all file handles are released (see the related question ).

Thus, for example, despite unlinkSync() successfully "deleting" the file, when rmdirSync() gets to the containing folder, it might fail with ENOTEMPTY since, from the filesystem point of view, the file is still there.

There is not much you can do if the file is in use by processes you don't control apart from polling for the file becoming available (see this question ), but if you just need to do a cleanup - spawn a child process right before exiting from the process:

//parent process
const { spawn } = require('child_process');

/**
 * @summary Spawns a completely detached child
 * @param {NodeJS.Process} parent 
 * @param {string} path 
 * @param {object} env 
 * @return {NodeJS.Process}
 */
const spawnResponsible = (parent, path, env) => {
    const child = spawn(parent.argv0, [path], {
        env,
        detached: true,
        stdio: "ignore"
    });

    child.unref();

    return child;
};

process.once('beforeExit', () => {
  spawnResponsible(
    process,
    'path to your child process script file',
    { PATHS: [] } // an array of paths
  );
});

Your child process might look like this (note that using sync methods is not recommended unless you are doing a setup or cleanup and cannot proceed without [using child process partially solves the problem, but at the expense of additional process running]):

// child process

const fs = require('fs');
const pt = require('path');

const { PATHS } = process.env;

/**
 * @summary Cleans root path and subpaths
 * @param {string} rootPath 
 */
const cleanOfEntries = (rootPath) => {
    if (fs.existsSync(rootPath)) {

        const entries = fs.readdirSync(rootPath, { withFileTypes: true });

        for (const entry of entries) {
            const thisPath = pt.resolve(rootPath, entry.name);

            if (fs.existsSync(thisPath)) {
                entry.isDirectory() && cleanOfEntries(thisPath);
                entry.isFile() && fs.unlinkSync(thisPath);
            }
        }

        fs.rmdirSync(rootPath);
    }
};

for (const path of PATHS.split(',')) {
    cleanOfEntries(path);
}

References

  1. unlinkSync
  2. spawn
  3. rmdirSync

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM