Commit cc83d92b0b

Jakub Konka <kubkon@jakubkonka.com>
2020-07-12 23:03:09
Start drafting out os.readlink on Windows
1 parent 9225763
Changed files (2)
lib
std
os
windows
lib/std/os/windows/bits.zig
@@ -1542,3 +1542,30 @@ pub const POSVERSIONINFOW = *OSVERSIONINFOW;
 pub const LPOSVERSIONINFOW = *OSVERSIONINFOW;
 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,
+        },
+    }
+};
+pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 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;
lib/std/os.zig
@@ -2355,6 +2355,8 @@ pub const ReadLinkError = error{
     FileNotFound,
     SystemResources,
     NotDir,
+    /// Windows-only.
+    UnsupportedSymlinkType,
 } || UnexpectedError;
 
 /// Read value of a symbolic link.
@@ -2373,9 +2375,35 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
 
 pub const readlinkC = @compileError("deprecated: renamed to readlinkZ");
 
-/// Windows-only. Same as `readlink` expecte `file_path` is null-terminated, WTF16 encoded.
-/// Seel also `readlinkZ`.
+/// Windows-only. Same as `readlink` except `file_path` is null-terminated, WTF16 encoded.
+/// See also `readlinkZ`.
 pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 {
+    const handle = windows.OpenFile(file_path, .{
+        .access_mask = 0,
+        .creation = c.FILE_OPEN_REPARSE_POINT | c.FILE_LIST_DIRECTORY,
+        .io_mode = 0,
+    }) 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,
+            else => return err,
+        }
+    };
+    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 = @bitCast(windows._REPARSE_DATA_BUFFER, reparse_buf[0..@sizeOf(windows._REPARSE_DATA_BUFFER)]);
+    switch (reparse_struct.ReparseTag) {
+        windows.IO_REPARSE_TAG_SYMLINK => {},
+        windows.IO_REPARSE_TAG_MOUNT_POINT => {},
+        else => |value| {
+            std.debug.print("unsupported symlink type: {}", value);
+            return error.UnsupportedSymlinkType;
+        },
+    }
     @compileError("TODO implement readlink for Windows");
 }