feature. See also
. The project being documented here (as the example) is the Zig library itself.
Uring.dirCreateFileAtomic
fn dirCreateFileAtomic(
userdata: ?*anyopaque,
dir: Dir,
dest_path: []const u8,
options: Dir.CreateFileAtomicOptions,
) Dir.CreateFileAtomicError!File.Atomic
File
Code
fn dirCreateFileAtomic(
userdata: ?*anyopaque,
dir: Dir,
dest_path: []const u8,
options: Dir.CreateFileAtomicOptions,
) Dir.CreateFileAtomicError!File.Atomic {
const ev: *Evented = @ptrCast(@alignCast(userdata));
// useless when we have to make up a bogus path name to do the rename()
// anyway.
if (!options.replace) tmpfile: {
const flags: linux.O = if (@hasField(linux.O, "TMPFILE")) .{
.ACCMODE = .RDWR,
.TMPFILE = true,
.DIRECTORY = true,
.CLOEXEC = true,
} else if (@hasField(linux.O, "TMPFILE0") and !@hasField(linux.O, "TMPFILE2")) .{
.ACCMODE = .RDWR,
.TMPFILE0 = true,
.TMPFILE1 = true,
.DIRECTORY = true,
.CLOEXEC = true,
} else break :tmpfile;
const dest_dirname = Dir.path.dirname(dest_path);
if (dest_dirname) |dirname| {
// ENOENT, avoiding the ambiguity below.
_ = dirCreateDirPath(ev, dir, dirname, .default_dir) catch |err| switch (err) {
error.IsDir,
error.Streaming,
error.DiskQuota,
error.PathAlreadyExists,
error.LinkQuotaExceeded,
error.PipeBusy,
error.FileTooBig,
error.DeviceBusy,
error.FileLocksUnsupported,
error.FileBusy,
=> return error.Unexpected,
else => |e| return e,
};
}
var path_buffer: [PATH_MAX]u8 = undefined;
const sub_path_posix = try pathToPosix(dest_dirname orelse ".", &path_buffer);
var cancel_region: CancelRegion = .init();
defer cancel_region.deinit();
return .{
.file = .{
.handle = ev.openat(
&cancel_region,
dir.handle,
sub_path_posix,
flags,
options.permissions.toMode(),
) catch |err| switch (err) {
error.IsDir, error.FileNotFound, error.OperationUnsupported => {
// does not support O_TMPFILE. Therefore, we must fall
// back to not using O_TMPFILE.
break :tmpfile;
},
error.FileTooBig => return errnoBug(.FBIG),
error.DeviceBusy => return errnoBug(.BUSY),
error.PathAlreadyExists => return errnoBug(.EXIST),
else => |e| return e,
},
.flags = .{ .nonblocking = false },
},
.file_basename_hex = 0,
.dest_sub_path = dest_path,
.file_open = true,
.file_exists = false,
.close_dir_on_deinit = false,
.dir = dir,
};
}
if (Dir.path.dirname(dest_path)) |dirname| {
const new_dir = if (options.make_path)
dirCreateDirPathOpen(ev, dir, dirname, .default_dir, .{}) catch |err| switch (err) {
error.IsDir,
error.Streaming,
error.DiskQuota,
error.PathAlreadyExists,
error.LinkQuotaExceeded,
error.PipeBusy,
error.FileTooBig,
error.FileLocksUnsupported,
error.DeviceBusy,
=> return error.Unexpected,
else => |e| return e,
}
else
try dirOpenDir(ev, dir, dirname, .{});
return ev.atomicFileInit(Dir.path.basename(dest_path), options.permissions, new_dir, true);
}
return ev.atomicFileInit(dest_path, options.permissions, dir, false);
}