Skip to content

Commit

Permalink
introduce std.fs.Dir.openFile and std.fs.Dir.createFile
Browse files Browse the repository at this point in the history
These functions have flags parameters which cover all the use cases. The
other functions are now deprecated.
  • Loading branch information
andrewrk committed Nov 30, 2019
1 parent 85e1e3b commit d039fed
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 87 deletions.
103 changes: 89 additions & 14 deletions lib/std/fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -698,29 +698,104 @@ pub const Dir = struct {
self.* = undefined;
}

/// Call `File.close` on the result when done.
pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File {
/// Opens a file for reading or writing, without attempting to create a new file.
/// Call `File.close` to release the resource.
pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
if (builtin.os == .windows) {
const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
return self.openReadW(&path_w);
return self.openFileW(&path_w, flags);
}
const path_c = try os.toPosixPath(sub_path);
return self.openReadC(&path_c);
return self.openFileC(&path_c, flags);
}

/// Call `File.close` on the result when done.
pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File {
/// Same as `openFile` but the path parameter is null-terminated.
pub fn openFileC(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
if (builtin.os == .windows) {
const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
return self.openReadW(&path_w);
return self.openFileW(&path_w, flags);
}
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
const fd = try os.openatC(self.fd, sub_path, flags, 0);
return File.openHandle(fd);
const os_flags = O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read)
@as(u32, os.O_RDWR)
else if (flags.write)
@as(u32, os.O_WRONLY)
else
@as(u32, os.O_RDONLY);
const fd = try os.openatC(self.fd, sub_path, os_flags, 0);
return File{ .handle = fd };
}

pub fn openReadW(self: Dir, sub_path_w: [*:0]const u16) File.OpenError!File {
/// Same as `openFile` but the path parameter is WTF-16 encoded.
pub fn openFileW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File {
const w = os.windows;
const access_mask = w.SYNCHRONIZE |
(if (flags.read) @as(u32, w.GENERIC_READ) else 0) |
(if (flags.write) @as(u32, w.GENERIC_WRITE) else 0);
return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN);
}

/// Creates, opens, or overwrites a file with write access.
/// Call `File.close` on the result when done.
pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
if (builtin.os == .windows) {
const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
return self.createFileW(&path_w, flags);
}
const path_c = try os.toPosixPath(sub_path);
return self.createFileC(&path_c, flags);
}

/// Same as `createFile` but the path parameter is null-terminated.
pub fn createFileC(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
if (builtin.os == .windows) {
const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
return self.createFileW(&path_w, flags);
}
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const os_flags = O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC |
(if (flags.truncate) @as(u32, os.O_TRUNC) else 0) |
(if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) |
(if (flags.exclusive) @as(u32, os.O_EXCL) else 0);
const fd = try os.openatC(self.fd, sub_path_c, os_flags, flags.mode);
return File{ .handle = fd };
}

