Skip to content

Commit

Permalink
node:fs.readdir: should not fail even if folder contains self-referen…
Browse files Browse the repository at this point in the history
…tial symlinks (#10679)
  • Loading branch information
nektro authored May 1, 2024
1 parent 2a40148 commit bd63246
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/bun.js/node/node_fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,12 @@ pub const AsyncReaddirRecursiveTask = struct {
is_root,
)) {
.err => |err| {
// readdir() should never fail with 'ELOOP: Too many levels of symbolic links'
if (err.getErrno() == .LOOP) {
this.writeResults(ResultType, &entries);
return;
}

for (entries.items) |*item| {
switch (ResultType) {
bun.String => item.deref(),
Expand Down Expand Up @@ -4967,6 +4973,8 @@ pub const NodeFS = struct {
// This is different than what Node does, at the time of writing.
// Node doesn't gracefully handle errors like these. It fails the entire operation.
.NOENT, .NOTDIR, .PERM => continue,
// readdir() should never fail with 'ELOOP: Too many levels of symbolic links'
.LOOP => continue,
else => {
const path_parts = [_]string{ args.path.slice(), basename };
return .{
Expand Down
1 change: 1 addition & 0 deletions test/js/node/fs/fixtures/readdir-loop/a/b/c/d/e/f
18 changes: 18 additions & 0 deletions test/js/node/fs/fs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import fs, {
existsSync,
mkdirSync,
openSync,
readdir,
readdirSync,
readFile,
readFileSync,
Expand Down Expand Up @@ -3030,3 +3031,20 @@ it("promises.fdatasync with a bad fd should include that in the error thrown", a
}
expect.unreachable();
});

it("readdirSync should not crash on symlink loops", () => {
// prettier-ignore
expect(readdirSync(join(import.meta.dirname, "./fixtures/readdir-loop"), { recursive: true }).length).toBe(symlink_fixture_depth());
});

it("readdir should not crash on symlink loops", async () => {
// prettier-ignore
expect((await promisify(readdir)(join(import.meta.dirname, "./fixtures/readdir-loop"), { recursive: true })).length).toBe(symlink_fixture_depth());
});

function symlink_fixture_depth() {
if (process.platform === "darwin") return 166;
if (process.platform === "linux") return 206;
if (process.platform === "win32") return 6;
throw new Error(`test unimplemented for '${process.platform}'`);
}

0 comments on commit bd63246

Please sign in to comment.