Commit 0e95fa455c

LemonBoy <thatlemon@gmail.com>
2020-11-04 15:55:36
std: Split kernel&libc definitions of stat struct
There's no guarantee for the kernel definition to be ABI compatible with the libc one (and vice versa). There's also no guarantee of ABI compatibility between musl/glibc. Fun, isn't it?
1 parent 346a686
lib/std/c/darwin.zig
@@ -30,16 +30,16 @@ pub extern "c" fn @"realpath$DARWIN_EXTSN"(noalias file_name: [*:0]const u8, noa
 
 pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize;
 
-extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
+extern "c" fn fstat(fd: fd_t, buf: *libc_stat) c_int;
 /// On x86_64 Darwin, fstat has to be manully linked with $INODE64 suffix to force 64bit version.
 /// Note that this is fixed on aarch64 and no longer necessary.
-extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int;
+extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *libc_stat) c_int;
 pub const _fstat = if (builtin.arch == .aarch64) fstat else @"fstat$INODE64";
 
-extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int;
+extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *libc_stat, flags: u32) c_int;
 /// On x86_64 Darwin, fstatat has to be manully linked with $INODE64 suffix to force 64bit version.
 /// Note that this is fixed on aarch64 and no longer necessary.
-extern "c" fn @"fstatat$INODE64"(dirfd: fd_t, path_name: [*:0]const u8, buf: *Stat, flags: u32) c_int;
+extern "c" fn @"fstatat$INODE64"(dirfd: fd_t, path_name: [*:0]const u8, buf: *libc_stat, flags: u32) c_int;
 pub const _fstatat = if (builtin.arch == .aarch64) fstatat else @"fstatat$INODE64";
 
 pub extern "c" fn mach_absolute_time() u64;
