@@ -2629,33 +2629,74 @@ pub fn renameatW(
2629
2629
};
2630
2630
defer windows .CloseHandle (src_fd );
2631
2631
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 ;
2646
2642
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
+ }
2648
2670
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
+ }
2656
2697
2657
2698
switch (rc ) {
2658
- .SUCCESS = > return ,
2699
+ .SUCCESS = > {} ,
2659
2700
.INVALID_HANDLE = > unreachable ,
2660
2701
.INVALID_PARAMETER = > unreachable ,
2661
2702
.OBJECT_PATH_SYNTAX_BAD = > unreachable ,
0 commit comments