Add readlink smoke test
parent
cc83d92b0b
commit
515c663cd6
|
@ -2355,6 +2355,8 @@ pub const ReadLinkError = error{
|
|||
FileNotFound,
|
||||
SystemResources,
|
||||
NotDir,
|
||||
InvalidUtf8,
|
||||
BadPathName,
|
||||
/// Windows-only.
|
||||
UnsupportedSymlinkType,
|
||||
} || UnexpectedError;
|
||||
|
@ -2366,7 +2368,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().ptr, out_buffer);
|
||||
return readlinkW(file_path_w.span(), out_buffer);
|
||||
} else {
|
||||
const file_path_c = try toPosixPath(file_path);
|
||||
return readlinkZ(&file_path_c, out_buffer);
|
||||
|
@ -2377,11 +2379,11 @@ 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: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 {
|
||||
pub fn readlinkW(file_path: []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,
|
||||
.creation = windows.FILE_OPEN_REPARSE_POINT | windows.FILE_LIST_DIRECTORY,
|
||||
.io_mode = std.io.default_mode,
|
||||
}) catch |err| {
|
||||
switch (err) {
|
||||
error.IsDir => unreachable,
|
||||
|
@ -2390,28 +2392,32 @@ pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8
|
|||
error.PipeBusy => unreachable,
|
||||
error.PathAlreadyExists => unreachable,
|
||||
error.WouldBlock => unreachable,
|
||||
else => return err,
|
||||
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 = @bitCast(windows._REPARSE_DATA_BUFFER, reparse_buf[0..@sizeOf(windows._REPARSE_DATA_BUFFER)]);
|
||||
const reparse_struct = mem.bytesAsValue(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 => {},
|
||||
windows.IO_REPARSE_TAG_SYMLINK => {
|
||||
std.debug.warn("got symlink!", .{});
|
||||
},
|
||||
windows.IO_REPARSE_TAG_MOUNT_POINT => {
|
||||
std.debug.warn("got mount point!", .{});
|
||||
},
|
||||
else => |value| {
|
||||
std.debug.print("unsupported symlink type: {}", value);
|
||||
std.debug.warn("unsupported symlink type: {}", .{value});
|
||||
return error.UnsupportedSymlinkType;
|
||||
},
|
||||
}
|
||||
@compileError("TODO implement readlink for Windows");
|
||||
@panic("Oh no!");
|
||||
}
|
||||
|
||||
/// Same as `readlink` except `file_path` is null-terminated.
|
||||
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().ptr, out_buffer);
|
||||
return readlinkW(file_path_w.span(), out_buffer);
|
||||
}
|
||||
const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);
|
||||
switch (errno(rc)) {
|
||||
|
|
|
@ -17,6 +17,7 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
|
|||
const AtomicOrder = builtin.AtomicOrder;
|
||||
const tmpDir = std.testing.tmpDir;
|
||||
const Dir = std.fs.Dir;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
|
||||
test "fstatat" {
|
||||
// enable when `fstat` and `fstatat` are implemented on Windows
|
||||
|
@ -40,6 +41,36 @@ test "fstatat" {
|
|||
expectEqual(stat, statat);
|
||||
}
|
||||
|
||||
test "readlink" {
|
||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
// create file
|
||||
try tmp.dir.writeFile("file.txt", "nonsense");
|
||||
|
||||
// get paths
|
||||
// TODO: use Dir's realpath function once that exists
|
||||
var arena = ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const base_path = blk: {
|
||||
const relative_path = try fs.path.join(&arena.allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..]});
|
||||
break :blk try fs.realpathAlloc(&arena.allocator, relative_path);
|
||||
};
|
||||
const target_path = try fs.path.join(&arena.allocator, &[_][]const u8{"file.txt"});
|
||||
const symlink_path = try fs.path.join(&arena.allocator, &[_][]const u8{"symlinked"});
|
||||
|
||||
// create symbolic link by path
|
||||
try os.symlink(target_path, symlink_path);
|
||||
|
||||
// now, read the link and verify
|
||||
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||
const given = try os.readlink(symlink_path, buffer[0..]);
|
||||
expect(mem.eql(u8, symlink_path, given));
|
||||
}
|
||||
|
||||
test "readlinkat" {
|
||||
// enable when `readlinkat` and `symlinkat` are implemented on Windows
|
||||
if (builtin.os.tag == .windows) return error.SkipZigTest;
|
||||
|
|
|
@ -488,7 +488,7 @@ pub const FILE_OPEN_BY_FILE_ID = 0x00002000;
|
|||
pub const FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000;
|
||||
pub const FILE_NO_COMPRESSION = 0x00008000;
|
||||
pub const FILE_RESERVE_OPFILTER = 0x00100000;
|
||||
pub const FILE_TRANSACTED_MODE = 0x00200000;
|
||||
pub const FILE_OPEN_REPARSE_POINT = 0x00200000;
|
||||
pub const FILE_OPEN_OFFLINE_FILE = 0x00400000;
|
||||
pub const FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000;
|
||||
|
||||
|
|
Loading…
Reference in New Issue