Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/std/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2416,7 +2416,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 {
const path_file = try fs.path.join(allocator, [_][]const u8{ appdata_path, "vcpkg.path.txt" });
defer allocator.free(path_file);

const file = fs.File.openRead(path_file) catch return null;
const file = fs.cwd().openFile(path_file, .{}) catch return null;
defer file.close();

const size = @intCast(usize, try file.getEndPos());
Expand Down
4 changes: 2 additions & 2 deletions lib/std/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
}

fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
var f = try File.openRead(line_info.file_name);
var f = try fs.cwd().openFile(line_info.file_name, .{});
defer f.close();
// TODO fstat and make sure that the file has the correct size

Expand Down Expand Up @@ -2089,7 +2089,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));

gop.kv.value = MachOFile{
.bytes = try std.fs.Dir.cwd().readFileAllocAligned(
.bytes = try std.fs.cwd().readFileAllocAligned(
di.ofiles.allocator,
ofile_path,
maxInt(usize),
Expand Down
276 changes: 227 additions & 49 deletions lib/std/fs.zig

Large diffs are not rendered by default.

129 changes: 56 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.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.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.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.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.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.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.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.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.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.cwd().createFileW(path_w, .{
.mode = file_mode,
.exclusive = true,
});
}

pub fn openHandle(handle: os.fd_t) File {
Expand Down Expand Up @@ -246,6 +228,7 @@ pub const File = struct {
windows.STATUS.SUCCESS => {},
windows.STATUS.BUFFER_OVERFLOW => {},
windows.STATUS.INVALID_PARAMETER => unreachable,
windows.STATUS.ACCESS_DENIED => return error.AccessDenied,
else => return windows.unexpectedStatus(rc),
}
return Stat{
Expand Down
33 changes: 32 additions & 1 deletion lib/std/fs/path.zig
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ test "join" {
testJoinPosix([_][]const u8{ "a/", "/c" }, "a/c");
}

pub fn isAbsoluteC(path_c: [*:0]const u8) bool {
if (builtin.os == .windows) {
return isAbsoluteWindowsC(path_c);
} else {
return isAbsolutePosixC(path_c);
}
}

pub fn isAbsolute(path: []const u8) bool {
if (builtin.os == .windows) {
return isAbsoluteWindows(path);
Expand All @@ -136,7 +144,7 @@ pub fn isAbsolute(path: []const u8) bool {
}
}

pub fn isAbsoluteW(path_w: [*]const u16) bool {
pub fn isAbsoluteW(path_w: [*:0]const u16) bool {
if (path_w[0] == '/')
return true;

Expand Down Expand Up @@ -174,10 +182,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool {
return false;
}

pub fn isAbsoluteWindowsC(path_c: [*:0]const u8) bool {
if (path_c[0] == '/')
return true;

if (path_c[0] == '\\') {
return true;
}
if (path_c[0] == 0 or path_c[1] == 0 or path_c[2] == 0) {
return false;
}
if (path_c[1] == ':') {
if (path_c[2] == '/')
return true;
if (path_c[2] == '\\')
return true;
}
return false;
}

pub fn isAbsolutePosix(path: []const u8) bool {
return path[0] == sep_posix;
}

pub fn isAbsolutePosixC(path_c: [*:0]const u8) bool {
return path_c[0] == sep_posix;
}

test "isAbsoluteWindows" {
testIsAbsoluteWindows("/", true);
testIsAbsoluteWindows("//", true);
Expand Down
11 changes: 4 additions & 7 deletions lib/std/io.zig
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream;
pub const InStream = @import("io/in_stream.zig").InStream;
pub const OutStream = @import("io/out_stream.zig").OutStream;

/// TODO move this to `std.fs` and add a version to `std.fs.Dir`.
/// Deprecated; use `std.fs.Dir.writeFile`.
pub fn writeFile(path: []const u8, data: []const u8) !void {
var file = try File.openWrite(path);
defer file.close();
try file.write(data);
return fs.cwd().writeFile(path, data);
}

/// On success, caller owns returned buffer.
/// This function is deprecated; use `std.fs.Dir.readFileAlloc`.
/// Deprecated; use `std.fs.Dir.readFileAlloc`.
pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 {
return fs.Dir.cwd().readFileAlloc(allocator, path, math.maxInt(usize));
return fs.cwd().readFileAlloc(allocator, path, math.maxInt(usize));
}

pub fn BufferedInStream(comptime Error: type) type {
Expand Down
28 changes: 15 additions & 13 deletions lib/std/io/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ test "write a file, read it, then delete it" {
var raw_bytes: [200 * 1024]u8 = undefined;
var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator;

const cwd = fs.cwd();

var data: [1024]u8 = undefined;
var prng = DefaultPrng.init(1234);
prng.random.bytes(data[0..]);
const tmp_file_name = "temp_test_file.txt";
{
var file = try File.openWrite(tmp_file_name);
var file = try cwd.createFile(tmp_file_name, .{});
defer file.close();

var file_out_stream = file.outStream();
Expand All @@ -32,16 +34,16 @@ test "write a file, read it, then delete it" {
}

{
// make sure openWriteNoClobber doesn't harm the file
if (File.openWriteNoClobber(tmp_file_name, File.default_mode)) |file| {
// Make sure the exclusive flag is honored.
if (cwd.createFile(tmp_file_name, .{ .exclusive = true })) |file| {
unreachable;
} else |err| {
std.debug.assert(err == File.OpenError.PathAlreadyExists);
}
}

{
var file = try File.openRead(tmp_file_name);
var file = try cwd.openFile(tmp_file_name, .{});
defer file.close();

const file_size = try file.getEndPos();
Expand All @@ -58,7 +60,7 @@ test "write a file, read it, then delete it" {
expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data));
expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
}
try fs.deleteFile(tmp_file_name);
try cwd.deleteFile(tmp_file_name);
}

test "BufferOutStream" {
Expand Down Expand Up @@ -274,7 +276,7 @@ test "BitOutStream" {
test "BitStreams with File Stream" {
const tmp_file_name = "temp_test_file.txt";
{
var file = try File.openWrite(tmp_file_name);
var file = try fs.cwd().createFile(tmp_file_name, .{});
defer file.close();

var file_out = file.outStream();
Expand All @@ -291,7 +293,7 @@ test "BitStreams with File Stream" {
try bit_stream.flushBits();
}
{
var file = try File.openRead(tmp_file_name);
var file = try fs.cwd().openFile(tmp_file_name, .{});
defer file.close();

var file_in = file.inStream();
Expand All @@ -316,7 +318,7 @@ test "BitStreams with File Stream" {

expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));
}
try fs.deleteFile(tmp_file_name);
try fs.cwd().deleteFile(tmp_file_name);
}

fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
Expand Down Expand Up @@ -599,7 +601,7 @@ test "c out stream" {
const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
defer {
_ = std.c.fclose(out_file);
fs.deleteFileC(filename) catch {};
fs.cwd().deleteFileC(filename) catch {};
}

const out_stream = &io.COutStream.init(out_file).stream;
Expand All @@ -608,10 +610,10 @@ test "c out stream" {

test "File seek ops" {
const tmp_file_name = "temp_test_file.txt";
var file = try File.openWrite(tmp_file_name);
var file = try fs.cwd().createFile(tmp_file_name, .{});
defer {
file.close();
fs.deleteFile(tmp_file_name) catch {};
fs.cwd().deleteFile(tmp_file_name) catch {};
}

try file.write([_]u8{0x55} ** 8192);
Expand All @@ -632,10 +634,10 @@ test "File seek ops" {

test "updateTimes" {
const tmp_file_name = "just_a_temporary_file.txt";
var file = try File.openWrite(tmp_file_name);
var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true });
defer {
file.close();
std.fs.deleteFile(tmp_file_name) catch {};
std.fs.cwd().deleteFile(tmp_file_name) catch {};
}
var stat_old = try file.stat();
// Set atime and mtime to 5s before
Expand Down
Loading