authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-07-13 08:29:11+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-07-22 08:51:22+02:00
log791795a63a34bc69af59717d5eff5d4c76349756
tree27f9c879e10d04b7f0f444975358bc2f6812de9b
parent515c663cd6e31d5f8ae07e804f2b32b99d025895

Finish symlink implementation on Windows


3 files changed, 49 insertions(+), 5 deletions(-)

lib/std/os.zig+14-1
...@@ -1541,6 +1541,10 @@ pub const SymLinkError = error{...@@ -1541,6 +1541,10 @@ pub const SymLinkError = error{
1541/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.1541/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
1542/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent1542/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
1543/// one; the latter case is known as a dangling link.1543/// one; the latter case is known as a dangling link.
1544/// On Windows, it is only legal to create a symbolic link to an existing resource. Furthermore,
1545/// this function will by default try creating a symbolic link to a file. If you would like to
1546/// create a symbolic link to a directory instead, see `symlinkW` for more information how to
1547/// do that.
1544/// If `sym_link_path` exists, it will not be overwritten.1548/// If `sym_link_path` exists, it will not be overwritten.
1545/// See also `symlinkC` and `symlinkW`.1549/// See also `symlinkC` and `symlinkW`.
1546pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {1550pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {
...@@ -1550,7 +1554,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!...@@ -1550,7 +1554,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!
1550 if (builtin.os.tag == .windows) {1554 if (builtin.os.tag == .windows) {
1551 const target_path_w = try windows.sliceToPrefixedFileW(target_path);1555 const target_path_w = try windows.sliceToPrefixedFileW(target_path);
1552 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);1556 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
1553 return windows.CreateSymbolicLinkW(sym_link_path_w.span().ptr, target_path_w.span().ptr, 0);1557 return symlinkW(sym_link_path_w.span().ptr, target_path_w.span().ptr);
1554 }1558 }
1555 const target_path_c = try toPosixPath(target_path);1559 const target_path_c = try toPosixPath(target_path);
1556 const sym_link_path_c = try toPosixPath(sym_link_path);1560 const sym_link_path_c = try toPosixPath(sym_link_path);
...@@ -1559,6 +1563,15 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!...@@ -1559,6 +1563,15 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!
15591563
1560pub const symlinkC = @compileError("deprecated: renamed to symlinkZ");1564pub const symlinkC = @compileError("deprecated: renamed to symlinkZ");
15611565
1566/// Windows-only. Same as `symlink` except the parameters are null-terminated, WTF16 encoded.
1567/// Note that this function will by default try creating a symbolic link to a file. If you would
1568/// like to create a symbolic link to a directory, use `std.os.windows.CreateSymbolicLinkW` directly
1569/// specifying as flags `std.os.windows.CreateSymbolicLinkFlags.Directory`.
1570pub fn symlinkW(target_path: [*:0]const u16, sym_link_path: [*:0]const u16) SymLinkError!void {
1571 const flags = windows.CreateSymbolicLinkFlags.File;
1572 return windows.CreateSymbolicLinkW(sym_link_path, target_path, flags);
1573}
1574
1562/// This is the same as `symlink` except the parameters are null-terminated pointers.1575/// This is the same as `symlink` except the parameters are null-terminated pointers.
1563/// See also `symlink`.1576/// See also `symlink`.
1564pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void {1577pub fn symlinkZ(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void {
lib/std/os/windows.zig+31-4
...@@ -601,12 +601,17 @@ pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {...@@ -601,12 +601,17 @@ pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {
601 return buffer[0..end_index];601 return buffer[0..end_index];
602}602}
603603
604pub const CreateSymbolicLinkError = error{Unexpected};604pub const CreateSymbolicLinkError = error{AccessDenied, FileNotFound, Unexpected};
605
606pub const CreateSymbolicLinkFlags = enum(DWORD) {
607 File = SYMBOLIC_LINK_FLAG_FILE,
608 Directory = SYMBOLIC_LINK_FLAG_DIRECTORY,
609};
605610
606pub fn CreateSymbolicLink(611pub fn CreateSymbolicLink(
607 sym_link_path: []const u8,612 sym_link_path: []const u8,
608 target_path: []const u8,613 target_path: []const u8,
609 flags: DWORD,614 flags: CreateSymbolicLinkFlags,
610) CreateSymbolicLinkError!void {615) CreateSymbolicLinkError!void {
611 const sym_link_path_w = try sliceToPrefixedFileW(sym_link_path);616 const sym_link_path_w = try sliceToPrefixedFileW(sym_link_path);
612 const target_path_w = try sliceToPrefixedFileW(target_path);617 const target_path_w = try sliceToPrefixedFileW(target_path);
...@@ -616,10 +621,32 @@ pub fn CreateSymbolicLink(...@@ -616,10 +621,32 @@ pub fn CreateSymbolicLink(
616pub fn CreateSymbolicLinkW(621pub fn CreateSymbolicLinkW(
617 sym_link_path: [*:0]const u16,622 sym_link_path: [*:0]const u16,
618 target_path: [*:0]const u16,623 target_path: [*:0]const u16,
619 flags: DWORD,624 flags: CreateSymbolicLinkFlags,
620) CreateSymbolicLinkError!void {625) CreateSymbolicLinkError!void {
621 if (kernel32.CreateSymbolicLinkW(sym_link_path, target_path, flags) == 0) {626 // Previously, until Win 10 Creators Update, creating symbolic links required
627 // SeCreateSymbolicLink privilege. Currently, this is no longer required if the
628 // OS is in Developer Mode; however, SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
629 // must be added to the input flags.
630 if (kernel32.CreateSymbolicLinkW(sym_link_path, target_path, @enumToInt(flags) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) == 0) {
622 switch (kernel32.GetLastError()) {631 switch (kernel32.GetLastError()) {
632 .INVALID_PARAMETER => {
633 // If we're on Windows pre Creators Update, SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
634 // flag is an invalid parameter, in which case repeat without the flag.
635 if (kernel32.CreateSymbolicLinkW(sym_link_path, target_path, @enumToInt(flags)) == 0) {
636 switch (kernel32.GetLastError()) {
637 .PRIVILEGE_NOT_HELD => return error.AccessDenied,
638 .FILE_NOT_FOUND => return error.FileNotFound,
639 .PATH_NOT_FOUND => return error.FileNotFound,
640 .ACCESS_DENIED => return error.AccessDenied,
641 else => |err| return unexpectedError(err),
642 }
643 }
644 return;
645 },
646 .PRIVILEGE_NOT_HELD => return error.AccessDenied,
647 .FILE_NOT_FOUND => return error.FileNotFound,
648 .PATH_NOT_FOUND => return error.FileNotFound,
649 .ACCESS_DENIED => return error.AccessDenied,
623 else => |err| return unexpectedError(err),650 else => |err| return unexpectedError(err),
624 }651 }
625 }652 }
lib/std/os/windows/bits.zig+4
...@@ -1569,3 +1569,7 @@ pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;...@@ -1569,3 +1569,7 @@ pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024;
1569pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8;1569pub const FSCTL_GET_REPARSE_POINT: DWORD = 0x900a8;
1570pub const IO_REPARSE_TAG_SYMLINK: ULONG = 0xa000000c;1570pub const IO_REPARSE_TAG_SYMLINK: ULONG = 0xa000000c;
1571pub const IO_REPARSE_TAG_MOUNT_POINT: ULONG = 0xa0000003;1571pub const IO_REPARSE_TAG_MOUNT_POINT: ULONG = 0xa0000003;
1572
1573pub const SYMBOLIC_LINK_FLAG_FILE: DWORD = 0x0;
1574pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1;
1575pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2;
\ No newline at end of file