@@ -2629,33 +2629,74 @@ 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 ));
2638-
2639- rename_info .* = .{
2640- .ReplaceIfExists = ReplaceIfExists ,
2641- .RootDirectory = if (std .fs .path .isAbsoluteWindowsWTF16 (new_path_w )) null else new_dir_fd ,
2642- .FileNameLength = @as (u32 , @intCast (new_path_w .len * 2 )), // already checked error.NameTooLong
2643- .FileName = undefined ,
2644- };
2645- @memcpy (@as ([* ]u16 , & rename_info .FileName )[0.. new_path_w .len ], new_path_w );
2632+ var need_fallback = true ;
2633+ var rc : windows.NTSTATUS = undefined ;
2634+ if (comptime builtin .target .os .version_range .windows .min .isAtLeast (.win10_rs1 )) {
2635+ const struct_buf_len = @sizeOf (windows .FILE_RENAME_INFORMATION_EX ) + (MAX_PATH_BYTES - 1 );
2636+ var rename_info_buf : [struct_buf_len ]u8 align (@alignOf (windows .FILE_RENAME_INFORMATION_EX )) = undefined ;
2637+ const struct_len = @sizeOf (windows .FILE_RENAME_INFORMATION_EX ) - 1 + new_path_w .len * 2 ;
2638+ if (struct_len > struct_buf_len ) return error .NameTooLong ;
2639+
2640+ const rename_info = @as (* windows .FILE_RENAME_INFORMATION_EX , @ptrCast (& rename_info_buf ));
2641+ var io_status_block : windows.IO_STATUS_BLOCK = undefined ;
26462642
2647- var io_status_block : windows.IO_STATUS_BLOCK = undefined ;
2643+ var flags : windows.ULONG = windows .FILE_RENAME_POSIX_SEMANTICS | windows .FILE_RENAME_IGNORE_READONLY_ATTRIBUTE ;
2644+ if (ReplaceIfExists == windows .TRUE ) flags |= windows .FILE_RENAME_REPLACE_IF_EXISTS ;
2645+ rename_info .* = .{
2646+ .Flags = flags ,
2647+ .RootDirectory = if (std .fs .path .isAbsoluteWindowsWTF16 (new_path_w )) null else new_dir_fd ,
2648+ .FileNameLength = @intCast (new_path_w .len * 2 ), // already checked error.NameTooLong
2649+ .FileName = undefined ,
2650+ };
2651+ @memcpy (@as ([* ]u16 , & rename_info .FileName )[0.. new_path_w .len ], new_path_w );
2652+ rc = windows .ntdll .NtSetInformationFile (
2653+ src_fd ,
2654+ & io_status_block ,
2655+ rename_info ,
2656+ @intCast (struct_len ), // already checked for error.NameTooLong
2657+ .FileRenameInformationEx ,
2658+ );
2659+ switch (rc ) {
2660+ .SUCCESS = > return ,
2661+ // INVALID_PARAMETER here means that the filesystem does not support FileRenameInformationEx
2662+ .INVALID_PARAMETER = > {},
2663+ .DIRECTORY_NOT_EMPTY = > return error .PathAlreadyExists ,
2664+ .FILE_IS_A_DIRECTORY = > return error .IsDir ,
2665+ .NOT_A_DIRECTORY = > return error .NotDir ,
2666+ // For all other statuses, fall down to the switch below to handle them.
2667+ else = > need_fallback = false ,
2668+ }
2669+ }
26482670
2649- const rc = windows .ntdll .NtSetInformationFile (
2650- src_fd ,
2651- & io_status_block ,
2652- rename_info ,
2653- @as (u32 , @intCast (struct_len )), // already checked for error.NameTooLong
2654- .FileRenameInformation ,
2655- );
2671+ if (need_fallback ) {
2672+ const struct_buf_len = @sizeOf (windows .FILE_RENAME_INFORMATION ) + (MAX_PATH_BYTES - 1 );
2673+ var rename_info_buf : [struct_buf_len ]u8 align (@alignOf (windows .FILE_RENAME_INFORMATION )) = undefined ;
2674+ const struct_len = @sizeOf (windows .FILE_RENAME_INFORMATION ) - 1 + new_path_w .len * 2 ;
2675+ if (struct_len > struct_buf_len ) return error .NameTooLong ;
2676+
2677+ const rename_info = @as (* windows .FILE_RENAME_INFORMATION , @ptrCast (& rename_info_buf ));
2678+ var io_status_block : windows.IO_STATUS_BLOCK = undefined ;
2679+
2680+ rename_info .* = .{
2681+ .Flags = ReplaceIfExists ,
2682+ .RootDirectory = if (std .fs .path .isAbsoluteWindowsWTF16 (new_path_w )) null else new_dir_fd ,
2683+ .FileNameLength = @intCast (new_path_w .len * 2 ), // already checked error.NameTooLong
2684+ .FileName = undefined ,
2685+ };
2686+ @memcpy (@as ([* ]u16 , & rename_info .FileName )[0.. new_path_w .len ], new_path_w );
2687+
2688+ rc =
2689+ windows .ntdll .NtSetInformationFile (
2690+ src_fd ,
2691+ & io_status_block ,
2692+ rename_info ,
2693+ @intCast (struct_len ), // already checked for error.NameTooLong
2694+ .FileRenameInformation ,
2695+ );
2696+ }
26562697
26572698 switch (rc ) {
2658- .SUCCESS = > return ,
2699+ .SUCCESS = > {} ,
26592700 .INVALID_HANDLE = > unreachable ,
26602701 .INVALID_PARAMETER = > unreachable ,
26612702 .OBJECT_PATH_SYNTAX_BAD = > unreachable ,
0 commit comments