authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-14 20:54:04-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-12-14 20:54:04-05:00
logc2f5848fe4dc3d3ffbebdbaaf8ff55fa2a9eb286
tree714af317059e20a7c8f6f075c946a3a2f30fe5c6
parent4af305b30acdefb9da380b21b446d2b31b5a6295
parentb911b54aeb45d2d2d7a8d616af5df04ad230bcc3
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11594 from KaneRoot/master

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,7 +67,7 @@ stage3-debug/bin/zig build test docs \
67 --zig-lib-dir "$(pwd)/../lib"67 --zig-lib-dir "$(pwd)/../lib"
6868
69# Look for HTML errors.69# Look for HTML errors.
70tidy --drop-empty-elements no -qe ../zig-cache/langref.html70tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html"
7171
72# Produce the experimental std lib documentation.72# Produce the experimental std lib documentation.
73stage3-debug/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib73stage3-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,7 +67,7 @@ stage3-release/bin/zig build test docs \
67 --zig-lib-dir "$(pwd)/../lib"67 --zig-lib-dir "$(pwd)/../lib"
6868
69# Look for HTML errors.69# Look for HTML errors.
70tidy --drop-empty-elements no -qe ../zig-cache/langref.html70tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html"
7171
72# Produce the experimental std lib documentation.72# Produce the experimental std lib documentation.
73stage3-release/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib73stage3-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,7 +66,7 @@ stage3-debug/bin/zig build test docs \
66 --zig-lib-dir "$(pwd)/../lib"66 --zig-lib-dir "$(pwd)/../lib"
6767
68# Look for HTML errors.68# Look for HTML errors.
69tidy --drop-empty-elements no -qe ../zig-cache/langref.html69tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html"
7070
71# Produce the experimental std lib documentation.71# Produce the experimental std lib documentation.
72stage3-debug/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib72stage3-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,7 +67,7 @@ stage3-release/bin/zig build test docs \
67 --zig-lib-dir "$(pwd)/../lib"67 --zig-lib-dir "$(pwd)/../lib"
6868
69# Look for HTML errors.69# Look for HTML errors.
70tidy --drop-empty-elements no -qe ../zig-cache/langref.html70tidy --drop-empty-elements no -qe "$ZIG_LOCAL_CACHE_DIR/langref.html"
7171
72# Produce the experimental std lib documentation.72# Produce the experimental std lib documentation.
73stage3-release/bin/zig test ../lib/std/std.zig -femit-docs -fno-emit-bin --zig-lib-dir ../lib73stage3-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,7 +229,7 @@ pub const EAI = enum(c_int) {
229pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;229pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
230pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;230pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;
231pub extern "c" fn fstat64(fd: fd_t, buf: *Stat) c_int;231pub extern "c" fn fstat64(fd: fd_t, buf: *Stat) c_int;
232pub extern "c" fn fstatat64(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int;232pub extern "c" fn fstatat64(dirfd: fd_t, noalias path: [*:0]const u8, noalias stat_buf: *Stat, flags: u32) c_int;
233pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;233pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
234pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;234pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
235pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;235pub 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,7 +150,6 @@ pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: Co
150 return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args);150 return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args);
151}151}
152152
153/// TODO update this API to avoid a getrandom syscall for every operation.
154pub const AtomicFile = struct {153pub const AtomicFile = struct {
155 file: File,154 file: File,
156 // TODO either replace this with rand_buf or use []u16 on Windows155 // TODO either replace this with rand_buf or use []u16 on Windows
...@@ -2598,14 +2597,32 @@ pub const Dir = struct {...@@ -2598,14 +2597,32 @@ pub const Dir = struct {
2598 return file.stat();2597 return file.stat();
2599 }2598 }
26002599
2601 pub const StatFileError = File.OpenError || StatError;2600 pub const StatFileError = File.OpenError || File.StatError || os.FStatAtError;
26022601
2603 // TODO: improve this to use the fstatat syscall instead of making 2 syscalls here.2602 /// Returns metadata for a file inside the directory.
2604 pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!File.Stat {2603 ///
2605 var file = try self.openFile(sub_path, .{});2604 /// On Windows, this requires three syscalls. On other operating systems, it
2606 defer file.close();2605 /// only takes one.
26072606 ///
2608 return file.stat();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 }
26102627
2611 const Permissions = File.Permissions;2628 const Permissions = File.Permissions;
lib/std/fs/file.zig+54-47
...@@ -294,14 +294,17 @@ pub const File = struct {...@@ -294,14 +294,17 @@ pub const File = struct {
294 }294 }
295295
296 pub const Stat = struct {296 pub const Stat = struct {
297 /// A number that the system uses to point to the file metadata. This number is not guaranteed to be297 /// A number that the system uses to point to the file metadata. This
298 /// unique across time, as some file systems may reuse an inode after its file has been deleted.298 /// number is not guaranteed to be unique across time, as some file
299 /// Some systems may change the inode of a file over time.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 what302 /// On Linux, the inode is a structure that stores the metadata, and
302 /// you see here: the index number of the inode.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 inode: INode,308 inode: INode,
306 size: u64,309 size: u64,
307 mode: Mode,310 mode: Mode,
...@@ -313,6 +316,50 @@ pub const File = struct {...@@ -313,6 +316,50 @@ pub const File = struct {
313 mtime: i128,316 mtime: i128,
314 /// Creation time in nanoseconds, relative to UTC 1970-01-01.317 /// Creation time in nanoseconds, relative to UTC 1970-01-01.
315 ctime: i128,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 };
317364
318 pub const StatError = os.FStatError;365 pub const StatError = os.FStatError;
...@@ -342,47 +389,7 @@ pub const File = struct {...@@ -342,47 +389,7 @@ pub const File = struct {
342 }389 }
343390
344 const st = try os.fstat(self.handle);391 const st = try os.fstat(self.handle);
345 const atime = st.atime();392 return Stat.fromSystem(st);
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 };
386 }393 }
387394
388 pub const ChmodError = std.os.FChmodError;395 pub const ChmodError = std.os.FChmodError;
src/Module.zig+1-1
...@@ -4156,7 +4156,7 @@ pub fn populateBuiltinFile(mod: *Module) !void {...@@ -4156,7 +4156,7 @@ pub fn populateBuiltinFile(mod: *Module) !void {
4156 file.status = .success_zir;4156 file.status = .success_zir;
4157}4157}
41584158
4159pub fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void {4159fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void {
4160 var af = try builtin_pkg.root_src_directory.handle.atomicFile(builtin_pkg.root_src_path, .{});4160 var af = try builtin_pkg.root_src_directory.handle.atomicFile(builtin_pkg.root_src_path, .{});
4161 defer af.deinit();4161 defer af.deinit();
4162 try af.file.writeAll(file.source);4162 try af.file.writeAll(file.source);