tools/node-hermes/nodelib/internal/fs/rimraf.js (203 lines of code) (raw):

// @nolint // This file is a modified version of the rimraf module on npm. It has been // modified in the following ways: // - Use of the assert module has been replaced with core's error system. // - All code related to the glob dependency has been removed. // - Bring your own custom fs module is not currently supported. // - Some basic code cleanup. 'use strict'; var _primordials = primordials, ArrayPrototypeForEach = _primordials.ArrayPrototypeForEach, Promise = _primordials.Promise, SafeSet = _primordials.SafeSet; var _require = require('buffer'), Buffer = _require.Buffer; var fs = require('fs'); var chmod = fs.chmod, chmodSync = fs.chmodSync, lstat = fs.lstat, lstatSync = fs.lstatSync, readdir = fs.readdir, readdirSync = fs.readdirSync, rmdir = fs.rmdir, rmdirSync = fs.rmdirSync, stat = fs.stat, statSync = fs.statSync, unlink = fs.unlink, unlinkSync = fs.unlinkSync; var _require2 = require('path'), sep = _require2.sep; var _require3 = require('timers'), setTimeout = _require3.setTimeout; var _require4 = require('internal/util'), sleep = _require4.sleep; var notEmptyErrorCodes = new SafeSet(['ENOTEMPTY', 'EEXIST', 'EPERM']); var retryErrorCodes = new SafeSet(['EBUSY', 'EMFILE', 'ENFILE', 'ENOTEMPTY', 'EPERM']); var isWindows = process.platform === 'win32'; var epermHandler = isWindows ? fixWinEPERM : _rmdir; var epermHandlerSync = isWindows ? fixWinEPERMSync : _rmdirSync; var readdirEncoding = 'buffer'; var separator = Buffer.from(sep); function rimraf(path, options, callback) { var retries = 0; _rimraf(path, options, function CB(err) { if (err) { if (retryErrorCodes.has(err.code) && retries < options.maxRetries) { retries++; var delay = retries * options.retryDelay; return setTimeout(_rimraf, delay, path, options, CB); } // The file is already gone. if (err.code === 'ENOENT') err = null; } callback(err); }); } function _rimraf(path, options, callback) { // SunOS lets the root user unlink directories. Use lstat here to make sure // it's not a directory. lstat(path, function (err, stats) { if (err) { if (err.code === 'ENOENT') return callback(null); // Windows can EPERM on stat. if (isWindows && err.code === 'EPERM') return fixWinEPERM(path, options, err, callback); } else if (stats.isDirectory()) { return _rmdir(path, options, err, callback); } unlink(path, function (err) { if (err) { if (err.code === 'ENOENT') return callback(null); if (err.code === 'EISDIR') return _rmdir(path, options, err, callback); if (err.code === 'EPERM') { return epermHandler(path, options, err, callback); } } return callback(err); }); }); } function fixWinEPERM(path, options, originalErr, callback) { chmod(path, 438, function (err) { if (err) return callback(err.code === 'ENOENT' ? null : originalErr); stat(path, function (err, stats) { if (err) return callback(err.code === 'ENOENT' ? null : originalErr); if (stats.isDirectory()) _rmdir(path, options, originalErr, callback);else unlink(path, callback); }); }); } function _rmdir(path, options, originalErr, callback) { rmdir(path, function (err) { if (err) { if (notEmptyErrorCodes.has(err.code)) return _rmchildren(path, options, callback); if (err.code === 'ENOTDIR') return callback(originalErr); } callback(err); }); } function _rmchildren(path, options, callback) { var pathBuf = Buffer.from(path); readdir(pathBuf, readdirEncoding, function (err, files) { if (err) return callback(err); var numFiles = files.length; if (numFiles === 0) return rmdir(path, callback); var done = false; ArrayPrototypeForEach(files, function (child) { var childPath = Buffer.concat([pathBuf, separator, child]); rimraf(childPath, options, function (err) { if (done) return; if (err) { done = true; return callback(err); } numFiles--; if (numFiles === 0) rmdir(path, callback); }); }); }); } function rimrafPromises(path, options) { return new Promise(function (resolve, reject) { rimraf(path, options, function (err) { if (err) return reject(err); resolve(); }); }); } function rimrafSync(path, options) { var stats; try { stats = lstatSync(path); } catch (err) { if (err.code === 'ENOENT') return; // Windows can EPERM on stat. if (isWindows && err.code === 'EPERM') fixWinEPERMSync(path, options, err); } try { var _stats; // SunOS lets the root user unlink directories. if ((_stats = stats) !== null && _stats !== void 0 && _stats.isDirectory()) _rmdirSync(path, options, null);else _unlinkSync(path, options); } catch (err) { if (err.code === 'ENOENT') return; if (err.code === 'EPERM') return epermHandlerSync(path, options, err); if (err.code !== 'EISDIR') throw err; _rmdirSync(path, options, err); } } function _unlinkSync(path, options) { var tries = options.maxRetries + 1; for (var i = 1; i <= tries; i++) { try { return unlinkSync(path); } catch (err) { // Only sleep if this is not the last try, and the delay is greater // than zero, and an error was encountered that warrants a retry. if (retryErrorCodes.has(err.code) && i < tries && options.retryDelay > 0) { sleep(i * options.retryDelay); } else if (err.code === 'ENOENT') { // The file is already gone. return; } else if (i === tries) { throw err; } } } } function _rmdirSync(path, options, originalErr) { try { rmdirSync(path); } catch (err) { if (err.code === 'ENOENT') return; if (err.code === 'ENOTDIR') { throw originalErr || err; } if (notEmptyErrorCodes.has(err.code)) { // Removing failed. Try removing all children and then retrying the // original removal. Windows has a habit of not closing handles promptly // when files are deleted, resulting in spurious ENOTEMPTY failures. Work // around that issue by retrying on Windows. var pathBuf = Buffer.from(path); ArrayPrototypeForEach(readdirSync(pathBuf, readdirEncoding), function (child) { var childPath = Buffer.concat([pathBuf, separator, child]); rimrafSync(childPath, options); }); var tries = options.maxRetries + 1; for (var i = 1; i <= tries; i++) { try { return fs.rmdirSync(path); } catch (err) { // Only sleep if this is not the last try, and the delay is greater // than zero, and an error was encountered that warrants a retry. if (retryErrorCodes.has(err.code) && i < tries && options.retryDelay > 0) { sleep(i * options.retryDelay); } else if (err.code === 'ENOENT') { // The file is already gone. return; } else if (i === tries) { throw err; } } } } throw originalErr || err; } } function fixWinEPERMSync(path, options, originalErr) { try { chmodSync(path, 438); } catch (err) { if (err.code === 'ENOENT') return; throw originalErr; } var stats; try { stats = statSync(path, { throwIfNoEntry: false }); } catch (_unused) { throw originalErr; } if (stats === undefined) return; if (stats.isDirectory()) _rmdirSync(path, options, originalErr);else _unlinkSync(path, options); } module.exports = { rimraf: rimraf, rimrafPromises: rimrafPromises, rimrafSync: rimrafSync };