| author | |
| committer | |
| log | c2f5848fe4dc3d3ffbebdbaaf8ff55fa2a9eb286 |
| tree | 714af317059e20a7c8f6f075c946a3a2f30fe5c6 |
| parent | 4af305b30acdefb9da380b21b446d2b31b5a6295 |
| parent | b911b54aeb45d2d2d7a8d616af5df04ad230bcc3 |
| signature |
Dir.statFile now uses fstatat (fewer syscalls)8 files changed, 85 insertions(+), 61 deletions(-)
ci/aarch64-linux-debug.sh+1-1| ... | ... | @@ -67,7 +67,7 @@ stage3-debug/bin/zig build test docs \ |
| 67 | 67 | --zig-lib-dir "$(pwd)/../lib" |
| 68 | 68 | |
| 69 | 69 | # Look for HTML errors. |
| 70 | tidy --drop-empty-elements no -qe ../zig-cache/langref.html | |
| 70 | tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html" | |
| 71 | 71 | |
| 72 | 72 | # Produce the experimental std lib documentation. |
| 73 | 73 | stage3-debug/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib |
ci/aarch64-linux-release.sh+1-1| ... | ... | @@ -67,7 +67,7 @@ stage3-release/bin/zig build test docs \ |
| 67 | 67 | --zig-lib-dir "$(pwd)/../lib" |
| 68 | 68 | |
| 69 | 69 | # Look for HTML errors. |
| 70 | tidy --drop-empty-elements no -qe ../zig-cache/langref.html | |
| 70 | tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html" | |
| 71 | 71 | |
| 72 | 72 | # Produce the experimental std lib documentation. |
| 73 | 73 | stage3-release/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib |
ci/x86_64-linux-debug.sh+1-1| ... | ... | @@ -66,7 +66,7 @@ stage3-debug/bin/zig build test docs \ |
| 66 | 66 | --zig-lib-dir "$(pwd)/../lib" |
| 67 | 67 | |
| 68 | 68 | # Look for HTML errors. |
| 69 | tidy --drop-empty-elements no -qe ../zig-cache/langref.html | |
| 69 | tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html" | |
| 70 | 70 | |
| 71 | 71 | # Produce the experimental std lib documentation. |
| 72 | 72 | stage3-debug/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib |
ci/x86_64-linux-release.sh+1-1| ... | ... | @@ -67,7 +67,7 @@ stage3-release/bin/zig build test docs \ |
| 67 | 67 | --zig-lib-dir "$(pwd)/../lib" |
| 68 | 68 | |
| 69 | 69 | # Look for HTML errors. |
| 70 | tidy --drop-empty-elements no -qe ../zig-cache/langref.html | |
| 70 | tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html" | |
| 71 | 71 | |
| 72 | 72 | # Produce the experimental std lib documentation. |
| 73 | 73 | stage3-release/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib |
lib/std/c/linux.zig+1-1| ... | ... | @@ -229,7 +229,7 @@ pub const EAI = enum(c_int) { |
| 229 | 229 | pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int; |
| 230 | 230 | pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE; |
| 231 | 231 | pub extern "c" fn fstat64(fd: fd_t, buf: *Stat) c_int; |
| 232 | pub extern "c" fn fstatat64(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int; | |
| 232 | pub extern "c" fn fstatat64(dirfd: fd_t, noalias path: [*:0]const u8, noalias stat_buf: *Stat, flags: u32) c_int; | |
| 233 | 233 | pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int; |
| 234 | 234 | pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int; |
| 235 | 235 | pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64; |
lib/std/fs.zig+25-8| ... | ... | @@ -150,7 +150,6 @@ pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: Co |
| 150 | 150 | return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); |
| 151 | 151 | } |
| 152 | 152 | |
| 153 | /// TODO update this API to avoid a getrandom syscall for every operation. | |
| 154 | 153 | pub const AtomicFile = struct { |
| 155 | 154 | file: File, |
| 156 | 155 | // TODO either replace this with rand_buf or use []u16 on Windows |
| ... | ... | @@ -2598,14 +2597,32 @@ pub const Dir = struct { |
| 2598 | 2597 | return file.stat(); |
| 2599 | 2598 | } |
| 2600 | 2599 | |
| 2601 | pub const StatFileError = File.OpenError || StatError; | |
| 2600 | pub const StatFileError = File.OpenError || File.StatError || os.FStatAtError; | |
| 2602 | 2601 | |
| 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(); | |
| 2607 | ||
| 2608 | return file.stat(); | |
| 2602 | /// Returns metadata for a file inside the directory. | |
| 2603 | /// | |
| 2604 | /// On Windows, this requires three syscalls. On other operating systems, it | |
| 2605 | /// only takes one. | |
| 2606 | /// | |
| 2607 | /// Symlinks are followed. | |
| 2608 | /// | |
| 2609 | /// `sub_path` may be absolute, in which case `self` is ignored. | |
| 2610 | pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat { | |
| 2611 | switch (builtin.os.tag) { | |
| 2612 | .windows => { | |
| 2613 | var file = try self.openFile(sub_path, .{}); | |
| 2614 | defer file.close(); | |
| 2615 | return file.stat(); | |
| 2616 | }, | |
| 2617 | .wasi => { | |
| 2618 | const st = try os.fstatatWasi(self.fd, sub_path, os.wasi.LOOKUP_SYMLINK_FOLLOW); | |
| 2619 | return Stat.fromSystem(st); | |
| 2620 | }, | |
| 2621 | else => { | |
| 2622 | const st = try os.fstatat(self.fd, sub_path, 0); | |
| 2623 | return Stat.fromSystem(st); | |
| 2624 | }, | |
| 2625 | } | |
| 2609 | 2626 | } |
| 2610 | 2627 | |
| 2611 | 2628 | const Permissions = File.Permissions; |
lib/std/fs/file.zig+54-47| ... | ... | @@ -294,14 +294,17 @@ pub const File = struct { |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | 296 | 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. | |
| 300 | 301 | /// |
| 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. | |
| 303 | 305 | /// |
| 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. | |
| 305 | 308 | inode: INode, |
| 306 | 309 | size: u64, |
| 307 | 310 | mode: Mode, |
| ... | ... | @@ -313,6 +316,50 @@ pub const File = struct { |
| 313 | 316 | mtime: i128, |
| 314 | 317 | /// Creation time in nanoseconds, relative to UTC 1970-01-01. |
| 315 | 318 | ctime: i128, |
| 319 | ||
| 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: { | |
| 333 | const m = st.mode & os.S.IFMT; | |
| 334 | switch (m) { | |
| 335 | os.S.IFBLK => break :blk Kind.BlockDevice, | |
| 336 | os.S.IFCHR => break :blk Kind.CharacterDevice, | |
| 337 | os.S.IFDIR => break :blk Kind.Directory, | |
| 338 | os.S.IFIFO => break :blk Kind.NamedPipe, | |
| 339 | os.S.IFLNK => break :blk Kind.SymLink, | |
| 340 | os.S.IFREG => break :blk Kind.File, | |
| 341 | os.S.IFSOCK => break :blk Kind.UnixDomainSocket, | |
| 342 | else => {}, | |
| 343 | } | |
| 344 | if (builtin.os.tag == .solaris) switch (m) { | |
| 345 | os.S.IFDOOR => break :blk Kind.Door, | |
| 346 | os.S.IFPORT => break :blk Kind.EventPort, | |
| 347 | else => {}, | |
| 348 | }; | |
| 349 | ||
| 350 | break :blk .Unknown; | |
| 351 | }; | |
| 352 | ||
| 353 | return Stat{ | |
| 354 | .inode = st.ino, | |
| 355 | .size = @bitCast(u64, st.size), | |
| 356 | .mode = st.mode, | |
| 357 | .kind = kind, | |
| 358 | .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec, | |
| 359 | .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec, | |
| 360 | .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec, | |
| 361 | }; | |
| 362 | } | |
| 316 | 363 | }; |
| 317 | 364 | |
| 318 | 365 | pub const StatError = os.FStatError; |
| ... | ... | @@ -342,47 +389,7 @@ pub const File = struct { |
| 342 | 389 | } |
| 343 | 390 | |
| 344 | 391 | const st = try os.fstat(self.handle); |
| 345 | const atime = st.atime(); | |
| 346 | const mtime = st.mtime(); | |
| 347 | const ctime = st.ctime(); | |
| 348 | const kind: Kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) { | |
| 349 | .BLOCK_DEVICE => Kind.BlockDevice, | |
| 350 | .CHARACTER_DEVICE => Kind.CharacterDevice, | |
| 351 | .DIRECTORY => Kind.Directory, | |
| 352 | .SYMBOLIC_LINK => Kind.SymLink, | |
| 353 | .REGULAR_FILE => Kind.File, | |
| 354 | .SOCKET_STREAM, .SOCKET_DGRAM => Kind.UnixDomainSocket, | |
| 355 | else => Kind.Unknown, | |
| 356 | } else blk: { | |
| 357 | const m = st.mode & os.S.IFMT; | |
| 358 | switch (m) { | |
| 359 | os.S.IFBLK => break :blk Kind.BlockDevice, | |
| 360 | os.S.IFCHR => break :blk Kind.CharacterDevice, | |
| 361 | os.S.IFDIR => break :blk Kind.Directory, | |
| 362 | os.S.IFIFO => break :blk Kind.NamedPipe, | |
| 363 | os.S.IFLNK => break :blk Kind.SymLink, | |
| 364 | os.S.IFREG => break :blk Kind.File, | |
| 365 | os.S.IFSOCK => break :blk Kind.UnixDomainSocket, | |
| 366 | else => {}, | |
| 367 | } | |
| 368 | if (builtin.os.tag == .solaris) switch (m) { | |
| 369 | os.S.IFDOOR => break :blk Kind.Door, | |
| 370 | os.S.IFPORT => break :blk Kind.EventPort, | |
| 371 | else => {}, | |
| 372 | }; | |
| 373 | ||
| 374 | break :blk .Unknown; | |
| 375 | }; | |
| 376 | ||
| 377 | return Stat{ | |
| 378 | .inode = st.ino, | |
| 379 | .size = @bitCast(u64, st.size), | |
| 380 | .mode = st.mode, | |
| 381 | .kind = kind, | |
| 382 | .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec, | |
| 383 | .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec, | |
| 384 | .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec, | |
| 385 | }; | |
| 392 | return Stat.fromSystem(st); | |
| 386 | 393 | } |
| 387 | 394 | |
| 388 | 395 | pub const ChmodError = std.os.FChmodError; |
src/Module.zig+1-1| ... | ... | @@ -4156,7 +4156,7 @@ pub fn populateBuiltinFile(mod: *Module) !void { |
| 4156 | 4156 | file.status = .success_zir; |
| 4157 | 4157 | } |
| 4158 | 4158 | |
| 4159 | pub fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void { | |
| 4159 | fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void { | |
| 4160 | 4160 | var af = try builtin_pkg.root_src_directory.handle.atomicFile(builtin_pkg.root_src_path, .{}); |
| 4161 | 4161 | defer af.deinit(); |
| 4162 | 4162 | try af.file.writeAll(file.source); |