-
Notifications
You must be signed in to change notification settings - Fork 4k
fix(Bun.write): create file for empty Response when createPath is false #26442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix(Bun.write): create file for empty Response when createPath is false #26442
Conversation
87dd289 to
1d90308
Compare
WalkthroughModify file-write logic to ensure empty Responses/Blobs create or truncate destination files; on ENOENT while opening for truncate/create, conditionally create missing parent directories (mkdirp) and retry. Add regression tests covering empty writes and createPath semantics. Changes
Suggested reviewers
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…se (oven-sh#6827) When writing empty content (e.g., `new Response("")`), the truncate syscall fails with ENOENT if the file doesn't exist. Previously, this would error out when `createPath: false` even if the parent directory existed. Now we attempt to create the file with open(O_WRONLY | O_CREAT | O_TRUNC) before checking mkdirp_if_not_exists, correctly separating file creation from parent directory creation.
1d90308 to
cc6e24e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/bun.js/webcore/Blob.zig`:
- Around line 934-938: The .fd arm in the second open attempt inside the while
loop in Blob.zig is dead code because any .fd pathlike would have triggered the
earlier err-handling branch and not reached the mkdirp/reopen logic; update the
switch on file.pathlike in that re-open block (the open_res assignment inside
the while loop) to either remove the .fd case and only handle .path, or replace
the .fd arm with `@unreachable`() to make the intent explicit and satisfy the
compiler, ensuring you keep the same flags (bun.O.WRONLY | bun.O.CREAT |
bun.O.TRUNC) and refer to the same buf sliceZ call used for the .path case.
| while (true) { | ||
| const open_res = bun.sys.open(file.pathlike.path.sliceZ(&buf), bun.O.CREAT | bun.O.TRUNC, mode); | ||
| const open_res = switch (file.pathlike) { | ||
| .path => |path| bun.sys.open(path.sliceZ(&buf), bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC, mode), | ||
| .fd => break :err, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
The .fd case in the second open attempt is unreachable.
After mkdirp succeeds, we re-open the file. However, if file.pathlike were .fd, we would have already exited the err block at line 912-919 before reaching mkdirp. This .fd case at line 937 is dead code.
♻️ Consider simplifying by using `unreachable` or removing the switch
while (true) {
- const open_res = switch (file.pathlike) {
- .path => |path| bun.sys.open(path.sliceZ(&buf), bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC, mode),
- .fd => break :err,
- };
+ // pathlike must be .path here - .fd case exits earlier at line 912-919
+ const open_res = bun.sys.open(file.pathlike.path.sliceZ(&buf), bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC, mode);🤖 Prompt for AI Agents
In `@src/bun.js/webcore/Blob.zig` around lines 934 - 938, The .fd arm in the
second open attempt inside the while loop in Blob.zig is dead code because any
.fd pathlike would have triggered the earlier err-handling branch and not
reached the mkdirp/reopen logic; update the switch on file.pathlike in that
re-open block (the open_res assignment inside the while loop) to either remove
the .fd case and only handle .path, or replace the .fd arm with `@unreachable`()
to make the intent explicit and satisfy the compiler, ensuring you keep the same
flags (bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC) and refer to the same buf
sliceZ call used for the .path case.
Summary
Fixes #6827
When writing empty content (e.g.,
new Response("")), thetruncatesyscall fails withENOENTif the file doesn't exist. Previously, this would error out whencreatePath: falseeven if the parent directory existed.Now we attempt to create the file with
open(O_WRONLY | O_CREAT | O_TRUNC)before checkingmkdirp_if_not_exists, correctly separating file creation from parent directory creation.createPath: falsenow only prevents creating missing parent directories, not the file itselfO_WRONLYflag to open calls for consistency with the rest of the codebaseTest plan
test/regression/issue/06827.test.tscovering:createPath: falsestill creates file when parent existscreatePath: falseerrors when parent dir missingbun-write.test.jssuite (30/30 pass)