mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 02:24:33 +01:00
std.Io.Dir: introduce renamePreserve and use it in File.Atomic.link
breaking change: the error for renaming over a non-empty directory now returns error.DirNotEmpty rather than error.PathAlreadyExists.
This commit is contained in:
parent
8e1850e277
commit
ee574f665c
11 changed files with 219 additions and 35 deletions
|
|
@ -676,6 +676,7 @@ pub const VTable = struct {
|
|||
dirDeleteFile: *const fn (?*anyopaque, Dir, []const u8) Dir.DeleteFileError!void,
|
||||
dirDeleteDir: *const fn (?*anyopaque, Dir, []const u8) Dir.DeleteDirError!void,
|
||||
dirRename: *const fn (?*anyopaque, old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) Dir.RenameError!void,
|
||||
dirRenamePreserve: *const fn (?*anyopaque, old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) Dir.RenamePreserveError!void,
|
||||
dirSymLink: *const fn (?*anyopaque, Dir, target_path: []const u8, sym_link_path: []const u8, Dir.SymLinkFlags) Dir.SymLinkError!void,
|
||||
dirReadLink: *const fn (?*anyopaque, Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLinkError!usize,
|
||||
dirSetOwner: *const fn (?*anyopaque, Dir, ?File.Uid, ?File.Gid) Dir.SetOwnerError!void,
|
||||
|
|
|
|||
|
|
@ -936,10 +936,9 @@ pub fn deleteDirAbsolute(io: Io, absolute_path: []const u8) DeleteDirError!void
|
|||
pub const RenameError = error{
|
||||
/// In WASI, this error may occur when the file descriptor does
|
||||
/// not hold the required rights to rename a resource by path relative to it.
|
||||
///
|
||||
/// On Windows, this error may be returned instead of PathAlreadyExists when
|
||||
/// renaming a directory over an existing directory.
|
||||
AccessDenied,
|
||||
/// Attempted to replace a nonempty directory.
|
||||
DirNotEmpty,
|
||||
PermissionDenied,
|
||||
FileBusy,
|
||||
DiskQuota,
|
||||
|
|
@ -950,9 +949,8 @@ pub const RenameError = error{
|
|||
NotDir,
|
||||
SystemResources,
|
||||
NoSpaceLeft,
|
||||
PathAlreadyExists,
|
||||
ReadOnlyFileSystem,
|
||||
RenameAcrossMountPoints,
|
||||
CrossDevice,
|
||||
NoDevice,
|
||||
SharingViolation,
|
||||
PipeBusy,
|
||||
|
|
@ -964,6 +962,7 @@ pub const RenameError = error{
|
|||
/// intercepts file system operations and makes them significantly slower
|
||||
/// in addition to possibly failing with this error code.
|
||||
AntivirusInterference,
|
||||
HardwareFailure,
|
||||
} || PathNameError || Io.Cancelable || Io.UnexpectedError;
|
||||
|
||||
/// Change the name or location of a file or directory.
|
||||
|
|
@ -973,9 +972,9 @@ pub const RenameError = error{
|
|||
/// Renaming a file over an existing directory or a directory over an existing
|
||||
/// file will fail with `error.IsDir` or `error.NotDir`
|
||||
///
|
||||
/// On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
|
||||
/// On WASI, both paths should be encoded as valid UTF-8.
|
||||
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
|
||||
/// * On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
|
||||
/// * On WASI, both paths should be encoded as valid UTF-8.
|
||||
/// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
|
||||
pub fn rename(
|
||||
old_dir: Dir,
|
||||
old_sub_path: []const u8,
|
||||
|
|
@ -993,6 +992,39 @@ pub fn renameAbsolute(old_path: []const u8, new_path: []const u8, io: Io) Rename
|
|||
return io.vtable.dirRename(io.userdata, my_cwd, old_path, my_cwd, new_path);
|
||||
}
|
||||
|
||||
pub const RenamePreserveError = error{
|
||||
/// In WASI, this error may occur when the file descriptor does
|
||||
/// not hold the required rights to rename a resource by path relative to it.
|
||||
///
|
||||
/// On Windows, this error may be returned instead of PathAlreadyExists when
|
||||
/// renaming a directory over an existing directory.
|
||||
AccessDenied,
|
||||
PathAlreadyExists,
|
||||
/// Operating system or file system does not support atomic nonreplacing
|
||||
/// rename.
|
||||
OperationUnsupported,
|
||||
} || RenameError;
|
||||
|
||||
/// Change the name or location of a file or directory.
|
||||
///
|
||||
/// If `new_sub_path` already exists, `error.PathAlreadyExists` will be returned.
|
||||
///
|
||||
/// Renaming a file over an existing directory or a directory over an existing
|
||||
/// file will fail with `error.IsDir` or `error.NotDir`
|
||||
///
|
||||
/// * On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
|
||||
/// * On WASI, both paths should be encoded as valid UTF-8.
|
||||
/// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
|
||||
pub fn renamePreserve(
|
||||
old_dir: Dir,
|
||||
old_sub_path: []const u8,
|
||||
new_dir: Dir,
|
||||
new_sub_path: []const u8,
|
||||
io: Io,
|
||||
) RenamePreserveError!void {
|
||||
return io.vtable.dirRenamePreserve(io.userdata, old_dir, old_sub_path, new_dir, new_sub_path);
|
||||
}
|
||||
|
||||
pub const HardLinkOptions = File.HardLinkOptions;
|
||||
|
||||
pub const HardLinkError = File.HardLinkError;
|
||||
|
|
|
|||
|
|
@ -726,7 +726,7 @@ pub const HardLinkError = error{
|
|||
SystemResources,
|
||||
NoSpaceLeft,
|
||||
ReadOnlyFileSystem,
|
||||
NotSameFileSystem,
|
||||
CrossDevice,
|
||||
NotDir,
|
||||
} || Io.Cancelable || Dir.PathNameError || Io.UnexpectedError;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,14 @@ pub fn deinit(af: *Atomic, io: Io) void {
|
|||
af.* = undefined;
|
||||
}
|
||||
|
||||
pub const LinkError = Dir.HardLinkError;
|
||||
pub const LinkError = Dir.HardLinkError || Dir.RenamePreserveError;
|
||||
|
||||
/// Atomically materializes the file into place, failing with
|
||||
/// `error.PathAlreadyExists` if something already exists there.
|
||||
///
|
||||
/// If this operation could not be done with an unnamed temporary file, the
|
||||
/// named temporary file will be deleted in a following operation, which may
|
||||
/// independently fail. The result of that operation is stored in `delete_err`.
|
||||
pub fn link(af: *Atomic, io: Io) LinkError!void {
|
||||
if (af.file_exists) {
|
||||
if (af.file_open) {
|
||||
|
|
@ -48,8 +52,7 @@ pub fn link(af: *Atomic, io: Io) LinkError!void {
|
|||
af.file_open = false;
|
||||
}
|
||||
const tmp_sub_path = std.fmt.hex(af.file_basename_hex);
|
||||
try af.dir.hardLink(&tmp_sub_path, af.dir, af.dest_sub_path, io, .{});
|
||||
af.dir.deleteFile(io, &tmp_sub_path) catch {};
|
||||
try af.dir.renamePreserve(&tmp_sub_path, af.dir, af.dest_sub_path, io);
|
||||
af.file_exists = false;
|
||||
} else {
|
||||
assert(af.file_open);
|
||||
|
|
|
|||
|
|
@ -1442,6 +1442,7 @@ pub fn io(t: *Threaded) Io {
|
|||
.dirDeleteFile = dirDeleteFile,
|
||||
.dirDeleteDir = dirDeleteDir,
|
||||
.dirRename = dirRename,
|
||||
.dirRenamePreserve = dirRenamePreserve,
|
||||
.dirSymLink = dirSymLink,
|
||||
.dirReadLink = dirReadLink,
|
||||
.dirSetOwner = dirSetOwner,
|
||||
|
|
@ -1593,6 +1594,7 @@ pub fn ioBasic(t: *Threaded) Io {
|
|||
.dirDeleteFile = dirDeleteFile,
|
||||
.dirDeleteDir = dirDeleteDir,
|
||||
.dirRename = dirRename,
|
||||
.dirRenamePreserve = dirRenamePreserve,
|
||||
.dirSymLink = dirSymLink,
|
||||
.dirReadLink = dirReadLink,
|
||||
.dirSetOwner = dirSetOwner,
|
||||
|
|
@ -5283,7 +5285,7 @@ fn linkat(
|
|||
.NOTDIR => return syscall.fail(error.NotDir),
|
||||
.PERM => return syscall.fail(error.PermissionDenied),
|
||||
.ROFS => return syscall.fail(error.ReadOnlyFileSystem),
|
||||
.XDEV => return syscall.fail(error.NotSameFileSystem),
|
||||
.XDEV => return syscall.fail(error.CrossDevice),
|
||||
.ILSEQ => return syscall.fail(error.BadPathName),
|
||||
.FAULT => |err| return syscall.errnoBug(err),
|
||||
.INVAL => |err| return syscall.errnoBug(err),
|
||||
|
|
@ -5692,15 +5694,44 @@ fn dirRenameWindows(
|
|||
new_dir: Dir,
|
||||
new_sub_path: []const u8,
|
||||
) Dir.RenameError!void {
|
||||
const w = windows;
|
||||
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||
_ = t;
|
||||
return dirRenameWindowsInner(old_dir, old_sub_path, new_dir, new_sub_path, true) catch |err| switch (err) {
|
||||
error.PathAlreadyExists => return error.Unexpected,
|
||||
error.OperationUnsupported => return error.Unexpected,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
fn dirRenamePreserve(
|
||||
userdata: ?*anyopaque,
|
||||
old_dir: Dir,
|
||||
old_sub_path: []const u8,
|
||||
new_dir: Dir,
|
||||
new_sub_path: []const u8,
|
||||
) Dir.RenamePreserveError!void {
|
||||
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||
if (is_windows) return dirRenameWindowsInner(old_dir, old_sub_path, new_dir, new_sub_path, false);
|
||||
if (native_os == .linux) return dirRenamePreserveLinux(old_dir, old_sub_path, new_dir, new_sub_path);
|
||||
// Make a hard link then delete the original.
|
||||
try dirHardLink(t, old_dir, old_sub_path, new_dir, new_sub_path, .{ .follow_symlinks = false });
|
||||
const prev = swapCancelProtection(t, .blocked);
|
||||
defer _ = swapCancelProtection(t, prev);
|
||||
dirDeleteFile(t, old_dir, old_sub_path) catch {};
|
||||
}
|
||||
|
||||
fn dirRenameWindowsInner(
|
||||
old_dir: Dir,
|
||||
old_sub_path: []const u8,
|
||||
new_dir: Dir,
|
||||
new_sub_path: []const u8,
|
||||
replace_if_exists: bool,
|
||||
) Dir.RenamePreserveError!void {
|
||||
const w = windows;
|
||||
const old_path_w_buf = try windows.sliceToPrefixedFileW(old_dir.handle, old_sub_path);
|
||||
const old_path_w = old_path_w_buf.span();
|
||||
const new_path_w_buf = try windows.sliceToPrefixedFileW(new_dir.handle, new_sub_path);
|
||||
const new_path_w = new_path_w_buf.span();
|
||||
const replace_if_exists = true;
|
||||
|
||||
const src_fd = src_fd: {
|
||||
const syscall: Syscall = try .start();
|
||||
|
|
@ -5802,9 +5833,9 @@ fn dirRenameWindows(
|
|||
.ACCESS_DENIED => return error.AccessDenied,
|
||||
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
|
||||
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
|
||||
.NOT_SAME_DEVICE => return error.RenameAcrossMountPoints,
|
||||
.NOT_SAME_DEVICE => return error.CrossDevice,
|
||||
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
|
||||
.DIRECTORY_NOT_EMPTY => return error.PathAlreadyExists,
|
||||
.DIRECTORY_NOT_EMPTY => return error.DirNotEmpty,
|
||||
.FILE_IS_A_DIRECTORY => return error.IsDir,
|
||||
.NOT_A_DIRECTORY => return error.NotDir,
|
||||
else => return w.unexpectedStatus(rc),
|
||||
|
|
@ -5848,10 +5879,10 @@ fn dirRenameWasi(
|
|||
.NOTDIR => return error.NotDir,
|
||||
.NOMEM => return error.SystemResources,
|
||||
.NOSPC => return error.NoSpaceLeft,
|
||||
.EXIST => return error.PathAlreadyExists,
|
||||
.NOTEMPTY => return error.PathAlreadyExists,
|
||||
.EXIST => return error.DirNotEmpty,
|
||||
.NOTEMPTY => return error.DirNotEmpty,
|
||||
.ROFS => return error.ReadOnlyFileSystem,
|
||||
.XDEV => return error.RenameAcrossMountPoints,
|
||||
.XDEV => return error.CrossDevice,
|
||||
.NOTCAPABLE => return error.AccessDenied,
|
||||
.ILSEQ => return error.BadPathName,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
|
|
@ -5877,9 +5908,105 @@ fn dirRenamePosix(
|
|||
const old_sub_path_posix = try pathToPosix(old_sub_path, &old_path_buffer);
|
||||
const new_sub_path_posix = try pathToPosix(new_sub_path, &new_path_buffer);
|
||||
|
||||
return renameat(old_dir.handle, old_sub_path_posix, new_dir.handle, new_sub_path_posix);
|
||||
}
|
||||
|
||||
fn dirRenamePreserveLinux(
|
||||
old_dir: Dir,
|
||||
old_sub_path: []const u8,
|
||||
new_dir: Dir,
|
||||
new_sub_path: []const u8,
|
||||
) Dir.RenamePreserveError!void {
|
||||
const linux = std.os.linux;
|
||||
|
||||
var old_path_buffer: [linux.PATH_MAX]u8 = undefined;
|
||||
var new_path_buffer: [linux.PATH_MAX]u8 = undefined;
|
||||
|
||||
const old_sub_path_posix = try pathToPosix(old_sub_path, &old_path_buffer);
|
||||
const new_sub_path_posix = try pathToPosix(new_sub_path, &new_path_buffer);
|
||||
|
||||
const syscall: Syscall = try .start();
|
||||
while (true) switch (linux.errno(linux.renameat2(
|
||||
old_dir.handle,
|
||||
old_sub_path_posix,
|
||||
new_dir.handle,
|
||||
new_sub_path_posix,
|
||||
.{ .NOREPLACE = true },
|
||||
))) {
|
||||
.SUCCESS => return syscall.finish(),
|
||||
.INTR => {
|
||||
try syscall.checkCancel();
|
||||
continue;
|
||||
},
|
||||
.ACCES => return syscall.fail(error.AccessDenied),
|
||||
.PERM => return syscall.fail(error.PermissionDenied),
|
||||
.BUSY => return syscall.fail(error.FileBusy),
|
||||
.DQUOT => return syscall.fail(error.DiskQuota),
|
||||
.ISDIR => return syscall.fail(error.IsDir),
|
||||
.LOOP => return syscall.fail(error.SymLinkLoop),
|
||||
.MLINK => return syscall.fail(error.LinkQuotaExceeded),
|
||||
.NAMETOOLONG => return syscall.fail(error.NameTooLong),
|
||||
.NOENT => return syscall.fail(error.FileNotFound),
|
||||
.NOTDIR => return syscall.fail(error.NotDir),
|
||||
.NOMEM => return syscall.fail(error.SystemResources),
|
||||
.NOSPC => return syscall.fail(error.NoSpaceLeft),
|
||||
.EXIST => return syscall.fail(error.PathAlreadyExists),
|
||||
.NOTEMPTY => return syscall.fail(error.DirNotEmpty),
|
||||
.ROFS => return syscall.fail(error.ReadOnlyFileSystem),
|
||||
.XDEV => return syscall.fail(error.CrossDevice),
|
||||
.ILSEQ => return syscall.fail(error.BadPathName),
|
||||
.FAULT => |err| return syscall.errnoBug(err),
|
||||
.INVAL => |err| return syscall.errnoBug(err),
|
||||
else => |err| return syscall.unexpectedErrno(err),
|
||||
};
|
||||
}
|
||||
|
||||
fn renameat(
|
||||
old_dir: posix.fd_t,
|
||||
old_sub_path: [*:0]const u8,
|
||||
new_dir: posix.fd_t,
|
||||
new_sub_path: [*:0]const u8,
|
||||
) Dir.RenameError!void {
|
||||
const syscall: Syscall = try .start();
|
||||
while (true) switch (posix.errno(posix.system.renameat(old_dir, old_sub_path, new_dir, new_sub_path))) {
|
||||
.SUCCESS => return syscall.finish(),
|
||||
.INTR => {
|
||||
try syscall.checkCancel();
|
||||
continue;
|
||||
},
|
||||
.ACCES => return syscall.fail(error.AccessDenied),
|
||||
.PERM => return syscall.fail(error.PermissionDenied),
|
||||
.BUSY => return syscall.fail(error.FileBusy),
|
||||
.DQUOT => return syscall.fail(error.DiskQuota),
|
||||
.ISDIR => return syscall.fail(error.IsDir),
|
||||
.IO => return syscall.fail(error.HardwareFailure),
|
||||
.LOOP => return syscall.fail(error.SymLinkLoop),
|
||||
.MLINK => return syscall.fail(error.LinkQuotaExceeded),
|
||||
.NAMETOOLONG => return syscall.fail(error.NameTooLong),
|
||||
.NOENT => return syscall.fail(error.FileNotFound),
|
||||
.NOTDIR => return syscall.fail(error.NotDir),
|
||||
.NOMEM => return syscall.fail(error.SystemResources),
|
||||
.NOSPC => return syscall.fail(error.NoSpaceLeft),
|
||||
.EXIST => return syscall.fail(error.DirNotEmpty),
|
||||
.NOTEMPTY => return syscall.fail(error.DirNotEmpty),
|
||||
.ROFS => return syscall.fail(error.ReadOnlyFileSystem),
|
||||
.XDEV => return syscall.fail(error.CrossDevice),
|
||||
.ILSEQ => return syscall.fail(error.BadPathName),
|
||||
.FAULT => |err| return syscall.errnoBug(err),
|
||||
.INVAL => |err| return syscall.errnoBug(err),
|
||||
else => |err| return syscall.unexpectedErrno(err),
|
||||
};
|
||||
}
|
||||
|
||||
fn renameatPreserve(
|
||||
old_dir: posix.fd_t,
|
||||
old_sub_path: [*:0]const u8,
|
||||
new_dir: posix.fd_t,
|
||||
new_sub_path: [*:0]const u8,
|
||||
) Dir.RenameError!void {
|
||||
const syscall: Syscall = try .start();
|
||||
while (true) {
|
||||
switch (posix.errno(posix.system.renameat(old_dir.handle, old_sub_path_posix, new_dir.handle, new_sub_path_posix))) {
|
||||
switch (posix.errno(posix.system.renameat(old_dir, old_sub_path, new_dir, new_sub_path))) {
|
||||
.SUCCESS => return syscall.finish(),
|
||||
.INTR => {
|
||||
try syscall.checkCancel();
|
||||
|
|
@ -5905,7 +6032,7 @@ fn dirRenamePosix(
|
|||
.EXIST => return error.PathAlreadyExists,
|
||||
.NOTEMPTY => return error.PathAlreadyExists,
|
||||
.ROFS => return error.ReadOnlyFileSystem,
|
||||
.XDEV => return error.RenameAcrossMountPoints,
|
||||
.XDEV => return error.CrossDevice,
|
||||
.ILSEQ => return error.BadPathName,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
|
|
@ -7686,7 +7813,7 @@ fn dirHardLink(
|
|||
.NOTDIR => return error.NotDir,
|
||||
.PERM => return error.PermissionDenied,
|
||||
.ROFS => return error.ReadOnlyFileSystem,
|
||||
.XDEV => return error.NotSameFileSystem,
|
||||
.XDEV => return error.CrossDevice,
|
||||
.INVAL => |err| return errnoBug(err),
|
||||
.ILSEQ => return error.BadPathName,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
|
|
|
|||
|
|
@ -1022,8 +1022,7 @@ test "Dir.rename directory onto non-empty dir" {
|
|||
file.close(io);
|
||||
target_dir.close(io);
|
||||
|
||||
// Rename should fail with PathAlreadyExists if target_dir is non-empty
|
||||
try expectError(error.PathAlreadyExists, ctx.dir.rename(test_dir_path, ctx.dir, target_dir_path, io));
|
||||
try expectError(error.DirNotEmpty, ctx.dir.rename(test_dir_path, ctx.dir, target_dir_path, io));
|
||||
|
||||
// Ensure the directory was not renamed
|
||||
var dir = try ctx.dir.openDir(io, test_dir_path, .{});
|
||||
|
|
|
|||
|
|
@ -501,6 +501,15 @@ pub const O = switch (native_arch) {
|
|||
else => @compileError("missing std.os.linux.O constants for this architecture"),
|
||||
};
|
||||
|
||||
pub const RENAME = packed struct(u32) {
|
||||
/// Cannot be set together with `EXCHANGE`.
|
||||
NOREPLACE: bool = false,
|
||||
/// Cannot be set together with `NOREPLACE`.
|
||||
EXCHANGE: bool = false,
|
||||
WHITEOUT: bool = false,
|
||||
_: u29 = 0,
|
||||
};
|
||||
|
||||
/// Set by startup code, used by `getauxval`.
|
||||
pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
|
||||
|
||||
|
|
@ -1346,9 +1355,22 @@ pub fn rename(old: [*:0]const u8, new: [*:0]const u8) usize {
|
|||
if (@hasField(SYS, "rename")) {
|
||||
return syscall2(.rename, @intFromPtr(old), @intFromPtr(new));
|
||||
} else if (@hasField(SYS, "renameat")) {
|
||||
return syscall4(.renameat, @as(usize, @bitCast(@as(isize, AT.FDCWD))), @intFromPtr(old), @as(usize, @bitCast(@as(isize, AT.FDCWD))), @intFromPtr(new));
|
||||
return syscall4(
|
||||
.renameat,
|
||||
@as(usize, @bitCast(@as(isize, AT.FDCWD))),
|
||||
@intFromPtr(old),
|
||||
@as(usize, @bitCast(@as(isize, AT.FDCWD))),
|
||||
@intFromPtr(new),
|
||||
);
|
||||
} else {
|
||||
return syscall5(.renameat2, @as(usize, @bitCast(@as(isize, AT.FDCWD))), @intFromPtr(old), @as(usize, @bitCast(@as(isize, AT.FDCWD))), @intFromPtr(new), 0);
|
||||
return syscall5(
|
||||
.renameat2,
|
||||
@as(usize, @bitCast(@as(isize, AT.FDCWD))),
|
||||
@intFromPtr(old),
|
||||
@as(usize, @bitCast(@as(isize, AT.FDCWD))),
|
||||
@intFromPtr(new),
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1373,14 +1395,14 @@ pub fn renameat(oldfd: i32, oldpath: [*:0]const u8, newfd: i32, newpath: [*:0]co
|
|||
}
|
||||
}
|
||||
|
||||
pub fn renameat2(oldfd: i32, oldpath: [*:0]const u8, newfd: i32, newpath: [*:0]const u8, flags: u32) usize {
|
||||
pub fn renameat2(oldfd: i32, oldpath: [*:0]const u8, newfd: i32, newpath: [*:0]const u8, flags: RENAME) usize {
|
||||
return syscall5(
|
||||
.renameat2,
|
||||
@as(usize, @bitCast(@as(isize, oldfd))),
|
||||
@intFromPtr(oldpath),
|
||||
@as(usize, @bitCast(@as(isize, newfd))),
|
||||
@intFromPtr(newpath),
|
||||
flags,
|
||||
@as(u32, @bitCast(flags)),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3194,7 +3194,7 @@ pub const RenameError = error{
|
|||
NetworkNotFound,
|
||||
AntivirusInterference,
|
||||
BadPathName,
|
||||
RenameAcrossMountPoints,
|
||||
CrossDevice,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub fn RenameFile(
|
||||
|
|
@ -3295,7 +3295,7 @@ pub fn RenameFile(
|
|||
.ACCESS_DENIED => return error.AccessDenied,
|
||||
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
|
||||
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
|
||||
.NOT_SAME_DEVICE => return error.RenameAcrossMountPoints,
|
||||
.NOT_SAME_DEVICE => return error.CrossDevice,
|
||||
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
|
||||
.DIRECTORY_NOT_EMPTY => return error.PathAlreadyExists,
|
||||
.FILE_IS_A_DIRECTORY => return error.IsDir,
|
||||
|
|
|
|||
|
|
@ -1594,7 +1594,7 @@ pub const FanotifyMarkError = error{
|
|||
NotDir,
|
||||
OperationUnsupported,
|
||||
PermissionDenied,
|
||||
NotSameFileSystem,
|
||||
CrossDevice,
|
||||
NameTooLong,
|
||||
} || UnexpectedError;
|
||||
|
||||
|
|
@ -1634,7 +1634,7 @@ pub fn fanotify_markZ(
|
|||
.NOTDIR => return error.NotDir,
|
||||
.OPNOTSUPP => return error.OperationUnsupported,
|
||||
.PERM => return error.PermissionDenied,
|
||||
.XDEV => return error.NotSameFileSystem,
|
||||
.XDEV => return error.CrossDevice,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3460,7 +3460,7 @@ fn renameTmpIntoCache(
|
|||
},
|
||||
else => return error.AccessDenied,
|
||||
},
|
||||
error.PathAlreadyExists => {
|
||||
error.DirNotEmpty => {
|
||||
try cache_directory.handle.deleteTree(io, o_sub_path);
|
||||
continue;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1476,7 +1476,7 @@ pub fn renameTmpIntoCache(io: Io, cache_dir: Io.Dir, tmp_dir_sub_path: []const u
|
|||
};
|
||||
continue;
|
||||
},
|
||||
error.PathAlreadyExists, error.AccessDenied => {
|
||||
error.DirNotEmpty, error.AccessDenied => {
|
||||
// Package has been already downloaded and may already be in use on the system.
|
||||
cache_dir.deleteTree(io, tmp_dir_sub_path) catch {
|
||||
// Garbage files leftover in zig-cache/tmp/ is, as they say
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue