diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2020-07-19 22:25:00 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2020-07-22 08:51:22 +0200 |
| commit | e0b77a6b77614538d18b9f0b9e3e7e434ccee4ff (patch) | |
| tree | 04b40728d9b672ef160431fe550e389863ce666d /lib/std/os.zig | |
| parent | 3c8ceb674eb00ac0a70d6a0742234ce520eccf06 (diff) | |
| download | zig-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.zig | 4 |
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 => { |
