Use windows.CreateFileW to open the reparse point

This commit is contained in:
Jakub Konka 2020-07-14 08:01:04 +02:00
parent 49b5815364
commit 9b00dc941b
3 changed files with 17 additions and 65 deletions

View File

@ -2381,7 +2381,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
@compileError("readlink is not supported in WASI; use readlinkat instead");
} else if (builtin.os.tag == .windows) {
const file_path_w = try windows.sliceToPrefixedFileW(file_path);
return readlinkW(file_path_w.span(), out_buffer);
return readlinkW(file_path_w.span().ptr, out_buffer);
} else {
const file_path_c = try toPosixPath(file_path);
return readlinkZ(&file_path_c, out_buffer);
@ -2392,26 +2392,28 @@ pub const readlinkC = @compileError("deprecated: renamed to readlinkZ");
/// Windows-only. Same as `readlink` except `file_path` is null-terminated, WTF16 encoded.
/// See also `readlinkZ`.
pub fn readlinkW(file_path: []const u16, out_buffer: []u8) ReadLinkError![]u8 {
const handle = windows.ReadLink(file_path) catch |err| {
pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 {
const w = windows;
const access_mode: w.DWORD = 0;
const sharing = w.FILE_SHARE_DELETE | w.FILE_SHARE_READ | w.FILE_SHARE_WRITE;
const disposition = w.OPEN_EXISTING;
const flags = w.FILE_FLAG_BACKUP_SEMANTICS | w.FILE_FLAG_OPEN_REPARSE_POINT;
const handle = w.CreateFileW(file_path, access_mode, sharing, null, disposition, flags, null) catch |err| {
switch (err) {
error.IsDir => unreachable,
error.NoDevice => return error.FileNotFound,
error.SharingViolation => return error.AccessDenied,
error.PipeBusy => unreachable,
error.PathAlreadyExists => unreachable,
error.WouldBlock => unreachable,
error.PipeBusy => unreachable,
else => |e| return e,
}
};
var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;
_ = try windows.DeviceIoControl(handle, windows.FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..], null);
const reparse_struct = mem.bytesAsValue(windows._REPARSE_DATA_BUFFER, reparse_buf[0..@sizeOf(windows._REPARSE_DATA_BUFFER)]);
var reparse_buf: [w.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;
_ = try w.DeviceIoControl(handle, w.FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..], null);
const reparse_struct = mem.bytesAsValue(w.REPARSE_DATA_BUFFER, reparse_buf[0..@sizeOf(w.REPARSE_DATA_BUFFER)]);
switch (reparse_struct.ReparseTag) {
windows.IO_REPARSE_TAG_SYMLINK => {
w.IO_REPARSE_TAG_SYMLINK => {
std.debug.warn("got symlink!", .{});
},
windows.IO_REPARSE_TAG_MOUNT_POINT => {
w.IO_REPARSE_TAG_MOUNT_POINT => {
std.debug.warn("got mount point!", .{});
},
else => |value| {
@ -2426,7 +2428,7 @@ pub fn readlinkW(file_path: []const u16, out_buffer: []u8) ReadLinkError![]u8 {
pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
if (builtin.os.tag == .windows) {
const file_path_w = try windows.cStrToPrefixedFileW(file_path);
return readlinkW(file_path_w.span(), out_buffer);
return readlinkW(file_path_w.span().ptr, out_buffer);
}
const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);
switch (errno(rc)) {

View File

@ -1370,54 +1370,4 @@ pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
std.debug.dumpCurrentStackTrace(null);
}
return error.Unexpected;
}
pub fn ReadLink(path_w: []const u16) OpenError!HANDLE {
var result: HANDLE = undefined;
const path_len_bytes = math.cast(u16, path_w.len * 2) catch |err| switch (err) {
error.Overflow => return error.NameTooLong,
};
var nt_name = UNICODE_STRING{
.Length = path_len_bytes,
.MaximumLength = path_len_bytes,
.Buffer = @intToPtr([*]u16, @ptrToInt(path_w.ptr)),
};
var attr = OBJECT_ATTRIBUTES{
.Length = @sizeOf(OBJECT_ATTRIBUTES),
.RootDirectory = null,
.Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
.ObjectName = &nt_name,
.SecurityDescriptor = null,
.SecurityQualityOfService = null,
};
var io: IO_STATUS_BLOCK = undefined;
const rc = ntdll.NtCreateFile(
&result,
FILE_LIST_DIRECTORY,
&attr,
&io,
null,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_OPEN_REPARSE_POINT,
null,
0,
);
switch (rc) {
.SUCCESS => return result,
.OBJECT_NAME_INVALID => unreachable,
.OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
.OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
.NO_MEDIA_IN_DEVICE => return error.NoDevice,
.INVALID_PARAMETER => unreachable,
.SHARING_VIOLATION => return error.WouldBlock,
.ACCESS_DENIED => return error.AccessDenied,
.PIPE_BUSY => return error.PipeBusy,
.OBJECT_PATH_SYNTAX_BAD => unreachable,
.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
.FILE_IS_A_DIRECTORY => return error.IsDir,
else => return unexpectedStatus(rc),
}
}

View File

@ -1543,7 +1543,7 @@ pub const LPOSVERSIONINFOW = *OSVERSIONINFOW;
pub const RTL_OSVERSIONINFOW = OSVERSIONINFOW;
pub const PRTL_OSVERSIONINFOW = *RTL_OSVERSIONINFOW;
pub const _REPARSE_DATA_BUFFER = extern struct {
pub const REPARSE_DATA_BUFFER = extern struct {
ReparseTag: ULONG, ReparseDataLength: USHORT, Reserved: USHORT, u: extern union {
SymbolicLinkReparseBuffer: extern struct {
SubstituteNameOffset: USHORT,
@ -1572,4 +1572,4 @@ pub const IO_REPARSE_TAG_MOUNT_POINT: ULONG = 0xa0000003;
pub const SYMBOLIC_LINK_FLAG_FILE: DWORD = 0x0;
pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1;
pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2;
pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2;