mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
std.Io: extract Dir to separate file
This commit is contained in:
parent
fc1e3d5bc9
commit
0e9280ef1a
9 changed files with 162 additions and 124 deletions
|
|
@ -548,6 +548,7 @@ pub fn PollFiles(comptime StreamEnum: type) type {
|
|||
}
|
||||
|
||||
test {
|
||||
_ = net;
|
||||
_ = Reader;
|
||||
_ = Writer;
|
||||
_ = tty;
|
||||
|
|
@ -688,42 +689,7 @@ pub const UnexpectedError = error{
|
|||
Unexpected,
|
||||
};
|
||||
|
||||
pub const Dir = struct {
|
||||
handle: Handle,
|
||||
|
||||
pub fn cwd() Dir {
|
||||
return .{ .handle = std.fs.cwd().fd };
|
||||
}
|
||||
|
||||
pub const Handle = std.posix.fd_t;
|
||||
|
||||
pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
return io.vtable.fileOpen(io.userdata, dir, sub_path, flags);
|
||||
}
|
||||
|
||||
pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
return io.vtable.createFile(io.userdata, dir, sub_path, flags);
|
||||
}
|
||||
|
||||
pub const WriteFileOptions = struct {
|
||||
/// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||
sub_path: []const u8,
|
||||
data: []const u8,
|
||||
flags: File.CreateFlags = .{},
|
||||
};
|
||||
|
||||
pub const WriteFileError = File.WriteError || File.OpenError || Cancelable;
|
||||
|
||||
/// Writes content to the file system, using the file creation flags provided.
|
||||
pub fn writeFile(dir: Dir, io: Io, options: WriteFileOptions) WriteFileError!void {
|
||||
var file = try dir.createFile(io, options.sub_path, options.flags);
|
||||
defer file.close(io);
|
||||
try file.writeAll(io, options.data);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Dir = @import("Io/Dir.zig");
|
||||
pub const File = @import("Io/File.zig");
|
||||
|
||||
pub const Timestamp = enum(i96) {
|
||||
|
|
|
|||
113
lib/std/Io/Dir.zig
Normal file
113
lib/std/Io/Dir.zig
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
const Dir = @This();
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const Io = std.Io;
|
||||
const File = Io.File;
|
||||
|
||||
handle: Handle,
|
||||
|
||||
pub fn cwd() Dir {
|
||||
return .{ .handle = std.fs.cwd().fd };
|
||||
}
|
||||
|
||||
pub const Handle = std.posix.fd_t;
|
||||
|
||||
pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
return io.vtable.fileOpen(io.userdata, dir, sub_path, flags);
|
||||
}
|
||||
|
||||
pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
return io.vtable.createFile(io.userdata, dir, sub_path, flags);
|
||||
}
|
||||
|
||||
pub const WriteFileOptions = struct {
|
||||
/// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
|
||||
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||
sub_path: []const u8,
|
||||
data: []const u8,
|
||||
flags: File.CreateFlags = .{},
|
||||
};
|
||||
|
||||
pub const WriteFileError = File.WriteError || File.OpenError || Io.Cancelable;
|
||||
|
||||
/// Writes content to the file system, using the file creation flags provided.
|
||||
pub fn writeFile(dir: Dir, io: Io, options: WriteFileOptions) WriteFileError!void {
|
||||
var file = try dir.createFile(io, options.sub_path, options.flags);
|
||||
defer file.close(io);
|
||||
try file.writeAll(io, options.data);
|
||||
}
|
||||
|
||||
pub const PrevStatus = enum {
|
||||
stale,
|
||||
fresh,
|
||||
};
|
||||
|
||||
pub const UpdateFileError = File.OpenError;
|
||||
|
||||
/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If
|
||||
/// they are equal, does nothing. Otherwise, atomically copies `source_path` to
|
||||
/// `dest_path`. The destination file gains the mtime, atime, and mode of the
|
||||
/// source file so that the next call to `updateFile` will not need a copy.
|
||||
///
|
||||
/// Returns the previous status of the file before updating.
|
||||
///
|
||||
/// * On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
|
||||
/// * On WASI, both paths should be encoded as valid UTF-8.
|
||||
/// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
|
||||
pub fn updateFile(
|
||||
source_dir: Dir,
|
||||
io: Io,
|
||||
source_path: []const u8,
|
||||
dest_dir: Dir,
|
||||
/// If directories in this path do not exist, they are created.
|
||||
dest_path: []const u8,
|
||||
options: std.fs.Dir.CopyFileOptions,
|
||||
) !PrevStatus {
|
||||
var src_file = try source_dir.openFile(io, source_path, .{});
|
||||
defer src_file.close();
|
||||
|
||||
const src_stat = try src_file.stat(io);
|
||||
const actual_mode = options.override_mode orelse src_stat.mode;
|
||||
check_dest_stat: {
|
||||
const dest_stat = blk: {
|
||||
var dest_file = dest_dir.openFile(io, dest_path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => break :check_dest_stat,
|
||||
else => |e| return e,
|
||||
};
|
||||
defer dest_file.close(io);
|
||||
|
||||
break :blk try dest_file.stat(io);
|
||||
};
|
||||
|
||||
if (src_stat.size == dest_stat.size and
|
||||
src_stat.mtime == dest_stat.mtime and
|
||||
actual_mode == dest_stat.mode)
|
||||
{
|
||||
return .fresh;
|
||||
}
|
||||
}
|
||||
|
||||
if (std.fs.path.dirname(dest_path)) |dirname| {
|
||||
try dest_dir.makePath(io, dirname);
|
||||
}
|
||||
|
||||
var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available.
|
||||
var atomic_file = try dest_dir.atomicFile(io, dest_path, .{
|
||||
.mode = actual_mode,
|
||||
.write_buffer = &buffer,
|
||||
});
|
||||
defer atomic_file.deinit();
|
||||
|
||||
var src_reader: File.Reader = .initSize(io, src_file, &.{}, src_stat.size);
|
||||
const dest_writer = &atomic_file.file_writer.interface;
|
||||
|
||||
_ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) {
|
||||
error.ReadFailed => return src_reader.err.?,
|
||||
error.WriteFailed => return atomic_file.file_writer.err.?,
|
||||
};
|
||||
try atomic_file.flush();
|
||||
try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime);
|
||||
try atomic_file.renameIntoPlace();
|
||||
return .stale;
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
const File = @This();
|
||||
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const Io = std.Io;
|
||||
const File = @This();
|
||||
const assert = std.debug.assert;
|
||||
|
||||
handle: Handle,
|
||||
|
|
|
|||
|
|
@ -593,3 +593,7 @@ pub const InterfaceIndexError = error{
|
|||
pub fn interfaceIndex(io: Io, name: []const u8) InterfaceIndexError!u32 {
|
||||
return io.vtable.netInterfaceIndex(io.userdata, name);
|
||||
}
|
||||
|
||||
test {
|
||||
_ = HostName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -629,3 +629,28 @@ pub const ResolvConf = struct {
|
|||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
||||
test ResolvConf {
|
||||
const input =
|
||||
\\# Generated by resolvconf
|
||||
\\nameserver 1.0.0.1
|
||||
\\nameserver 1.1.1.1
|
||||
\\nameserver fe80::e0e:76ff:fed4:cf22%eno1
|
||||
\\options edns0
|
||||
\\
|
||||
;
|
||||
var reader: Io.Reader = .fixed(input);
|
||||
|
||||
var rc: ResolvConf = .{
|
||||
.nameservers_buffer = undefined,
|
||||
.nameservers_len = 0,
|
||||
.search_buffer = undefined,
|
||||
.search_len = 0,
|
||||
.ndots = 1,
|
||||
.timeout = 5,
|
||||
.attempts = 2,
|
||||
};
|
||||
|
||||
try rc.parse(&reader);
|
||||
try std.testing.expect(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,13 +107,15 @@ pub fn updateFileAbsolute(
|
|||
source_path: []const u8,
|
||||
dest_path: []const u8,
|
||||
args: Dir.CopyFileOptions,
|
||||
) !Dir.PrevStatus {
|
||||
) !std.Io.Dir.PrevStatus {
|
||||
assert(path.isAbsolute(source_path));
|
||||
assert(path.isAbsolute(dest_path));
|
||||
const my_cwd = cwd();
|
||||
return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args);
|
||||
}
|
||||
|
||||
test updateFileAbsolute {}
|
||||
|
||||
/// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path`
|
||||
/// are absolute. See `Dir.copyFile` for a function that operates on both
|
||||
/// absolute and relative paths.
|
||||
|
|
@ -131,6 +133,8 @@ pub fn copyFileAbsolute(
|
|||
return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args);
|
||||
}
|
||||
|
||||
test copyFileAbsolute {}
|
||||
|
||||
/// Create a new directory, based on an absolute path.
|
||||
/// Asserts that the path is absolute. See `Dir.makeDir` for a function that operates
|
||||
/// on both absolute and relative paths.
|
||||
|
|
@ -142,12 +146,16 @@ pub fn makeDirAbsolute(absolute_path: []const u8) !void {
|
|||
return posix.mkdir(absolute_path, Dir.default_mode);
|
||||
}
|
||||
|
||||
test makeDirAbsolute {}
|
||||
|
||||
/// Same as `makeDirAbsolute` except the parameter is null-terminated.
|
||||
pub fn makeDirAbsoluteZ(absolute_path_z: [*:0]const u8) !void {
|
||||
assert(path.isAbsoluteZ(absolute_path_z));
|
||||
return posix.mkdirZ(absolute_path_z, Dir.default_mode);
|
||||
}
|
||||
|
||||
test makeDirAbsoluteZ {}
|
||||
|
||||
/// Same as `makeDirAbsolute` except the parameter is a null-terminated WTF-16 LE-encoded string.
|
||||
pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {
|
||||
assert(path.isAbsoluteWindowsW(absolute_path_w));
|
||||
|
|
@ -702,16 +710,10 @@ pub fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]u8 {
|
|||
}
|
||||
|
||||
test {
|
||||
if (native_os != .wasi) {
|
||||
_ = &makeDirAbsolute;
|
||||
_ = &makeDirAbsoluteZ;
|
||||
_ = ©FileAbsolute;
|
||||
_ = &updateFileAbsolute;
|
||||
}
|
||||
_ = &AtomicFile;
|
||||
_ = &Dir;
|
||||
_ = &File;
|
||||
_ = &path;
|
||||
_ = AtomicFile;
|
||||
_ = Dir;
|
||||
_ = File;
|
||||
_ = path;
|
||||
_ = @import("fs/test.zig");
|
||||
_ = @import("fs/get_app_data_dir.zig");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2630,74 +2630,6 @@ pub const CopyFileOptions = struct {
|
|||
override_mode: ?File.Mode = null,
|
||||
};
|
||||
|
||||
pub const PrevStatus = enum {
|
||||
stale,
|
||||
fresh,
|
||||
};
|
||||
|
||||
/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing.
|
||||
/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime,
|
||||
/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.
|
||||
/// Returns the previous status of the file before updating.
|
||||
/// If any of the directories do not exist for dest_path, they are created.
|
||||
/// On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/).
|
||||
/// On WASI, both paths should be encoded as valid UTF-8.
|
||||
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
|
||||
pub fn updateFile(
|
||||
source_dir: Dir,
|
||||
source_path: []const u8,
|
||||
dest_dir: Dir,
|
||||
dest_path: []const u8,
|
||||
options: CopyFileOptions,
|
||||
) !PrevStatus {
|
||||
var src_file = try source_dir.openFile(source_path, .{});
|
||||
defer src_file.close();
|
||||
|
||||
const src_stat = try src_file.stat();
|
||||
const actual_mode = options.override_mode orelse src_stat.mode;
|
||||
check_dest_stat: {
|
||||
const dest_stat = blk: {
|
||||
var dest_file = dest_dir.openFile(dest_path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => break :check_dest_stat,
|
||||
else => |e| return e,
|
||||
};
|
||||
defer dest_file.close();
|
||||
|
||||
break :blk try dest_file.stat();
|
||||
};
|
||||
|
||||
if (src_stat.size == dest_stat.size and
|
||||
src_stat.mtime == dest_stat.mtime and
|
||||
actual_mode == dest_stat.mode)
|
||||
{
|
||||
return PrevStatus.fresh;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs.path.dirname(dest_path)) |dirname| {
|
||||
try dest_dir.makePath(dirname);
|
||||
}
|
||||
|
||||
var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available.
|
||||
var atomic_file = try dest_dir.atomicFile(dest_path, .{
|
||||
.mode = actual_mode,
|
||||
.write_buffer = &buffer,
|
||||
});
|
||||
defer atomic_file.deinit();
|
||||
|
||||
var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size);
|
||||
const dest_writer = &atomic_file.file_writer.interface;
|
||||
|
||||
_ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) {
|
||||
error.ReadFailed => return src_reader.err.?,
|
||||
error.WriteFailed => return atomic_file.file_writer.err.?,
|
||||
};
|
||||
try atomic_file.flush();
|
||||
try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime);
|
||||
try atomic_file.renameIntoPlace();
|
||||
return .stale;
|
||||
}
|
||||
|
||||
pub const CopyFileError = File.OpenError || File.StatError ||
|
||||
AtomicFile.InitError || AtomicFile.FinishError ||
|
||||
File.ReadError || File.WriteError;
|
||||
|
|
|
|||
|
|
@ -1144,13 +1144,7 @@ pub const Reader = struct {
|
|||
fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
|
||||
const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
|
||||
switch (r.mode) {
|
||||
.positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) {
|
||||
error.Unimplemented => {
|
||||
r.mode = r.mode.toReading();
|
||||
return 0;
|
||||
},
|
||||
else => |e| return e,
|
||||
},
|
||||
.positional, .streaming => @panic("TODO"),
|
||||
.positional_reading => {
|
||||
const dest = limit.slice(try w.writableSliceGreedy(1));
|
||||
var data: [1][]u8 = .{dest};
|
||||
|
|
|
|||
|
|
@ -939,7 +939,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
|
|||
}
|
||||
}
|
||||
|
||||
pub const PReadError = std.Io.ReadPositionalError;
|
||||
pub const PReadError = std.Io.File.ReadPositionalError;
|
||||
|
||||
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
|
||||
///
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue