diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 5b1e5ba3fa3cc5168467322a799220096ebba8a5..3b688ecc93c36631fa0c0bad423155abb8020eeb 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -14176,6 +14176,16 @@ fn processCurrentPath(userdata: ?*anyopaque, buffer: []u8) process.CurrentPathEr .SUCCESS => return std.mem.findScalar(u8, buffer, 0).?, .NOENT => return error.CurrentDirUnlinked, .RANGE => return error.NameTooLong, + // On Linux, this indicates that the buffer may have been large enough, but the path + // is too long for the syscall to handle since it exceeds PATH_MAX. + // https://github.com/torvalds/linux/blob/e4b275531887fef7f7d8a7284bfc32f0fbbd4208/fs/d_path.c#L406-L407 + // + // This is returned as a distinct error to differentiate it from RANGE, since + // this NAMETOOLONG return is never recoverable by increasing the buffer size. + // The way to recover from it would be to reconstruct the cwd piece-by-piece by e.g. + // walking the filesystem backwards starting from "." (many libc implementations + // of `getcwd` do this fallback-to-filesystem-walking automatically). + .NAMETOOLONG => return error.PathExceedsLimit, .FAULT => |e| return errnoBug(e), .INVAL => |e| return errnoBug(e), else => return posix.unexpectedErrno(err), diff --git a/lib/std/process.zig b/lib/std/process.zig index 4f0b388b80ec5ff6a521bfa0e57009a4c5ba3fbe..651d854edb623b25437e418640fa54f7f4e6c67a 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -58,9 +58,14 @@ pub const Init = struct { }; pub const CurrentPathError = error{ + /// Buffer is too small to contain the current path. NameTooLong, /// Not possible on Windows. Always returned on WASI. CurrentDirUnlinked, + /// The current path cannot be retrieved due to a limitation of the + /// underlying libc or syscall implementation. Retrying with a larger + /// buffer will not succeed. + PathExceedsLimit, } || Io.Cancelable || Io.UnexpectedError; /// On Windows, the result is encoded as [WTF-8](https://wtf-8.codeberg.page/). @@ -70,11 +75,10 @@ pub fn currentPath(io: Io, buffer: []u8) CurrentPathError!usize { return io.vtable.processCurrentPath(io.userdata, buffer); } -pub const CurrentPathAllocError = Allocator.Error || error{ - /// Not possible on Windows. Always returned on WASI. - CurrentDirUnlinked, -} || Io.Cancelable || Io.UnexpectedError; +pub const CurrentPathAllocError = Allocator.Error || CurrentPathError; +/// Shortcut for calling `currentPath` with a buffer of size `max_path_bytes`. +/// /// On Windows, the result is encoded as [WTF-8](https://wtf-8.codeberg.page/). /// On other platforms, the result is an opaque sequence of bytes with no /// particular encoding. @@ -82,10 +86,7 @@ pub const CurrentPathAllocError = Allocator.Error || error{ /// Caller owns returned memory. pub fn currentPathAlloc(io: Io, allocator: Allocator) CurrentPathAllocError![:0]u8 { var buffer: [max_path_bytes]u8 = undefined; - const n = currentPath(io, &buffer) catch |err| switch (err) { - error.NameTooLong => unreachable, - else => |e| return e, - }; + const n = try currentPath(io, &buffer); return allocator.dupeSentinel(u8, buffer[0..n], 0); }