Skip to content

Commit

Permalink
ziglang#12474: Code improvement and add a new test case
Browse files Browse the repository at this point in the history
  • Loading branch information
QusaiHroub committed Aug 3, 2023
1 parent 767b03e commit a0866c8
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 13 deletions.
38 changes: 25 additions & 13 deletions lib/std/fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1481,13 +1481,18 @@ pub const Dir = struct {
}
}

fn openDirAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no_follow: bool) OpenError!Dir {
/// Calls makeOpenDirAccessMaskW recursively to make an entire path
/// (i.e. falling back if the parent directory does not exist). Opens the dir if the path
/// already exists and is a directory.
/// This function is not atomic, and if it returns an error, the file system may
/// have been modified regardless.
fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no_follow: bool) OpenError!Dir {
const w = os.windows;
var end_index: usize = sub_path.len;

return while (true) {
const sub_path_w = try w.sliceToPrefixedFileW(sub_path[0..end_index]);
const result = self.openDirWithAccessAndCreationW(sub_path_w.span().ptr, access_mask, .{
const result = self.makeOpenDirAccessMaskW(sub_path_w.span().ptr, access_mask, .{
.no_follow = no_follow,
.create_disposition = if (end_index == sub_path.len) w.FILE_OPEN_IF else w.FILE_CREATE,
}) catch |err| switch (err) {
Expand Down Expand Up @@ -1515,19 +1520,23 @@ pub const Dir = struct {
/// This function performs `makePath`, followed by `openDir`.
/// If supported by the OS, this operation is atomic. It is not atomic on
/// all operating systems.
/// On Windows, this function preforms `makeOpenPathAccessMaskW`.
pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !Dir {
return switch (builtin.os.tag) {
.windows => {
const w = os.windows;
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
w.SYNCHRONIZE | w.FILE_TRAVERSE;

return self.openDirAccessMaskW(sub_path, base_flags, open_dir_options.no_follow);
return self.makeOpenPathAccessMaskW(sub_path, base_flags, open_dir_options.no_follow);
},
else => {
return self.openDir(sub_path, open_dir_options) catch {
try self.makePath(sub_path);
return self.openDir(sub_path, open_dir_options);
return self.openDir(sub_path, open_dir_options) catch |err| switch (err) {
error.FileNotFound => {
try self.makePath(sub_path);
return self.openDir(sub_path, open_dir_options);
},
else => |e| return e,
};
},
};
Expand All @@ -1544,13 +1553,16 @@ pub const Dir = struct {
w.SYNCHRONIZE | w.FILE_TRAVERSE | w.FILE_LIST_DIRECTORY;

return IterableDir{
.dir = try self.openDirAccessMaskW(sub_path, base_flags, open_dir_options.no_follow),
.dir = try self.makeOpenPathAccessMaskW(sub_path, base_flags, open_dir_options.no_follow),
};
},
else => {
return self.openIterableDir(sub_path, open_dir_options) catch {
try self.makePath(sub_path);
return self.openIterableDir(sub_path, open_dir_options);
return self.openIterableDir(sub_path, open_dir_options) catch |err| switch (err) {
error.FileNotFound => {
try self.makePath(sub_path);
return self.openIterableDir(sub_path, open_dir_options);
},
else => |e| return e,
};
},
};
Expand Down Expand Up @@ -1807,7 +1819,7 @@ pub const Dir = struct {
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
w.SYNCHRONIZE | w.FILE_TRAVERSE;
const flags: u32 = if (iterable) base_flags | w.FILE_LIST_DIRECTORY else base_flags;
var dir = try self.openDirWithAccessAndCreationW(sub_path_w, flags, .{
var dir = try self.makeOpenDirAccessMaskW(sub_path_w, flags, .{
.no_follow = args.no_follow,
.create_disposition = w.FILE_OPEN,
});
Expand All @@ -1833,12 +1845,12 @@ pub const Dir = struct {
return Dir{ .fd = fd };
}

const OpenDirWithAccessAndCreationWOptions = struct {
const MakeOpenDirAccessMaskWOptions = struct {
no_follow: bool,
create_disposition: u32,
};

fn openDirWithAccessAndCreationW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32, flags: OpenDirWithAccessAndCreationWOptions) OpenError!Dir {
fn makeOpenDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32, flags: MakeOpenDirAccessMaskWOptions) OpenError!Dir {
const w = os.windows;

var result = Dir{
Expand Down
7 changes: 7 additions & 0 deletions lib/std/fs/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,13 @@ test "file operations on directories" {
dir.close();
}

test "makeOpenPath parent dirs do not exist" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;

var dir = try fs.cwd().makeOpenPath("root_dir/parent_dir/some_dir", .{});
defer dir.close();
}

test "deleteDir" {
var tmp_dir = tmpDir(.{});
defer tmp_dir.cleanup();
Expand Down

0 comments on commit a0866c8

Please sign in to comment.