| author | |
| committer | |
| log | 7bc0166b7c34ac0120f50aceb7132ffaa4aeec83 |
| tree | e9fff72403af7557e5b7b4aa3aa7cc781981d3e1 |
| parent | b042e935228db5d46271d4d3d17afeb9ba5d7ce3 |
unfortunately, Io.Dir.SelectiveWalker is copying the iterator which
has multiple problems3 files changed, 151 insertions(+), 215 deletions(-)
lib/std/Io/Dir.zig+7-7| ... | ... | @@ -184,6 +184,11 @@ pub const SelectiveWalker = struct { |
| 184 | 184 | |
| 185 | 185 | pub const Error = Io.Dir.Iterator.Error || Allocator.Error; |
| 186 | 186 | |
| 187 | const StackItem = struct { | |
| 188 | iter: Dir.Iterator, | |
| 189 | dirname_len: usize, | |
| 190 | }; | |
| 191 | ||
| 187 | 192 | /// After each call to this function, and on deinit(), the memory returned |
| 188 | 193 | /// from this function becomes invalid. A copy must be made in order to keep |
| 189 | 194 | /// a reference to the path. |
| ... | ... | @@ -268,7 +273,7 @@ pub const SelectiveWalker = struct { |
| 268 | 273 | /// Recursively iterates over a directory, but requires the user to |
| 269 | 274 | /// opt-in to recursing into each directory entry. |
| 270 | 275 | /// |
| 271 | /// `dir` must have been opened with `OpenOptions{.iterate = true}`. | |
| 276 | /// `dir` must have been opened with `OpenOptions.iterate` set to `true`. | |
| 272 | 277 | /// |
| 273 | 278 | /// `Walker.deinit` releases allocated memory and directory handles. |
| 274 | 279 | /// |
| ... | ... | @@ -278,7 +283,7 @@ pub const SelectiveWalker = struct { |
| 278 | 283 | /// |
| 279 | 284 | /// See also `walk`. |
| 280 | 285 | pub fn walkSelectively(dir: Dir, allocator: Allocator) !SelectiveWalker { |
| 281 | var stack: std.ArrayList(Walker.StackItem) = .empty; | |
| 286 | var stack: std.ArrayList(SelectiveWalker.StackItem) = .empty; | |
| 282 | 287 | |
| 283 | 288 | try stack.append(allocator, .{ |
| 284 | 289 | .iter = dir.iterate(), |
| ... | ... | @@ -312,11 +317,6 @@ pub const Walker = struct { |
| 312 | 317 | } |
| 313 | 318 | }; |
| 314 | 319 | |
| 315 | const StackItem = struct { | |
| 316 | iter: Dir.Iterator, | |
| 317 | dirname_len: usize, | |
| 318 | }; | |
| 319 | ||
| 320 | 320 | /// After each call to this function, and on deinit(), the memory returned |
| 321 | 321 | /// from this function becomes invalid. A copy must be made in order to keep |
| 322 | 322 | /// a reference to the path. |
lib/std/Io/Threaded.zig+144-37| ... | ... | @@ -3271,12 +3271,113 @@ fn dirClose(userdata: ?*anyopaque, dirs: []const Dir) void { |
| 3271 | 3271 | for (dirs) |dir| posix.close(dir.handle); |
| 3272 | 3272 | } |
| 3273 | 3273 | |
| 3274 | fn dirRead(userdata: ?*anyopaque, dir_reader: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize { | |
| 3274 | const dirRead = switch (native_os) { | |
| 3275 | .linux => dirReadLinux, | |
| 3276 | else => dirReadUnimplemented, | |
| 3277 | }; | |
| 3278 | ||
| 3279 | fn dirReadLinux(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize { | |
| 3280 | const linux = std.os.linux; | |
| 3275 | 3281 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 3276 | _ = t; | |
| 3282 | const current_thread = Thread.getCurrent(t); | |
| 3283 | const Header = extern struct { | |
| 3284 | fill_end: usize, | |
| 3285 | }; | |
| 3286 | const header: *Header = @ptrCast(&dr.buffer); | |
| 3287 | const header_end: usize = @sizeOf(Header); | |
| 3288 | if (dr.index < header_end) { | |
| 3289 | // Initialize header. | |
| 3290 | dr.index = header_end; | |
| 3291 | header.* = .{ .fill_end = header_end }; | |
| 3292 | } | |
| 3293 | var buffer_index: usize = 0; | |
| 3294 | while (buffer.len - buffer_index != 0) { | |
| 3295 | if (header.fill_end - dr.index == 0) { | |
| 3296 | // Refill the buffer, unless we've already created references to | |
| 3297 | // buffered data. | |
| 3298 | if (buffer_index != 0) break; | |
| 3299 | if (dr.state == .reset) { | |
| 3300 | posixSeekTo(current_thread, dr.dir.handle, 0) catch |err| switch (err) { | |
| 3301 | error.Unseekable => return error.Unexpected, | |
| 3302 | else => |e| return e, | |
| 3303 | }; | |
| 3304 | dr.state = .reading; | |
| 3305 | } | |
| 3306 | const dents_buffer = dr.buffer[header_end..]; | |
| 3307 | try current_thread.beginSyscall(); | |
| 3308 | const n = while (true) { | |
| 3309 | const rc = linux.getdents64(dr.dir.handle, dents_buffer.ptr, dents_buffer.len); | |
| 3310 | switch (linux.errno(rc)) { | |
| 3311 | .SUCCESS => { | |
| 3312 | current_thread.endSyscall(); | |
| 3313 | break rc; | |
| 3314 | }, | |
| 3315 | .INTR => { | |
| 3316 | try current_thread.checkCancel(); | |
| 3317 | continue; | |
| 3318 | }, | |
| 3319 | .CANCELED => return current_thread.endSyscallCanceled(), | |
| 3320 | else => |e| { | |
| 3321 | current_thread.endSyscall(); | |
| 3322 | switch (e) { | |
| 3323 | .BADF => |err| return errnoBug(err), // Dir is invalid or was opened without iteration ability. | |
| 3324 | .FAULT => |err| return errnoBug(err), | |
| 3325 | .NOTDIR => |err| return errnoBug(err), | |
| 3326 | // To be consistent across platforms, iteration | |
| 3327 | // ends if the directory being iterated is deleted | |
| 3328 | // during iteration. This matches the behavior of | |
| 3329 | // non-Linux UNIX platforms. | |
| 3330 | .NOENT => { | |
| 3331 | dr.state = .finished; | |
| 3332 | return 0; | |
| 3333 | }, | |
| 3334 | .INVAL => return error.Unexpected, // Linux may in some cases return EINVAL when reading /proc/$PID/net. | |
| 3335 | .ACCES => return error.AccessDenied, // Lacking permission to iterate this directory. | |
| 3336 | else => |err| return posix.unexpectedErrno(err), | |
| 3337 | } | |
| 3338 | }, | |
| 3339 | } | |
| 3340 | }; | |
| 3341 | if (n == 0) { | |
| 3342 | dr.state = .finished; | |
| 3343 | return 0; | |
| 3344 | } | |
| 3345 | dr.index = header_end; | |
| 3346 | header.fill_end = header_end + n; | |
| 3347 | } | |
| 3348 | const linux_entry: *align(1) linux.dirent64 = @ptrCast(&dr.buffer[dr.index]); | |
| 3349 | const next_index = dr.index + linux_entry.reclen; | |
| 3350 | dr.index = next_index; | |
| 3351 | ||
| 3352 | const name = std.mem.sliceTo(@as([*:0]u8, @ptrCast(&linux_entry.name)), 0); | |
| 3353 | // Skip "." and ".." entries. | |
| 3354 | if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, "..")) continue; | |
| 3355 | ||
| 3356 | const entry_kind: File.Kind = switch (linux_entry.type) { | |
| 3357 | linux.DT.BLK => .block_device, | |
| 3358 | linux.DT.CHR => .character_device, | |
| 3359 | linux.DT.DIR => .directory, | |
| 3360 | linux.DT.FIFO => .named_pipe, | |
| 3361 | linux.DT.LNK => .sym_link, | |
| 3362 | linux.DT.REG => .file, | |
| 3363 | linux.DT.SOCK => .unix_domain_socket, | |
| 3364 | else => .unknown, | |
| 3365 | }; | |
| 3366 | buffer[buffer_index] = .{ | |
| 3367 | .name = name, | |
| 3368 | .kind = entry_kind, | |
| 3369 | .inode = linux_entry.ino, | |
| 3370 | }; | |
| 3371 | buffer_index += 1; | |
| 3372 | } | |
| 3373 | return buffer_index; | |
| 3374 | } | |
| 3375 | ||
| 3376 | fn dirReadUnimplemented(userdata: ?*anyopaque, dir_reader: *Dir.Reader, buffer: []Dir.Entry) Dir.Reader.Error!usize { | |
| 3377 | _ = userdata; | |
| 3277 | 3378 | _ = dir_reader; |
| 3278 | 3379 | _ = buffer; |
| 3279 | @panic("TODO"); | |
| 3380 | return error.Unimplemented; | |
| 3280 | 3381 | } |
| 3281 | 3382 | |
| 3282 | 3383 | const dirRealPath = switch (native_os) { |
| ... | ... | @@ -5908,11 +6009,16 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi |
| 5908 | 6009 | const current_thread = Thread.getCurrent(t); |
| 5909 | 6010 | const fd = file.handle; |
| 5910 | 6011 | |
| 5911 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | |
| 6012 | if (native_os == .windows) { | |
| 6013 | try current_thread.checkCancel(); | |
| 6014 | return windows.SetFilePointerEx_BEGIN(fd, offset); | |
| 6015 | } | |
| 6016 | ||
| 6017 | if (native_os == .wasi and !builtin.link_libc) { | |
| 5912 | 6018 | try current_thread.beginSyscall(); |
| 5913 | 6019 | while (true) { |
| 5914 | var result: u64 = undefined; | |
| 5915 | switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) { | |
| 6020 | var new_offset: std.os.wasi.filesize_t = undefined; | |
| 6021 | switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) { | |
| 5916 | 6022 | .SUCCESS => { |
| 5917 | 6023 | current_thread.endSyscall(); |
| 5918 | 6024 | return; |
| ... | ... | @@ -5930,6 +6036,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi |
| 5930 | 6036 | .OVERFLOW => return error.Unseekable, |
| 5931 | 6037 | .SPIPE => return error.Unseekable, |
| 5932 | 6038 | .NXIO => return error.Unseekable, |
| 6039 | .NOTCAPABLE => return error.AccessDenied, | |
| 5933 | 6040 | else => |err| return posix.unexpectedErrno(err), |
| 5934 | 6041 | } |
| 5935 | 6042 | }, |
| ... | ... | @@ -5937,40 +6044,40 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi |
| 5937 | 6044 | } |
| 5938 | 6045 | } |
| 5939 | 6046 | |
| 5940 | if (native_os == .windows) { | |
| 5941 | try current_thread.checkCancel(); | |
| 5942 | return windows.SetFilePointerEx_BEGIN(fd, offset); | |
| 5943 | } | |
| 6047 | if (posix.SEEK == void) return error.Unseekable; | |
| 5944 | 6048 | |
| 5945 | if (native_os == .wasi and !builtin.link_libc) while (true) { | |
| 5946 | var new_offset: std.os.wasi.filesize_t = undefined; | |
| 6049 | return posixSeekTo(current_thread, fd, offset); | |
| 6050 | } | |
| 6051 | ||
| 6052 | fn posixSeekTo(current_thread: *Thread, fd: posix.fd_t, offset: u64) File.SeekError!void { | |
| 6053 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | |
| 5947 | 6054 | try current_thread.beginSyscall(); |
| 5948 | switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) { | |
| 5949 | .SUCCESS => { | |
| 5950 | current_thread.endSyscall(); | |
| 5951 | return; | |
| 5952 | }, | |
| 5953 | .INTR => { | |
| 5954 | try current_thread.checkCancel(); | |
| 5955 | continue; | |
| 5956 | }, | |
| 5957 | .CANCELED => return current_thread.endSyscallCanceled(), | |
| 5958 | else => |e| { | |
| 5959 | current_thread.endSyscall(); | |
| 5960 | switch (e) { | |
| 5961 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | |
| 5962 | .INVAL => return error.Unseekable, | |
| 5963 | .OVERFLOW => return error.Unseekable, | |
| 5964 | .SPIPE => return error.Unseekable, | |
| 5965 | .NXIO => return error.Unseekable, | |
| 5966 | .NOTCAPABLE => return error.AccessDenied, | |
| 5967 | else => |err| return posix.unexpectedErrno(err), | |
| 5968 | } | |
| 5969 | }, | |
| 6055 | while (true) { | |
| 6056 | var result: u64 = undefined; | |
| 6057 | switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) { | |
| 6058 | .SUCCESS => { | |
| 6059 | current_thread.endSyscall(); | |
| 6060 | return; | |
| 6061 | }, | |
| 6062 | .INTR => { | |
| 6063 | try current_thread.checkCancel(); | |
| 6064 | continue; | |
| 6065 | }, | |
| 6066 | .CANCELED => return current_thread.endSyscallCanceled(), | |
| 6067 | else => |e| { | |
| 6068 | current_thread.endSyscall(); | |
| 6069 | switch (e) { | |
| 6070 | .BADF => |err| return errnoBug(err), // File descriptor used after closed. | |
| 6071 | .INVAL => return error.Unseekable, | |
| 6072 | .OVERFLOW => return error.Unseekable, | |
| 6073 | .SPIPE => return error.Unseekable, | |
| 6074 | .NXIO => return error.Unseekable, | |
| 6075 | else => |err| return posix.unexpectedErrno(err), | |
| 6076 | } | |
| 6077 | }, | |
| 6078 | } | |
| 5970 | 6079 | } |
| 5971 | }; | |
| 5972 | ||
| 5973 | if (posix.SEEK == void) return error.Unseekable; | |
| 6080 | } | |
| 5974 | 6081 | |
| 5975 | 6082 | try current_thread.beginSyscall(); |
| 5976 | 6083 | while (true) { |
lib/std/posix.zig-171| ... | ... | @@ -2986,177 +2986,6 @@ pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void { |
| 2986 | 2986 | } |
| 2987 | 2987 | } |
| 2988 | 2988 | |
| 2989 | pub const SeekError = std.Io.File.SeekError; | |
| 2990 | ||
| 2991 | pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { | |
| 2992 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | |
| 2993 | var result: u64 = undefined; | |
| 2994 | switch (errno(system.llseek(fd, offset, &result, SEEK.SET))) { | |
| 2995 | .SUCCESS => return, | |
| 2996 | .BADF => unreachable, // always a race condition | |
| 2997 | .INVAL => return error.Unseekable, | |
| 2998 | .OVERFLOW => return error.Unseekable, | |
| 2999 | .SPIPE => return error.Unseekable, | |
| 3000 | .NXIO => return error.Unseekable, | |
| 3001 | else => |err| return unexpectedErrno(err), | |
| 3002 | } | |
| 3003 | } | |
| 3004 | if (native_os == .windows) { | |
| 3005 | return windows.SetFilePointerEx_BEGIN(fd, offset); | |
| 3006 | } | |
| 3007 | if (native_os == .wasi and !builtin.link_libc) { | |
| 3008 | var new_offset: wasi.filesize_t = undefined; | |
| 3009 | switch (wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) { | |
| 3010 | .SUCCESS => return, | |
| 3011 | .BADF => unreachable, // always a race condition | |
| 3012 | .INVAL => return error.Unseekable, | |
| 3013 | .OVERFLOW => return error.Unseekable, | |
| 3014 | .SPIPE => return error.Unseekable, | |
| 3015 | .NXIO => return error.Unseekable, | |
| 3016 | .NOTCAPABLE => return error.AccessDenied, | |
| 3017 | else => |err| return unexpectedErrno(err), | |
| 3018 | } | |
| 3019 | } | |
| 3020 | ||
| 3021 | const lseek_sym = if (lfs64_abi) system.lseek64 else system.lseek; | |
| 3022 | switch (errno(lseek_sym(fd, @bitCast(offset), SEEK.SET))) { | |
| 3023 | .SUCCESS => return, | |
| 3024 | .BADF => unreachable, // always a race condition | |
| 3025 | .INVAL => return error.Unseekable, | |
| 3026 | .OVERFLOW => return error.Unseekable, | |
| 3027 | .SPIPE => return error.Unseekable, | |
| 3028 | .NXIO => return error.Unseekable, | |
| 3029 | else => |err| return unexpectedErrno(err), | |
| 3030 | } | |
| 3031 | } | |
| 3032 | ||
| 3033 | /// Repositions read/write file offset relative to the current offset. | |
| 3034 | pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void { | |
| 3035 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | |
| 3036 | var result: u64 = undefined; | |
| 3037 | switch (errno(system.llseek(fd, @bitCast(offset), &result, SEEK.CUR))) { | |
| 3038 | .SUCCESS => return, | |
| 3039 | .BADF => unreachable, // always a race condition | |
| 3040 | .INVAL => return error.Unseekable, | |
| 3041 | .OVERFLOW => return error.Unseekable, | |
| 3042 | .SPIPE => return error.Unseekable, | |
| 3043 | .NXIO => return error.Unseekable, | |
| 3044 | else => |err| return unexpectedErrno(err), | |
| 3045 | } | |
| 3046 | } | |
| 3047 | if (native_os == .windows) { | |
| 3048 | return windows.SetFilePointerEx_CURRENT(fd, offset); | |
| 3049 | } | |
| 3050 | if (native_os == .wasi and !builtin.link_libc) { | |
| 3051 | var new_offset: wasi.filesize_t = undefined; | |
| 3052 | switch (wasi.fd_seek(fd, offset, .CUR, &new_offset)) { | |
| 3053 | .SUCCESS => return, | |
| 3054 | .BADF => unreachable, // always a race condition | |
| 3055 | .INVAL => return error.Unseekable, | |
| 3056 | .OVERFLOW => return error.Unseekable, | |
| 3057 | .SPIPE => return error.Unseekable, | |
| 3058 | .NXIO => return error.Unseekable, | |
| 3059 | .NOTCAPABLE => return error.AccessDenied, | |
| 3060 | else => |err| return unexpectedErrno(err), | |
| 3061 | } | |
| 3062 | } | |
| 3063 | const lseek_sym = if (lfs64_abi) system.lseek64 else system.lseek; | |
| 3064 | switch (errno(lseek_sym(fd, @bitCast(offset), SEEK.CUR))) { | |
| 3065 | .SUCCESS => return, | |
| 3066 | .BADF => unreachable, // always a race condition | |
| 3067 | .INVAL => return error.Unseekable, | |
| 3068 | .OVERFLOW => return error.Unseekable, | |
| 3069 | .SPIPE => return error.Unseekable, | |
| 3070 | .NXIO => return error.Unseekable, | |
| 3071 | else => |err| return unexpectedErrno(err), | |
| 3072 | } | |
| 3073 | } | |
| 3074 | ||
| 3075 | /// Repositions read/write file offset relative to the end. | |
| 3076 | pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void { | |
| 3077 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | |
| 3078 | var result: u64 = undefined; | |
| 3079 | switch (errno(system.llseek(fd, @bitCast(offset), &result, SEEK.END))) { | |
| 3080 | .SUCCESS => return, | |
| 3081 | .BADF => unreachable, // always a race condition | |
| 3082 | .INVAL => return error.Unseekable, | |
| 3083 | .OVERFLOW => return error.Unseekable, | |
| 3084 | .SPIPE => return error.Unseekable, | |
| 3085 | .NXIO => return error.Unseekable, | |
| 3086 | else => |err| return unexpectedErrno(err), | |
| 3087 | } | |
| 3088 | } | |
| 3089 | if (native_os == .windows) { | |
| 3090 | return windows.SetFilePointerEx_END(fd, offset); | |
| 3091 | } | |
| 3092 | if (native_os == .wasi and !builtin.link_libc) { | |
| 3093 | var new_offset: wasi.filesize_t = undefined; | |
| 3094 | switch (wasi.fd_seek(fd, offset, .END, &new_offset)) { | |
| 3095 | .SUCCESS => return, | |
| 3096 | .BADF => unreachable, // always a race condition | |
| 3097 | .INVAL => return error.Unseekable, | |
| 3098 | .OVERFLOW => return error.Unseekable, | |
| 3099 | .SPIPE => return error.Unseekable, | |
| 3100 | .NXIO => return error.Unseekable, | |
| 3101 | .NOTCAPABLE => return error.AccessDenied, | |
| 3102 | else => |err| return unexpectedErrno(err), | |
| 3103 | } | |
| 3104 | } | |
| 3105 | const lseek_sym = if (lfs64_abi) system.lseek64 else system.lseek; | |
| 3106 | switch (errno(lseek_sym(fd, @bitCast(offset), SEEK.END))) { | |
| 3107 | .SUCCESS => return, | |
| 3108 | .BADF => unreachable, // always a race condition | |
| 3109 | .INVAL => return error.Unseekable, | |
| 3110 | .OVERFLOW => return error.Unseekable, | |
| 3111 | .SPIPE => return error.Unseekable, | |
| 3112 | .NXIO => return error.Unseekable, | |
| 3113 | else => |err| return unexpectedErrno(err), | |
| 3114 | } | |
| 3115 | } | |
| 3116 | ||
| 3117 | /// Returns the read/write file offset relative to the beginning. | |
| 3118 | pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { | |
| 3119 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { | |
| 3120 | var result: u64 = undefined; | |
| 3121 | switch (errno(system.llseek(fd, 0, &result, SEEK.CUR))) { | |
| 3122 | .SUCCESS => return result, | |
| 3123 | .BADF => unreachable, // always a race condition | |
| 3124 | .INVAL => return error.Unseekable, | |
| 3125 | .OVERFLOW => return error.Unseekable, | |
| 3126 | .SPIPE => return error.Unseekable, | |
| 3127 | .NXIO => return error.Unseekable, | |
| 3128 | else => |err| return unexpectedErrno(err), | |
| 3129 | } | |
| 3130 | } | |
| 3131 | if (native_os == .windows) { | |
| 3132 | return windows.SetFilePointerEx_CURRENT_get(fd); | |
| 3133 | } | |
| 3134 | if (native_os == .wasi and !builtin.link_libc) { | |
| 3135 | var new_offset: wasi.filesize_t = undefined; | |
| 3136 | switch (wasi.fd_seek(fd, 0, .CUR, &new_offset)) { | |
| 3137 | .SUCCESS => return new_offset, | |
| 3138 | .BADF => unreachable, // always a race condition | |
| 3139 | .INVAL => return error.Unseekable, | |
| 3140 | .OVERFLOW => return error.Unseekable, | |
| 3141 | .SPIPE => return error.Unseekable, | |
| 3142 | .NXIO => return error.Unseekable, | |
| 3143 | .NOTCAPABLE => return error.AccessDenied, | |
| 3144 | else => |err| return unexpectedErrno(err), | |
| 3145 | } | |
| 3146 | } | |
| 3147 | const lseek_sym = if (lfs64_abi) system.lseek64 else system.lseek; | |
| 3148 | const rc = lseek_sym(fd, 0, SEEK.CUR); | |
| 3149 | switch (errno(rc)) { | |
| 3150 | .SUCCESS => return @bitCast(rc), | |
| 3151 | .BADF => unreachable, // always a race condition | |
| 3152 | .INVAL => return error.Unseekable, | |
| 3153 | .OVERFLOW => return error.Unseekable, | |
| 3154 | .SPIPE => return error.Unseekable, | |
| 3155 | .NXIO => return error.Unseekable, | |
| 3156 | else => |err| return unexpectedErrno(err), | |
| 3157 | } | |
| 3158 | } | |
| 3159 | ||
| 3160 | 2989 | pub const FcntlError = error{ |
| 3161 | 2990 | PermissionDenied, |
| 3162 | 2991 | FileBusy, |