From d17c9b3591ba822df3af341a0d4cf5f004413f4a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 14 Jul 2020 08:45:04 +0200 Subject: [PATCH] Fix incorrect byte format of REPARSE_DATA_BUFFER struct --- lib/std/os.zig | 22 ++++++++++++------- lib/std/os/windows/bits.zig | 42 ++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 75254b52c8..24de1d83f2 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2394,11 +2394,10 @@ pub const readlinkC = @compileError("deprecated: renamed to readlinkZ"); /// See also `readlinkZ`. 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| { + const handle = w.CreateFileW(file_path, 0, sharing, null, disposition, flags, null) catch |err| { switch (err) { error.SharingViolation => return error.AccessDenied, error.PathAlreadyExists => unreachable, @@ -2406,22 +2405,31 @@ pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 else => |e| return e, } }; - var reparse_buf: [w.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined; + var reparse_buf align(@alignOf(w.REPARSE_DATA_BUFFER)) = [_]u8{0} ** (w.MAXIMUM_REPARSE_DATA_BUFFER_SIZE); _ = 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)]); + const reparse_struct = @ptrCast(*const w.REPARSE_DATA_BUFFER, &reparse_buf[0]); switch (reparse_struct.ReparseTag) { w.IO_REPARSE_TAG_SYMLINK => { - std.debug.warn("got symlink!", .{}); + const alignment = @alignOf(w.SymbolicLinkReparseBuffer); + const buf = @ptrCast(*const w.SymbolicLinkReparseBuffer, @alignCast(alignment, &reparse_struct.DataBuffer[0])); + const offset = buf.SubstituteNameOffset / 2; + const len = buf.SubstituteNameLength / 2; + const f = buf.Flags; + const path_buf = @as([*]const u16, &buf.PathBuffer); + std.debug.warn("got symlink => offset={}, len={}, flags = {}, {}\n", .{ offset, len, f, w.SYMLINK_FLAG_RELATIVE }); + // TODO handle absolute paths and namespace prefix + const out_len = std.unicode.utf16leToUtf8(out_buffer, path_buf[offset .. offset + len]) catch unreachable; + std.debug.warn("got symlink => utf8={}\n", .{out_buffer[0..out_len]}); + return out_buffer[0..out_len]; }, w.IO_REPARSE_TAG_MOUNT_POINT => { - std.debug.warn("got mount point!", .{}); + @panic("TODO parse mount point"); }, else => |value| { std.debug.warn("unsupported symlink type: {}", .{value}); return error.UnsupportedSymlinkType; }, } - @panic("Oh no!"); } /// Same as `readlink` except `file_path` is null-terminated. diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig index fef9af9bda..66ea5bb512 100644 --- a/lib/std/os/windows/bits.zig +++ b/lib/std/os/windows/bits.zig @@ -1544,31 +1544,31 @@ pub const RTL_OSVERSIONINFOW = OSVERSIONINFOW; pub const PRTL_OSVERSIONINFOW = *RTL_OSVERSIONINFOW; pub const REPARSE_DATA_BUFFER = extern struct { - ReparseTag: ULONG, ReparseDataLength: USHORT, Reserved: USHORT, u: extern union { - SymbolicLinkReparseBuffer: extern struct { - SubstituteNameOffset: USHORT, - SubstituteNameLength: USHORT, - PrintNameOffset: USHORT, - PrintNameLength: USHORT, - Flags: ULONG, - PathBuffer: [1]WCHAR, - }, - MountPointReparseBuffer: extern struct { - SubstituteNameOffset: USHORT, - SubstituteNameLength: USHORT, - PrintNameOffset: USHORT, - PrintNameLength: USHORT, - PathBuffer: [1]WCHAR, - }, - GenericReparseBuffer: extern struct { - DataBuffer: [1]UCHAR, - }, - } + ReparseTag: ULONG, + ReparseDataLength: USHORT, + Reserved: USHORT, + DataBuffer: [1]UCHAR, }; -pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; +pub const SymbolicLinkReparseBuffer = extern struct { + SubstituteNameOffset: USHORT, + SubstituteNameLength: USHORT, + PrintNameOffset: USHORT, + PrintNameLength: USHORT, + Flags: ULONG, + PathBuffer: [1]WCHAR, +}; +pub const MountPointReparseBuffer = extern struct { + SubstituteNameOffset: USHORT, + SubstituteNameLength: USHORT, + PrintNameOffset: USHORT, + PrintNameLength: USHORT, + PathBuffer: [1]WCHAR, +}; +pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: ULONG = 16 * 1024; pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8; pub const IO_REPARSE_TAG_SYMLINK: ULONG = 0xa000000c; pub const IO_REPARSE_TAG_MOUNT_POINT: ULONG = 0xa0000003; +pub const SYMLINK_FLAG_RELATIVE: ULONG = 0x1; pub const SYMBOLIC_LINK_FLAG_FILE: DWORD = 0x0; pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1;