mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
handle lack of privilege to create symbolic links on windows
This commit is contained in:
parent
e355bcce36
commit
ac85befbb4
@ -25,12 +25,20 @@ test "Dir.readLink" {
|
||||
|
||||
{
|
||||
// Create symbolic link by path
|
||||
try tmp.dir.symLink("file.txt", "symlink1", .{});
|
||||
tmp.dir.symLink("file.txt", "symlink1", .{}) catch |err| switch (err) {
|
||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
||||
error.AccessDenied => return error.SkipZigTest,
|
||||
else => return err,
|
||||
};
|
||||
try testReadLink(tmp.dir, "file.txt", "symlink1");
|
||||
}
|
||||
{
|
||||
// Create symbolic link by path
|
||||
try tmp.dir.symLink("subdir", "symlink2", .{ .is_directory = true });
|
||||
tmp.dir.symLink("subdir", "symlink2", .{ .is_directory = true }) catch |err| switch (err) {
|
||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
||||
error.AccessDenied => return error.SkipZigTest,
|
||||
else => return err,
|
||||
};
|
||||
try testReadLink(tmp.dir, "subdir", "symlink2");
|
||||
}
|
||||
}
|
||||
@ -66,7 +74,11 @@ test "readLinkAbsolute" {
|
||||
const symlink_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "symlink1" });
|
||||
|
||||
// Create symbolic link by path
|
||||
try fs.symLinkAbsolute(target_path, symlink_path, .{});
|
||||
fs.symLinkAbsolute(target_path, symlink_path, .{}) catch |err| switch (err) {
|
||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
||||
error.AccessDenied => return error.SkipZigTest,
|
||||
else => return err,
|
||||
};
|
||||
try testReadLinkAbsolute(target_path, symlink_path);
|
||||
}
|
||||
{
|
||||
@ -74,7 +86,11 @@ test "readLinkAbsolute" {
|
||||
const symlink_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "symlink2" });
|
||||
|
||||
// Create symbolic link by path
|
||||
try fs.symLinkAbsolute(target_path, symlink_path, .{ .is_directory = true });
|
||||
fs.symLinkAbsolute(target_path, symlink_path, .{ .is_directory = true }) catch |err| switch (err) {
|
||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
||||
error.AccessDenied => return error.SkipZigTest,
|
||||
else => return err,
|
||||
};
|
||||
try testReadLinkAbsolute(target_path, symlink_path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,20 @@ test "symlink with relative paths" {
|
||||
try cwd.writeFile("file.txt", "nonsense");
|
||||
|
||||
if (builtin.os.tag == .windows) {
|
||||
try os.windows.CreateSymbolicLink(cwd.fd, &[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' }, &[_]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' }, false);
|
||||
os.windows.CreateSymbolicLink(
|
||||
cwd.fd,
|
||||
&[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' },
|
||||
&[_]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
|
||||
false,
|
||||
) catch |err| switch (err) {
|
||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
||||
error.AccessDenied => {
|
||||
try cwd.deleteFile("file.txt");
|
||||
try cwd.deleteFile("symlinked");
|
||||
return error.SkipZigTest;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
} else {
|
||||
try os.symlink("file.txt", "symlinked");
|
||||
}
|
||||
@ -183,7 +196,16 @@ test "readlinkat" {
|
||||
|
||||
// create a symbolic link
|
||||
if (builtin.os.tag == .windows) {
|
||||
try os.windows.CreateSymbolicLink(tmp.dir.fd, &[_]u16{ 'l', 'i', 'n', 'k' }, &[_]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' }, false);
|
||||
os.windows.CreateSymbolicLink(
|
||||
tmp.dir.fd,
|
||||
&[_]u16{ 'l', 'i', 'n', 'k' },
|
||||
&[_]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
|
||||
false,
|
||||
) catch |err| switch (err) {
|
||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
||||
error.AccessDenied => return error.SkipZigTest,
|
||||
else => return err,
|
||||
};
|
||||
} else {
|
||||
try os.symlinkat("file.txt", tmp.dir.fd, "link");
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ pub fn CreateEventExW(attributes: ?*SECURITY_ATTRIBUTES, nameW: [*:0]const u16,
|
||||
}
|
||||
}
|
||||
|
||||
pub const DeviceIoControlError = error{Unexpected};
|
||||
pub const DeviceIoControlError = error{ AccessDenied, Unexpected };
|
||||
|
||||
/// A Zig wrapper around `NtDeviceIoControlFile` and `NtFsControlFile` syscalls.
|
||||
/// It implements similar behavior to `DeviceIoControl` and is meant to serve
|
||||
@ -216,6 +216,7 @@ pub fn DeviceIoControl(
|
||||
};
|
||||
switch (rc) {
|
||||
.SUCCESS => {},
|
||||
.PRIVILEGE_NOT_HELD => return error.AccessDenied,
|
||||
.INVALID_PARAMETER => unreachable,
|
||||
else => return unexpectedStatus(rc),
|
||||
}
|
||||
@ -593,6 +594,12 @@ pub const CreateSymbolicLinkError = error{
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
/// Needs either:
|
||||
/// - `SeCreateSymbolicLinkPrivilege` privilege
|
||||
/// or
|
||||
/// - Developper mode on Windows 10
|
||||
/// otherwise fails with `error.AccessDenied`. In which case `sym_link_path` may still
|
||||
/// be created on the file system but will lack reparse processing data applied to it.
|
||||
pub fn CreateSymbolicLink(
|
||||
dir: ?HANDLE,
|
||||
sym_link_path: []const u16,
|
||||
@ -710,7 +717,10 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin
|
||||
defer CloseHandle(result_handle);
|
||||
|
||||
var reparse_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;
|
||||
_ = try DeviceIoControl(result_handle, FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..]);
|
||||
_ = DeviceIoControl(result_handle, FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..]) catch |err| switch (err) {
|
||||
error.AccessDenied => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
const reparse_struct = @ptrCast(*const REPARSE_DATA_BUFFER, @alignCast(@alignOf(REPARSE_DATA_BUFFER), &reparse_buf[0]));
|
||||
switch (reparse_struct.ReparseTag) {
|
||||
@ -992,7 +1002,10 @@ pub fn GetFinalPathNameByHandle(
|
||||
input_struct.DeviceNameLength = @intCast(USHORT, volume_name.FileNameLength);
|
||||
@memcpy(input_buf[@sizeOf(MOUNTMGR_MOUNT_POINT)..], @ptrCast([*]const u8, &volume_name.FileName[0]), volume_name.FileNameLength);
|
||||
|
||||
try DeviceIoControl(mgmt_handle, IOCTL_MOUNTMGR_QUERY_POINTS, input_buf[0..], output_buf[0..]);
|
||||
DeviceIoControl(mgmt_handle, IOCTL_MOUNTMGR_QUERY_POINTS, input_buf[0..], output_buf[0..]) catch |err| switch (err) {
|
||||
error.AccessDenied => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
const mount_points_struct = @ptrCast(*const MOUNTMGR_MOUNT_POINTS, &output_buf[0]);
|
||||
|
||||
const mount_points = @ptrCast(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user