From #5717:
I didn't include a read-only test because I was unsure about how to handle the differing errors per-platform, as mentioned here:
On Linux, when opening a file with read-only permissions, there is no way to determine whether the file descriptor is a directory handle without an additional syscall.
That is, open on Linux only returns EISDIR when "pathname refers to a directory and the access requested involved writing".
The following code will give error.IsDir on Windows, but will succeed on Linux/FreeBSD/Mac/etc:
const std = @import("std");
const fs = std.fs;
pub fn main() !void {
try fs.cwd().makePath("dir");
const file = try fs.cwd().openFile("dir", .{});
file.close();
}
(note that doing something like file.readAll afterwards on Linux/etc will fail with error.IsDir)
There are two ways that this can be addressed that I can imagine:
- Do a
stat in fs.Dir.openFile on POSIX systems and return error.IsDir if the path is a directory.
- Document this and make users deal with the platform-specific behavior
Neither seems quite ideal.
For an example of what option 2 would look like from the user's perspective, this is what zig fmt does:
|
const source_file = try dir.openFile(sub_path, .{}); |
|
var file_closed = false; |
|
errdefer if (!file_closed) source_file.close(); |
|
|
|
const stat = try source_file.stat(); |
|
|
|
if (stat.kind == .Directory) |
|
return error.IsDir; |
That is, on Windows, the try dir.openFile(sub_path, .{}); returns error.IsDir, while on other platforms, stat is used afterwards to return error.IsDir manually. Note, though, that in this case, the stat info is used again later, so moving the stat in the openFile call would lose the possibility for that optimization.
From #5717:
The following code will give
error.IsDiron Windows, but will succeed on Linux/FreeBSD/Mac/etc:(note that doing something like
file.readAllafterwards on Linux/etc will fail witherror.IsDir)There are two ways that this can be addressed that I can imagine:
statinfs.Dir.openFileon POSIX systems and returnerror.IsDirif the path is a directory.Neither seems quite ideal.
For an example of what option 2 would look like from the user's perspective, this is what
zig fmtdoes:zig/src-self-hosted/main.zig
Lines 752 to 759 in 626b5ec
That is, on Windows, the
try dir.openFile(sub_path, .{});returnserror.IsDir, while on other platforms,statis used afterwards to returnerror.IsDirmanually. Note, though, that in this case, thestatinfo is used again later, so moving the stat in theopenFilecall would lose the possibility for that optimization.