@@ -178,7 +178,13 @@ pub fn CreateEventExW(attributes: ?*SECURITY_ATTRIBUTES, nameW: [*:0]const u16,
178
178
}
179
179
}
180
180
181
- pub const DeviceIoControlError = error { AccessDenied , Unexpected };
181
+ pub const DeviceIoControlError = error {
182
+ AccessDenied ,
183
+ /// The volume does not contain a recognized file system. File system
184
+ /// drivers might not be loaded, or the volume may be corrupt.
185
+ UnrecognizedVolume ,
186
+ Unexpected ,
187
+ };
182
188
183
189
/// A Zig wrapper around `NtDeviceIoControlFile` and `NtFsControlFile` syscalls.
184
190
/// It implements similar behavior to `DeviceIoControl` and is meant to serve
@@ -234,6 +240,7 @@ pub fn DeviceIoControl(
234
240
.ACCESS_DENIED = > return error .AccessDenied ,
235
241
.INVALID_DEVICE_REQUEST = > return error .AccessDenied , // Not supported by the underlying filesystem
236
242
.INVALID_PARAMETER = > unreachable ,
243
+ .UNRECOGNIZED_VOLUME = > return error .UnrecognizedVolume ,
237
244
else = > return unexpectedStatus (rc ),
238
245
}
239
246
}
@@ -606,6 +613,9 @@ pub const CreateSymbolicLinkError = error{
606
613
NoDevice ,
607
614
NetworkNotFound ,
608
615
BadPathName ,
616
+ /// The volume does not contain a recognized file system. File system
617
+ /// drivers might not be loaded, or the volume may be corrupt.
618
+ UnrecognizedVolume ,
609
619
Unexpected ,
610
620
};
611
621
@@ -688,12 +698,12 @@ pub fn CreateSymbolicLink(
688
698
const target_is_absolute = std .fs .path .isAbsoluteWindowsWTF16 (final_target_path );
689
699
const symlink_data = SYMLINK_DATA {
690
700
.ReparseTag = IO_REPARSE_TAG_SYMLINK ,
691
- .ReparseDataLength = @as ( u16 , @ intCast (buf_len - header_len ) ),
701
+ .ReparseDataLength = @intCast (buf_len - header_len ),
692
702
.Reserved = 0 ,
693
- .SubstituteNameOffset = @as ( u16 , @ intCast (final_target_path .len * 2 ) ),
694
- .SubstituteNameLength = @as ( u16 , @ intCast (final_target_path .len * 2 ) ),
703
+ .SubstituteNameOffset = @intCast (final_target_path .len * 2 ),
704
+ .SubstituteNameLength = @intCast (final_target_path .len * 2 ),
695
705
.PrintNameOffset = 0 ,
696
- .PrintNameLength = @as ( u16 , @ intCast (final_target_path .len * 2 ) ),
706
+ .PrintNameLength = @intCast (final_target_path .len * 2 ),
697
707
.Flags = if (! target_is_absolute ) SYMLINK_FLAG_RELATIVE else 0 ,
698
708
};
699
709
@@ -769,7 +779,8 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin
769
779
770
780
var reparse_buf : [MAXIMUM_REPARSE_DATA_BUFFER_SIZE ]u8 align (@alignOf (REPARSE_DATA_BUFFER )) = undefined ;
771
781
_ = DeviceIoControl (result_handle , FSCTL_GET_REPARSE_POINT , null , reparse_buf [0.. ]) catch | err | switch (err ) {
772
- error .AccessDenied = > unreachable ,
782
+ error .AccessDenied = > return error .Unexpected ,
783
+ error .UnrecognizedVolume = > return error .Unexpected ,
773
784
else = > | e | return e ,
774
785
};
775
786
@@ -1084,6 +1095,9 @@ pub const GetFinalPathNameByHandleError = error{
1084
1095
BadPathName ,
1085
1096
FileNotFound ,
1086
1097
NameTooLong ,
1098
+ /// The volume does not contain a recognized file system. File system
1099
+ /// drivers might not be loaded, or the volume may be corrupt.
1100
+ UnrecognizedVolume ,
1087
1101
Unexpected ,
1088
1102
};
1089
1103
@@ -1174,16 +1188,16 @@ pub fn GetFinalPathNameByHandle(
1174
1188
};
1175
1189
defer CloseHandle (mgmt_handle );
1176
1190
1177
- var input_struct = @as ( * MOUNTMGR_MOUNT_POINT , @ptrCast (& input_buf [0 ]) );
1191
+ var input_struct : * MOUNTMGR_MOUNT_POINT = @ptrCast (& input_buf [0 ]);
1178
1192
input_struct .DeviceNameOffset = @sizeOf (MOUNTMGR_MOUNT_POINT );
1179
- input_struct .DeviceNameLength = @as ( USHORT , @ intCast (volume_name_u16 .len * 2 ) );
1193
+ input_struct .DeviceNameLength = @intCast (volume_name_u16 .len * 2 );
1180
1194
@memcpy (input_buf [@sizeOf (MOUNTMGR_MOUNT_POINT ).. ][0 .. volume_name_u16 .len * 2 ], @as ([* ]const u8 , @ptrCast (volume_name_u16 .ptr )));
1181
1195
1182
1196
DeviceIoControl (mgmt_handle , IOCTL_MOUNTMGR_QUERY_POINTS , & input_buf , & output_buf ) catch | err | switch (err ) {
1183
- error .AccessDenied = > unreachable ,
1197
+ error .AccessDenied = > return error . Unexpected ,
1184
1198
else = > | e | return e ,
1185
1199
};
1186
- const mount_points_struct = @as ( * const MOUNTMGR_MOUNT_POINTS , @ptrCast (& output_buf [0 ]) );
1200
+ const mount_points_struct : * const MOUNTMGR_MOUNT_POINTS = @ptrCast (& output_buf [0 ]);
1187
1201
1188
1202
const mount_points = @as (
1189
1203
[* ]const MOUNTMGR_MOUNT_POINT ,
@@ -2203,7 +2217,7 @@ pub fn wToPrefixedFileW(dir: ?HANDLE, path: [:0]const u16) !PathSpace {
2203
2217
.unc_absolute = > nt_prefix .len + 2 ,
2204
2218
else = > nt_prefix .len ,
2205
2219
};
2206
- const buf_len = @as ( u32 , @ intCast (path_space .data .len - path_buf_offset ) );
2220
+ const buf_len : u32 = @intCast (path_space .data .len - path_buf_offset );
2207
2221
const path_to_get : [:0 ]const u16 = path_to_get : {
2208
2222
// If dir is null, then we don't need to bother with GetFinalPathNameByHandle because
2209
2223
// RtlGetFullPathName_U will resolve relative paths against the CWD for us.
@@ -2221,7 +2235,24 @@ pub fn wToPrefixedFileW(dir: ?HANDLE, path: [:0]const u16) !PathSpace {
2221
2235
// canonicalize it. We do this by getting the path of the `dir`
2222
2236
// and appending the relative path to it.
2223
2237
var dir_path_buf : [PATH_MAX_WIDE :0 ]u16 = undefined ;
2224
- const dir_path = try GetFinalPathNameByHandle (dir .? , .{}, & dir_path_buf );
2238
+ const dir_path = GetFinalPathNameByHandle (dir .? , .{}, & dir_path_buf ) catch | err | switch (err ) {
2239
+ // This mapping is not correct; it is actually expected
2240
+ // that calling GetFinalPathNameByHandle might return
2241
+ // error.UnrecognizedVolume, and in fact has been observed
2242
+ // in the wild. The problem is that wToPrefixedFileW was
2243
+ // never intended to make *any* OS syscall APIs. It's only
2244
+ // supposed to convert a string to one that is eligible to
2245
+ // be used in the ntdll syscalls.
2246
+ //
2247
+ // To solve this, this function needs to no longer call
2248
+ // GetFinalPathNameByHandle under any conditions, or the
2249
+ // calling function needs to get reworked to not need to
2250
+ // call this function.
2251
+ //
2252
+ // This may involve making breaking API changes.
2253
+ error .UnrecognizedVolume = > return error .Unexpected ,
2254
+ else = > | e | return e ,
2255
+ };
2225
2256
if (dir_path .len + 1 + path .len > PATH_MAX_WIDE ) {
2226
2257
return error .NameTooLong ;
2227
2258
}
0 commit comments