mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
113 lines
3.9 KiB
Zig
113 lines
3.9 KiB
Zig
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;
|
|
}
|