Commit f65cdef7c8
Changed files (3)
src
lib/std/fs/file.zig
@@ -313,6 +313,57 @@ pub const File = struct {
mtime: i128,
/// Creation time in nanoseconds, relative to UTC 1970-01-01.
ctime: i128,
+
+ pub fn systemStatKindToFsKind(st: os.system.Stat) Kind {
+ const kind: File.Kind = if (builtin.os.tag == .wasi and !builtin.link_libc)
+ switch (st.filetype) {
+ .BLOCK_DEVICE => Kind.BlockDevice,
+ .CHARACTER_DEVICE => Kind.CharacterDevice,
+ .DIRECTORY => Kind.Directory,
+ .SYMBOLIC_LINK => Kind.SymLink,
+ .REGULAR_FILE => Kind.File,
+ .SOCKET_STREAM, .SOCKET_DGRAM => Kind.UnixDomainSocket,
+ else => Kind.Unknown,
+ }
+ else blk: {
+ const m = st.mode & os.S.IFMT;
+ switch (m) {
+ os.S.IFBLK => break :blk Kind.BlockDevice,
+ os.S.IFCHR => break :blk Kind.CharacterDevice,
+ os.S.IFDIR => break :blk Kind.Directory,
+ os.S.IFIFO => break :blk Kind.NamedPipe,
+ os.S.IFLNK => break :blk Kind.SymLink,
+ os.S.IFREG => break :blk Kind.File,
+ os.S.IFSOCK => break :blk Kind.UnixDomainSocket,
+ else => {},
+ }
+ if (builtin.os.tag == .solaris) switch (m) {
+ os.S.IFDOOR => break :blk Kind.Door,
+ os.S.IFPORT => break :blk Kind.EventPort,
+ else => {},
+ };
+
+ break :blk .Unknown;
+ };
+ return kind;
+ }
+
+ pub fn fromSystemStat(st: os.system.Stat) File.StatError!Stat {
+ const atime = st.atime();
+ const mtime = st.mtime();
+ const ctime = st.ctime();
+ const kind = systemStatKindToFsKind(st);
+
+ return Stat{
+ .inode = st.ino,
+ .size = @bitCast(u64, st.size),
+ .mode = st.mode,
+ .kind = kind,
+ .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
+ .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
+ .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
+ };
+ }
};
pub const StatError = os.FStatError;
lib/std/fs.zig
@@ -2598,14 +2598,26 @@ pub const Dir = struct {
return file.stat();
}
- pub const StatFileError = File.OpenError || StatError;
+ pub const StatFileError = File.OpenError || File.StatError || os.FStatAtError;
+
+ /// Provides info on a file (File.Stat) for any file in the opened directory,
+ /// with a single syscall (fstatat), except on Windows.
+ /// Currently on Windows, files are opened then closed (implying several syscalls, unfortunately).
+ /// Symlinks are not followed on linux, haiku, solaris and *BSDs.
+ /// Other OSs have a default behavior (they currently lack an os.AT.SYMLINK_NOFOLLOW flag).
+ pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {
+ if (builtin.os.tag == .windows) {
+ var file = try self.openFile(sub_path, .{});
+ defer file.close();
+ return file.stat();
+ }
- // TODO: improve this to use the fstatat syscall instead of making 2 syscalls here.
- pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!File.Stat {
- var file = try self.openFile(sub_path, .{});
- defer file.close();
+ const flags = switch (builtin.os.tag) {
+ .linux, .haiku, .solaris, .freebsd, .netbsd, .dragonfly, .openbsd => os.AT.SYMLINK_NOFOLLOW,
+ else => 0, // TODO: correct flags not yet implemented
+ };
- return file.stat();
+ return Stat.fromSystemStat(try os.fstatat(self.fd, sub_path, flags));
}
const Permissions = File.Permissions;
src/Module.zig
@@ -4137,14 +4137,19 @@ pub fn populateBuiltinFile(mod: *Module) !void {
};
}
} else |err| switch (err) {
- error.BadPathName => unreachable, // it's always "builtin.zig"
error.NameTooLong => unreachable, // it's always "builtin.zig"
- error.PipeBusy => unreachable, // it's not a pipe
- error.WouldBlock => unreachable, // not asking for non-blocking I/O
-
error.FileNotFound => try writeBuiltinFile(file, builtin_pkg),
-
- else => |e| return e,
+ else => |e| {
+ if (builtin.os.tag == .windows) {
+ switch (e) {
+ error.BadPathName => unreachable, // it's always "builtin.zig"
+ error.PipeBusy => unreachable, // it's not a pipe
+ error.WouldBlock => unreachable, // not asking for non-blocking I/O
+ else => return e,
+ }
+ }
+ return e;
+ },
}
file.tree = try std.zig.parse(gpa, file.source);