| ... | ... | @@ -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, |