Zig Version
0.14.0-dev.3029+bebd8d7ff
Steps to Reproduce and Observed Behavior
I'm fixing some of Zig's Posix file tests, and they change the current working directory (CWD), so to protect subsequent tests I tried starting the test with:
// Restore default CWD at end of test.
const orig_cwd = try std.fs.cwd();
defer orig_cwd.setAsCwd() catch unreachable;
I read this code as using defer to restore the current working directory to the original value after the main part of the test has completed.
However, this doesn't work (on Linux**) because the CWD returned is a stateless file descriptor that means "current working directory" (Posix's AT_FDCWD). So the code in the defer ends up being a no-op.
To capture a stateful "cwd" descriptor I can open ., and now the deferred restore works as I expect (but now I also have a real file descriptor that I have to close at some point):
var orig_cwd = try std.fs.cwd().openDir(".", .{});
defer orig_cwd.setAsCwd() catch unreachable;
This problem came up tangentially in #9688 and #17616 and #15592. While I can see how the current semantics of cwd() are slick and efficient (its basically the entrypoint for all relative-path file operations), this does seem like very surprising behavior to someone expecting the Dir returned from std.fs.cwd() to act like other stateful file descriptor-backed handles. If the current semantics are correct as-is, then at least the doc needs an update on cwd(). And probably on setAsCwd() to say it will transparently "update" results from earlier cwd() calls. Or remove setAsCwd()?
Here's a full test to reproduce the problem:
const std = @import("std");
test "first" {
const orig_cwd = std.fs.cwd(); // save off CWD handle
var orig_path_buf: [std.fs.max_path_bytes]u8 = undefined;
const orig_path = try std.posix.getcwd(orig_path_buf[0..]);
const pdir = try std.fs.cwd().openDir("..", .{});
try pdir.setAsCwd(); // change CWD to something new
// ... in a real test do something here...
try orig_cwd.setAsCwd(); // "restore" the CWD to the original
var after_path_buf: [std.fs.max_path_bytes]u8 = undefined;
const after_path = try std.posix.getcwd(after_path_buf[0..]);
try std.testing.expectEqualSlices(u8, orig_path, after_path);
}
** Windows uses windows.peb().ProcessParameters.CurrentDirectory.Handle for fs.cwd(), and I'm not sure if that has the same semantics as AT_FDCWD on Linux or if its stateful.
Expected Behavior
The test above should pass. Or the doc on cwd() should call out that its always whatever the CWD is, and is not a stable handle to the current CWD.
Zig Version
0.14.0-dev.3029+bebd8d7ff
Steps to Reproduce and Observed Behavior
I'm fixing some of Zig's Posix file tests, and they change the current working directory (CWD), so to protect subsequent tests I tried starting the test with:
I read this code as using
deferto restore the current working directory to the original value after the main part of the test has completed.However, this doesn't work (on Linux**) because the CWD returned is a stateless file descriptor that means "current working directory" (Posix's
AT_FDCWD). So the code in the defer ends up being a no-op.To capture a stateful "cwd" descriptor I can open
., and now the deferred restore works as I expect (but now I also have a real file descriptor that I have to close at some point):This problem came up tangentially in #9688 and #17616 and #15592. While I can see how the current semantics of
cwd()are slick and efficient (its basically the entrypoint for all relative-path file operations), this does seem like very surprising behavior to someone expecting theDirreturned fromstd.fs.cwd()to act like other stateful file descriptor-backed handles. If the current semantics are correct as-is, then at least the doc needs an update oncwd(). And probably onsetAsCwd()to say it will transparently "update" results from earliercwd()calls. Or removesetAsCwd()?Here's a full test to reproduce the problem:
** Windows uses
windows.peb().ProcessParameters.CurrentDirectory.Handleforfs.cwd(), and I'm not sure if that has the same semantics asAT_FDCWDon Linux or if its stateful.Expected Behavior
The test above should pass. Or the doc on
cwd()should call out that its always whatever the CWD is, and is not a stable handle to the current CWD.