mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std.Io: implement dirOpenFile
This commit is contained in:
parent
8a1e6c8c39
commit
b1733b7bce
5 changed files with 140 additions and 229 deletions
|
|
@ -657,9 +657,9 @@ pub const VTable = struct {
|
|||
dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void,
|
||||
dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat,
|
||||
dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat,
|
||||
dirCreateFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.CreateFlags) File.OpenError!File,
|
||||
dirOpenFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.OpenFlags) File.OpenError!File,
|
||||
fileStat: *const fn (?*anyopaque, File) File.StatError!File.Stat,
|
||||
createFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.CreateFlags) File.OpenError!File,
|
||||
fileOpen: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.OpenFlags) File.OpenError!File,
|
||||
fileClose: *const fn (?*anyopaque, File) void,
|
||||
pwrite: *const fn (?*anyopaque, File, buffer: []const u8, offset: std.posix.off_t) File.PWriteError!usize,
|
||||
/// Returns 0 on end of stream.
|
||||
|
|
|
|||
|
|
@ -39,11 +39,11 @@ pub const OpenError = error{
|
|||
} || PathNameError || Io.Cancelable || Io.UnexpectedError;
|
||||
|
||||
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);
|
||||
return io.vtable.dirOpenFile(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);
|
||||
return io.vtable.dirCreateFile(io.userdata, dir, sub_path, flags);
|
||||
}
|
||||
|
||||
pub const WriteFileOptions = struct {
|
||||
|
|
|
|||
|
|
@ -178,12 +178,12 @@ pub fn io(pool: *Pool) Io {
|
|||
.wasi => fileStatWasi,
|
||||
else => fileStatPosix,
|
||||
},
|
||||
.createFile = switch (builtin.os.tag) {
|
||||
.dirCreateFile = switch (builtin.os.tag) {
|
||||
.windows => @panic("TODO"),
|
||||
.wasi => @panic("TODO"),
|
||||
else => createFilePosix,
|
||||
else => dirCreateFilePosix,
|
||||
},
|
||||
.fileOpen = fileOpen,
|
||||
.dirOpenFile = dirOpenFile,
|
||||
.fileClose = fileClose,
|
||||
.pwrite = pwrite,
|
||||
.fileReadStreaming = fileReadStreaming,
|
||||
|
|
@ -966,8 +966,9 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.
|
|||
}
|
||||
|
||||
const have_flock = @TypeOf(posix.system.flock) != void;
|
||||
const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat;
|
||||
|
||||
fn createFilePosix(
|
||||
fn dirCreateFilePosix(
|
||||
userdata: ?*anyopaque,
|
||||
dir: Io.Dir,
|
||||
sub_path: []const u8,
|
||||
|
|
@ -1003,8 +1004,6 @@ fn createFilePosix(
|
|||
},
|
||||
};
|
||||
|
||||
const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat;
|
||||
|
||||
const fd: posix.fd_t = while (true) {
|
||||
try pool.checkCancel();
|
||||
const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
|
||||
|
|
@ -1088,24 +1087,139 @@ fn createFilePosix(
|
|||
return .{ .handle = fd };
|
||||
}
|
||||
|
||||
fn fileOpen(
|
||||
fn dirOpenFile(
|
||||
userdata: ?*anyopaque,
|
||||
dir: Io.Dir,
|
||||
sub_path: []const u8,
|
||||
flags: Io.File.OpenFlags,
|
||||
) Io.File.OpenError!Io.File {
|
||||
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
||||
|
||||
var path_buffer: [posix.PATH_MAX]u8 = undefined;
|
||||
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
|
||||
|
||||
var os_flags: posix.O = switch (native_os) {
|
||||
.wasi => .{
|
||||
.read = flags.mode != .write_only,
|
||||
.write = flags.mode != .read_only,
|
||||
},
|
||||
else => .{
|
||||
.ACCMODE = switch (flags.mode) {
|
||||
.read_only => .RDONLY,
|
||||
.write_only => .WRONLY,
|
||||
.read_write => .RDWR,
|
||||
},
|
||||
},
|
||||
};
|
||||
if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
|
||||
if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
|
||||
if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty;
|
||||
|
||||
// Use the O locking flags if the os supports them to acquire the lock
|
||||
// atomically.
|
||||
const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
|
||||
if (has_flock_open_flags) {
|
||||
// Note that the NONBLOCK flag is removed after the openat() call
|
||||
// is successful.
|
||||
switch (flags.lock) {
|
||||
.none => {},
|
||||
.shared => {
|
||||
os_flags.SHLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
.exclusive => {
|
||||
os_flags.EXLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
}
|
||||
}
|
||||
const fd: posix.fd_t = while (true) {
|
||||
try pool.checkCancel();
|
||||
const fs_dir: std.fs.Dir = .{ .fd = dir.handle };
|
||||
const fs_file = try fs_dir.openFile(sub_path, flags);
|
||||
return .{ .handle = fs_file.handle };
|
||||
const rc = openat_sym(dir.handle, sub_path_posix, os_flags, 0);
|
||||
switch (posix.errno(rc)) {
|
||||
.SUCCESS => break @intCast(rc),
|
||||
.INTR => continue,
|
||||
|
||||
.FAULT => |err| return errnoBug(err),
|
||||
.INVAL => return error.BadPathName,
|
||||
.BADF => |err| return errnoBug(err),
|
||||
.ACCES => return error.AccessDenied,
|
||||
.FBIG => return error.FileTooBig,
|
||||
.OVERFLOW => return error.FileTooBig,
|
||||
.ISDIR => return error.IsDir,
|
||||
.LOOP => return error.SymLinkLoop,
|
||||
.MFILE => return error.ProcessFdQuotaExceeded,
|
||||
.NAMETOOLONG => return error.NameTooLong,
|
||||
.NFILE => return error.SystemFdQuotaExceeded,
|
||||
.NODEV => return error.NoDevice,
|
||||
.NOENT => return error.FileNotFound,
|
||||
.SRCH => return error.ProcessNotFound,
|
||||
.NOMEM => return error.SystemResources,
|
||||
.NOSPC => return error.NoSpaceLeft,
|
||||
.NOTDIR => return error.NotDir,
|
||||
.PERM => return error.PermissionDenied,
|
||||
.EXIST => return error.PathAlreadyExists,
|
||||
.BUSY => return error.DeviceBusy,
|
||||
.OPNOTSUPP => return error.FileLocksNotSupported,
|
||||
//.AGAIN => return error.WouldBlock,
|
||||
.TXTBSY => return error.FileBusy,
|
||||
.NXIO => return error.NoDevice,
|
||||
.ILSEQ => return error.BadPathName,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
};
|
||||
errdefer posix.close(fd);
|
||||
|
||||
if (have_flock and !has_flock_open_flags and flags.lock != .none) {
|
||||
const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
|
||||
const lock_flags = switch (flags.lock) {
|
||||
.none => unreachable,
|
||||
.shared => posix.LOCK.SH | lock_nonblocking,
|
||||
.exclusive => posix.LOCK.EX | lock_nonblocking,
|
||||
};
|
||||
while (true) {
|
||||
try pool.checkCancel();
|
||||
switch (posix.errno(posix.system.flock(fd, lock_flags))) {
|
||||
.SUCCESS => break,
|
||||
.INTR => continue,
|
||||
|
||||
.BADF => |err| return errnoBug(err),
|
||||
.INVAL => |err| return errnoBug(err), // invalid parameters
|
||||
.NOLCK => return error.SystemResources,
|
||||
//.AGAIN => return error.WouldBlock,
|
||||
.OPNOTSUPP => return error.FileLocksNotSupported,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_flock_open_flags and flags.lock_nonblocking) {
|
||||
var fl_flags: usize = while (true) {
|
||||
try pool.checkCancel();
|
||||
switch (posix.errno(posix.system.fcntl(fd, posix.F.GETFL, 0))) {
|
||||
.SUCCESS => break,
|
||||
.INTR => continue,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
};
|
||||
fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
|
||||
while (true) {
|
||||
try pool.checkCancel();
|
||||
switch (posix.errno(posix.fcntl(fd, posix.F.SETFL, fl_flags))) {
|
||||
.SUCCESS => break,
|
||||
.INTR => continue,
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .{ .handle = fd };
|
||||
}
|
||||
|
||||
fn fileClose(userdata: ?*anyopaque, file: Io.File) void {
|
||||
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
||||
_ = pool;
|
||||
const fs_file: std.fs.File = .{ .handle = file.handle };
|
||||
return fs_file.close();
|
||||
posix.close(file.handle);
|
||||
}
|
||||
|
||||
fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.ReadStreamingError!usize {
|
||||
|
|
|
|||
|
|
@ -260,12 +260,6 @@ pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.O
|
|||
return cwd().openFile(absolute_path, flags);
|
||||
}
|
||||
|
||||
/// Same as `openFileAbsolute` but the path parameter is null-terminated.
|
||||
pub fn openFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
assert(path.isAbsoluteZ(absolute_path_c));
|
||||
return cwd().openFileZ(absolute_path_c, flags);
|
||||
}
|
||||
|
||||
/// Same as `openFileAbsolute` but the path parameter is WTF-16-encoded.
|
||||
pub fn openFileAbsoluteW(absolute_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File {
|
||||
assert(path.isAbsoluteWindowsWTF16(absolute_path_w));
|
||||
|
|
@ -284,11 +278,6 @@ pub fn accessAbsolute(absolute_path: []const u8, flags: File.OpenFlags) Dir.Acce
|
|||
assert(path.isAbsolute(absolute_path));
|
||||
try cwd().access(absolute_path, flags);
|
||||
}
|
||||
/// Same as `accessAbsolute` but the path parameter is null-terminated.
|
||||
pub fn accessAbsoluteZ(absolute_path: [*:0]const u8, flags: File.OpenFlags) Dir.AccessError!void {
|
||||
assert(path.isAbsoluteZ(absolute_path));
|
||||
try cwd().accessZ(absolute_path, flags);
|
||||
}
|
||||
/// Same as `accessAbsolute` but the path parameter is WTF-16 encoded.
|
||||
pub fn accessAbsoluteW(absolute_path: [*:0]const u16, flags: File.OpenFlags) Dir.AccessError!void {
|
||||
assert(path.isAbsoluteWindowsW(absolute_path));
|
||||
|
|
@ -309,12 +298,6 @@ pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) Fi
|
|||
return cwd().createFile(absolute_path, flags);
|
||||
}
|
||||
|
||||
/// Same as `createFileAbsolute` but the path parameter is null-terminated.
|
||||
pub fn createFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
assert(path.isAbsoluteZ(absolute_path_c));
|
||||
return cwd().createFileZ(absolute_path_c, flags);
|
||||
}
|
||||
|
||||
/// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded.
|
||||
pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File {
|
||||
assert(path.isAbsoluteWindowsW(absolute_path_w));
|
||||
|
|
@ -333,12 +316,6 @@ pub fn deleteFileAbsolute(absolute_path: []const u8) Dir.DeleteFileError!void {
|
|||
return cwd().deleteFile(absolute_path);
|
||||
}
|
||||
|
||||
/// Same as `deleteFileAbsolute` except the parameter is null-terminated.
|
||||
pub fn deleteFileAbsoluteZ(absolute_path_c: [*:0]const u8) Dir.DeleteFileError!void {
|
||||
assert(path.isAbsoluteZ(absolute_path_c));
|
||||
return cwd().deleteFileZ(absolute_path_c);
|
||||
}
|
||||
|
||||
/// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded.
|
||||
pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) Dir.DeleteFileError!void {
|
||||
assert(path.isAbsoluteWindowsW(absolute_path_w));
|
||||
|
|
@ -383,12 +360,6 @@ pub fn readlinkAbsoluteW(pathname_w: [*:0]const u16, buffer: *[max_path_bytes]u8
|
|||
return posix.readlinkW(mem.span(pathname_w), buffer);
|
||||
}
|
||||
|
||||
/// Same as `readLink`, except the path parameter is null-terminated.
|
||||
pub fn readLinkAbsoluteZ(pathname_c: [*:0]const u8, buffer: *[max_path_bytes]u8) ![]u8 {
|
||||
assert(path.isAbsoluteZ(pathname_c));
|
||||
return posix.readlinkZ(pathname_c, buffer);
|
||||
}
|
||||
|
||||
/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
|
||||
/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
|
||||
/// one; the latter case is known as a dangling link.
|
||||
|
|
@ -426,28 +397,11 @@ pub fn symLinkAbsoluteW(
|
|||
return windows.CreateSymbolicLink(null, mem.span(sym_link_path_w), mem.span(target_path_w), flags.is_directory);
|
||||
}
|
||||
|
||||
/// Same as `symLinkAbsolute` except the parameters are null-terminated pointers.
|
||||
/// See also `symLinkAbsolute`.
|
||||
pub fn symLinkAbsoluteZ(
|
||||
target_path_c: [*:0]const u8,
|
||||
sym_link_path_c: [*:0]const u8,
|
||||
flags: Dir.SymLinkFlags,
|
||||
) !void {
|
||||
assert(path.isAbsoluteZ(target_path_c));
|
||||
assert(path.isAbsoluteZ(sym_link_path_c));
|
||||
if (native_os == .windows) {
|
||||
const target_path_w = try windows.cStrToPrefixedFileW(null, target_path_c);
|
||||
const sym_link_path_w = try windows.cStrToPrefixedFileW(null, sym_link_path_c);
|
||||
return windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
|
||||
}
|
||||
return posix.symlinkZ(target_path_c, sym_link_path_c);
|
||||
}
|
||||
|
||||
pub const OpenSelfExeError = posix.OpenError || SelfExePathError || posix.FlockError;
|
||||
|
||||
pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
||||
if (native_os == .linux or native_os == .serenity) {
|
||||
return openFileAbsoluteZ("/proc/self/exe", flags);
|
||||
return openFileAbsolute("/proc/self/exe", flags);
|
||||
}
|
||||
if (native_os == .windows) {
|
||||
// If ImagePathName is a symlink, then it will contain the path of the symlink,
|
||||
|
|
@ -463,7 +417,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
|||
var buf: [max_path_bytes]u8 = undefined;
|
||||
const self_exe_path = try selfExePath(&buf);
|
||||
buf[self_exe_path.len] = 0;
|
||||
return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags);
|
||||
return openFileAbsolute(buf[0..self_exe_path.len :0], flags);
|
||||
}
|
||||
|
||||
// This is `posix.ReadLinkError || posix.RealPathError` with impossible errors excluded
|
||||
|
|
|
|||
|
|
@ -885,94 +885,9 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
|
|||
const fd = try posix.openatWasi(self.fd, sub_path, .{}, .{}, .{}, base, .{});
|
||||
return .{ .handle = fd };
|
||||
}
|
||||
const path_c = try posix.toPosixPath(sub_path);
|
||||
return self.openFileZ(&path_c, flags);
|
||||
}
|
||||
|
||||
/// Same as `openFile` but the path parameter is null-terminated.
|
||||
pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
switch (native_os) {
|
||||
.windows => {
|
||||
const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openFileW(path_w.span(), flags);
|
||||
},
|
||||
// Use the libc API when libc is linked because it implements things
|
||||
// such as opening absolute file paths.
|
||||
.wasi => if (!builtin.link_libc) {
|
||||
return openFile(self, mem.sliceTo(sub_path, 0), flags);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
var os_flags: posix.O = switch (native_os) {
|
||||
.wasi => .{
|
||||
.read = flags.mode != .write_only,
|
||||
.write = flags.mode != .read_only,
|
||||
},
|
||||
else => .{
|
||||
.ACCMODE = switch (flags.mode) {
|
||||
.read_only => .RDONLY,
|
||||
.write_only => .WRONLY,
|
||||
.read_write => .RDWR,
|
||||
},
|
||||
},
|
||||
};
|
||||
if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
|
||||
if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
|
||||
if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty;
|
||||
|
||||
// Use the O locking flags if the os supports them to acquire the lock
|
||||
// atomically.
|
||||
const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
|
||||
if (has_flock_open_flags) {
|
||||
// Note that the NONBLOCK flag is removed after the openat() call
|
||||
// is successful.
|
||||
switch (flags.lock) {
|
||||
.none => {},
|
||||
.shared => {
|
||||
os_flags.SHLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
.exclusive => {
|
||||
os_flags.EXLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
}
|
||||
}
|
||||
const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0);
|
||||
errdefer posix.close(fd);
|
||||
|
||||
if (have_flock and !has_flock_open_flags and flags.lock != .none) {
|
||||
// TODO: integrate async I/O
|
||||
const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
|
||||
try posix.flock(fd, switch (flags.lock) {
|
||||
.none => unreachable,
|
||||
.shared => posix.LOCK.SH | lock_nonblocking,
|
||||
.exclusive => posix.LOCK.EX | lock_nonblocking,
|
||||
});
|
||||
}
|
||||
|
||||
if (has_flock_open_flags and flags.lock_nonblocking) {
|
||||
var fl_flags = posix.fcntl(fd, posix.F.GETFL, 0) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
error.PermissionDenied => unreachable,
|
||||
error.DeadLock => unreachable,
|
||||
error.LockedRegionLimitExceeded => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
|
||||
_ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
error.PermissionDenied => unreachable,
|
||||
error.DeadLock => unreachable,
|
||||
error.LockedRegionLimitExceeded => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
return .{ .handle = fd };
|
||||
var threaded: Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
return .adaptFromNewApi(try Io.Dir.openFile(self.adaptToNewApi(), io, sub_path, flags));
|
||||
}
|
||||
|
||||
/// Same as `openFile` but Windows-only and the path parameter is
|
||||
|
|
@ -1048,82 +963,10 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File
|
|||
}, .{}),
|
||||
};
|
||||
}
|
||||
const path_c = try posix.toPosixPath(sub_path);
|
||||
return self.createFileZ(&path_c, flags);
|
||||
}
|
||||
|
||||
/// Same as `createFile` but the path parameter is null-terminated.
|
||||
pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
switch (native_os) {
|
||||
.windows => {
|
||||
const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||
return self.createFileW(path_w.span(), flags);
|
||||
},
|
||||
.wasi => {
|
||||
return createFile(self, mem.sliceTo(sub_path_c, 0), flags);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
var os_flags: posix.O = .{
|
||||
.ACCMODE = if (flags.read) .RDWR else .WRONLY,
|
||||
.CREAT = true,
|
||||
.TRUNC = flags.truncate,
|
||||
.EXCL = flags.exclusive,
|
||||
};
|
||||
if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
|
||||
if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
|
||||
|
||||
// Use the O locking flags if the os supports them to acquire the lock
|
||||
// atomically. Note that the NONBLOCK flag is removed after the openat()
|
||||
// call is successful.
|
||||
const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
|
||||
if (has_flock_open_flags) switch (flags.lock) {
|
||||
.none => {},
|
||||
.shared => {
|
||||
os_flags.SHLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
.exclusive => {
|
||||
os_flags.EXLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
};
|
||||
|
||||
const fd = try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode);
|
||||
errdefer posix.close(fd);
|
||||
|
||||
if (have_flock and !has_flock_open_flags and flags.lock != .none) {
|
||||
// TODO: integrate async I/O
|
||||
const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
|
||||
try posix.flock(fd, switch (flags.lock) {
|
||||
.none => unreachable,
|
||||
.shared => posix.LOCK.SH | lock_nonblocking,
|
||||
.exclusive => posix.LOCK.EX | lock_nonblocking,
|
||||
});
|
||||
}
|
||||
|
||||
if (has_flock_open_flags and flags.lock_nonblocking) {
|
||||
var fl_flags = posix.fcntl(fd, posix.F.GETFL, 0) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
error.PermissionDenied => unreachable,
|
||||
error.DeadLock => unreachable,
|
||||
error.LockedRegionLimitExceeded => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
|
||||
_ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
error.PermissionDenied => unreachable,
|
||||
error.DeadLock => unreachable,
|
||||
error.LockedRegionLimitExceeded => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
return .{ .handle = fd };
|
||||
var threaded: Io.Threaded = .init_single_threaded;
|
||||
const io = threaded.io();
|
||||
const new_file = try Io.Dir.createFile(self.adaptToNewApi(), io, sub_path, flags);
|
||||
return .adaptFromNewApi(new_file);
|
||||
}
|
||||
|
||||
/// Same as `createFile` but Windows-only and the path parameter is
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue