mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 08:33:06 +00:00
std.os.windows: add error.UnrecognizedVolume
Thanks to @matklad for finding this additional NTSTATUS possibility when calling GetFinalPathNameByHandle.
This commit is contained in:
parent
2176a73d66
commit
0183b44bb1
@ -5364,6 +5364,10 @@ pub const RealPathError = error{
|
||||
/// intercepts file system operations and makes them significantly slower
|
||||
/// in addition to possibly failing with this error code.
|
||||
AntivirusInterference,
|
||||
|
||||
/// On Windows, the volume does not contain a recognized file system. File
|
||||
/// system drivers might not be loaded, or the volume may be corrupt.
|
||||
UnrecognizedVolume,
|
||||
} || UnexpectedError;
|
||||
|
||||
/// Return the canonicalized absolute pathname.
|
||||
@ -5371,6 +5375,7 @@ pub const RealPathError = error{
|
||||
/// extra `/` characters in `pathname`.
|
||||
/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
|
||||
/// See also `realpathZ` and `realpathW`.
|
||||
/// Calling this function is usually a bug.
|
||||
pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const pathname_w = try windows.sliceToPrefixedFileW(null, pathname);
|
||||
@ -5383,6 +5388,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE
|
||||
}
|
||||
|
||||
/// Same as `realpath` except `pathname` is null-terminated.
|
||||
/// Calling this function is usually a bug.
|
||||
pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const pathname_w = try windows.cStrToPrefixedFileW(null, pathname);
|
||||
@ -5431,6 +5437,7 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP
|
||||
}
|
||||
|
||||
/// Same as `realpath` except `pathname` is UTF16LE-encoded.
|
||||
/// Calling this function is usually a bug.
|
||||
pub fn realpathW(pathname: []const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
|
||||
const w = windows;
|
||||
|
||||
@ -5479,6 +5486,7 @@ pub fn isGetFdPathSupportedOnTarget(os: std.Target.Os) bool {
|
||||
/// This function is very host-specific and is not universally supported by all hosts.
|
||||
/// For example, while it generally works on Linux, macOS, FreeBSD or Windows, it is
|
||||
/// unsupported on WASI.
|
||||
/// Calling this function is usually a bug.
|
||||
pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
|
||||
if (!comptime isGetFdPathSupportedOnTarget(builtin.os)) {
|
||||
@compileError("querying for canonical path of a handle is unsupported on this host");
|
||||
|
@ -178,7 +178,13 @@ pub fn CreateEventExW(attributes: ?*SECURITY_ATTRIBUTES, nameW: [*:0]const u16,
|
||||
}
|
||||
}
|
||||
|
||||
pub const DeviceIoControlError = error{ AccessDenied, Unexpected };
|
||||
pub const DeviceIoControlError = error{
|
||||
AccessDenied,
|
||||
/// The volume does not contain a recognized file system. File system
|
||||
/// drivers might not be loaded, or the volume may be corrupt.
|
||||
UnrecognizedVolume,
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
/// A Zig wrapper around `NtDeviceIoControlFile` and `NtFsControlFile` syscalls.
|
||||
/// It implements similar behavior to `DeviceIoControl` and is meant to serve
|
||||
@ -234,6 +240,7 @@ pub fn DeviceIoControl(
|
||||
.ACCESS_DENIED => return error.AccessDenied,
|
||||
.INVALID_DEVICE_REQUEST => return error.AccessDenied, // Not supported by the underlying filesystem
|
||||
.INVALID_PARAMETER => unreachable,
|
||||
.UNRECOGNIZED_VOLUME => return error.UnrecognizedVolume,
|
||||
else => return unexpectedStatus(rc),
|
||||
}
|
||||
}
|
||||
@ -606,6 +613,9 @@ pub const CreateSymbolicLinkError = error{
|
||||
NoDevice,
|
||||
NetworkNotFound,
|
||||
BadPathName,
|
||||
/// The volume does not contain a recognized file system. File system
|
||||
/// drivers might not be loaded, or the volume may be corrupt.
|
||||
UnrecognizedVolume,
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
@ -688,12 +698,12 @@ pub fn CreateSymbolicLink(
|
||||
const target_is_absolute = std.fs.path.isAbsoluteWindowsWTF16(final_target_path);
|
||||
const symlink_data = SYMLINK_DATA{
|
||||
.ReparseTag = IO_REPARSE_TAG_SYMLINK,
|
||||
.ReparseDataLength = @as(u16, @intCast(buf_len - header_len)),
|
||||
.ReparseDataLength = @intCast(buf_len - header_len),
|
||||
.Reserved = 0,
|
||||
.SubstituteNameOffset = @as(u16, @intCast(final_target_path.len * 2)),
|
||||
.SubstituteNameLength = @as(u16, @intCast(final_target_path.len * 2)),
|
||||
.SubstituteNameOffset = @intCast(final_target_path.len * 2),
|
||||
.SubstituteNameLength = @intCast(final_target_path.len * 2),
|
||||
.PrintNameOffset = 0,
|
||||
.PrintNameLength = @as(u16, @intCast(final_target_path.len * 2)),
|
||||
.PrintNameLength = @intCast(final_target_path.len * 2),
|
||||
.Flags = if (!target_is_absolute) SYMLINK_FLAG_RELATIVE else 0,
|
||||
};
|
||||
|
||||
@ -769,7 +779,8 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin
|
||||
|
||||
var reparse_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(REPARSE_DATA_BUFFER)) = undefined;
|
||||
_ = DeviceIoControl(result_handle, FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..]) catch |err| switch (err) {
|
||||
error.AccessDenied => unreachable,
|
||||
error.AccessDenied => return error.Unexpected,
|
||||
error.UnrecognizedVolume => return error.Unexpected,
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
@ -1084,6 +1095,9 @@ pub const GetFinalPathNameByHandleError = error{
|
||||
BadPathName,
|
||||
FileNotFound,
|
||||
NameTooLong,
|
||||
/// The volume does not contain a recognized file system. File system
|
||||
/// drivers might not be loaded, or the volume may be corrupt.
|
||||
UnrecognizedVolume,
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
@ -1174,16 +1188,16 @@ pub fn GetFinalPathNameByHandle(
|
||||
};
|
||||
defer CloseHandle(mgmt_handle);
|
||||
|
||||
var input_struct = @as(*MOUNTMGR_MOUNT_POINT, @ptrCast(&input_buf[0]));
|
||||
var input_struct: *MOUNTMGR_MOUNT_POINT = @ptrCast(&input_buf[0]);
|
||||
input_struct.DeviceNameOffset = @sizeOf(MOUNTMGR_MOUNT_POINT);
|
||||
input_struct.DeviceNameLength = @as(USHORT, @intCast(volume_name_u16.len * 2));
|
||||
input_struct.DeviceNameLength = @intCast(volume_name_u16.len * 2);
|
||||
@memcpy(input_buf[@sizeOf(MOUNTMGR_MOUNT_POINT)..][0 .. volume_name_u16.len * 2], @as([*]const u8, @ptrCast(volume_name_u16.ptr)));
|
||||
|
||||
DeviceIoControl(mgmt_handle, IOCTL_MOUNTMGR_QUERY_POINTS, &input_buf, &output_buf) catch |err| switch (err) {
|
||||
error.AccessDenied => unreachable,
|
||||
error.AccessDenied => return error.Unexpected,
|
||||
else => |e| return e,
|
||||
};
|
||||
const mount_points_struct = @as(*const MOUNTMGR_MOUNT_POINTS, @ptrCast(&output_buf[0]));
|
||||
const mount_points_struct: *const MOUNTMGR_MOUNT_POINTS = @ptrCast(&output_buf[0]);
|
||||
|
||||
const mount_points = @as(
|
||||
[*]const MOUNTMGR_MOUNT_POINT,
|
||||
@ -2203,7 +2217,7 @@ pub fn wToPrefixedFileW(dir: ?HANDLE, path: [:0]const u16) !PathSpace {
|
||||
.unc_absolute => nt_prefix.len + 2,
|
||||
else => nt_prefix.len,
|
||||
};
|
||||
const buf_len = @as(u32, @intCast(path_space.data.len - path_buf_offset));
|
||||
const buf_len: u32 = @intCast(path_space.data.len - path_buf_offset);
|
||||
const path_to_get: [:0]const u16 = path_to_get: {
|
||||
// If dir is null, then we don't need to bother with GetFinalPathNameByHandle because
|
||||
// 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 {
|
||||
// canonicalize it. We do this by getting the path of the `dir`
|
||||
// and appending the relative path to it.
|
||||
var dir_path_buf: [PATH_MAX_WIDE:0]u16 = undefined;
|
||||
const dir_path = try GetFinalPathNameByHandle(dir.?, .{}, &dir_path_buf);
|
||||
const dir_path = GetFinalPathNameByHandle(dir.?, .{}, &dir_path_buf) catch |err| switch (err) {
|
||||
// This mapping is not correct; it is actually expected
|
||||
// that calling GetFinalPathNameByHandle might return
|
||||
// error.UnrecognizedVolume, and in fact has been observed
|
||||
// in the wild. The problem is that wToPrefixedFileW was
|
||||
// never intended to make *any* OS syscall APIs. It's only
|
||||
// supposed to convert a string to one that is eligible to
|
||||
// be used in the ntdll syscalls.
|
||||
//
|
||||
// To solve this, this function needs to no longer call
|
||||
// GetFinalPathNameByHandle under any conditions, or the
|
||||
// calling function needs to get reworked to not need to
|
||||
// call this function.
|
||||
//
|
||||
// This may involve making breaking API changes.
|
||||
error.UnrecognizedVolume => return error.Unexpected,
|
||||
else => |e| return e,
|
||||
};
|
||||
if (dir_path.len + 1 + path.len > PATH_MAX_WIDE) {
|
||||
return error.NameTooLong;
|
||||
}
|
||||
|
@ -543,6 +543,7 @@ pub const File = struct {
|
||||
UnexpectedTable,
|
||||
UnexpectedValue,
|
||||
UnknownFeature,
|
||||
UnrecognizedVolume,
|
||||
Unseekable,
|
||||
UnsupportedCpuArchitecture,
|
||||
UnsupportedVersion,
|
||||
|
Loading…
Reference in New Issue
Block a user