11cb0ef41Sopenharmony_ci// This file is a modified version of the rimraf module on npm. It has been
21cb0ef41Sopenharmony_ci// modified in the following ways:
31cb0ef41Sopenharmony_ci// - Use of the assert module has been replaced with core's error system.
41cb0ef41Sopenharmony_ci// - All code related to the glob dependency has been removed.
51cb0ef41Sopenharmony_ci// - Bring your own custom fs module is not currently supported.
61cb0ef41Sopenharmony_ci// - Some basic code cleanup.
71cb0ef41Sopenharmony_ci'use strict';
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst {
101cb0ef41Sopenharmony_ci  ArrayPrototypeForEach,
111cb0ef41Sopenharmony_ci  Promise,
121cb0ef41Sopenharmony_ci  SafeSet,
131cb0ef41Sopenharmony_ci} = primordials;
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciconst { Buffer } = require('buffer');
161cb0ef41Sopenharmony_ciconst fs = require('fs');
171cb0ef41Sopenharmony_ciconst {
181cb0ef41Sopenharmony_ci  chmod,
191cb0ef41Sopenharmony_ci  chmodSync,
201cb0ef41Sopenharmony_ci  lstat,
211cb0ef41Sopenharmony_ci  lstatSync,
221cb0ef41Sopenharmony_ci  readdir,
231cb0ef41Sopenharmony_ci  readdirSync,
241cb0ef41Sopenharmony_ci  rmdir,
251cb0ef41Sopenharmony_ci  rmdirSync,
261cb0ef41Sopenharmony_ci  stat,
271cb0ef41Sopenharmony_ci  statSync,
281cb0ef41Sopenharmony_ci  unlink,
291cb0ef41Sopenharmony_ci  unlinkSync,
301cb0ef41Sopenharmony_ci} = fs;
311cb0ef41Sopenharmony_ciconst { sep } = require('path');
321cb0ef41Sopenharmony_ciconst { setTimeout } = require('timers');
331cb0ef41Sopenharmony_ciconst { sleep } = require('internal/util');
341cb0ef41Sopenharmony_ciconst notEmptyErrorCodes = new SafeSet(['ENOTEMPTY', 'EEXIST', 'EPERM']);
351cb0ef41Sopenharmony_ciconst retryErrorCodes = new SafeSet(
361cb0ef41Sopenharmony_ci  ['EBUSY', 'EMFILE', 'ENFILE', 'ENOTEMPTY', 'EPERM']);
371cb0ef41Sopenharmony_ciconst isWindows = process.platform === 'win32';
381cb0ef41Sopenharmony_ciconst epermHandler = isWindows ? fixWinEPERM : _rmdir;
391cb0ef41Sopenharmony_ciconst epermHandlerSync = isWindows ? fixWinEPERMSync : _rmdirSync;
401cb0ef41Sopenharmony_ciconst readdirEncoding = 'buffer';
411cb0ef41Sopenharmony_ciconst separator = Buffer.from(sep);
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cifunction rimraf(path, options, callback) {
451cb0ef41Sopenharmony_ci  let retries = 0;
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  _rimraf(path, options, function CB(err) {
481cb0ef41Sopenharmony_ci    if (err) {
491cb0ef41Sopenharmony_ci      if (retryErrorCodes.has(err.code) && retries < options.maxRetries) {
501cb0ef41Sopenharmony_ci        retries++;
511cb0ef41Sopenharmony_ci        const delay = retries * options.retryDelay;
521cb0ef41Sopenharmony_ci        return setTimeout(_rimraf, delay, path, options, CB);
531cb0ef41Sopenharmony_ci      }
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci      // The file is already gone.
561cb0ef41Sopenharmony_ci      if (err.code === 'ENOENT')
571cb0ef41Sopenharmony_ci        err = null;
581cb0ef41Sopenharmony_ci    }
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci    callback(err);
611cb0ef41Sopenharmony_ci  });
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_cifunction _rimraf(path, options, callback) {
661cb0ef41Sopenharmony_ci  // SunOS lets the root user unlink directories. Use lstat here to make sure
671cb0ef41Sopenharmony_ci  // it's not a directory.
681cb0ef41Sopenharmony_ci  lstat(path, (err, stats) => {
691cb0ef41Sopenharmony_ci    if (err) {
701cb0ef41Sopenharmony_ci      if (err.code === 'ENOENT')
711cb0ef41Sopenharmony_ci        return callback(null);
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci      // Windows can EPERM on stat.
741cb0ef41Sopenharmony_ci      if (isWindows && err.code === 'EPERM')
751cb0ef41Sopenharmony_ci        return fixWinEPERM(path, options, err, callback);
761cb0ef41Sopenharmony_ci    } else if (stats.isDirectory()) {
771cb0ef41Sopenharmony_ci      return _rmdir(path, options, err, callback);
781cb0ef41Sopenharmony_ci    }
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci    unlink(path, (err) => {
811cb0ef41Sopenharmony_ci      if (err) {
821cb0ef41Sopenharmony_ci        if (err.code === 'ENOENT')
831cb0ef41Sopenharmony_ci          return callback(null);
841cb0ef41Sopenharmony_ci        if (err.code === 'EISDIR')
851cb0ef41Sopenharmony_ci          return _rmdir(path, options, err, callback);
861cb0ef41Sopenharmony_ci        if (err.code === 'EPERM') {
871cb0ef41Sopenharmony_ci          return epermHandler(path, options, err, callback);
881cb0ef41Sopenharmony_ci        }
891cb0ef41Sopenharmony_ci      }
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci      return callback(err);
921cb0ef41Sopenharmony_ci    });
931cb0ef41Sopenharmony_ci  });
941cb0ef41Sopenharmony_ci}
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_cifunction fixWinEPERM(path, options, originalErr, callback) {
981cb0ef41Sopenharmony_ci  chmod(path, 0o666, (err) => {
991cb0ef41Sopenharmony_ci    if (err)
1001cb0ef41Sopenharmony_ci      return callback(err.code === 'ENOENT' ? null : originalErr);
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci    stat(path, (err, stats) => {
1031cb0ef41Sopenharmony_ci      if (err)
1041cb0ef41Sopenharmony_ci        return callback(err.code === 'ENOENT' ? null : originalErr);
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci      if (stats.isDirectory())
1071cb0ef41Sopenharmony_ci        _rmdir(path, options, originalErr, callback);
1081cb0ef41Sopenharmony_ci      else
1091cb0ef41Sopenharmony_ci        unlink(path, callback);
1101cb0ef41Sopenharmony_ci    });
1111cb0ef41Sopenharmony_ci  });
1121cb0ef41Sopenharmony_ci}
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_cifunction _rmdir(path, options, originalErr, callback) {
1161cb0ef41Sopenharmony_ci  rmdir(path, (err) => {
1171cb0ef41Sopenharmony_ci    if (err) {
1181cb0ef41Sopenharmony_ci      if (notEmptyErrorCodes.has(err.code))
1191cb0ef41Sopenharmony_ci        return _rmchildren(path, options, callback);
1201cb0ef41Sopenharmony_ci      if (err.code === 'ENOTDIR')
1211cb0ef41Sopenharmony_ci        return callback(originalErr);
1221cb0ef41Sopenharmony_ci    }
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci    callback(err);
1251cb0ef41Sopenharmony_ci  });
1261cb0ef41Sopenharmony_ci}
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_cifunction _rmchildren(path, options, callback) {
1301cb0ef41Sopenharmony_ci  const pathBuf = Buffer.from(path);
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  readdir(pathBuf, readdirEncoding, (err, files) => {
1331cb0ef41Sopenharmony_ci    if (err)
1341cb0ef41Sopenharmony_ci      return callback(err);
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci    let numFiles = files.length;
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci    if (numFiles === 0)
1391cb0ef41Sopenharmony_ci      return rmdir(path, callback);
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    let done = false;
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci    ArrayPrototypeForEach(files, (child) => {
1441cb0ef41Sopenharmony_ci      const childPath = Buffer.concat([pathBuf, separator, child]);
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci      rimraf(childPath, options, (err) => {
1471cb0ef41Sopenharmony_ci        if (done)
1481cb0ef41Sopenharmony_ci          return;
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci        if (err) {
1511cb0ef41Sopenharmony_ci          done = true;
1521cb0ef41Sopenharmony_ci          return callback(err);
1531cb0ef41Sopenharmony_ci        }
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci        numFiles--;
1561cb0ef41Sopenharmony_ci        if (numFiles === 0)
1571cb0ef41Sopenharmony_ci          rmdir(path, callback);
1581cb0ef41Sopenharmony_ci      });
1591cb0ef41Sopenharmony_ci    });
1601cb0ef41Sopenharmony_ci  });
1611cb0ef41Sopenharmony_ci}
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_cifunction rimrafPromises(path, options) {
1651cb0ef41Sopenharmony_ci  return new Promise((resolve, reject) => {
1661cb0ef41Sopenharmony_ci    rimraf(path, options, (err) => {
1671cb0ef41Sopenharmony_ci      if (err)
1681cb0ef41Sopenharmony_ci        return reject(err);
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci      resolve();
1711cb0ef41Sopenharmony_ci    });
1721cb0ef41Sopenharmony_ci  });
1731cb0ef41Sopenharmony_ci}
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_cifunction rimrafSync(path, options) {
1771cb0ef41Sopenharmony_ci  let stats;
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  try {
1801cb0ef41Sopenharmony_ci    stats = lstatSync(path);
1811cb0ef41Sopenharmony_ci  } catch (err) {
1821cb0ef41Sopenharmony_ci    if (err.code === 'ENOENT')
1831cb0ef41Sopenharmony_ci      return;
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci    // Windows can EPERM on stat.
1861cb0ef41Sopenharmony_ci    if (isWindows && err.code === 'EPERM')
1871cb0ef41Sopenharmony_ci      fixWinEPERMSync(path, options, err);
1881cb0ef41Sopenharmony_ci  }
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  try {
1911cb0ef41Sopenharmony_ci    // SunOS lets the root user unlink directories.
1921cb0ef41Sopenharmony_ci    if (stats?.isDirectory())
1931cb0ef41Sopenharmony_ci      _rmdirSync(path, options, null);
1941cb0ef41Sopenharmony_ci    else
1951cb0ef41Sopenharmony_ci      _unlinkSync(path, options);
1961cb0ef41Sopenharmony_ci  } catch (err) {
1971cb0ef41Sopenharmony_ci    if (err.code === 'ENOENT')
1981cb0ef41Sopenharmony_ci      return;
1991cb0ef41Sopenharmony_ci    if (err.code === 'EPERM')
2001cb0ef41Sopenharmony_ci      return epermHandlerSync(path, options, err);
2011cb0ef41Sopenharmony_ci    if (err.code !== 'EISDIR')
2021cb0ef41Sopenharmony_ci      throw err;
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci    _rmdirSync(path, options, err);
2051cb0ef41Sopenharmony_ci  }
2061cb0ef41Sopenharmony_ci}
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_cifunction _unlinkSync(path, options) {
2101cb0ef41Sopenharmony_ci  const tries = options.maxRetries + 1;
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci  for (let i = 1; i <= tries; i++) {
2131cb0ef41Sopenharmony_ci    try {
2141cb0ef41Sopenharmony_ci      return unlinkSync(path);
2151cb0ef41Sopenharmony_ci    } catch (err) {
2161cb0ef41Sopenharmony_ci      // Only sleep if this is not the last try, and the delay is greater
2171cb0ef41Sopenharmony_ci      // than zero, and an error was encountered that warrants a retry.
2181cb0ef41Sopenharmony_ci      if (retryErrorCodes.has(err.code) &&
2191cb0ef41Sopenharmony_ci          i < tries &&
2201cb0ef41Sopenharmony_ci          options.retryDelay > 0) {
2211cb0ef41Sopenharmony_ci        sleep(i * options.retryDelay);
2221cb0ef41Sopenharmony_ci      } else if (err.code === 'ENOENT') {
2231cb0ef41Sopenharmony_ci        // The file is already gone.
2241cb0ef41Sopenharmony_ci        return;
2251cb0ef41Sopenharmony_ci      } else if (i === tries) {
2261cb0ef41Sopenharmony_ci        throw err;
2271cb0ef41Sopenharmony_ci      }
2281cb0ef41Sopenharmony_ci    }
2291cb0ef41Sopenharmony_ci  }
2301cb0ef41Sopenharmony_ci}
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_cifunction _rmdirSync(path, options, originalErr) {
2341cb0ef41Sopenharmony_ci  try {
2351cb0ef41Sopenharmony_ci    rmdirSync(path);
2361cb0ef41Sopenharmony_ci  } catch (err) {
2371cb0ef41Sopenharmony_ci    if (err.code === 'ENOENT')
2381cb0ef41Sopenharmony_ci      return;
2391cb0ef41Sopenharmony_ci    if (err.code === 'ENOTDIR') {
2401cb0ef41Sopenharmony_ci      throw originalErr || err;
2411cb0ef41Sopenharmony_ci    }
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci    if (notEmptyErrorCodes.has(err.code)) {
2441cb0ef41Sopenharmony_ci      // Removing failed. Try removing all children and then retrying the
2451cb0ef41Sopenharmony_ci      // original removal. Windows has a habit of not closing handles promptly
2461cb0ef41Sopenharmony_ci      // when files are deleted, resulting in spurious ENOTEMPTY failures. Work
2471cb0ef41Sopenharmony_ci      // around that issue by retrying on Windows.
2481cb0ef41Sopenharmony_ci      const pathBuf = Buffer.from(path);
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci      ArrayPrototypeForEach(readdirSync(pathBuf, readdirEncoding), (child) => {
2511cb0ef41Sopenharmony_ci        const childPath = Buffer.concat([pathBuf, separator, child]);
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci        rimrafSync(childPath, options);
2541cb0ef41Sopenharmony_ci      });
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci      const tries = options.maxRetries + 1;
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci      for (let i = 1; i <= tries; i++) {
2591cb0ef41Sopenharmony_ci        try {
2601cb0ef41Sopenharmony_ci          return fs.rmdirSync(path);
2611cb0ef41Sopenharmony_ci        } catch (err) {
2621cb0ef41Sopenharmony_ci          // Only sleep if this is not the last try, and the delay is greater
2631cb0ef41Sopenharmony_ci          // than zero, and an error was encountered that warrants a retry.
2641cb0ef41Sopenharmony_ci          if (retryErrorCodes.has(err.code) &&
2651cb0ef41Sopenharmony_ci              i < tries &&
2661cb0ef41Sopenharmony_ci              options.retryDelay > 0) {
2671cb0ef41Sopenharmony_ci            sleep(i * options.retryDelay);
2681cb0ef41Sopenharmony_ci          } else if (err.code === 'ENOENT') {
2691cb0ef41Sopenharmony_ci            // The file is already gone.
2701cb0ef41Sopenharmony_ci            return;
2711cb0ef41Sopenharmony_ci          } else if (i === tries) {
2721cb0ef41Sopenharmony_ci            throw err;
2731cb0ef41Sopenharmony_ci          }
2741cb0ef41Sopenharmony_ci        }
2751cb0ef41Sopenharmony_ci      }
2761cb0ef41Sopenharmony_ci    }
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci    throw originalErr || err;
2791cb0ef41Sopenharmony_ci  }
2801cb0ef41Sopenharmony_ci}
2811cb0ef41Sopenharmony_ci
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_cifunction fixWinEPERMSync(path, options, originalErr) {
2841cb0ef41Sopenharmony_ci  try {
2851cb0ef41Sopenharmony_ci    chmodSync(path, 0o666);
2861cb0ef41Sopenharmony_ci  } catch (err) {
2871cb0ef41Sopenharmony_ci    if (err.code === 'ENOENT')
2881cb0ef41Sopenharmony_ci      return;
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci    throw originalErr;
2911cb0ef41Sopenharmony_ci  }
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci  let stats;
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci  try {
2961cb0ef41Sopenharmony_ci    stats = statSync(path, { throwIfNoEntry: false });
2971cb0ef41Sopenharmony_ci  } catch {
2981cb0ef41Sopenharmony_ci    throw originalErr;
2991cb0ef41Sopenharmony_ci  }
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci  if (stats === undefined) return;
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_ci  if (stats.isDirectory())
3041cb0ef41Sopenharmony_ci    _rmdirSync(path, options, originalErr);
3051cb0ef41Sopenharmony_ci  else
3061cb0ef41Sopenharmony_ci    _unlinkSync(path, options);
3071cb0ef41Sopenharmony_ci}
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_cimodule.exports = { rimraf, rimrafPromises, rimrafSync };
311