Commit a909db6aea

LemonBoy <thatlemon@gmail.com>
2021-05-07 09:41:26
std: Prefer 64bit libc functions where possible
While musl decided to hard-wire off_t to a 64bit quantity, glibc is much older and defaults to 32bit offsets and offers some -64 suffixed versions of I/O functions. There's a weird mix-up of types: sometimes off_t is used, sometimes not, sometimes it's defined as a signed quantity and sometimes as an unsigned one, but we'll sort this problem later.
1 parent 28a9e4c
Changed files (2)
lib
lib/std/c/linux.zig
@@ -61,6 +61,23 @@ pub const EAI = extern enum(c_int) {
     _,
 };
 
+pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: i64, len: i64) 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: *libc_stat) c_int;
+pub extern "c" fn fstatat64(dirfd: fd_t, path: [*:0]const u8, stat_buf: *libc_stat, flags: u32) c_int;
+pub extern "c" fn ftruncate64(fd: c_int, length: i64) c_int;
+pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
+pub extern "c" fn lseek64(fd: fd_t, offset: u64, whence: c_int) u64;
+pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: u64) *c_void;
+pub extern "c" fn open64(path: [*:0]const u8, oflag: c_uint, ...) c_int;
+pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
+pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize;
+pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: u64) isize;
+pub extern "c" fn pwrite64(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize;
+pub extern "c" fn pwritev64(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: u64) isize;
+pub extern "c" fn sendfile64(out_fd: fd_t, in_fd: fd_t, offset: ?*i64, count: usize) isize;
+pub extern "c" fn setrlimit64(resource: rlimit_resource, rlim: *const rlimit) c_int;
+
 pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
 pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;
 pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int;
@@ -90,8 +107,6 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
 
 pub extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
 
-pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
-
 pub extern "c" fn sendfile(
     out_fd: fd_t,
     in_fd: fd_t,
lib/std/os.zig
@@ -497,8 +497,13 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
     };
     const adjusted_len = math.min(max_count, buf.len);
 
+    const pread_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.pread64
+    else
+        system.pread;
+
     while (true) {
-        const rc = system.pread(fd, buf.ptr, adjusted_len, offset);
+        const rc = pread_sym(fd, buf.ptr, adjusted_len, offset);
         switch (errno(rc)) {
             0 => return @intCast(usize, rc),
             EINTR => continue,
@@ -567,15 +572,12 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
     }
 
     while (true) {
-        const rc = if (builtin.link_libc)
-            if (std.Target.current.os.tag == .linux)
-                system.ftruncate64(fd, @bitCast(off_t, length))
-            else
-                system.ftruncate(fd, @bitCast(off_t, length))
+        const ftruncate_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+            system.ftruncate64
         else
-            system.ftruncate(fd, length);
+            system.ftruncate;
 
-        switch (errno(rc)) {
+        switch (errno(ftruncate_sym(fd, @bitCast(off_t, length)))) {
             0 => return,
             EINTR => continue,
             EFBIG => return error.FileTooBig,
@@ -637,8 +639,13 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
 
     const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);
 
+    const preadv_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.preadv64
+    else
+        system.preadv;
+
     while (true) {
-        const rc = system.preadv(fd, iov.ptr, iov_count, offset);
+        const rc = preadv_sym(fd, iov.ptr, iov_count, offset);
         switch (errno(rc)) {
             0 => return @bitCast(usize, rc),
             EINTR => continue,
@@ -895,8 +902,13 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
     };
     const adjusted_len = math.min(max_count, bytes.len);
 
+    const pwrite_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.pwrite64
+    else
+        system.pwrite;
+
     while (true) {
-        const rc = system.pwrite(fd, bytes.ptr, adjusted_len, offset);
+        const rc = pwrite_sym(fd, bytes.ptr, adjusted_len, offset);
         switch (errno(rc)) {
             0 => return @intCast(usize, rc),
             EINTR => continue,
@@ -977,9 +989,14 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
         }
     }
 
+    const pwritev_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.pwritev64
+    else
+        system.pwritev;
+
     const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);
     while (true) {
-        const rc = system.pwritev(fd, iov.ptr, iov_count, offset);
+        const rc = pwritev_sym(fd, iov.ptr, iov_count, offset);
         switch (errno(rc)) {
             0 => return @intCast(usize, rc),
             EINTR => continue,
@@ -1068,8 +1085,14 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t
         const file_path_w = try windows.cStrToPrefixedFileW(file_path);
         return openW(file_path_w.span(), flags, perm);
     }
+
+    const open_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.open64
+    else
+        system.open;
+
     while (true) {
-        const rc = system.open(file_path, flags, perm);
+        const rc = open_sym(file_path, flags, perm);
         switch (errno(rc)) {
             0 => return @intCast(fd_t, rc),
             EINTR => continue,
@@ -1202,8 +1225,14 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)
         const file_path_w = try windows.cStrToPrefixedFileW(file_path);
         return openatW(dir_fd, file_path_w.span(), flags, mode);
     }
+
+    const openat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.openat64
+    else
+        system.openat;
+
     while (true) {
-        const rc = system.openat(dir_fd, file_path, flags, mode);
+        const rc = openat_sym(dir_fd, file_path, flags, mode);
         switch (errno(rc)) {
             0 => return @intCast(fd_t, rc),
             EINTR => continue,
@@ -3437,8 +3466,13 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
         @compileError("fstat is not yet implemented on Windows");
     }
 
+    const fstat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.fstat64
+    else
+        system.fstat;
+
     var stat = mem.zeroes(Stat);
-    switch (errno(system.fstat(fd, &stat))) {
+    switch (errno(fstat_sym(fd, &stat))) {
         0 => return stat,
         EINVAL => unreachable,
         EBADF => unreachable, // Always a race condition.
@@ -3488,8 +3522,13 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
 /// Same as `fstatat` but `pathname` is null-terminated.
 /// See also `fstatat`.
 pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {
+    const fstatat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.fstatat64
+    else
+        system.fstatat;
+
     var stat = mem.zeroes(Stat);
-    switch (errno(system.fstatat(dirfd, pathname, &stat, flags))) {
+    switch (errno(fstatat_sym(dirfd, pathname, &stat, flags))) {
         0 => return stat,
         EINVAL => unreachable,
         EBADF => unreachable, // Always a race condition.
@@ -3701,12 +3740,16 @@ pub fn mmap(
     fd: fd_t,
     offset: u64,
 ) MMapError![]align(mem.page_size) u8 {
+    const mmap_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.mmap64
+    else
+        system.mmap;
+
+    const rc = mmap_sym(ptr, length, prot, flags, fd, offset);
     const err = if (builtin.link_libc) blk: {
-        const rc = std.c.mmap(ptr, length, prot, flags, fd, offset);
         if (rc != std.c.MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length];
         break :blk system._errno().*;
     } else blk: {
-        const rc = system.mmap(ptr, length, prot, flags, fd, offset);
         const err = errno(rc);
         if (err == 0) return @intToPtr([*]align(mem.page_size) u8, rc)[0..length];
         break :blk err;
@@ -4139,7 +4182,12 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
             else => |err| return unexpectedErrno(err),
         }
     }
-    switch (errno(system.lseek(fd, offset, SEEK_END))) {
+    const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.lseek64
+    else
+        system.lseek;
+
+    switch (errno(lseek_sym(fd, offset, SEEK_END))) {
         0 => return,
         EBADF => unreachable, // always a race condition
         EINVAL => return error.Unseekable,
@@ -4180,7 +4228,12 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
             else => |err| return unexpectedErrno(err),
         }
     }
-    const rc = system.lseek(fd, 0, SEEK_CUR);
+    const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.lseek64
+    else
+        system.lseek;
+
+    const rc = lseek_sym(fd, 0, SEEK_CUR);
     switch (errno(rc)) {
         0 => return @bitCast(u64, rc),
         EBADF => unreachable, // always a race condition
@@ -5198,9 +5251,14 @@ pub fn sendfile(
             // Here we match BSD behavior, making a zero count value send as many bytes as possible.
             const adjusted_count = if (in_len == 0) max_count else math.min(in_len, @as(size_t, max_count));
 
+            const sendfile_sym = if (builtin.link_libc)
+                system.sendfile64
+            else
+                system.sendfile;
+
             while (true) {
                 var offset: off_t = @bitCast(off_t, in_offset);
-                const rc = system.sendfile(out_fd, in_fd, &offset, adjusted_count);
+                const rc = sendfile_sym(out_fd, in_fd, &offset, adjusted_count);
                 switch (errno(rc)) {
                     0 => {
                         const amt = @bitCast(usize, rc);
@@ -6018,9 +6076,13 @@ pub fn prctl(option: PR, args: anytype) PrctlError!u31 {
 pub const GetrlimitError = UnexpectedError;
 
 pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {
+    const getrlimit_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.getrlimit64
+    else
+        system.getrlimit;
+
     var limits: rlimit = undefined;
-    const rc = system.getrlimit(resource, &limits);
-    switch (errno(rc)) {
+    switch (errno(getrlimit_sym(resource, &limits))) {
         0 => return limits,
         EFAULT => unreachable, // bogus pointer
         EINVAL => unreachable,
@@ -6031,8 +6093,12 @@ pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {
 pub const SetrlimitError = error{PermissionDenied} || UnexpectedError;
 
 pub fn setrlimit(resource: rlimit_resource, limits: rlimit) SetrlimitError!void {
-    const rc = system.setrlimit(resource, &limits);
-    switch (errno(rc)) {
+    const setrlimit_sym = if (builtin.os.tag == .linux and builtin.link_libc)
+        system.setrlimit64
+    else
+        system.setrlimit;
+
+    switch (errno(setrlimit_sym(resource, &limits))) {
         0 => return,
         EFAULT => unreachable, // bogus pointer
         EINVAL => unreachable,