aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-12-31 16:35:01 -0800
committerAndrew Kelley <andrew@ziglang.org>2022-01-02 16:58:05 -0800
commitd3f87f8ac01039722197a13a12342fc747a90567 (patch)
tree226dfc7c6e61533b34a083f810b3e1429390e679 /lib/std
parentb4d6e85a339e971829404dc1a260bde4062735f8 (diff)
downloadzig-d3f87f8ac01039722197a13a12342fc747a90567.tar.gz
zig-d3f87f8ac01039722197a13a12342fc747a90567.zip
std.fs.rename: fix Windows implementation
The semantics of this function are that it moves both files and directories. Previously we had this `is_dir` boolean field of `std.os.windows.OpenFile` which required the API user to choose: are we opening a file or directory? And the other kind would either cause error.IsDir or error.NotDir. But that is not a limitation of the Windows file system API; it was self-imposed. On Windows, rename is implemented internally with `NtCreateFile` so we need to allow it to open either files or directories. This is now done by `std.os.windows.OpenFile` accepting enum{file_only,dir_only,any} instead of a boolean.
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/fs.zig2
-rw-r--r--lib/std/fs/watch.zig2
-rw-r--r--lib/std/os.zig11
-rw-r--r--lib/std/os/windows.zig23
4 files changed, 26 insertions, 12 deletions
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 6e1821178f..a09f9f2ed2 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -1361,7 +1361,7 @@ pub const Dir = struct {
.share_access = share_access,
.creation = creation,
.io_mode = .blocking,
- .open_dir = true,
+ .filter = .dir_only,
}) catch |er| switch (er) {
error.WouldBlock => unreachable,
else => |e2| return e2,
diff --git a/lib/std/fs/watch.zig b/lib/std/fs/watch.zig
index c103925bdd..e2ec8b8061 100644
--- a/lib/std/fs/watch.zig
+++ b/lib/std/fs/watch.zig
@@ -401,7 +401,7 @@ pub fn Watch(comptime V: type) type {
.access_mask = windows.FILE_LIST_DIRECTORY,
.creation = windows.FILE_OPEN,
.io_mode = .evented,
- .open_dir = true,
+ .filter = .dir_only,
});
errdefer windows.CloseHandle(dir_handle);
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 1728c2ac0d..7be8825fcc 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -1353,7 +1353,7 @@ fn openOptionsFromFlags(flags: u32) windows.OpenFileOptions {
access_mask |= w.GENERIC_READ | w.GENERIC_WRITE;
}
- const open_dir: bool = flags & O.DIRECTORY != 0;
+ const filter: windows.OpenFileOptions.Filter = if (flags & O.DIRECTORY != 0) .dir_only else .file_only;
const follow_symlinks: bool = flags & O.NOFOLLOW == 0;
const creation: w.ULONG = blk: {
@@ -1369,7 +1369,7 @@ fn openOptionsFromFlags(flags: u32) windows.OpenFileOptions {
.access_mask = access_mask,
.io_mode = .blocking,
.creation = creation,
- .open_dir = open_dir,
+ .filter = filter,
.follow_symlinks = follow_symlinks,
};
}
@@ -2324,6 +2324,7 @@ pub fn renameatW(
.access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE,
.creation = windows.FILE_OPEN,
.io_mode = .blocking,
+ .filter = .any, // This function is supposed to rename both files and directories.
}) catch |err| switch (err) {
error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
else => |e| return e,
@@ -2435,7 +2436,7 @@ pub fn mkdiratW(dir_fd: fd_t, sub_path_w: []const u16, mode: u32) MakeDirError!v
.access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE,
.creation = windows.FILE_CREATE,
.io_mode = .blocking,
- .open_dir = true,
+ .filter = .dir_only,
}) catch |err| switch (err) {
error.IsDir => unreachable,
error.PipeBusy => unreachable,
@@ -2511,7 +2512,7 @@ pub fn mkdirW(dir_path_w: []const u16, mode: u32) MakeDirError!void {
.access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE,
.creation = windows.FILE_CREATE,
.io_mode = .blocking,
- .open_dir = true,
+ .filter = .dir_only,
}) catch |err| switch (err) {
error.IsDir => unreachable,
error.PipeBusy => unreachable,
@@ -4693,7 +4694,7 @@ pub fn realpathW(pathname: []const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPat
.share_access = share_access,
.creation = creation,
.io_mode = .blocking,
- .open_dir = true,
+ .filter = .dir_only,
}) catch |er| switch (er) {
error.WouldBlock => unreachable,
else => |e2| return e2,
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index 59e65ed54c..0d9907893c 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -53,17 +53,26 @@ pub const OpenFileOptions = struct {
io_mode: std.io.ModeOverride,
/// If true, tries to open path as a directory.
/// Defaults to false.
- open_dir: bool = false,
+ filter: Filter = .file_only,
/// If false, tries to open path as a reparse point without dereferencing it.
/// Defaults to true.
follow_symlinks: bool = true,
+
+ pub const Filter = enum {
+ /// Causes `OpenFile` to return `error.IsDir` if the opened handle would be a directory.
+ file_only,
+ /// Causes `OpenFile` to return `error.NotDir` if the opened handle would be a file.
+ dir_only,
+ /// `OpenFile` does not discriminate between opening files and directories.
+ any,
+ };
};
pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HANDLE {
- if (mem.eql(u16, sub_path_w, &[_]u16{'.'}) and !options.open_dir) {
+ if (mem.eql(u16, sub_path_w, &[_]u16{'.'}) and options.filter == .file_only) {
return error.IsDir;
}
- if (mem.eql(u16, sub_path_w, &[_]u16{ '.', '.' }) and !options.open_dir) {
+ if (mem.eql(u16, sub_path_w, &[_]u16{ '.', '.' }) and options.filter == .file_only) {
return error.IsDir;
}
@@ -87,7 +96,11 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN
};
var io: IO_STATUS_BLOCK = undefined;
const blocking_flag: ULONG = if (options.io_mode == .blocking) FILE_SYNCHRONOUS_IO_NONALERT else 0;
- const file_or_dir_flag: ULONG = if (options.open_dir) FILE_DIRECTORY_FILE else FILE_NON_DIRECTORY_FILE;
+ const file_or_dir_flag: ULONG = switch (options.filter) {
+ .file_only => FILE_NON_DIRECTORY_FILE,
+ .dir_only => FILE_DIRECTORY_FILE,
+ .any => 0,
+ };
// If we're not following symlinks, we need to ensure we don't pass in any synchronization flags such as FILE_SYNCHRONOUS_IO_NONALERT.
const flags: ULONG = if (options.follow_symlinks) file_or_dir_flag | blocking_flag else file_or_dir_flag | FILE_OPEN_REPARSE_POINT;
@@ -695,7 +708,7 @@ pub fn CreateSymbolicLink(
.dir = dir,
.creation = FILE_CREATE,
.io_mode = .blocking,
- .open_dir = is_directory,
+ .filter = if (is_directory) .dir_only else .file_only,
}) catch |err| switch (err) {
error.IsDir => return error.PathAlreadyExists,
error.NotDir => unreachable,