authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-07-13 08:01:01+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-07-22 08:51:22+02:00
log515c663cd6e31d5f8ae07e804f2b32b99d025895
tree5950337a1fe1a4362594b73e9879369480e0fc42
parentcc83d92b0b12f5b3fa6462ed878cd7bec7412940

Add readlink smoke test


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

lib/std/os.zig+17-11
...@@ -2355,6 +2355,8 @@ pub const ReadLinkError = error{...@@ -2355,6 +2355,8 @@ pub const ReadLinkError = error{
2355 FileNotFound,2355 FileNotFound,
2356 SystemResources,2356 SystemResources,
2357 NotDir,2357 NotDir,
2358 InvalidUtf8,
2359 BadPathName,
2358 /// Windows-only.2360 /// Windows-only.
2359 UnsupportedSymlinkType,2361 UnsupportedSymlinkType,
2360} || UnexpectedError;2362} || UnexpectedError;
...@@ -2366,7 +2368,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {...@@ -2366,7 +2368,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
2366 @compileError("readlink is not supported in WASI; use readlinkat instead");2368 @compileError("readlink is not supported in WASI; use readlinkat instead");
2367 } else if (builtin.os.tag == .windows) {2369 } else if (builtin.os.tag == .windows) {
2368 const file_path_w = try windows.sliceToPrefixedFileW(file_path);2370 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
2369 return readlinkW(file_path_w.span().ptr, out_buffer);2371 return readlinkW(file_path_w.span(), out_buffer);
2370 } else {2372 } else {
2371 const file_path_c = try toPosixPath(file_path);2373 const file_path_c = try toPosixPath(file_path);
2372 return readlinkZ(&file_path_c, out_buffer);2374 return readlinkZ(&file_path_c, out_buffer);
...@@ -2377,11 +2379,11 @@ pub const readlinkC = @compileError("deprecated: renamed to readlinkZ");...@@ -2377,11 +2379,11 @@ pub const readlinkC = @compileError("deprecated: renamed to readlinkZ");
23772379
2378/// Windows-only. Same as `readlink` except `file_path` is null-terminated, WTF16 encoded.2380/// Windows-only. Same as `readlink` except `file_path` is null-terminated, WTF16 encoded.
2379/// See also `readlinkZ`.2381/// See also `readlinkZ`.
2380pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8 {2382pub fn readlinkW(file_path: []const u16, out_buffer: []u8) ReadLinkError![]u8 {
2381 const handle = windows.OpenFile(file_path, .{2383 const handle = windows.OpenFile(file_path, .{
2382 .access_mask = 0,2384 .access_mask = 0,
2383 .creation = c.FILE_OPEN_REPARSE_POINT | c.FILE_LIST_DIRECTORY,2385 .creation = windows.FILE_OPEN_REPARSE_POINT | windows.FILE_LIST_DIRECTORY,
2384 .io_mode = 0,2386 .io_mode = std.io.default_mode,
2385 }) catch |err| {2387 }) catch |err| {
2386 switch (err) {2388 switch (err) {
2387 error.IsDir => unreachable,2389 error.IsDir => unreachable,
...@@ -2390,28 +2392,32 @@ pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8...@@ -2390,28 +2392,32 @@ pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8
2390 error.PipeBusy => unreachable,2392 error.PipeBusy => unreachable,
2391 error.PathAlreadyExists => unreachable,2393 error.PathAlreadyExists => unreachable,
2392 error.WouldBlock => unreachable,2394 error.WouldBlock => unreachable,
2393 else => return err,2395 else => |e| return e,
2394 }2396 }
2395 };2397 };
2396 var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;2398 var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;
2397 _ = try windows.DeviceIoControl(handle, windows.FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..], null);2399 _ = try windows.DeviceIoControl(handle, windows.FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..], null);
2398 const reparse_struct = @bitCast(windows._REPARSE_DATA_BUFFER, reparse_buf[0..@sizeOf(windows._REPARSE_DATA_BUFFER)]);2400 const reparse_struct = mem.bytesAsValue(windows._REPARSE_DATA_BUFFER, reparse_buf[0..@sizeOf(windows._REPARSE_DATA_BUFFER)]);
2399 switch (reparse_struct.ReparseTag) {2401 switch (reparse_struct.ReparseTag) {
2400 windows.IO_REPARSE_TAG_SYMLINK => {},2402 windows.IO_REPARSE_TAG_SYMLINK => {
2401 windows.IO_REPARSE_TAG_MOUNT_POINT => {},2403 std.debug.warn("got symlink!", .{});
2404 },
2405 windows.IO_REPARSE_TAG_MOUNT_POINT => {
2406 std.debug.warn("got mount point!", .{});
2407 },
2402 else => |value| {2408 else => |value| {
2403 std.debug.print("unsupported symlink type: {}", value);2409 std.debug.warn("unsupported symlink type: {}", .{value});
2404 return error.UnsupportedSymlinkType;2410 return error.UnsupportedSymlinkType;
2405 },2411 },
2406 }2412 }
2407 @compileError("TODO implement readlink for Windows");2413 @panic("Oh no!");
2408}2414}
24092415
2410/// Same as `readlink` except `file_path` is null-terminated.2416/// Same as `readlink` except `file_path` is null-terminated.
2411pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {2417pub fn readlinkZ(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 {
2412 if (builtin.os.tag == .windows) {2418 if (builtin.os.tag == .windows) {
2413 const file_path_w = try windows.cStrToPrefixedFileW(file_path);2419 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
2414 return readlinkW(file_path_w.span().ptr, out_buffer);2420 return readlinkW(file_path_w.span(), out_buffer);
2415 }2421 }
2416 const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);2422 const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);
2417 switch (errno(rc)) {2423 switch (errno(rc)) {
lib/std/os/test.zig+31
...@@ -17,6 +17,7 @@ const AtomicRmwOp = builtin.AtomicRmwOp;...@@ -17,6 +17,7 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
17const AtomicOrder = builtin.AtomicOrder;17const AtomicOrder = builtin.AtomicOrder;
18const tmpDir = std.testing.tmpDir;18const tmpDir = std.testing.tmpDir;
19const Dir = std.fs.Dir;19const Dir = std.fs.Dir;
20const ArenaAllocator = std.heap.ArenaAllocator;
2021
21test "fstatat" {22test "fstatat" {
22 // enable when `fstat` and `fstatat` are implemented on Windows23 // enable when `fstat` and `fstatat` are implemented on Windows
...@@ -40,6 +41,36 @@ test "fstatat" {...@@ -40,6 +41,36 @@ test "fstatat" {
40 expectEqual(stat, statat);41 expectEqual(stat, statat);
41}42}
4243
44test "readlink" {
45 if (builtin.os.tag == .wasi) return error.SkipZigTest;
46
47 var tmp = tmpDir(.{});
48 defer tmp.cleanup();
49
50 // create file
51 try tmp.dir.writeFile("file.txt", "nonsense");
52
53 // get paths
54 // TODO: use Dir's realpath function once that exists
55 var arena = ArenaAllocator.init(testing.allocator);
56 defer arena.deinit();
57
58 const base_path = blk: {
59 const relative_path = try fs.path.join(&arena.allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..]});
60 break :blk try fs.realpathAlloc(&arena.allocator, relative_path);
61 };
62 const target_path = try fs.path.join(&arena.allocator, &[_][]const u8{"file.txt"});
63 const symlink_path = try fs.path.join(&arena.allocator, &[_][]const u8{"symlinked"});
64
65 // create symbolic link by path
66 try os.symlink(target_path, symlink_path);
67
68 // now, read the link and verify
69 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
70 const given = try os.readlink(symlink_path, buffer[0..]);
71 expect(mem.eql(u8, symlink_path, given));
72}
73
43test "readlinkat" {74test "readlinkat" {
44 // enable when `readlinkat` and `symlinkat` are implemented on Windows75 // enable when `readlinkat` and `symlinkat` are implemented on Windows
45 if (builtin.os.tag == .windows) return error.SkipZigTest;76 if (builtin.os.tag == .windows) return error.SkipZigTest;
lib/std/os/windows/bits.zig+1-1
...@@ -488,7 +488,7 @@ pub const FILE_OPEN_BY_FILE_ID = 0x00002000;...@@ -488,7 +488,7 @@ pub const FILE_OPEN_BY_FILE_ID = 0x00002000;
488pub const FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000;488pub const FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000;
489pub const FILE_NO_COMPRESSION = 0x00008000;489pub const FILE_NO_COMPRESSION = 0x00008000;
490pub const FILE_RESERVE_OPFILTER = 0x00100000;490pub const FILE_RESERVE_OPFILTER = 0x00100000;
491pub const FILE_TRANSACTED_MODE = 0x00200000;491pub const FILE_OPEN_REPARSE_POINT = 0x00200000;
492pub const FILE_OPEN_OFFLINE_FILE = 0x00400000;492pub const FILE_OPEN_OFFLINE_FILE = 0x00400000;
493pub const FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000;493pub const FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000;
494494