| ... | @@ -342,7 +342,7 @@ pub fn seekTo(self: File, offset: u64) SeekError!void { | ... | @@ -342,7 +342,7 @@ pub fn seekTo(self: File, offset: u64) SeekError!void { |
| 342 | return posix.lseek_SET(self.handle, offset); | 342 | return posix.lseek_SET(self.handle, offset); |
| 343 | } | 343 | } |
| 344 | | 344 | |
| 345 | pub const GetSeekPosError = posix.SeekError || posix.FStatError; | 345 | pub const GetSeekPosError = posix.SeekError || StatError; |
| 346 | | 346 | |
| 347 | /// TODO: integrate with async I/O | 347 | /// TODO: integrate with async I/O |
| 348 | pub fn getPos(self: File) GetSeekPosError!u64 { | 348 | pub fn getPos(self: File) GetSeekPosError!u64 { |
| ... | @@ -357,7 +357,7 @@ pub fn getEndPos(self: File) GetSeekPosError!u64 { | ... | @@ -357,7 +357,7 @@ pub fn getEndPos(self: File) GetSeekPosError!u64 { |
| 357 | return (try self.stat()).size; | 357 | return (try self.stat()).size; |
| 358 | } | 358 | } |
| 359 | | 359 | |
| 360 | pub const ModeError = posix.FStatError; | 360 | pub const ModeError = StatError; |
| 361 | | 361 | |
| 362 | /// TODO: integrate with async I/O | 362 | /// TODO: integrate with async I/O |
| 363 | pub fn mode(self: File) ModeError!Mode { | 363 | pub fn mode(self: File) ModeError!Mode { |
| ... | @@ -392,7 +392,7 @@ pub const Stat = struct { | ... | @@ -392,7 +392,7 @@ pub const Stat = struct { |
| 392 | /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01. | 392 | /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01. |
| 393 | ctime: i128, | 393 | ctime: i128, |
| 394 | | 394 | |
| 395 | pub fn fromSystem(st: posix.Stat) Stat { | 395 | pub fn fromPosix(st: posix.Stat) Stat { |
| 396 | const atime = st.atime(); | 396 | const atime = st.atime(); |
| 397 | const mtime = st.mtime(); | 397 | const mtime = st.mtime(); |
| 398 | const ctime = st.ctime(); | 398 | const ctime = st.ctime(); |
| ... | @@ -426,6 +426,31 @@ pub const Stat = struct { | ... | @@ -426,6 +426,31 @@ pub const Stat = struct { |
| 426 | }; | 426 | }; |
| 427 | } | 427 | } |
| 428 | | 428 | |
| | 429 | pub fn fromLinux(stx: linux.Statx) Stat { |
| | 430 | const atime = stx.atime; |
| | 431 | const mtime = stx.mtime; |
| | 432 | const ctime = stx.ctime; |
| | 433 | |
| | 434 | return .{ |
| | 435 | .inode = stx.ino, |
| | 436 | .size = stx.size, |
| | 437 | .mode = stx.mode, |
| | 438 | .kind = switch (stx.mode & linux.S.IFMT) { |
| | 439 | linux.S.IFDIR => .directory, |
| | 440 | linux.S.IFCHR => .character_device, |
| | 441 | linux.S.IFBLK => .block_device, |
| | 442 | linux.S.IFREG => .file, |
| | 443 | linux.S.IFIFO => .named_pipe, |
| | 444 | linux.S.IFLNK => .sym_link, |
| | 445 | linux.S.IFSOCK => .unix_domain_socket, |
| | 446 | else => .unknown, |
| | 447 | }, |
| | 448 | .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec, |
| | 449 | .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec, |
| | 450 | .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec, |
| | 451 | }; |
| | 452 | } |
| | 453 | |
| 429 | pub fn fromWasi(st: std.os.wasi.filestat_t) Stat { | 454 | pub fn fromWasi(st: std.os.wasi.filestat_t) Stat { |
| 430 | return .{ | 455 | return .{ |
| 431 | .inode = st.ino, | 456 | .inode = st.ino, |
| ... | @@ -502,8 +527,34 @@ pub fn stat(self: File) StatError!Stat { | ... | @@ -502,8 +527,34 @@ pub fn stat(self: File) StatError!Stat { |
| 502 | return Stat.fromWasi(st); | 527 | return Stat.fromWasi(st); |
| 503 | } | 528 | } |
| 504 | | 529 | |
| | 530 | if (builtin.os.tag == .linux) { |
| | 531 | var stx = std.mem.zeroes(linux.Statx); |
| | 532 | |
| | 533 | const rc = linux.statx( |
| | 534 | self.handle, |
| | 535 | "", |
| | 536 | linux.AT.EMPTY_PATH, |
| | 537 | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME, |
| | 538 | &stx, |
| | 539 | ); |
| | 540 | |
| | 541 | return switch (linux.E.init(rc)) { |
| | 542 | .SUCCESS => Stat.fromLinux(stx), |
| | 543 | .ACCES => unreachable, |
| | 544 | .BADF => unreachable, |
| | 545 | .FAULT => unreachable, |
| | 546 | .INVAL => unreachable, |
| | 547 | .LOOP => unreachable, |
| | 548 | .NAMETOOLONG => unreachable, |
| | 549 | .NOENT => unreachable, |
| | 550 | .NOMEM => error.SystemResources, |
| | 551 | .NOTDIR => unreachable, |
| | 552 | else => |err| posix.unexpectedErrno(err), |
| | 553 | }; |
| | 554 | } |
| | 555 | |
| 505 | const st = try posix.fstat(self.handle); | 556 | const st = try posix.fstat(self.handle); |
| 506 | return Stat.fromSystem(st); | 557 | return Stat.fromPosix(st); |
| 507 | } | 558 | } |
| 508 | | 559 | |
| 509 | pub const ChmodError = posix.FChmodError; | 560 | pub const ChmodError = posix.FChmodError; |
| ... | @@ -1009,16 +1060,29 @@ pub fn metadata(self: File) MetadataError!Metadata { | ... | @@ -1009,16 +1060,29 @@ pub fn metadata(self: File) MetadataError!Metadata { |
| 1009 | }; | 1060 | }; |
| 1010 | }, | 1061 | }, |
| 1011 | .linux => blk: { | 1062 | .linux => blk: { |
| 1012 | const l = std.os.linux; | 1063 | var stx = std.mem.zeroes(linux.Statx); |
| 1013 | var stx = std.mem.zeroes(l.Statx); | 1064 | |
| 1014 | const rcx = l.statx(self.handle, "\x00", l.AT.EMPTY_PATH, l.STATX_TYPE | | 1065 | // We are gathering information for Metadata, which is meant to contain all the |
| 1015 | l.STATX_MODE | l.STATX_ATIME | l.STATX_MTIME | l.STATX_BTIME, &stx); | 1066 | // native OS information about the file, so use all known flags. |
| 1016 | | 1067 | const rc = linux.statx( |
| 1017 | switch (posix.errno(rcx)) { | 1068 | self.handle, |
| | 1069 | "", |
| | 1070 | linux.AT.EMPTY_PATH, |
| | 1071 | linux.STATX_BASIC_STATS | linux.STATX_BTIME, |
| | 1072 | &stx, |
| | 1073 | ); |
| | 1074 | |
| | 1075 | switch (posix.errno(rc)) { |
| 1018 | .SUCCESS => {}, | 1076 | .SUCCESS => {}, |
| | 1077 | .ACCES => unreachable, |
| 1019 | .BADF => unreachable, | 1078 | .BADF => unreachable, |
| 1020 | .FAULT => unreachable, | 1079 | .FAULT => unreachable, |
| | 1080 | .INVAL => unreachable, |
| | 1081 | .LOOP => unreachable, |
| | 1082 | .NAMETOOLONG => unreachable, |
| | 1083 | .NOENT => unreachable, |
| 1021 | .NOMEM => return error.SystemResources, | 1084 | .NOMEM => return error.SystemResources, |
| | 1085 | .NOTDIR => unreachable, |
| 1022 | else => |err| return posix.unexpectedErrno(err), | 1086 | else => |err| return posix.unexpectedErrno(err), |
| 1023 | } | 1087 | } |
| 1024 | | 1088 | |
| ... | @@ -1712,6 +1776,7 @@ const posix = std.posix; | ... | @@ -1712,6 +1776,7 @@ const posix = std.posix; |
| 1712 | const io = std.io; | 1776 | const io = std.io; |
| 1713 | const math = std.math; | 1777 | const math = std.math; |
| 1714 | const assert = std.debug.assert; | 1778 | const assert = std.debug.assert; |
| | 1779 | const linux = std.os.linux; |
| 1715 | const windows = std.os.windows; | 1780 | const windows = std.os.windows; |
| 1716 | const Os = std.builtin.Os; | 1781 | const Os = std.builtin.Os; |
| 1717 | const maxInt = std.math.maxInt; | 1782 | const maxInt = std.math.maxInt; |