Commit 9b00dc941b

Jakub Konka <kubkon@jakubkonka.com>
2020-07-14 08:01:04
Use windows.CreateFileW to open the reparse point
1 parent 49b5815
Changed files (3)
lib
lib/std/os/windows/bits.zig
@@ -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;
\ No newline at end of file
+pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2;
lib/std/os/windows.zig
@@ -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),
-    }
 }
\ No newline at end of file
lib/std/os.zig
@@ -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)) {