authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-09 09:55:09-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-14 14:26:02-07:00
loga62c8d36d530dc78f88dc0f41ce3f244c3c273bd
treefd92869eefe7bd99af8cf3fbcad1533bb5797ec8
parentf65cdef7c8bfe7a47e1c30cfa3903ca2d53495cf

std.fs.Dir.statFile rework

* revert changes to Module because the error set is consistent across operating systems. * remove duplicated Stat.fromSystem code and use a less redundant name. * make fs.Dir.statFile follow symlinks, and avoid pointless control flow through the posix layer.

3 files changed, 51 insertions(+), 94 deletions(-)

lib/std/fs.zig+22-16
......@@ -2600,24 +2600,30 @@ pub const Dir = struct {
26002600
26012601 pub const StatFileError = File.OpenError || File.StatError || os.FStatAtError;
26022602
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).
2603 /// Returns metadata for a file inside the directory.
2604 ///
2605 /// On Windows, this requires three syscalls. On other operating systems, it
2606 /// only takes one.
2607 ///
2608 /// Symlinks are followed.
2609 ///
2610 /// `sub_path` may be absolute, in which case `self` is ignored.
26082611 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();
2612 switch (builtin.os.tag) {
2613 .windows => {
2614 var file = try self.openFile(sub_path, .{});
2615 defer file.close();
2616 return file.stat();
2617 },
2618 .wasi => {
2619 const st = try os.fstatatWasi(self.fd, sub_path, os.wasi.LOOKUP_SYMLINK_FOLLOW);
2620 return Stat.fromSystem(st);
2621 },
2622 else => {
2623 const st = try os.fstatat(self.fd, sub_path, 0);
2624 return Stat.fromSystem(st);
2625 },
26132626 }
2614
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 };
2619
2620 return Stat.fromSystemStat(try os.fstatat(self.fd, sub_path, flags));
26212627 }
26222628
26232629 const Permissions = File.Permissions;
lib/std/fs/file.zig+23-67
......@@ -294,14 +294,17 @@ pub const File = struct {
294294 }
295295
296296 pub const Stat = struct {
297 /// A number that the system uses to point to the file metadata. This number is not guaranteed to be
298 /// unique across time, as some file systems may reuse an inode after its file has been deleted.
299 /// Some systems may change the inode of a file over time.
297 /// A number that the system uses to point to the file metadata. This
298 /// number is not guaranteed to be unique across time, as some file
299 /// systems may reuse an inode after its file has been deleted. Some
300 /// systems may change the inode of a file over time.
300301 ///
301 /// On Linux, the inode is a structure that stores the metadata, and the inode _number_ is what
302 /// you see here: the index number of the inode.
302 /// On Linux, the inode is a structure that stores the metadata, and
303 /// the inode _number_ is what you see here: the index number of the
304 /// inode.
303305 ///
304 /// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem.
306 /// The FileIndex on Windows is similar. It is a number for a file that
307 /// is unique to each filesystem.
305308 inode: INode,
306309 size: u64,
307310 mode: Mode,
......@@ -314,18 +317,19 @@ pub const File = struct {
314317 /// Creation time in nanoseconds, relative to UTC 1970-01-01.
315318 ctime: i128,
316319
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: {
320 pub fn fromSystem(st: os.system.Stat) Stat {
321 const atime = st.atime();
322 const mtime = st.mtime();
323 const ctime = st.ctime();
324 const kind: Kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) {
325 .BLOCK_DEVICE => Kind.BlockDevice,
326 .CHARACTER_DEVICE => Kind.CharacterDevice,
327 .DIRECTORY => Kind.Directory,
328 .SYMBOLIC_LINK => Kind.SymLink,
329 .REGULAR_FILE => Kind.File,
330 .SOCKET_STREAM, .SOCKET_DGRAM => Kind.UnixDomainSocket,
331 else => Kind.Unknown,
332 } else blk: {
329333 const m = st.mode & os.S.IFMT;
330334 switch (m) {
331335 os.S.IFBLK => break :blk Kind.BlockDevice,
......@@ -345,14 +349,6 @@ pub const File = struct {
345349
346350 break :blk .Unknown;
347351 };
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);
356352
357353 return Stat{
358354 .inode = st.ino,
......@@ -393,47 +389,7 @@ pub const File = struct {
393389 }
394390
395391 const st = try os.fstat(self.handle);
396 const atime = st.atime();
397 const mtime = st.mtime();
398 const ctime = st.ctime();
399 const kind: Kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) {
400 .BLOCK_DEVICE => Kind.BlockDevice,
401 .CHARACTER_DEVICE => Kind.CharacterDevice,
402 .DIRECTORY => Kind.Directory,
403 .SYMBOLIC_LINK => Kind.SymLink,
404 .REGULAR_FILE => Kind.File,
405 .SOCKET_STREAM, .SOCKET_DGRAM => Kind.UnixDomainSocket,
406 else => Kind.Unknown,
407 } else blk: {
408 const m = st.mode & os.S.IFMT;
409 switch (m) {
410 os.S.IFBLK => break :blk Kind.BlockDevice,
411 os.S.IFCHR => break :blk Kind.CharacterDevice,
412 os.S.IFDIR => break :blk Kind.Directory,
413 os.S.IFIFO => break :blk Kind.NamedPipe,
414 os.S.IFLNK => break :blk Kind.SymLink,
415 os.S.IFREG => break :blk Kind.File,
416 os.S.IFSOCK => break :blk Kind.UnixDomainSocket,
417 else => {},
418 }
419 if (builtin.os.tag == .solaris) switch (m) {
420 os.S.IFDOOR => break :blk Kind.Door,
421 os.S.IFPORT => break :blk Kind.EventPort,
422 else => {},
423 };
424
425 break :blk .Unknown;
426 };
427
428 return Stat{
429 .inode = st.ino,
430 .size = @bitCast(u64, st.size),
431 .mode = st.mode,
432 .kind = kind,
433 .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
434 .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
435 .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
436 };
392 return Stat.fromSystem(st);
437393 }
438394
439395 pub const ChmodError = std.os.FChmodError;
src/Module.zig+6-11
......@@ -4137,19 +4137,14 @@ pub fn populateBuiltinFile(mod: *Module) !void {
41374137 };
41384138 }
41394139 } else |err| switch (err) {
4140 error.BadPathName => unreachable, // it's always "builtin.zig"
41404141 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
41414145 error.FileNotFound => try writeBuiltinFile(file, builtin_pkg),
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 },
4146
4147 else => |e| return e,
41534148 }
41544149
41554150 file.tree = try std.zig.parse(gpa, file.source);