diff --git a/ci/aarch64-linux-debug.sh b/ci/aarch64-linux-debug.sh index 0452b7d7dd..758085c759 100644 --- a/ci/aarch64-linux-debug.sh +++ b/ci/aarch64-linux-debug.sh @@ -67,7 +67,7 @@ stage3-debug/bin/zig build test docs \ --zig-lib-dir "$(pwd)/../lib" # Look for HTML errors. -tidy --drop-empty-elements no -qe ../zig-cache/langref.html +tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html" # Produce the experimental std lib documentation. stage3-debug/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib diff --git a/ci/aarch64-linux-release.sh b/ci/aarch64-linux-release.sh index ef24accda4..59b7d7f9b9 100644 --- a/ci/aarch64-linux-release.sh +++ b/ci/aarch64-linux-release.sh @@ -67,7 +67,7 @@ stage3-release/bin/zig build test docs \ --zig-lib-dir "$(pwd)/../lib" # Look for HTML errors. -tidy --drop-empty-elements no -qe ../zig-cache/langref.html +tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html" # Produce the experimental std lib documentation. stage3-release/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib diff --git a/ci/x86_64-linux-debug.sh b/ci/x86_64-linux-debug.sh index 6ee2ce9b89..069dc78657 100755 --- a/ci/x86_64-linux-debug.sh +++ b/ci/x86_64-linux-debug.sh @@ -66,7 +66,7 @@ stage3-debug/bin/zig build test docs \ --zig-lib-dir "$(pwd)/../lib" # Look for HTML errors. -tidy --drop-empty-elements no -qe ../zig-cache/langref.html +tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html" # Produce the experimental std lib documentation. stage3-debug/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib diff --git a/ci/x86_64-linux-release.sh b/ci/x86_64-linux-release.sh index d9c1172b04..06f9e48c66 100755 --- a/ci/x86_64-linux-release.sh +++ b/ci/x86_64-linux-release.sh @@ -67,7 +67,7 @@ stage3-release/bin/zig build test docs \ --zig-lib-dir "$(pwd)/../lib" # Look for HTML errors. -tidy --drop-empty-elements no -qe ../zig-cache/langref.html +tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html" # Produce the experimental std lib documentation. stage3-release/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib diff --git a/lib/std/c/linux.zig b/lib/std/c/linux.zig index cfdf5dfc45..d72fd15a57 100644 --- a/lib/std/c/linux.zig +++ b/lib/std/c/linux.zig @@ -229,7 +229,7 @@ pub const EAI = enum(c_int) { pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int; pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE; pub extern "c" fn fstat64(fd: fd_t, buf: *Stat) c_int; -pub extern "c" fn fstatat64(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int; +pub extern "c" fn fstatat64(dirfd: fd_t, noalias path: [*:0]const u8, noalias stat_buf: *Stat, flags: u32) c_int; pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int; pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int; pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index e253aaff9e..d2df596b3e 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -150,7 +150,6 @@ pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: Co return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); } -/// TODO update this API to avoid a getrandom syscall for every operation. pub const AtomicFile = struct { file: File, // TODO either replace this with rand_buf or use []u16 on Windows @@ -2598,14 +2597,32 @@ pub const Dir = struct { return file.stat(); } - pub const StatFileError = File.OpenError || StatError; + pub const StatFileError = File.OpenError || File.StatError || os.FStatAtError; - // 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(); - - return file.stat(); + /// Returns metadata for a file inside the directory. + /// + /// On Windows, this requires three syscalls. On other operating systems, it + /// only takes one. + /// + /// Symlinks are followed. + /// + /// `sub_path` may be absolute, in which case `self` is ignored. + pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat { + switch (builtin.os.tag) { + .windows => { + var file = try self.openFile(sub_path, .{}); + defer file.close(); + return file.stat(); + }, + .wasi => { + const st = try os.fstatatWasi(self.fd, sub_path, os.wasi.LOOKUP_SYMLINK_FOLLOW); + return Stat.fromSystem(st); + }, + else => { + const st = try os.fstatat(self.fd, sub_path, 0); + return Stat.fromSystem(st); + }, + } } const Permissions = File.Permissions; diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index a1e81c9b94..cb048adb30 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -294,14 +294,17 @@ pub const File = struct { } pub const Stat = struct { - /// A number that the system uses to point to the file metadata. This number is not guaranteed to be - /// unique across time, as some file systems may reuse an inode after its file has been deleted. - /// Some systems may change the inode of a file over time. + /// A number that the system uses to point to the file metadata. This + /// number is not guaranteed to be unique across time, as some file + /// systems may reuse an inode after its file has been deleted. Some + /// systems may change the inode of a file over time. /// - /// On Linux, the inode is a structure that stores the metadata, and the inode _number_ is what - /// you see here: the index number of the inode. + /// On Linux, the inode is a structure that stores the metadata, and + /// the inode _number_ is what you see here: the index number of the + /// inode. /// - /// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem. + /// The FileIndex on Windows is similar. It is a number for a file that + /// is unique to each filesystem. inode: INode, size: u64, mode: Mode, @@ -313,6 +316,50 @@ pub const File = struct { mtime: i128, /// Creation time in nanoseconds, relative to UTC 1970-01-01. ctime: i128, + + pub fn fromSystem(st: os.system.Stat) Stat { + const atime = st.atime(); + const mtime = st.mtime(); + const ctime = st.ctime(); + const kind: 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 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; @@ -342,47 +389,7 @@ pub const File = struct { } const st = try os.fstat(self.handle); - const atime = st.atime(); - const mtime = st.mtime(); - const ctime = st.ctime(); - const kind: 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 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, - }; + return Stat.fromSystem(st); } pub const ChmodError = std.os.FChmodError; diff --git a/src/Module.zig b/src/Module.zig index 83294f3068..3347280f59 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4156,7 +4156,7 @@ pub fn populateBuiltinFile(mod: *Module) !void { file.status = .success_zir; } -pub fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void { +fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void { var af = try builtin_pkg.root_src_directory.handle.atomicFile(builtin_pkg.root_src_path, .{}); defer af.deinit(); try af.file.writeAll(file.source);