| ... | ... | @@ -28,10 +28,6 @@ pub const gdi32 = @import("windows/gdi32.zig"); |
| 28 | 28 | |
| 29 | 29 | pub usingnamespace @import("windows/bits.zig"); |
| 30 | 30 | |
| 31 | | //version detection |
| 32 | | const version = std.zig.system.windows; |
| 33 | | const WindowsVersion = version.WindowsVersion; |
| 34 | | |
| 35 | 31 | pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize)); |
| 36 | 32 | |
| 37 | 33 | pub const OpenError = error{ |
| ... | ... | @@ -1034,65 +1030,35 @@ pub fn GetFinalPathNameByHandle( |
| 1034 | 1030 | out_buffer: []u16, |
| 1035 | 1031 | ) GetFinalPathNameByHandleError![]u16 { |
| 1036 | 1032 | var path_buffer: [math.max(@sizeOf(FILE_NAME_INFORMATION), @sizeOf(OBJECT_NAME_INFORMATION)) + PATH_MAX_WIDE * 2]u8 align(@alignOf(FILE_NAME_INFORMATION)) = undefined; |
| 1037 | | var volume_buffer: [@sizeOf(FILE_NAME_INFORMATION) + MAX_PATH]u8 align(@alignOf(FILE_NAME_INFORMATION)) = undefined; // MAX_PATH bytes should be enough since it's Windows-defined name |
| 1038 | | |
| 1039 | | var file_name_u16: []const u16 = undefined; |
| 1040 | | var volume_name_u16: []const u16 = undefined; |
| 1041 | | if ((comptime (std.builtin.os.version_range.windows.isAtLeast(WindowsVersion.win10_rs4) != true)) and !version.detectRuntimeVersion().isAtLeast(WindowsVersion.win10_rs4)) { |
| 1042 | | const final_path = QueryObjectName(hFile, mem.bytesAsSlice(u16, &path_buffer)) catch |err| return switch (err) { |
| 1043 | | // we assume InvalidHandle is close enough to FileNotFound in semantics |
| 1044 | | // to not further complicate the error set |
| 1045 | | error.InvalidHandle => error.FileNotFound, |
| 1046 | | else => |e| e, |
| 1047 | | }; |
| 1033 | const final_path = QueryObjectName(hFile, mem.bytesAsSlice(u16, &path_buffer)) catch |err| switch (err) { |
| 1034 | // we assume InvalidHandle is close enough to FileNotFound in semantics |
| 1035 | // to not further complicate the error set |
| 1036 | error.InvalidHandle => return error.FileNotFound, |
| 1037 | else => |e| return e, |
| 1038 | }; |
| 1048 | 1039 | |
| 1049 | | if (fmt.volume_name == .Nt) { |
| 1040 | switch (fmt.volume_name) { |
| 1041 | .Nt => { |
| 1042 | // the returned path is already in .Nt format |
| 1050 | 1043 | if (out_buffer.len < final_path.len) { |
| 1051 | 1044 | return error.NameTooLong; |
| 1052 | 1045 | } |
| 1053 | 1046 | mem.copy(u16, out_buffer, final_path); |
| 1054 | 1047 | return out_buffer[0..final_path.len]; |
| 1055 | | } |
| 1056 | | |
| 1057 | | //otherwise we need to parse the string for volume path for the .Dos logic below to work |
| 1058 | | const expected_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\"); |
| 1059 | | |
| 1060 | | // TODO find out if a path can start with something besides `\Device\<volume name>`, |
| 1061 | | // and if we need to handle it differently |
| 1062 | | // (i.e. how to determine the start and end of the volume name in that case) |
| 1063 | | if (!mem.eql(u16, expected_prefix, final_path[0..expected_prefix.len])) return error.Unexpected; |
| 1064 | | |
| 1065 | | const index = mem.indexOfPos(u16, final_path, expected_prefix.len, &[_]u16{'\\'}) orelse unreachable; |
| 1066 | | volume_name_u16 = final_path[0..index]; |
| 1067 | | file_name_u16 = final_path[index..]; |
| 1068 | | |
| 1069 | | //fallthrough for fmt.volume_name != .Nt |
| 1070 | | } else { |
| 1071 | | // Get normalized path; doesn't include volume name though. |
| 1072 | | try QueryInformationFile(hFile, .FileNormalizedNameInformation, &path_buffer); |
| 1073 | | const file_name = @ptrCast(*const FILE_NAME_INFORMATION, &path_buffer); |
| 1074 | | file_name_u16 = @ptrCast([*]const u16, &file_name.FileName)[0..@divExact(file_name.FileNameLength, 2)]; |
| 1075 | | |
| 1076 | | // Get NT volume name. |
| 1077 | | try QueryInformationFile(hFile, .FileVolumeNameInformation, &volume_buffer); |
| 1078 | | const volume_name_info = @ptrCast(*const FILE_NAME_INFORMATION, &volume_buffer); |
| 1079 | | volume_name_u16 = @ptrCast([*]const u16, &volume_name_info.FileName)[0..@divExact(volume_name_info.FileNameLength, 2)]; |
| 1048 | }, |
| 1049 | .Dos => { |
| 1050 | // parse the string to separate volume path from file path |
| 1051 | const expected_prefix = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\"); |
| 1080 | 1052 | |
| 1081 | | if (fmt.volume_name == .Nt) { |
| 1082 | | // Nothing to do, we simply copy the bytes to the user-provided buffer. |
| 1083 | | if (out_buffer.len < volume_name_u16.len + file_name_u16.len) return error.NameTooLong; |
| 1053 | // TODO find out if a path can start with something besides `\Device\<volume name>`, |
| 1054 | // and if we need to handle it differently |
| 1055 | // (i.e. how to determine the start and end of the volume name in that case) |
| 1056 | if (!mem.eql(u16, expected_prefix, final_path[0..expected_prefix.len])) return error.Unexpected; |
| 1084 | 1057 | |
| 1085 | | mem.copy(u16, out_buffer, volume_name_u16); |
| 1086 | | mem.copy(u16, out_buffer[volume_name_u16.len..], file_name_u16); |
| 1058 | const file_path_begin_index = mem.indexOfPos(u16, final_path, expected_prefix.len, &[_]u16{'\\'}) orelse unreachable; |
| 1059 | const volume_name_u16 = final_path[0..file_path_begin_index]; |
| 1060 | const file_name_u16 = final_path[file_path_begin_index..]; |
| 1087 | 1061 | |
| 1088 | | return out_buffer[0 .. volume_name_u16.len + file_name_u16.len]; |
| 1089 | | } |
| 1090 | | //fallthrough for fmt.volume_name != .Nt |
| 1091 | | } |
| 1092 | | |
| 1093 | | switch (fmt.volume_name) { |
| 1094 | | .Nt => unreachable, //handled above |
| 1095 | | .Dos => { |
| 1096 | 1062 | // Get DOS volume name. DOS volume names are actually symbolic link objects to the |
| 1097 | 1063 | // actual NT volume. For example: |
| 1098 | 1064 | // (NT) \Device\HarddiskVolume4 => (DOS) \DosDevices\C: == (DOS) C: |