Skip to content

Commit a62c8d3

Browse files
committed
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.
1 parent f65cdef commit a62c8d3

3 files changed

Lines changed: 51 additions & 94 deletions

File tree

lib/std/fs.zig

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 23 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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);

0 commit comments

Comments
 (0)