| ... | @@ -593,7 +593,10 @@ const CachedFd = struct { | ... | @@ -593,7 +593,10 @@ const CachedFd = struct { |
| 593 | @atomicStore(Once, &cached_fd.once, .uninitialized, .monotonic); | 593 | @atomicStore(Once, &cached_fd.once, .uninitialized, .monotonic); |
| 594 | futexWake(ev, @ptrCast(&cached_fd.once), 1); | 594 | futexWake(ev, @ptrCast(&cached_fd.once), 1); |
| 595 | } | 595 | } |
| 596 | const fd = try ev.openat(cancel_region, linux.AT.FDCWD, path, flags, 0); | 596 | const fd = ev.openat(cancel_region, linux.AT.FDCWD, path, flags, 0) catch |err| switch (err) { |
| | 597 | error.OperationUnsupported => return error.Unexpected, // Not expecting O_TMPFILE flag |
| | 598 | else => |e| return e, |
| | 599 | }; |
| 597 | @atomicStore(Once, &cached_fd.once, .fromFd(fd), .monotonic); | 600 | @atomicStore(Once, &cached_fd.once, .fromFd(fd), .monotonic); |
| 598 | futexWake(ev, @ptrCast(&cached_fd.once), std.math.maxInt(u32)); | 601 | futexWake(ev, @ptrCast(&cached_fd.once), std.math.maxInt(u32)); |
| 599 | return fd; | 602 | return fd; |
| ... | @@ -2725,9 +2728,8 @@ fn dirOpenDir( | ... | @@ -2725,9 +2728,8 @@ fn dirOpenDir( |
| 2725 | error.DeviceBusy => return errnoBug(.BUSY), // O_EXCL not passed | 2728 | error.DeviceBusy => return errnoBug(.BUSY), // O_EXCL not passed |
| 2726 | error.FileBusy => return errnoBug(.TXTBSY), | 2729 | error.FileBusy => return errnoBug(.TXTBSY), |
| 2727 | error.PathAlreadyExists => return errnoBug(.EXIST), // Not creating. | 2730 | error.PathAlreadyExists => return errnoBug(.EXIST), // Not creating. |
| 2728 | error.PipeBusy => return error.Unexpected, // Not opening a pipe. | | |
| 2729 | error.AntivirusInterference => unreachable, // Windows-only | | |
| 2730 | error.FileLocksUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for locks. | 2731 | error.FileLocksUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for locks. |
| | 2732 | error.OperationUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for O_TMPFILE. |
| 2731 | else => |e| return e, | 2733 | else => |e| return e, |
| 2732 | }, | 2734 | }, |
| 2733 | }; | 2735 | }; |
| ... | @@ -2810,13 +2812,16 @@ fn dirCreateFile( | ... | @@ -2810,13 +2812,16 @@ fn dirCreateFile( |
| 2810 | | 2812 | |
| 2811 | var maybe_sync: CancelRegion.Sync.Maybe = .{ .cancel_region = .init() }; | 2813 | var maybe_sync: CancelRegion.Sync.Maybe = .{ .cancel_region = .init() }; |
| 2812 | defer maybe_sync.deinit(ev); | 2814 | defer maybe_sync.deinit(ev); |
| 2813 | const fd = try ev.openat(&maybe_sync.cancel_region, dir.handle, sub_path_posix, .{ | 2815 | const fd = ev.openat(&maybe_sync.cancel_region, dir.handle, sub_path_posix, .{ |
| 2814 | .ACCMODE = if (flags.read) .RDWR else .WRONLY, | 2816 | .ACCMODE = if (flags.read) .RDWR else .WRONLY, |
| 2815 | .CREAT = true, | 2817 | .CREAT = true, |
| 2816 | .TRUNC = flags.truncate, | 2818 | .TRUNC = flags.truncate, |
| 2817 | .EXCL = flags.exclusive, | 2819 | .EXCL = flags.exclusive, |
| 2818 | .CLOEXEC = true, | 2820 | .CLOEXEC = true, |
| 2819 | }, flags.permissions.toMode()); | 2821 | }, flags.permissions.toMode()) catch |err| switch (err) { |
| | 2822 | error.OperationUnsupported => return error.Unexpected, // TMPFILE bit not set. |
| | 2823 | else => |e| return e, |
| | 2824 | }; |
| 2820 | errdefer ev.closeAsync(fd); | 2825 | errdefer ev.closeAsync(fd); |
| 2821 | | 2826 | |
| 2822 | switch (flags.lock) { | 2827 | switch (flags.lock) { |
| ... | @@ -2892,7 +2897,7 @@ fn dirCreateFileAtomic( | ... | @@ -2892,7 +2897,7 @@ fn dirCreateFileAtomic( |
| 2892 | flags, | 2897 | flags, |
| 2893 | options.permissions.toMode(), | 2898 | options.permissions.toMode(), |
| 2894 | ) catch |err| switch (err) { | 2899 | ) catch |err| switch (err) { |
| 2895 | error.IsDir, error.FileNotFound => { | 2900 | error.IsDir, error.FileNotFound, error.OperationUnsupported => { |
| 2896 | // Ambiguous error code. It might mean the file system | 2901 | // Ambiguous error code. It might mean the file system |
| 2897 | // does not support O_TMPFILE. Therefore, we must fall | 2902 | // does not support O_TMPFILE. Therefore, we must fall |
| 2898 | // back to not using O_TMPFILE. | 2903 | // back to not using O_TMPFILE. |
| ... | @@ -2901,8 +2906,6 @@ fn dirCreateFileAtomic( | ... | @@ -2901,8 +2906,6 @@ fn dirCreateFileAtomic( |
| 2901 | error.FileTooBig => return errnoBug(.FBIG), | 2906 | error.FileTooBig => return errnoBug(.FBIG), |
| 2902 | error.DeviceBusy => return errnoBug(.BUSY), // O_EXCL not passed | 2907 | error.DeviceBusy => return errnoBug(.BUSY), // O_EXCL not passed |
| 2903 | error.PathAlreadyExists => return errnoBug(.EXIST), // Not creating. | 2908 | error.PathAlreadyExists => return errnoBug(.EXIST), // Not creating. |
| 2904 | error.PipeBusy => return error.Unexpected, // Not opening a pipe. | | |
| 2905 | error.AntivirusInterference => unreachable, // Windows-only | | |
| 2906 | error.FileLocksUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for locks. | 2909 | error.FileLocksUnsupported => return errnoBug(.OPNOTSUPP), // Not asking for locks. |
| 2907 | else => |e| return e, | 2910 | else => |e| return e, |
| 2908 | }, | 2911 | }, |
| ... | @@ -2994,7 +2997,7 @@ fn dirOpenFile( | ... | @@ -2994,7 +2997,7 @@ fn dirOpenFile( |
| 2994 | | 2997 | |
| 2995 | var maybe_sync: CancelRegion.Sync.Maybe = .{ .cancel_region = .init() }; | 2998 | var maybe_sync: CancelRegion.Sync.Maybe = .{ .cancel_region = .init() }; |
| 2996 | defer maybe_sync.deinit(ev); | 2999 | defer maybe_sync.deinit(ev); |
| 2997 | const fd = try ev.openat(&maybe_sync.cancel_region, dir.handle, sub_path_posix, .{ | 3000 | const fd = ev.openat(&maybe_sync.cancel_region, dir.handle, sub_path_posix, .{ |
| 2998 | .ACCMODE = switch (flags.mode) { | 3001 | .ACCMODE = switch (flags.mode) { |
| 2999 | .read_only => .RDONLY, | 3002 | .read_only => .RDONLY, |
| 3000 | .write_only => .WRONLY, | 3003 | .write_only => .WRONLY, |
| ... | @@ -3004,7 +3007,10 @@ fn dirOpenFile( | ... | @@ -3004,7 +3007,10 @@ fn dirOpenFile( |
| 3004 | .NOFOLLOW = !flags.follow_symlinks, | 3007 | .NOFOLLOW = !flags.follow_symlinks, |
| 3005 | .CLOEXEC = true, | 3008 | .CLOEXEC = true, |
| 3006 | .PATH = flags.path_only, | 3009 | .PATH = flags.path_only, |
| 3007 | }, 0); | 3010 | }, 0) catch |err| switch (err) { |
| | 3011 | error.OperationUnsupported => return error.Unexpected, // TMPFILE bit not set. |
| | 3012 | else => |e| return e, |
| | 3013 | }; |
| 3008 | errdefer ev.closeAsync(fd); | 3014 | errdefer ev.closeAsync(fd); |
| 3009 | | 3015 | |
| 3010 | if (!flags.allow_directory) { | 3016 | if (!flags.allow_directory) { |
| ... | @@ -5609,6 +5615,27 @@ fn lseek( | ... | @@ -5609,6 +5615,27 @@ fn lseek( |
| 5609 | } | 5615 | } |
| 5610 | } | 5616 | } |
| 5611 | | 5617 | |
| | 5618 | const OpenError = error{ |
| | 5619 | AccessDenied, |
| | 5620 | FileTooBig, |
| | 5621 | IsDir, |
| | 5622 | SymLinkLoop, |
| | 5623 | ProcessFdQuotaExceeded, |
| | 5624 | SystemFdQuotaExceeded, |
| | 5625 | NoDevice, |
| | 5626 | FileNotFound, |
| | 5627 | SystemResources, |
| | 5628 | NoSpaceLeft, |
| | 5629 | NotDir, |
| | 5630 | PermissionDenied, |
| | 5631 | PathAlreadyExists, |
| | 5632 | DeviceBusy, |
| | 5633 | OperationUnsupported, |
| | 5634 | FileLocksUnsupported, |
| | 5635 | WouldBlock, |
| | 5636 | FileBusy, |
| | 5637 | } || Dir.PathNameError || Io.Cancelable || Io.UnexpectedError; |
| | 5638 | |
| 5612 | fn openat( | 5639 | fn openat( |
| 5613 | ev: *Evented, | 5640 | ev: *Evented, |
| 5614 | cancel_region: *CancelRegion, | 5641 | cancel_region: *CancelRegion, |
| ... | @@ -5616,7 +5643,7 @@ fn openat( | ... | @@ -5616,7 +5643,7 @@ fn openat( |
| 5616 | path: [*:0]const u8, | 5643 | path: [*:0]const u8, |
| 5617 | flags: linux.O, | 5644 | flags: linux.O, |
| 5618 | mode: linux.mode_t, | 5645 | mode: linux.mode_t, |
| 5619 | ) File.OpenError!fd_t { | 5646 | ) OpenError!fd_t { |
| 5620 | var mut_flags = flags; | 5647 | var mut_flags = flags; |
| 5621 | if (@hasField(linux.O, "LARGEFILE")) mut_flags.LARGEFILE = true; | 5648 | if (@hasField(linux.O, "LARGEFILE")) mut_flags.LARGEFILE = true; |
| 5622 | while (true) { | 5649 | while (true) { |
| ... | @@ -5662,7 +5689,8 @@ fn openat( | ... | @@ -5662,7 +5689,8 @@ fn openat( |
| 5662 | .PERM => return error.PermissionDenied, | 5689 | .PERM => return error.PermissionDenied, |
| 5663 | .EXIST => return error.PathAlreadyExists, | 5690 | .EXIST => return error.PathAlreadyExists, |
| 5664 | .BUSY => return error.DeviceBusy, | 5691 | .BUSY => return error.DeviceBusy, |
| 5665 | .OPNOTSUPP => return error.FileLocksUnsupported, | 5692 | // File locking and TMPFILE are mutually exclusive |
| | 5693 | .OPNOTSUPP => return if (flags.TMPFILE) error.OperationUnsupported else error.FileLocksUnsupported, |
| 5666 | .AGAIN => return error.WouldBlock, | 5694 | .AGAIN => return error.WouldBlock, |
| 5667 | .TXTBSY => return error.FileBusy, | 5695 | .TXTBSY => return error.FileBusy, |
| 5668 | .NXIO => return error.NoDevice, | 5696 | .NXIO => return error.NoDevice, |