lib/std/os/bits/linux/arm-eabi.zig
@@ -553,13 +553,8 @@ pub const ino_t = u64;
 pub const dev_t = u64;
 pub const blkcnt_t = i64;
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+// The `stat` definition used by the Linux kernel.
+pub const kernel_stat = extern struct {
     dev: dev_t,
     __dev_padding: u32,
     __ino_truncated: u32,
@@ -577,19 +572,22 @@ pub const Stat = extern struct {
     ctim: timespec,
     ino: ino_t,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
 
+// The `stat64` definition used by the libc.
+pub const libc_stat = kernel_stat;
+
 pub const timespec = extern struct {
     tv_sec: i32,
     tv_nsec: i32,
lib/std/os/bits/linux/arm64.zig
@@ -424,13 +424,8 @@ pub const ino_t = usize;
 pub const dev_t = usize;
 pub const blkcnt_t = isize;
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+// The `stat` definition used by the Linux kernel.
+pub const kernel_stat = extern struct {
     dev: dev_t,
     ino: ino_t,
     mode: mode_t,
@@ -448,19 +443,22 @@ pub const Stat = extern struct {
     ctim: timespec,
     __unused: [2]u32,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
 
+// The `stat64` definition used by the libc.
+pub const libc_stat = kernel_stat;
+
 pub const timespec = extern struct {
     tv_sec: time_t,
     tv_nsec: isize,
lib/std/os/bits/linux/i386.zig
@@ -546,13 +546,8 @@ pub const ino_t = u64;
 pub const dev_t = u64;
 pub const blkcnt_t = i64;
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+// The `stat` definition used by the Linux kernel.
+pub const kernel_stat = extern struct {
     dev: dev_t,
     __dev_padding: u32,
     __ino_truncated: u32,
@@ -570,19 +565,22 @@ pub const Stat = extern struct {
     ctim: timespec,
     ino: ino_t,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
 
+// The `stat64` definition used by the libc.
+pub const libc_stat = kernel_stat;
+
 pub const timespec = extern struct {
     tv_sec: i32,
     tv_nsec: i32,
lib/std/os/bits/linux/mips.zig
@@ -536,41 +536,74 @@ pub const Flock = extern struct {
 
 pub const blksize_t = i32;
 pub const nlink_t = u32;
-pub const time_t = isize;
+pub const time_t = i32;
 pub const mode_t = u32;
 pub const off_t = i64;
 pub const ino_t = u64;
-pub const dev_t = usize;
+pub const dev_t = u64;
 pub const blkcnt_t = i64;
 
-pub const Stat = extern struct {
+// The `stat` definition used by the Linux kernel.
+pub const kernel_stat = extern struct {
     dev: u32,
-    __pad0: [3]u32,
+    __pad0: [3]u32, // Reserved for st_dev expansion
     ino: ino_t,
     mode: mode_t,
     nlink: nlink_t,
     uid: uid_t,
     gid: gid_t,
-    rdev: dev_t,
+    rdev: u32,
     __pad1: [3]u32,
     size: off_t,
     atim: timespec,
     mtim: timespec,
     ctim: timespec,
     blksize: blksize_t,
-    __pad3: [1]u32,
+    __pad3: u32,
     blocks: blkcnt_t,
     __pad4: [14]usize,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
+        return self.atim;
+    }
+
+    pub fn mtime(self: @This()) timespec {
+        return self.mtim;
+    }
+
+    pub fn ctime(self: @This()) timespec {
+        return self.ctim;
+    }
+};
+
+pub const libc_stat = extern struct {
+    dev: dev_t,
+    __pad0: [2]u32,
+    ino: ino_t,
+    mode: mode_t,
+    nlink: nlink_t,
+    uid: uid_t,
+    gid: gid_t,
+    rdev: dev_t,
+    __pad1: [2]u32,
+    size: off_t,
+    atim: timespec,
+    mtim: timespec,
+    ctim: timespec,
+    blksize: blksize_t,
+    __pad3: u32,
+    blocks: blkcnt_t,
+    __pad4: [14]u32,
+
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
lib/std/os/bits/linux/powerpc64.zig
@@ -516,13 +516,8 @@ pub const ino_t = u64;
 pub const dev_t = u64;
 pub const blkcnt_t = i64;
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+// The `stat` definition used by the Linux kernel.
+pub const kernel_stat = extern struct {
     dev: dev_t,
     ino: ino_t,
     nlink: nlink_t,
@@ -538,19 +533,22 @@ pub const Stat = extern struct {
     ctim: timespec,
     __unused: [3]u64,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
 
+// The `stat64` definition used by the libc.
+pub const libc_stat = kernel_stat;
+
 pub const timespec = extern struct {
     tv_sec: time_t,
     tv_nsec: isize,
lib/std/os/bits/linux/riscv64.zig
@@ -381,13 +381,8 @@ pub const Flock = extern struct {
     __unused: [4]u8,
 };
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+// The `stat` definition used by the Linux kernel.
+pub const kernel_stat = extern struct {
     dev: dev_t,
     ino: ino_t,
     mode: mode_t,
@@ -405,17 +400,20 @@ pub const Stat = extern struct {
     ctim: timespec,
     __unused: [2]u32,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
 
+// The `stat64` definition used by the libc.
+pub const libc_stat = kernel_stat;
+
 pub const Elf_Symndx = u32;
lib/std/os/bits/linux/sparc64.zig
@@ -484,11 +484,7 @@ pub const off_t = i64;
 pub const ino_t = u64;
 pub const mode_t = u32;
 
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
+// The `stat64` definition used by the libc.
 pub const libc_stat = extern struct {
     dev: u64,
     ino: ino_t,
@@ -522,45 +518,40 @@ pub const libc_stat = extern struct {
     }
 };
 
+// The `stat64` definition used by the kernel.
 pub const kernel_stat = extern struct {
-    dev: u32,
-    ino: ino_t,
-    mode: mode_t,
-    nlink: i16,
+    dev: u64,
+    ino: u64,
+    nlink: u64,
 
+    mode: u32,
     uid: u32,
     gid: u32,
-    rdev: u32,
-
-    size: off_t,
-    atim: isize,
-    mtim: isize,
-    ctim: isize,
+    __pad0: u32,
 
-    blksize: off_t,
-    blocks: off_t,
+    rdev: u64,
+    size: i64,
+    blksize: i64,
+    blocks: i64,
 
-    __unused4: [2]isize,
+    atim: timespec,
+    mtim: timespec,
+    ctim: timespec,
+    __unused: [3]u64,
 
-    // Hack to make the stdlib not complain about atime
-    // and friends not being a method.
-    // TODO what should tv_nsec be filled with?
-    pub fn atime(self: kernel_stat) timespec {
-        return timespec{.tv_sec=self.atim, .tv_nsec=0};
+    pub fn atime(self: @This()) timespec {
+        return self.atim;
     }
 
-    pub fn mtime(self: kernel_stat) timespec {
-        return timespec{.tv_sec=self.mtim, .tv_nsec=0};
+    pub fn mtime(self: @This()) timespec {
+        return self.mtim;
     }
 
-    pub fn ctime(self: kernel_stat) timespec {
-        return timespec{.tv_sec=self.ctim, .tv_nsec=0};
+    pub fn ctime(self: @This()) timespec {
+        return self.ctim;
     }
 };
 
-/// Renamed to Stat to not conflict with the stat function.
-pub const Stat = if (std.builtin.link_libc) libc_stat else kernel_stat;
-
 pub const timespec = extern struct {
     tv_sec: isize,
     tv_nsec: isize,
lib/std/os/bits/linux/x86_64.zig
@@ -512,13 +512,8 @@ pub const msghdr_const = extern struct {
 pub const off_t = i64;
 pub const ino_t = u64;
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+// The `stat` definition used by the Linux kernel.
+pub const kernel_stat = extern struct {
     dev: u64,
     ino: ino_t,
     nlink: usize,
@@ -537,19 +532,22 @@ pub const Stat = extern struct {
     ctim: timespec,
     __unused: [3]isize,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
 
+// The `stat64` definition used by the libc.
+pub const libc_stat = kernel_stat;
+
 pub const timespec = extern struct {
     tv_sec: isize,
     tv_nsec: isize,
lib/std/os/bits/darwin.zig
@@ -72,13 +72,7 @@ pub const Flock = extern struct {
     l_whence: i16,
 };
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+pub const libc_stat = extern struct {
     dev: i32,
     mode: u16,
     nlink: u16,
@@ -102,21 +96,21 @@ pub const Stat = extern struct {
     lspare: i32,
     qspare: [2]i64,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return timespec{
             .tv_sec = self.atimesec,
             .tv_nsec = self.atimensec,
         };
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return timespec{
             .tv_sec = self.mtimesec,
             .tv_nsec = self.mtimensec,
         };
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return timespec{
             .tv_sec = self.ctimesec,
             .tv_nsec = self.ctimensec,
lib/std/os/bits/dragonfly.zig
@@ -152,7 +152,7 @@ pub const PATH_MAX = 1024;
 
 pub const ino_t = c_ulong;
 
-pub const Stat = extern struct {
+pub const libc_stat = extern struct {
     ino: ino_t,
     nlink: c_uint,
     dev: c_uint,
@@ -172,15 +172,15 @@ pub const Stat = extern struct {
     lspare: i32,
     qspare1: i64,
     qspare2: i64,
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
lib/std/os/bits/freebsd.zig
@@ -119,13 +119,7 @@ pub const msghdr_const = extern struct {
 pub const off_t = i64;
 pub const ino_t = u64;
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+pub const libc_stat = extern struct {
     dev: u64,
     ino: ino_t,
     nlink: usize,
@@ -149,15 +143,15 @@ pub const Stat = extern struct {
     gen: u64,
     __spare: [10]u64,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
lib/std/os/bits/netbsd.zig
@@ -153,13 +153,7 @@ pub const msghdr_const = extern struct {
     msg_flags: i32,
 };
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+pub const libc_stat = extern struct {
     dev: dev_t,
     mode: mode_t,
     ino: ino_t,
@@ -178,15 +172,15 @@ pub const Stat = extern struct {
     gen: u32,
     __spare: [2]u32,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
lib/std/os/bits/openbsd.zig
@@ -152,13 +152,7 @@ pub const msghdr_const = extern struct {
     msg_flags: i32,
 };
 
-/// Renamed to Stat to not conflict with the stat function.
-/// atime, mtime, and ctime have functions to return `timespec`,
-/// because although this is a POSIX API, the layout and names of
-/// the structs are inconsistent across operating systems, and
-/// in C, macros are used to hide the differences. Here we use
-/// methods to accomplish this.
-pub const Stat = extern struct {
+pub const libc_stat = extern struct {
     mode: mode_t,
     dev: dev_t,
     ino: ino_t,
@@ -176,15 +170,15 @@ pub const Stat = extern struct {
     gen: u32,
     birthtim: timespec,
 
-    pub fn atime(self: Stat) timespec {
+    pub fn atime(self: @This()) timespec {
         return self.atim;
     }
 
-    pub fn mtime(self: Stat) timespec {
+    pub fn mtime(self: @This()) timespec {
         return self.mtim;
     }
 
-    pub fn ctime(self: Stat) timespec {
+    pub fn ctime(self: @This()) timespec {
         return self.ctim;
     }
 };
lib/std/os/bits/wasi.zig
@@ -31,7 +31,7 @@ pub const timespec = struct {
     }
 };
 
-pub const Stat = struct {
+pub const libc_stat = struct {
     dev: device_t,
     ino: inode_t,
     mode: mode_t,
lib/std/os/linux/sparc64.zig
@@ -12,6 +12,7 @@ pub fn syscall_pipe(fd: *[2]i32) usize {
         \\1:
         \\ st %%o0, [%%g3+0]
         \\ st %%o1, [%%g3+4]
+        \\ clr %%o0
         \\2:
         : [ret] "={o0}" (-> usize)
         : [number] "{g1}" (@enumToInt(SYS.pipe)),
lib/std/os/linux/test.zig
@@ -67,7 +67,7 @@ test "statx" {
         else => unreachable,
     }
 
-    var stat_buf: linux.Stat = undefined;
+    var stat_buf: linux.kernel_stat = undefined;
     switch (linux.getErrno(linux.fstatat(file.handle, "", &stat_buf, linux.AT_EMPTY_PATH))) {
         0 => {},
         else => unreachable,
lib/std/os/linux.zig
@@ -1047,7 +1047,7 @@ pub fn accept4(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t, flag
     return syscall4(.accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags);
 }
 
-pub fn fstat(fd: i32, stat_buf: *Stat) usize {
+pub fn fstat(fd: i32, stat_buf: *kernel_stat) usize {
     if (@hasField(SYS, "fstat64")) {
         return syscall2(.fstat64, @bitCast(usize, @as(isize, fd)), @ptrToInt(stat_buf));
     } else {
@@ -1055,7 +1055,7 @@ pub fn fstat(fd: i32, stat_buf: *Stat) usize {
     }
 }
 
-pub fn stat(pathname: [*:0]const u8, statbuf: *Stat) usize {
+pub fn stat(pathname: [*:0]const u8, statbuf: *kernel_stat) usize {
     if (@hasField(SYS, "stat64")) {
         return syscall2(.stat64, @ptrToInt(pathname), @ptrToInt(statbuf));
     } else {
@@ -1063,7 +1063,7 @@ pub fn stat(pathname: [*:0]const u8, statbuf: *Stat) usize {
     }
 }
 
-pub fn lstat(pathname: [*:0]const u8, statbuf: *Stat) usize {
+pub fn lstat(pathname: [*:0]const u8, statbuf: *kernel_stat) usize {
     if (@hasField(SYS, "lstat64")) {
         return syscall2(.lstat64, @ptrToInt(pathname), @ptrToInt(statbuf));
     } else {
@@ -1071,7 +1071,7 @@ pub fn lstat(pathname: [*:0]const u8, statbuf: *Stat) usize {
     }
 }
 
-pub fn fstatat(dirfd: i32, path: [*:0]const u8, stat_buf: *Stat, flags: u32) usize {
+pub fn fstatat(dirfd: i32, path: [*:0]const u8, stat_buf: *kernel_stat, flags: u32) usize {
     if (@hasField(SYS, "fstatat64")) {
         return syscall4(.fstatat64, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
     } else {
lib/std/c.zig
@@ -128,7 +128,7 @@ pub usingnamespace switch (builtin.os.tag) {
     },
     else => struct {
         pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
-        pub extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int;
+        pub extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *libc_stat, flags: u32) c_int;
     },
 };
 
@@ -202,26 +202,26 @@ pub usingnamespace switch (builtin.os.tag) {
         pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
         pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
         pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
-        pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
+        pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;
     },
     .windows => struct {
         // TODO: copied the else case and removed the socket function (because its in ws2_32)
         //       need to verify which of these is actually supported on windows
         pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
         pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
-        pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
+        pub extern "c" fn fstat(fd: fd_t, buf: *libc_stat) c_int;
         pub extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
         pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
         pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
         pub extern "c" fn sched_yield() c_int;
         pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
         pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
-        pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
+        pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;
     },
     else => struct {
         pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
         pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
-        pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
+        pub extern "c" fn fstat(fd: fd_t, buf: *libc_stat) c_int;
         pub extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
         pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
         pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
@@ -229,7 +229,7 @@ pub usingnamespace switch (builtin.os.tag) {
         pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int;
         pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
         pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
-        pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
+        pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *libc_stat) c_int;
     },
 };
 
lib/std/os.zig
@@ -3267,6 +3267,11 @@ pub fn waitpid(pid: pid_t, flags: u32) WaitPidResult {
     }
 }
 
+pub const Stat = if (builtin.link_libc)
+    system.libc_stat
+else
+    system.kernel_stat;
+
 pub const FStatError = error{
     SystemResources,