| author | |
| committer | |
| log | 4428d52ea145ed0f14af2e39569026c2a708e547 |
| tree | e7a7dac17992fe0e8b906a27c4cd19486798a5d9 |
| parent | 77aa4155ea62fa88895ddcc566ed99d0d7031c55 |
| signature | Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM |
with link/unlink fallback. closes #319602 files changed, 18 insertions(+), 4 deletions(-)
lib/std/Io/Dir.zig+7-2| ... | @@ -1122,8 +1122,7 @@ pub const RenamePreserveError = error{ | ... | @@ -1122,8 +1122,7 @@ pub const RenamePreserveError = error{ |
| 1122 | /// policy of the current thread or process disallows dataless directory materialization. | 1122 | /// policy of the current thread or process disallows dataless directory materialization. |
| 1123 | AccessDenied, | 1123 | AccessDenied, |
| 1124 | PathAlreadyExists, | 1124 | PathAlreadyExists, |
| 1125 | /// Operating system or file system does not support atomic nonreplacing | 1125 | /// Operating system or file system does not support atomic nonreplacing rename. |
| 1126 | /// rename. | ||
| 1127 | OperationUnsupported, | 1126 | OperationUnsupported, |
| 1128 | } || RenameError; | 1127 | } || RenameError; |
| 1129 | 1128 | ||
| ... | @@ -1131,6 +1130,12 @@ pub const RenamePreserveError = error{ | ... | @@ -1131,6 +1130,12 @@ pub const RenamePreserveError = error{ |
| 1131 | /// | 1130 | /// |
| 1132 | /// If `new_sub_path` already exists, `error.PathAlreadyExists` will be returned. | 1131 | /// If `new_sub_path` already exists, `error.PathAlreadyExists` will be returned. |
| 1133 | /// | 1132 | /// |
| 1133 | /// If the operating system supports it, the entire operation will be done atomically. If unsupported, will | ||
| 1134 | /// fall back to hard link followed by unlink, which is atomic with respect to `new_sub_path` but leaves a | ||
| 1135 | /// window where the cleanup of `old_sub_path may fail. Although the operation is fairly portable, technically | ||
| 1136 | /// this fallback, too, may be unsupported in some environments, in which case `error.OperationUnsupported` is | ||
| 1137 | /// returned. | ||
| 1138 | /// | ||
| 1134 | /// * On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/). | 1139 | /// * On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/). |
| 1135 | /// * On WASI, both paths should be encoded as valid UTF-8. | 1140 | /// * On WASI, both paths should be encoded as valid UTF-8. |
| 1136 | /// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | 1141 | /// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding. |
lib/std/Io/Threaded.zig+11-2| ... | @@ -7734,7 +7734,14 @@ fn dirRenamePreserve( | ... | @@ -7734,7 +7734,14 @@ fn dirRenamePreserve( |
| 7734 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 7734 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 7735 | if (is_windows) return dirRenameWindowsInner(old_dir, old_sub_path, new_dir, new_sub_path, false); | 7735 | if (is_windows) return dirRenameWindowsInner(old_dir, old_sub_path, new_dir, new_sub_path, false); |
| 7736 | if (is_darwin) return dirRenamePreserveDarwin(old_dir, old_sub_path, new_dir, new_sub_path); | 7736 | if (is_darwin) return dirRenamePreserveDarwin(old_dir, old_sub_path, new_dir, new_sub_path); |
| 7737 | if (native_os == .linux) return dirRenamePreserveLinux(old_dir, old_sub_path, new_dir, new_sub_path); | 7737 | if (native_os == .linux) { |
| 7738 | if (dirRenamePreserveLinux(old_dir, old_sub_path, new_dir, new_sub_path)) |_| { | ||
| 7739 | return; | ||
| 7740 | } else |err| switch (err) { | ||
| 7741 | else => |e| return e, | ||
| 7742 | error.OperationUnsupported => {}, // Fall back to link/unlink below. | ||
| 7743 | } | ||
| 7744 | } | ||
| 7738 | // Make a hard link then delete the original. | 7745 | // Make a hard link then delete the original. |
| 7739 | try dirHardLink(t, old_dir, old_sub_path, new_dir, new_sub_path, .{ .follow_symlinks = false }); | 7746 | try dirHardLink(t, old_dir, old_sub_path, new_dir, new_sub_path, .{ .follow_symlinks = false }); |
| 7740 | const prev = swapCancelProtection(t, .blocked); | 7747 | const prev = swapCancelProtection(t, .blocked); |
| ... | @@ -8062,8 +8069,10 @@ fn dirRenamePreserveLinux( | ... | @@ -8062,8 +8069,10 @@ fn dirRenamePreserveLinux( |
| 8062 | .ROFS => return syscall.fail(error.ReadOnlyFileSystem), | 8069 | .ROFS => return syscall.fail(error.ReadOnlyFileSystem), |
| 8063 | .XDEV => return syscall.fail(error.CrossDevice), | 8070 | .XDEV => return syscall.fail(error.CrossDevice), |
| 8064 | .ILSEQ => return syscall.fail(error.BadPathName), | 8071 | .ILSEQ => return syscall.fail(error.BadPathName), |
| 8072 | // EINVAL when passing NOREPLACE=true observed on ext4, 7.0.0-38-generic #38~24.04.4-Ubuntu. | ||
| 8073 | // OPNOTSUPP handled defensively. | ||
| 8074 | .INVAL, .OPNOTSUPP => return syscall.fail(error.OperationUnsupported), | ||
| 8065 | .FAULT => |err| return syscall.errnoBug(err), | 8075 | .FAULT => |err| return syscall.errnoBug(err), |
| 8066 | .INVAL => return syscall.fail(error.OperationUnsupported), | ||
| 8067 | else => |err| return syscall.unexpectedErrno(err), | 8076 | else => |err| return syscall.unexpectedErrno(err), |
| 8068 | }; | 8077 | }; |
| 8069 | } | 8078 | } |