| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent cc0c586 commit a124429
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,7 +24,9 @@ const { | |||
| 24 | 24 | const { sep } = require('path'); | |
| 25 | 25 | const { setTimeout } = require('timers'); | |
| 26 | 26 | const { isWindows } = require('internal/util'); | |
| 27 | - const notEmptyErrorCodes = new SafeSet(['ENOTEMPTY', 'EEXIST', 'EPERM']); | ||
| 27 | + const notEmptyErrorCodes = isWindows ? | ||
| 28 | + new SafeSet(['ENOTEMPTY', 'EEXIST']) : | ||
| 29 | + new SafeSet(['ENOTEMPTY', 'EEXIST', 'EPERM']); | ||
| 28 | 30 | const retryErrorCodes = new SafeSet( | |
| 29 | 31 | ['EBUSY', 'EMFILE', 'ENFILE', 'ENOTEMPTY', 'EPERM']); | |
| 30 | 32 | const epermHandler = isWindows ? fixWinEPERM : _rmdir; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -567,5 +567,67 @@ if (isGitPresent) { | |||
| 567 | 567 | makeDirectoryWritable(middle); | |
| 568 | 568 | } | |
| 569 | 569 | } | |
| 570 | + | ||
| 571 | + if (common.isWindows) { | ||
| 572 | + // On Windows, EPERM from rmdir on a directory that cannot be deleted | ||
| 573 | + // due to permissions must not be treated as ENOTEMPTY (which would | ||
| 574 | + // cause rimraf to recurse into and delete the directory's children). | ||
| 575 | + const dirname = nextDirPath(); | ||
| 576 | + const parent = path.join(dirname, 'parent'); | ||
| 577 | + const child = path.join(parent, 'child'); | ||
| 578 | + const childFile = path.join(child, 'childFile.txt'); | ||
| 579 | + fs.mkdirSync(child, common.mustNotMutateObjectDeep({ recursive: true })); | ||
| 580 | + fs.writeFileSync(childFile, 'hello'); | ||
| 581 | + | ||
| 582 | + // (DC) denies deleting children; (DE) denies deleting the directory | ||
| 583 | + // itself. Combined denies on each layer guarantee rmdir returns EPERM. | ||
| 584 | + execSync(`icacls "${dirname}" /deny "everyone:(DC)"`); | ||
| 585 | + execSync(`icacls "${parent}" /deny "everyone:(DE,DC)"`); | ||
| 586 | + execSync(`icacls "${child}" /deny "everyone:(DE)"`); | ||
| 587 | + | ||
| 588 | + const cleanup = () => { | ||
| 589 | + try { | ||
| 590 | + execSync(`icacls "${child}" /remove:d "everyone"`); | ||
| 591 | + } catch { | ||
| 592 | + // Best-effort cleanup; ignore failures (e.g. already cleared). | ||
| 593 | + } | ||
| 594 | + try { | ||
| 595 | + execSync(`icacls "${parent}" /remove:d "everyone"`); | ||
| 596 | + } catch { | ||
| 597 | + // Best-effort cleanup; ignore failures. | ||
| 598 | + } | ||
| 599 | + try { | ||
| 600 | + execSync(`icacls "${dirname}" /remove:d "everyone"`); | ||
| 601 | + } catch { | ||
| 602 | + // Best-effort cleanup; ignore failures. | ||
| 603 | + } | ||
| 604 | + try { | ||
| 605 | + fs.rmSync(dirname, common.mustNotMutateObjectDeep({ | ||
| 606 | + recursive: true, | ||
| 607 | + force: true, | ||
| 608 | + })); | ||
| 609 | + } catch { | ||
| 610 | + // Best-effort cleanup; ignore failures. | ||
| 611 | + } | ||
| 612 | + }; | ||
| 613 | + process.on('exit', cleanup); | ||
| 614 | + | ||
| 615 | + fs.rm(dirname, common.mustNotMutateObjectDeep({ recursive: true }), | ||
| 616 | + common.mustCall((err) => { | ||
| 617 | + try { | ||
| 618 | + assert.ok(err, 'expected EPERM error'); | ||
| 619 | + assert.strictEqual(err.code, 'EPERM'); | ||
| 620 | + assert.strictEqual(err.syscall, 'rmdir'); | ||
| 621 | + assert.ok(err.path.endsWith('\\parent')); | ||
| 622 | + assert.ok( | ||
| 623 | + fs.existsSync(child), | ||
| 624 | + 'EPERM from rmdir must propagate without recursing into children', | ||
| 625 | + ); | ||
| 626 | + } finally { | ||
| 627 | + process.removeListener('exit', cleanup); | ||
| 628 | + cleanup(); | ||
| 629 | + } | ||
| 630 | + })); | ||
| 631 | + } | ||
| 570 | 632 | } | |
| 571 | 633 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments