Skip to content

Commit 60c139b

Browse files
committed
use same strategy as in ziglang#16499 suggested by @squeek502
Also add optimization for happy path with early return. No idea, why this worked before.
1 parent 87c5096 commit 60c139b

File tree

2 files changed

+60
-35
lines changed

2 files changed

+60
-35
lines changed

lib/std/os.zig

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,14 +2629,16 @@ pub fn renameatW(
26292629
};
26302630
defer windows.CloseHandle(src_fd);
26312631

2632-
const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (MAX_PATH_BYTES - 1);
2633-
var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION)) = undefined;
2634-
const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION) - 1 + new_path_w.len * 2;
2635-
if (struct_len > struct_buf_len) return error.NameTooLong;
2636-
2637-
const rename_info = @as(*windows.FILE_RENAME_INFORMATION, @ptrCast(&rename_info_buf));
2632+
var need_fallback = true;
2633+
if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) {
2634+
const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION_EX) + (MAX_PATH_BYTES - 1);
2635+
var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION_EX)) = undefined;
2636+
const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION_EX) - 1 + new_path_w.len * 2;
2637+
if (struct_len > struct_buf_len) return error.NameTooLong;
2638+
2639+
const rename_info = @as(*windows.FILE_RENAME_INFORMATION_EX, @ptrCast(&rename_info_buf));
2640+
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
26382641

2639-
if (builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) {
26402642
var flags: windows.ULONG = windows.FILE_RENAME_POSIX_SEMANTICS | windows.FILE_RENAME_IGNORE_READONLY_ATTRIBUTE;
26412643
if (ReplaceIfExists == windows.TRUE) flags |= windows.FILE_RENAME_REPLACE_IF_EXISTS;
26422644
rename_info.* = .{
@@ -2645,47 +2647,61 @@ pub fn renameatW(
26452647
.FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong
26462648
.FileName = undefined,
26472649
};
2648-
} else {
2650+
@memcpy(@as([*]u16, &rename_info.FileName)[0..new_path_w.len], new_path_w);
2651+
const rc = windows.ntdll.NtSetInformationFile(
2652+
src_fd,
2653+
&io_status_block,
2654+
rename_info,
2655+
@intCast(struct_len), // already checked for error.NameTooLong
2656+
.FileRenameInformationEx,
2657+
);
2658+
switch (rc) {
2659+
.SUCCESS => return,
2660+
// INVALID_PARAMETER here means that the filesystem does not support FileRenameInformationEx
2661+
.INVALID_PARAMETER => {},
2662+
// For all other statuses, fall down to the switch below to handle them.
2663+
else => need_fallback = false,
2664+
}
2665+
}
2666+
2667+
if (need_fallback) {
2668+
const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (MAX_PATH_BYTES - 1);
2669+
var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION)) = undefined;
2670+
const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION) - 1 + new_path_w.len * 2;
2671+
if (struct_len > struct_buf_len) return error.NameTooLong;
2672+
2673+
const rename_info = @as(*windows.FILE_RENAME_INFORMATION, @ptrCast(&rename_info_buf));
2674+
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
2675+
26492676
rename_info.* = .{
26502677
.Flags = ReplaceIfExists,
26512678
.RootDirectory = if (std.fs.path.isAbsoluteWindowsWTF16(new_path_w)) null else new_dir_fd,
26522679
.FileNameLength = @intCast(new_path_w.len * 2), // already checked error.NameTooLong
26532680
.FileName = undefined,
26542681
};
2655-
}
2656-
@memcpy(@as([*]u16, &rename_info.FileName)[0..new_path_w.len], new_path_w);
2657-
2658-
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
2682+
@memcpy(@as([*]u16, &rename_info.FileName)[0..new_path_w.len], new_path_w);
26592683

2660-
const rc = if (comptime builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) {
2661-
windows.ntdll.NtSetInformationFile(
2662-
src_fd,
2663-
&io_status_block,
2664-
rename_info,
2665-
@intCast(struct_len), // already checked for error.NameTooLong
2666-
.FileRenameInformationEx,
2667-
);
2668-
} else {
2669-
windows.ntdll.NtSetInformationFile(
2684+
const rc =
2685+
windows.ntdll.NtSetInformationFile(
26702686
src_fd,
26712687
&io_status_block,
26722688
rename_info,
26732689
@intCast(struct_len), // already checked for error.NameTooLong
26742690
.FileRenameInformation,
26752691
);
2676-
};
26772692

2678-
switch (rc) {
2679-
.SUCCESS => return,
2680-
.INVALID_HANDLE => unreachable,
2681-
.INVALID_PARAMETER => unreachable,
2682-
.OBJECT_PATH_SYNTAX_BAD => unreachable,
2683-
.ACCESS_DENIED => return error.AccessDenied,
2684-
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
2685-
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
2686-
.NOT_SAME_DEVICE => return error.RenameAcrossMountPoints,
2687-
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
2688-
else => return windows.unexpectedStatus(rc),
2693+
switch (rc) {
2694+
.SUCCESS => {},
2695+
.INVALID_HANDLE => unreachable,
2696+
.INVALID_PARAMETER => unreachable,
2697+
.OBJECT_PATH_SYNTAX_BAD => unreachable,
2698+
.ACCESS_DENIED => return error.AccessDenied,
2699+
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
2700+
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
2701+
.NOT_SAME_DEVICE => return error.RenameAcrossMountPoints,
2702+
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
2703+
else => return windows.unexpectedStatus(rc),
2704+
}
26892705
}
26902706
}
26912707

lib/std/os/windows.zig

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
972972
.FileDispositionInformationEx,
973973
);
974974
switch (rc) {
975+
.SUCCESS => return,
975976
// INVALID_PARAMETER here means that the filesystem does not support FileDispositionInformationEx
976977
.INVALID_PARAMETER => {},
977978
// For all other statuses, fall down to the switch below to handle them.
@@ -2726,7 +2727,15 @@ pub const FILE_RENAME_FORCE_RESIZE_SOURCE_SR = 0x00000100;
27262727
pub const FILE_RENAME_FORCE_RESIZE_SR = 0x00000180;
27272728

27282729
pub const FILE_RENAME_INFORMATION = extern struct {
2729-
Flags: if (builtin.target.os.version_range.windows.min.isAtLeast(.win10_rs1)) ULONG else BOOLEAN,
2730+
Flags: BOOLEAN,
2731+
RootDirectory: ?HANDLE,
2732+
FileNameLength: ULONG,
2733+
FileName: [1]WCHAR,
2734+
};
2735+
2736+
// FileRenameInformationEx (since .win10_rs1)
2737+
pub const FILE_RENAME_INFORMATION_EX = extern struct {
2738+
Flags: ULONG,
27302739
RootDirectory: ?HANDLE,
27312740
FileNameLength: ULONG,
27322741
FileName: [1]WCHAR,

0 commit comments

Comments
 (0)