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,
|
dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void,
|
||||||
dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat,
|
dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat,
|
||||||
dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.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,
|
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,
|
fileClose: *const fn (?*anyopaque, File) void,
|
||||||
pwrite: *const fn (?*anyopaque, File, buffer: []const u8, offset: std.posix.off_t) File.PWriteError!usize,
|
pwrite: *const fn (?*anyopaque, File, buffer: []const u8, offset: std.posix.off_t) File.PWriteError!usize,
|
||||||
/// Returns 0 on end of stream.
|
/// Returns 0 on end of stream.
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,11 @@ pub const OpenError = error{
|
||||||
} || PathNameError || Io.Cancelable || Io.UnexpectedError;
|
} || PathNameError || Io.Cancelable || Io.UnexpectedError;
|
||||||
|
|
||||||
pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
|
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 {
|
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 {
|
pub const WriteFileOptions = struct {
|
||||||
|
|
|
||||||
|
|
@ -178,12 +178,12 @@ pub fn io(pool: *Pool) Io {
|
||||||
.wasi => fileStatWasi,
|
.wasi => fileStatWasi,
|
||||||
else => fileStatPosix,
|
else => fileStatPosix,
|
||||||
},
|
},
|
||||||
.createFile = switch (builtin.os.tag) {
|
.dirCreateFile = switch (builtin.os.tag) {
|
||||||
.windows => @panic("TODO"),
|
.windows => @panic("TODO"),
|
||||||
.wasi => @panic("TODO"),
|
.wasi => @panic("TODO"),
|
||||||
else => createFilePosix,
|
else => dirCreateFilePosix,
|
||||||
},
|
},
|
||||||
.fileOpen = fileOpen,
|
.dirOpenFile = dirOpenFile,
|
||||||
.fileClose = fileClose,
|
.fileClose = fileClose,
|
||||||
.pwrite = pwrite,
|
.pwrite = pwrite,
|
||||||
.fileReadStreaming = fileReadStreaming,
|
.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 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,
|
userdata: ?*anyopaque,
|
||||||
dir: Io.Dir,
|
dir: Io.Dir,
|
||||||
sub_path: []const u8,
|
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) {
|
const fd: posix.fd_t = while (true) {
|
||||||
try pool.checkCancel();
|
try pool.checkCancel();
|
||||||
const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
|
const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode);
|
||||||
|
|
@ -1088,24 +1087,139 @@ fn createFilePosix(
|
||||||
return .{ .handle = fd };
|
return .{ .handle = fd };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fileOpen(
|
fn dirOpenFile(
|
||||||
userdata: ?*anyopaque,
|
userdata: ?*anyopaque,
|
||||||
dir: Io.Dir,
|
dir: Io.Dir,
|
||||||
sub_path: []const u8,
|
sub_path: []const u8,
|
||||||
flags: Io.File.OpenFlags,
|
flags: Io.File.OpenFlags,
|
||||||
) Io.File.OpenError!Io.File {
|
) Io.File.OpenError!Io.File {
|
||||||
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
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();
|
try pool.checkCancel();
|
||||||
const fs_dir: std.fs.Dir = .{ .fd = dir.handle };
|
const rc = openat_sym(dir.handle, sub_path_posix, os_flags, 0);
|
||||||
const fs_file = try fs_dir.openFile(sub_path, flags);
|
switch (posix.errno(rc)) {
|
||||||
return .{ .handle = fs_file.handle };
|
.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 {
|
fn fileClose(userdata: ?*anyopaque, file: Io.File) void {
|
||||||
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
const pool: *Pool = @ptrCast(@alignCast(userdata));
|
||||||
_ = pool;
|
_ = pool;
|
||||||
const fs_file: std.fs.File = .{ .handle = file.handle };
|
posix.close(file.handle);
|
||||||
return fs_file.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.ReadStreamingError!usize {
|
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);
|
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.
|
/// 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 {
|
pub fn openFileAbsoluteW(absolute_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File {
|
||||||
assert(path.isAbsoluteWindowsWTF16(absolute_path_w));
|
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));
|
assert(path.isAbsolute(absolute_path));
|
||||||
try cwd().access(absolute_path, flags);
|
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.
|
/// 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 {
|
pub fn accessAbsoluteW(absolute_path: [*:0]const u16, flags: File.OpenFlags) Dir.AccessError!void {
|
||||||
assert(path.isAbsoluteWindowsW(absolute_path));
|
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);
|
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.
|
/// 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 {
|
pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File {
|
||||||
assert(path.isAbsoluteWindowsW(absolute_path_w));
|
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);
|
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.
|
/// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded.
|
||||||
pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) Dir.DeleteFileError!void {
|
pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) Dir.DeleteFileError!void {
|
||||||
assert(path.isAbsoluteWindowsW(absolute_path_w));
|
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);
|
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`.
|
/// 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
|
/// 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.
|
/// 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);
|
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 const OpenSelfExeError = posix.OpenError || SelfExePathError || posix.FlockError;
|
||||||
|
|
||||||
pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
||||||
if (native_os == .linux or native_os == .serenity) {
|
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 (native_os == .windows) {
|
||||||
// If ImagePathName is a symlink, then it will contain the path of the symlink,
|
// 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;
|
var buf: [max_path_bytes]u8 = undefined;
|
||||||
const self_exe_path = try selfExePath(&buf);
|
const self_exe_path = try selfExePath(&buf);
|
||||||
buf[self_exe_path.len] = 0;
|
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
|
// 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, .{});
|
const fd = try posix.openatWasi(self.fd, sub_path, .{}, .{}, .{}, base, .{});
|
||||||
return .{ .handle = fd };
|
return .{ .handle = fd };
|
||||||
}
|
}
|
||||||
const path_c = try posix.toPosixPath(sub_path);
|
var threaded: Io.Threaded = .init_single_threaded;
|
||||||
return self.openFileZ(&path_c, flags);
|
const io = threaded.io();
|
||||||
}
|
return .adaptFromNewApi(try Io.Dir.openFile(self.adaptToNewApi(), io, sub_path, 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 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `openFile` but Windows-only and the path parameter is
|
/// 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);
|
var threaded: Io.Threaded = .init_single_threaded;
|
||||||
return self.createFileZ(&path_c, flags);
|
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 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 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `createFile` but Windows-only and the path parameter is
|
/// Same as `createFile` but Windows-only and the path parameter is
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue