aboutsummaryrefslogtreecommitdiff
path: root/lib/std/os.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2020-07-19 22:25:00 +0200
committerJakub Konka <kubkon@jakubkonka.com>2020-07-22 08:51:22 +0200
commite0b77a6b77614538d18b9f0b9e3e7e434ccee4ff (patch)
tree04b40728d9b672ef160431fe550e389863ce666d /lib/std/os.zig
parent3c8ceb674eb00ac0a70d6a0742234ce520eccf06 (diff)
downloadzig-e0b77a6b77614538d18b9f0b9e3e7e434ccee4ff.tar.gz
zig-e0b77a6b77614538d18b9f0b9e3e7e434ccee4ff.zip
Ensure Dir.deleteTree does not dereference symlinks
Otherwise, the behaviour can lead to unexpected results, resulting in removing an entire tree that's not necessarily under the root. Furthermore, this change is needed if are to properly handle dir symlinks on Windows. Without explicitly requiring that a directory or file is opened with `FILE_OPEN_REPARSE_POINT`, Windows automatically dereferences all symlinks along the way. This commit adds another option to `OpenDirOptions`, namely `.no_follow`, which defaults to `false` and can be used to specifically open a directory symlink on Windows or call `openat` with `O_NOFOLLOW` flag in POSIX.
Diffstat (limited to 'lib/std/os.zig')
-rw-r--r--lib/std/os.zig4
1 files changed, 3 insertions, 1 deletions
diff --git a/lib/std/os.zig b/lib/std/os.zig
index ebe457fe4d..86a5a7ad08 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -1815,7 +1815,7 @@ pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatEr
const want_rmdir_behavior = (flags & AT_REMOVEDIR) != 0;
const create_options_flags = if (want_rmdir_behavior)
- @as(w.ULONG, w.FILE_DELETE_ON_CLOSE | w.FILE_DIRECTORY_FILE)
+ @as(w.ULONG, w.FILE_DELETE_ON_CLOSE | w.FILE_DIRECTORY_FILE | w.FILE_OPEN_REPARSE_POINT)
else
@as(w.ULONG, w.FILE_DELETE_ON_CLOSE | w.FILE_NON_DIRECTORY_FILE | w.FILE_OPEN_REPARSE_POINT); // would we ever want to delete the target instead?
@@ -2390,9 +2390,11 @@ pub fn readlinkW(file_path: [*:0]const u16, out_buffer: []u8) ReadLinkError![]u8
else => |e| return e,
}
};
+ defer w.CloseHandle(handle);
var reparse_buf: [w.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 = undefined;
_ = try w.DeviceIoControl(handle, w.FSCTL_GET_REPARSE_POINT, null, reparse_buf[0..], null);
+
const reparse_struct = @ptrCast(*const w.REPARSE_DATA_BUFFER, @alignCast(@alignOf(w.REPARSE_DATA_BUFFER), &reparse_buf[0]));
switch (reparse_struct.ReparseTag) {
w.IO_REPARSE_TAG_SYMLINK => {