/// Same as `createFile` but the path parameter is WTF-16 encoded.
pub fn createFileW(self: Dir, sub_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File {
const w = os.windows;
const access_mask = w.SYNCHRONIZE | w.GENERIC_WRITE |
(if (flags.read) @as(u32, w.GENERIC_READ) else 0);
const creation = if (flags.exclusive)
@as(u32, w.FILE_CREATE)
else if (flags.truncate)
@as(u32, w.FILE_OVERWRITE_IF)
else
@as(u32, w.FILE_OPEN_IF);
return self.openFileWindows(sub_path_w, access_mask, creation);
}

/// Deprecated; call `openFile` directly.
pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File {
return self.openFile(sub_path, .{});
}

/// Deprecated; call `openFileC` directly.
pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File {
return self.openFileC(sub_path, .{});
}

/// Deprecated; call `openFileW` directly.
pub fn openReadW(self: Dir, sub_path: [*:0]const u16) File.OpenError!File {
return self.openFileW(sub_path, .{});
}

pub fn openFileWindows(
self: Dir,
sub_path_w: [*:0]const u16,
access_mask: os.windows.ACCESS_MASK,
creation: os.windows.ULONG,
) File.OpenError!File {
const w = os.windows;

var result = File{ .handle = undefined };
Expand Down Expand Up @@ -750,13 +825,13 @@ pub const Dir = struct {
var io: w.IO_STATUS_BLOCK = undefined;
const rc = w.ntdll.NtCreateFile(
&result.handle,
w.GENERIC_READ | w.SYNCHRONIZE,
access_mask,
&attr,
&io,
null,
w.FILE_ATTRIBUTE_NORMAL,
w.FILE_SHARE_READ,
w.FILE_OPEN,
w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,
creation,
w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
null,
0,
Expand Down
128 changes: 55 additions & 73 deletions lib/std/fs/file.zig
Original file line number Diff line number Diff line change
Expand Up @@ -25,105 +25,87 @@ pub const File = struct {

pub const OpenError = windows.CreateFileError || os.OpenError;

/// Deprecated; call `std.fs.Dir.openRead` directly.
/// TODO https://github.com/ziglang/zig/issues/3802
pub const OpenFlags = struct {
read: bool = true,
write: bool = false,
};

/// TODO https://github.com/ziglang/zig/issues/3802
pub const CreateFlags = struct {
/// Whether the file will be created with read access.
read: bool = false,

/// If the file already exists, and is a regular file, and the access
/// mode allows writing, it will be truncated to length 0.
truncate: bool = true,

/// Ensures that this open call creates the file, otherwise causes
/// `error.FileAlreadyExists` to be returned.
exclusive: bool = false,

/// For POSIX systems this is the file system mode the file will
/// be created with.
mode: Mode = default_mode,
};

/// Deprecated; call `std.fs.Dir.openFile` directly.
pub fn openRead(path: []const u8) OpenError!File {
return std.fs.Dir.cwd().openRead(path);
return std.fs.Dir.cwd().openFile(path, .{});
}

/// Deprecated; call `std.fs.Dir.openReadC` directly.
/// Deprecated; call `std.fs.Dir.openFileC` directly.
pub fn openReadC(path_c: [*:0]const u8) OpenError!File {
return std.fs.Dir.cwd().openReadC(path_c);
return std.fs.Dir.cwd().openFileC(path_c, .{});
}

/// Deprecated; call `std.fs.Dir.openReadW` directly.
/// Deprecated; call `std.fs.Dir.openFileW` directly.
pub fn openReadW(path_w: [*]const u16) OpenError!File {
return std.fs.Dir.cwd().openReadW(path_w);
return std.fs.Dir.cwd().openFileW(path_w, .{});
}

/// Calls `openWriteMode` with `default_mode` for the mode.
/// TODO: deprecate this and move it to `std.fs.Dir`.
/// Deprecated; call `std.fs.Dir.createFile` directly.
pub fn openWrite(path: []const u8) OpenError!File {
return openWriteMode(path, default_mode);
return std.fs.Dir.cwd().createFile(path, .{});
}

/// If the path does not exist it will be created.
/// If a file already exists in the destination it will be truncated.
/// Call close to clean up.
/// TODO: deprecate this and move it to `std.fs.Dir`.
/// Deprecated; call `std.fs.Dir.createFile` directly.
pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.sliceToPrefixedFileW(path);
return openWriteModeW(&path_w, file_mode);
}
const path_c = try os.toPosixPath(path);
return openWriteModeC(&path_c, file_mode);
return std.fs.Dir.cwd().createFile(path, .{ .mode = file_mode });
}

/// Same as `openWriteMode` except `path` is null-terminated.
/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWriteModeC(path: [*:0]const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.cStrToPrefixedFileW(path);
return openWriteModeW(&path_w, file_mode);
}
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
const fd = try os.openC(path, flags, file_mode);
return openHandle(fd);
/// Deprecated; call `std.fs.Dir.createFileC` directly.
pub fn openWriteModeC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File {
return std.fs.Dir.cwd().createFileC(path_c, .{ .mode = file_mode });
}

/// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded
/// TODO: deprecate this and move it to `std.fs.Dir`.
/// Deprecated; call `std.fs.Dir.createFileW` directly.
pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {
const handle = try windows.CreateFileW(
path_w,
windows.GENERIC_WRITE,
windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
null,
windows.CREATE_ALWAYS,
windows.FILE_ATTRIBUTE_NORMAL,
null,
);
return openHandle(handle);
return std.fs.Dir.cwd().createFileW(path_w, .{ .mode = file_mode });
}

/// If the path does not exist it will be created.
/// If a file already exists in the destination this returns OpenError.PathAlreadyExists
/// Call close to clean up.
/// TODO: deprecate this and move it to `std.fs.Dir`.
/// Deprecated; call `std.fs.Dir.createFile` directly.
pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.sliceToPrefixedFileW(path);
return openWriteNoClobberW(&path_w, file_mode);
}
const path_c = try os.toPosixPath(path);
return openWriteNoClobberC(&path_c, file_mode);
return std.fs.Dir.cwd().createFile(path, .{
.mode = file_mode,
.exclusive = true,
});
}

/// TODO: deprecate this and move it to `std.fs.Dir`.
pub fn openWriteNoClobberC(path: [*:0]const u8, file_mode: Mode) OpenError!File {
if (builtin.os == .windows) {
const path_w = try windows.cStrToPrefixedFileW(path);
return openWriteNoClobberW(&path_w, file_mode);
}
const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_EXCL;
const fd = try os.openC(path, flags, file_mode);
return openHandle(fd);
/// Deprecated; call `std.fs.Dir.createFileC` directly.
pub fn openWriteNoClobberC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File {
return std.fs.Dir.cwd().createFileC(path_c, .{
.mode = file_mode,
.exclusive = true,
});
}

/// TODO: deprecate this and move it to `std.fs.Dir`.
/// Deprecated; call `std.fs.Dir.createFileW` directly.
pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {
const handle = try windows.CreateFileW(
path_w,
windows.GENERIC_WRITE,
windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
null,
windows.CREATE_NEW,
windows.FILE_ATTRIBUTE_NORMAL,
null,
);
return openHandle(handle);
return std.fs.Dir.cwd().createFileW(path_w, .{
.mode = file_mode,
.exclusive = true,
});
}

pub fn openHandle(handle: os.fd_t) File {
Expand Down

0 comments on commit d039fed

Please sign in to comment.