mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
std.windows: use atomic rename, if possible (#16717)
Mitigates #14978. Uses the same strategy as in #16499 suggested by @squeek502
This commit is contained in:
parent
6780a6bbfa
commit
7a834e2581
@ -2629,33 +2629,74 @@ pub fn renameatW(
|
||||
};
|
||||
defer windows.CloseHandle(src_fd);
|
||||
|
||||
const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (MAX_PATH_BYTES - 1);
|
||||
var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION)) = undefined;
|
||||
const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION) - 1 + new_path_w.len * 2;
|
||||
if (struct_len > struct_buf_len) return error.NameTooLong;
|
||||
var need_fallback = true;
|
||||
var rc: windows.NTSTATUS = undefined;
|
||||
if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) {
|
||||
const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION_EX) + (MAX_PATH_BYTES - 1);
|
||||
var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION_EX)) = undefined;
|
||||
const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION_EX) - 1 + new_path_w.len * 2;
|
||||
if (struct_len > struct_buf_len) return error.NameTooLong;
|
||||
|
||||
const rename_info = @as(*windows.FILE_RENAME_INFORMATION, @ptrCast(&rename_info_buf));
|
||||
const rename_info = @as(*windows.FILE_RENAME_INFORMATION_EX, @ptrCast(&rename_info_buf));
|
||||
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
|
||||
|
||||
rename_info.* = .{
|
||||
.ReplaceIfExists = ReplaceIfExists,
|
||||
.RootDirectory = if (std.fs.path.isAbsoluteWindowsWTF16(new_path_w)) null else new_dir_fd,
|
||||
.FileNameLength = @as(u32, @intCast(new_path_w.len * 2)), // already checked error.NameTooLong
|
||||
.FileName = undefined,
|
||||
};
|
||||
@memcpy(@as([*]u16, &rename_info.FileName)[0..new_path_w.len], new_path_w);
|
||||
var flags: windows.ULONG = windows.FILE_RENAME_POSIX_SEMANTICS | windows.FILE_RENAME_IGNORE_READONLY_ATTRIBUTE;
|
||||
if (ReplaceIfExists == windows.TRUE) flags |= windows.FILE_RENAME_REPLACE_IF_EXISTS;
|
||||
rename_info.* = .{
|
||||
.Flags = flags,
|
||||
.RootDirectory = if (std.fs.path.isAbsoluteWindowsWTF16(new_path_w)) null else new_dir_fd,
|
||||
.FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong
|
||||
.FileName = undefined,
|
||||
};
|
||||
@memcpy(@as([*]u16, &rename_info.FileName)[0..new_path_w.len], new_path_w);
|
||||
rc = windows.ntdll.NtSetInformationFile(
|
||||
src_fd,
|
||||
&io_status_block,
|
||||
rename_info,
|
||||
@intCast(struct_len), // already checked for error.NameTooLong
|
||||
.FileRenameInformationEx,
|
||||
);
|
||||
switch (rc) {
|
||||
.SUCCESS => return,
|
||||
// INVALID_PARAMETER here means that the filesystem does not support FileRenameInformationEx
|
||||
.INVALID_PARAMETER => {},
|
||||
.DIRECTORY_NOT_EMPTY => return error.PathAlreadyExists,
|
||||
.FILE_IS_A_DIRECTORY => return error.IsDir,
|
||||
.NOT_A_DIRECTORY => return error.NotDir,
|
||||
// For all other statuses, fall down to the switch below to handle them.
|
||||
else => need_fallback = false,
|
||||
}
|
||||
}
|
||||
|
||||
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
|
||||
if (need_fallback) {
|
||||
const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (MAX_PATH_BYTES - 1);
|
||||
var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION)) = undefined;
|
||||
const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION) - 1 + new_path_w.len * 2;
|
||||
if (struct_len > struct_buf_len) return error.NameTooLong;
|
||||
|
||||
const rc = windows.ntdll.NtSetInformationFile(
|
||||
src_fd,
|
||||
&io_status_block,
|
||||
rename_info,
|
||||
@as(u32, @intCast(struct_len)), // already checked for error.NameTooLong
|
||||
.FileRenameInformation,
|
||||
);
|
||||
const rename_info = @as(*windows.FILE_RENAME_INFORMATION, @ptrCast(&rename_info_buf));
|
||||
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
|
||||
|
||||
rename_info.* = .{
|
||||
.Flags = ReplaceIfExists,
|
||||
.RootDirectory = if (std.fs.path.isAbsoluteWindowsWTF16(new_path_w)) null else new_dir_fd,
|
||||
.FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong
|
||||
.FileName = undefined,
|
||||
};
|
||||
@memcpy(@as([*]u16, &rename_info.FileName)[0..new_path_w.len], new_path_w);
|
||||
|
||||
rc =
|
||||
windows.ntdll.NtSetInformationFile(
|
||||
src_fd,
|
||||
&io_status_block,
|
||||
rename_info,
|
||||
@intCast(struct_len), // already checked for error.NameTooLong
|
||||
.FileRenameInformation,
|
||||
);
|
||||
}
|
||||
|
||||
switch (rc) {
|
||||
.SUCCESS => return,
|
||||
.SUCCESS => {},
|
||||
.INVALID_HANDLE => unreachable,
|
||||
.INVALID_PARAMETER => unreachable,
|
||||
.OBJECT_PATH_SYNTAX_BAD => unreachable,
|
||||
|
||||
@ -1009,6 +1009,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
|
||||
.FileDispositionInformationEx,
|
||||
);
|
||||
switch (rc) {
|
||||
.SUCCESS => return,
|
||||
// INVALID_PARAMETER here means that the filesystem does not support FileDispositionInformationEx
|
||||
.INVALID_PARAMETER => {},
|
||||
// For all other statuses, fall down to the switch below to handle them.
|
||||
@ -2856,8 +2857,29 @@ const FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK: ULONG = 0x00000004;
|
||||
const FILE_DISPOSITION_ON_CLOSE: ULONG = 0x00000008;
|
||||
const FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: ULONG = 0x00000010;
|
||||
|
||||
// FILE_RENAME_INFORMATION.Flags
|
||||
pub const FILE_RENAME_REPLACE_IF_EXISTS = 0x00000001;
|
||||
pub const FILE_RENAME_POSIX_SEMANTICS = 0x00000002;
|
||||
pub const FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE = 0x00000004;
|
||||
pub const FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE = 0x00000008;
|
||||
pub const FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE = 0x00000010;
|
||||
pub const FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE = 0x00000020;
|
||||
pub const FILE_RENAME_PRESERVE_AVAILABLE_SPACE = 0x00000030;
|
||||
pub const FILE_RENAME_IGNORE_READONLY_ATTRIBUTE = 0x00000040;
|
||||
pub const FILE_RENAME_FORCE_RESIZE_TARGET_SR = 0x00000080;
|
||||
pub const FILE_RENAME_FORCE_RESIZE_SOURCE_SR = 0x00000100;
|
||||
pub const FILE_RENAME_FORCE_RESIZE_SR = 0x00000180;
|
||||
|
||||
pub const FILE_RENAME_INFORMATION = extern struct {
|
||||
ReplaceIfExists: BOOLEAN,
|
||||
Flags: BOOLEAN,
|
||||
RootDirectory: ?HANDLE,
|
||||
FileNameLength: ULONG,
|
||||
FileName: [1]WCHAR,
|
||||
};
|
||||
|
||||
// FileRenameInformationEx (since .win10_rs1)
|
||||
pub const FILE_RENAME_INFORMATION_EX = extern struct {
|
||||
Flags: ULONG,
|
||||
RootDirectory: ?HANDLE,
|
||||
FileNameLength: ULONG,
|
||||
FileName: [1]WCHAR,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user