authorgravatar for karchnu@karchnu.frPhilippe Pittoli <karchnu@karchnu.fr> 2022-05-06 01:03:03+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-14 14:11:59-07:00
logf65cdef7c8bfe7a47e1c30cfa3903ca2d53495cf
tree0978f79f6f7a6c0aa6324f9d582a9587f0631480
parent4af305b30acdefb9da380b21b446d2b31b5a6295

std.fs.Dir.statFile: use fstatat

This avoids extra syscalls.

3 files changed, 80 insertions(+), 12 deletions(-)

lib/std/fs.zig+18-6
......@@ -2598,14 +2598,26 @@ pub const Dir = struct {
25982598 return file.stat();
25992599 }
26002600
2601 pub const StatFileError = File.OpenError || StatError;
2601 pub const StatFileError = File.OpenError || File.StatError || os.FStatAtError;
2602
2603 /// Provides info on a file (File.Stat) for any file in the opened directory,
2604 /// with a single syscall (fstatat), except on Windows.
2605 /// Currently on Windows, files are opened then closed (implying several syscalls, unfortunately).
2606 /// Symlinks are not followed on linux, haiku, solaris and *BSDs.
2607 /// Other OSs have a default behavior (they currently lack an os.AT.SYMLINK_NOFOLLOW flag).
2608 pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {
2609 if (builtin.os.tag == .windows) {
2610 var file = try self.openFile(sub_path, .{});
2611 defer file.close();
2612 return file.stat();
2613 }
26022614
2603 // TODO: improve this to use the fstatat syscall instead of making 2 syscalls here.
2604 pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!File.Stat {
2605 var file = try self.openFile(sub_path, .{});
2606 defer file.close();
2615 const flags = switch (builtin.os.tag) {
2616 .linux, .haiku, .solaris, .freebsd, .netbsd, .dragonfly, .openbsd => os.AT.SYMLINK_NOFOLLOW,
2617 else => 0, // TODO: correct flags not yet implemented
2618 };
26072619
2608 return file.stat();
2620 return Stat.fromSystemStat(try os.fstatat(self.fd, sub_path, flags));
26092621 }
26102622
26112623 const Permissions = File.Permissions;
lib/std/fs/file.zig+51
......@@ -313,6 +313,57 @@ pub const File = struct {
313313 mtime: i128,
314314 /// Creation time in nanoseconds, relative to UTC 1970-01-01.
315315 ctime: i128,
316
317 pub fn systemStatKindToFsKind(st: os.system.Stat) Kind {
318 const kind: File.Kind = if (builtin.os.tag == .wasi and !builtin.link_libc)
319 switch (st.filetype) {
320 .BLOCK_DEVICE => Kind.BlockDevice,
321 .CHARACTER_DEVICE => Kind.CharacterDevice,
322 .DIRECTORY => Kind.Directory,
323 .SYMBOLIC_LINK => Kind.SymLink,
324 .REGULAR_FILE => Kind.File,
325 .SOCKET_STREAM, .SOCKET_DGRAM => Kind.UnixDomainSocket,
326 else => Kind.Unknown,
327 }
328 else blk: {
329 const m = st.mode & os.S.IFMT;
330 switch (m) {
331 os.S.IFBLK => break :blk Kind.BlockDevice,
332 os.S.IFCHR => break :blk Kind.CharacterDevice,
333 os.S.IFDIR => break :blk Kind.Directory,
334 os.S.IFIFO => break :blk Kind.NamedPipe,
335 os.S.IFLNK => break :blk Kind.SymLink,
336 os.S.IFREG => break :blk Kind.File,
337 os.S.IFSOCK => break :blk Kind.UnixDomainSocket,
338 else => {},
339 }
340 if (builtin.os.tag == .solaris) switch (m) {
341 os.S.IFDOOR => break :blk Kind.Door,
342 os.S.IFPORT => break :blk Kind.EventPort,
343 else => {},
344 };
345
346 break :blk .Unknown;
347 };
348 return kind;
349 }
350
351 pub fn fromSystemStat(st: os.system.Stat) File.StatError!Stat {
352 const atime = st.atime();
353 const mtime = st.mtime();
354 const ctime = st.ctime();
355 const kind = systemStatKindToFsKind(st);
356
357 return Stat{
358 .inode = st.ino,
359 .size = @bitCast(u64, st.size),
360 .mode = st.mode,
361 .kind = kind,
362 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
363 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
364 .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
365 };
366 }
316367 };
317368
318369 pub const StatError = os.FStatError;
src/Module.zig+11-6
......@@ -4137,14 +4137,19 @@ pub fn populateBuiltinFile(mod: *Module) !void {
41374137 };
41384138 }
41394139 } else |err| switch (err) {
4140 error.BadPathName => unreachable, // it's always "builtin.zig"
41414140 error.NameTooLong => unreachable, // it's always "builtin.zig"
4142 error.PipeBusy => unreachable, // it's not a pipe
4143 error.WouldBlock => unreachable, // not asking for non-blocking I/O
4144
41454141 error.FileNotFound => try writeBuiltinFile(file, builtin_pkg),
4146
4147 else => |e| return e,
4142 else => |e| {
4143 if (builtin.os.tag == .windows) {
4144 switch (e) {
4145 error.BadPathName => unreachable, // it's always "builtin.zig"
4146 error.PipeBusy => unreachable, // it's not a pipe
4147 error.WouldBlock => unreachable, // not asking for non-blocking I/O
4148 else => return e,
4149 }
4150 }
4151 return e;
4152 },
41484153 }
41494154
41504155 file.tree = try std.zig.parse(gpa, file.source);