mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
## Summary - Adds birthtime (file creation time) support on Linux using the `statx` syscall - Stores birthtime in architecture-specific unused fields of the kernel Stat struct (x86_64 and aarch64) - Falls back to traditional `stat` on kernels < 4.11 that don't support `statx` - Includes comprehensive tests validating birthtime behavior Fixes #6585 ## Implementation Details **src/sys.zig:** - Added `StatxField` enum for field selection - Implemented `statxImpl()`, `fstatx()`, `statx()`, and `lstatx()` functions - Stores birthtime in unused padding fields (architecture-specific for x86_64 and aarch64) - Graceful fallback to traditional stat if statx is not supported **src/bun.js/node/node_fs.zig:** - Updated `stat()`, `fstat()`, and `lstat()` to use statx functions on Linux **src/bun.js/node/Stat.zig:** - Added `getBirthtime()` helper to extract birthtime from architecture-specific storage **test/js/node/fs/fs-birthtime-linux.test.ts:** - Tests non-zero birthtime values - Verifies birthtime immutability across file modifications - Validates consistency across stat/lstat/fstat - Tests BigInt stats with nanosecond precision - Verifies birthtime ordering relative to other timestamps ## Test Plan - [x] Run `bun bd test test/js/node/fs/fs-birthtime-linux.test.ts` - all 5 tests pass - [x] Compare behavior with Node.js - identical behavior - [x] Compare with system Bun - system Bun returns epoch, new implementation returns real birthtime 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import fsPromises from "fs/promises";
|
|
import { tempDirWithFiles } from "harness";
|
|
import { join } from "path";
|
|
|
|
test("delete() and stat() should work with unicode paths", async () => {
|
|
const dir = tempDirWithFiles("delete-stat-unicode-path", {
|
|
"another-file.txt": "HEY",
|
|
});
|
|
const filename = join(dir, "🌟.txt");
|
|
|
|
expect(async () => {
|
|
await Bun.file(filename).delete();
|
|
}).toThrow(`ENOENT: no such file or directory, unlink '${filename}'`);
|
|
|
|
expect(async () => {
|
|
await Bun.file(filename).stat();
|
|
}).toThrow(
|
|
process.platform === "linux"
|
|
? `ENOENT: no such file or directory, statx '${filename}'`
|
|
: `ENOENT: no such file or directory, stat '${filename}'`,
|
|
);
|
|
|
|
await Bun.write(filename, "HI");
|
|
|
|
expect(await Bun.file(filename).stat()).toMatchObject({ size: 2 });
|
|
expect(await Bun.file(filename).delete()).toBe(undefined);
|
|
|
|
expect(await Bun.file(filename).exists()).toBe(false);
|
|
});
|
|
|
|
test("writer.end() should not close the fd if it does not own the fd", async () => {
|
|
const dir = tempDirWithFiles("writer-end-fd", {
|
|
"tmp.txt": "HI",
|
|
});
|
|
const filename = join(dir, "tmp.txt");
|
|
|
|
for (let i = 0; i < 30; i++) {
|
|
const fileHandle = await fsPromises.open(filename, "w", 0o666);
|
|
const fd = fileHandle.fd;
|
|
|
|
await Bun.file(fd).writer().end();
|
|
// @ts-ignore
|
|
await fsPromises.close(fd);
|
|
expect(await Bun.file(filename).text()).toBe("");
|
|
}
|
|
});
|