authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-07-21 08:44:26+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-07-22 08:51:23+02:00
log99f0e64fa0037ae0b8894ec326f854531ef3bfe6
tree2209acf9675ef12d1f22056c0ac63586a7e82a8d
parentc53bcd027f4522753d2f27c80e69c36980f3f754

Draft out dir symlinks branch


1 files changed, 62 insertions(+), 10 deletions(-)

lib/std/os/windows.zig+62-10
......@@ -604,7 +604,7 @@ pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {
604604
605605pub const CreateSymbolicLinkError = error{ AccessDenied, PathAlreadyExists, FileNotFound, NameTooLong, InvalidUtf8, BadPathName, Unexpected };
606606
607pub fn NtCreateSymbolicLinkW(dir: ?HANDLE, sym_link_path: []const u16, target_path: []const u16) CreateSymbolicLinkError!void {
607pub fn NtCreateSymbolicLinkW(dir: ?HANDLE, sym_link_path: [:0]const u16, target_path: [:0]const u16, is_directory: bool) CreateSymbolicLinkError!void {
608608 const SYMLINK_DATA = extern struct {
609609 ReparseTag: ULONG,
610610 ReparseDataLength: USHORT,
......@@ -616,15 +616,67 @@ pub fn NtCreateSymbolicLinkW(dir: ?HANDLE, sym_link_path: []const u16, target_pa
616616 Flags: ULONG,
617617 };
618618
619 const symlink_handle = OpenFile(sym_link_path, .{
620 .access_mask = SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
621 .dir = dir,
622 .creation = FILE_CREATE,
623 .io_mode = .blocking,
624 }) catch |err| switch (err) {
625 error.IsDir => unreachable, // TODO
626 else => |e| unreachable,
627 };
619 var symlink_handle: HANDLE = undefined;
620 if (is_directory) {
621 const sym_link_len_bytes = math.cast(u16, sym_link_path.len * 2) catch |err| switch (err) {
622 error.Overflow => return error.NameTooLong,
623 };
624 var nt_name = UNICODE_STRING{
625 .Length = sym_link_len_bytes,
626 .MaximumLength = sym_link_len_bytes,
627 .Buffer = @intToPtr([*]u16, @ptrToInt(sym_link_path.ptr)),
628 };
629
630 if (sym_link_path[0] == '.' and sym_link_path[1] == 0) {
631 // Windows does not recognize this, but it does work with empty string.
632 nt_name.Length = 0;
633 }
634
635 var attr = OBJECT_ATTRIBUTES{
636 .Length = @sizeOf(OBJECT_ATTRIBUTES),
637 .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sym_link_path)) null else dir,
638 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
639 .ObjectName = &nt_name,
640 .SecurityDescriptor = null,
641 .SecurityQualityOfService = null,
642 };
643
644 var io: IO_STATUS_BLOCK = undefined;
645 const rc = ntdll.NtCreateFile(
646 &symlink_handle,
647 GENERIC_READ | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
648 &attr,
649 &io,
650 null,
651 FILE_ATTRIBUTE_NORMAL,
652 FILE_SHARE_READ,
653 FILE_CREATE,
654 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
655 null,
656 0,
657 );
658 switch (rc) {
659 .SUCCESS => {},
660 .OBJECT_NAME_INVALID => unreachable,
661 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
662 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
663 // .NO_MEDIA_IN_DEVICE => return error.NoDevice,
664 .INVALID_PARAMETER => unreachable,
665 .ACCESS_DENIED => return error.AccessDenied,
666 .OBJECT_PATH_SYNTAX_BAD => unreachable,
667 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
668 else => return unexpectedStatus(rc),
669 }
670 } else {
671 symlink_handle = OpenFile(sym_link_path, .{
672 .access_mask = SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
673 .dir = dir,
674 .creation = FILE_CREATE,
675 .io_mode = .blocking,
676 }) catch |err| switch (err) {
677 else => |e| unreachable,
678 };
679 }
628680 defer CloseHandle(symlink_handle);
629681
630682 // prepare reparse data buffer