rimraf-posix.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // the simple recursive removal, where unlink and rmdir are atomic
  2. // Note that this approach does NOT work on Windows!
  3. // We stat first and only unlink if the Dirent isn't a directory,
  4. // because sunos will let root unlink a directory, and some
  5. // SUPER weird breakage happens as a result.
  6. import { lstatSync, promises, rmdirSync, unlinkSync } from './fs.js';
  7. const { lstat, rmdir, unlink } = promises;
  8. import { parse, resolve } from 'path';
  9. import { readdirOrError, readdirOrErrorSync } from './readdir-or-error.js';
  10. import { ignoreENOENT, ignoreENOENTSync } from './ignore-enoent.js';
  11. export const rimrafPosix = async (path, opt) => {
  12. if (opt?.signal?.aborted) {
  13. throw opt.signal.reason;
  14. }
  15. try {
  16. return await rimrafPosixDir(path, opt, await lstat(path));
  17. }
  18. catch (er) {
  19. if (er?.code === 'ENOENT')
  20. return true;
  21. throw er;
  22. }
  23. };
  24. export const rimrafPosixSync = (path, opt) => {
  25. if (opt?.signal?.aborted) {
  26. throw opt.signal.reason;
  27. }
  28. try {
  29. return rimrafPosixDirSync(path, opt, lstatSync(path));
  30. }
  31. catch (er) {
  32. if (er?.code === 'ENOENT')
  33. return true;
  34. throw er;
  35. }
  36. };
  37. const rimrafPosixDir = async (path, opt, ent) => {
  38. if (opt?.signal?.aborted) {
  39. throw opt.signal.reason;
  40. }
  41. const entries = ent.isDirectory() ? await readdirOrError(path) : null;
  42. if (!Array.isArray(entries)) {
  43. // this can only happen if lstat/readdir lied, or if the dir was
  44. // swapped out with a file at just the right moment.
  45. /* c8 ignore start */
  46. if (entries) {
  47. if (entries.code === 'ENOENT') {
  48. return true;
  49. }
  50. if (entries.code !== 'ENOTDIR') {
  51. throw entries;
  52. }
  53. }
  54. /* c8 ignore stop */
  55. if (opt.filter && !(await opt.filter(path, ent))) {
  56. return false;
  57. }
  58. await ignoreENOENT(unlink(path));
  59. return true;
  60. }
  61. const removedAll = (await Promise.all(entries.map(ent => rimrafPosixDir(resolve(path, ent.name), opt, ent)))).reduce((a, b) => a && b, true);
  62. if (!removedAll) {
  63. return false;
  64. }
  65. // we don't ever ACTUALLY try to unlink /, because that can never work
  66. // but when preserveRoot is false, we could be operating on it.
  67. // No need to check if preserveRoot is not false.
  68. if (opt.preserveRoot === false && path === parse(path).root) {
  69. return false;
  70. }
  71. if (opt.filter && !(await opt.filter(path, ent))) {
  72. return false;
  73. }
  74. await ignoreENOENT(rmdir(path));
  75. return true;
  76. };
  77. const rimrafPosixDirSync = (path, opt, ent) => {
  78. if (opt?.signal?.aborted) {
  79. throw opt.signal.reason;
  80. }
  81. const entries = ent.isDirectory() ? readdirOrErrorSync(path) : null;
  82. if (!Array.isArray(entries)) {
  83. // this can only happen if lstat/readdir lied, or if the dir was
  84. // swapped out with a file at just the right moment.
  85. /* c8 ignore start */
  86. if (entries) {
  87. if (entries.code === 'ENOENT') {
  88. return true;
  89. }
  90. if (entries.code !== 'ENOTDIR') {
  91. throw entries;
  92. }
  93. }
  94. /* c8 ignore stop */
  95. if (opt.filter && !opt.filter(path, ent)) {
  96. return false;
  97. }
  98. ignoreENOENTSync(() => unlinkSync(path));
  99. return true;
  100. }
  101. let removedAll = true;
  102. for (const ent of entries) {
  103. const p = resolve(path, ent.name);
  104. removedAll = rimrafPosixDirSync(p, opt, ent) && removedAll;
  105. }
  106. if (opt.preserveRoot === false && path === parse(path).root) {
  107. return false;
  108. }
  109. if (!removedAll) {
  110. return false;
  111. }
  112. if (opt.filter && !opt.filter(path, ent)) {
  113. return false;
  114. }
  115. ignoreENOENTSync(() => rmdirSync(path));
  116. return true;
  117. };
  118. //# sourceMappingURL=rimraf-posix.js.map