| author | |
| committer | |
| log | cdd6e545cc7e4c6cb32d1a87695f215ce9d5f753 |
| tree | bfb9dc6d5a84eaf40b83ab0446e1be54505dbb24 |
| parent | 59f14713067c59751dff4d6f73f81893a2284793 |
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 | 1122 | /// policy of the current thread or process disallows dataless directory materialization. |
| 1123 | 1123 | AccessDenied, |
| 1124 | 1124 | PathAlreadyExists, |
| 1125 | /// Operating system or file system does not support atomic nonreplacing | |
| 1126 | /// rename. | |
| 1125 | /// Operating system or file system does not support atomic nonreplacing rename. | |
| 1127 | 1126 | OperationUnsupported, |
| 1128 | 1127 | } || RenameError; |
| 1129 | 1128 | |
| ... | ... | @@ -1131,6 +1130,12 @@ pub const RenamePreserveError = error{ |
| 1131 | 1130 | /// |
| 1132 | 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 | 1139 | /// * On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/). |
| 1135 | 1140 | /// * On WASI, both paths should be encoded as valid UTF-8. |
| 1136 | 1141 | /// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding. |
lib/std/Io/Threaded.zig+11-2| ... | ... | @@ -7756,7 +7756,14 @@ fn dirRenamePreserve( |
| 7756 | 7756 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 7757 | 7757 | if (is_windows) return dirRenameWindowsInner(old_dir, old_sub_path, new_dir, new_sub_path, false); |
| 7758 | 7758 | if (is_darwin) return dirRenamePreserveDarwin(old_dir, old_sub_path, new_dir, new_sub_path); |
| 7759 | if (native_os == .linux) return dirRenamePreserveLinux(old_dir, old_sub_path, new_dir, new_sub_path); | |
| 7759 | if (native_os == .linux) { | |
| 7760 | if (dirRenamePreserveLinux(old_dir, old_sub_path, new_dir, new_sub_path)) |_| { | |
| 7761 | return; | |
| 7762 | } else |err| switch (err) { | |
| 7763 | else => |e| return e, | |
| 7764 | error.OperationUnsupported => {}, // Fall back to link/unlink below. | |
| 7765 | } | |
| 7766 | } | |
| 7760 | 7767 | // Make a hard link then delete the original. |
| 7761 | 7768 | try dirHardLink(t, old_dir, old_sub_path, new_dir, new_sub_path, .{ .follow_symlinks = false }); |
| 7762 | 7769 | const prev = swapCancelProtection(t, .blocked); |
| ... | ... | @@ -8084,8 +8091,10 @@ fn dirRenamePreserveLinux( |
| 8084 | 8091 | .ROFS => return syscall.fail(error.ReadOnlyFileSystem), |
| 8085 | 8092 | .XDEV => return syscall.fail(error.CrossDevice), |
| 8086 | 8093 | .ILSEQ => return syscall.fail(error.BadPathName), |
| 8094 | // EINVAL when passing NOREPLACE=true observed on ext4, 7.0.0-38-generic #38~24.04.4-Ubuntu. | |
| 8095 | // OPNOTSUPP handled defensively. | |
| 8096 | .INVAL, .OPNOTSUPP => return syscall.fail(error.OperationUnsupported), | |
| 8087 | 8097 | .FAULT => |err| return syscall.errnoBug(err), |
| 8088 | .INVAL => return syscall.fail(error.OperationUnsupported), | |
| 8089 | 8098 | else => |err| return syscall.unexpectedErrno(err), |
| 8090 | 8099 | }; |
| 8091 | 8100 | } |