| author | |
| committer | |
| log | b1733b7bcec44ddd73a210ede09c3c9eeb411d27 |
| tree | 2d60aeac5fd30893103c1f6e852ce4a46314318e |
| parent | 8a1e6c8c394058a25cb21f60ad414f28cd37db22 |
5 files changed, 140 insertions(+), 229 deletions(-)
lib/std/Io.zig+2-2| ... | @@ -657,9 +657,9 @@ pub const VTable = struct { | ... | @@ -657,9 +657,9 @@ pub const VTable = struct { |
| 657 | dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void, | 657 | dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, mode: Dir.Mode) Dir.MakeError!void, |
| 658 | dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat, | 658 | dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat, |
| 659 | dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat, | 659 | dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat, |
| 660 | dirCreateFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.CreateFlags) File.OpenError!File, | ||
| 661 | dirOpenFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.OpenFlags) File.OpenError!File, | ||
| 660 | fileStat: *const fn (?*anyopaque, File) File.StatError!File.Stat, | 662 | fileStat: *const fn (?*anyopaque, File) File.StatError!File.Stat, |
| 661 | createFile: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.CreateFlags) File.OpenError!File, | ||
| 662 | fileOpen: *const fn (?*anyopaque, Dir, sub_path: []const u8, File.OpenFlags) File.OpenError!File, | ||
| 663 | fileClose: *const fn (?*anyopaque, File) void, | 663 | fileClose: *const fn (?*anyopaque, File) void, |
| 664 | pwrite: *const fn (?*anyopaque, File, buffer: []const u8, offset: std.posix.off_t) File.PWriteError!usize, | 664 | pwrite: *const fn (?*anyopaque, File, buffer: []const u8, offset: std.posix.off_t) File.PWriteError!usize, |
| 665 | /// Returns 0 on end of stream. | 665 | /// Returns 0 on end of stream. |
lib/std/Io/Dir.zig+2-2| ... | @@ -39,11 +39,11 @@ pub const OpenError = error{ | ... | @@ -39,11 +39,11 @@ pub const OpenError = error{ |
| 39 | } || PathNameError || Io.Cancelable || Io.UnexpectedError; | 39 | } || PathNameError || Io.Cancelable || Io.UnexpectedError; |
| 40 | 40 | ||
| 41 | pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | 41 | pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { |
| 42 | return io.vtable.fileOpen(io.userdata, dir, sub_path, flags); | 42 | return io.vtable.dirOpenFile(io.userdata, dir, sub_path, flags); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | 45 | pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { |
| 46 | return io.vtable.createFile(io.userdata, dir, sub_path, flags); | 46 | return io.vtable.dirCreateFile(io.userdata, dir, sub_path, flags); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | pub const WriteFileOptions = struct { | 49 | pub const WriteFileOptions = struct { |
lib/std/Io/Threaded.zig+127-13| ... | @@ -178,12 +178,12 @@ pub fn io(pool: *Pool) Io { | ... | @@ -178,12 +178,12 @@ pub fn io(pool: *Pool) Io { |
| 178 | .wasi => fileStatWasi, | 178 | .wasi => fileStatWasi, |
| 179 | else => fileStatPosix, | 179 | else => fileStatPosix, |
| 180 | }, | 180 | }, |
| 181 | .createFile = switch (builtin.os.tag) { | 181 | .dirCreateFile = switch (builtin.os.tag) { |
| 182 | .windows => @panic("TODO"), | 182 | .windows => @panic("TODO"), |
| 183 | .wasi => @panic("TODO"), | 183 | .wasi => @panic("TODO"), |
| 184 | else => createFilePosix, | 184 | else => dirCreateFilePosix, |
| 185 | }, | 185 | }, |
| 186 | .fileOpen = fileOpen, | 186 | .dirOpenFile = dirOpenFile, |
| 187 | .fileClose = fileClose, | 187 | .fileClose = fileClose, |
| 188 | .pwrite = pwrite, | 188 | .pwrite = pwrite, |
| 189 | .fileReadStreaming = fileReadStreaming, | 189 | .fileReadStreaming = fileReadStreaming, |
| ... | @@ -966,8 +966,9 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. | ... | @@ -966,8 +966,9 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. |
| 966 | } | 966 | } |
| 967 | 967 | ||
| 968 | const have_flock = @TypeOf(posix.system.flock) != void; | 968 | const have_flock = @TypeOf(posix.system.flock) != void; |
| 969 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; | ||
| 969 | 970 | ||
| 970 | fn createFilePosix( | 971 | fn dirCreateFilePosix( |
| 971 | userdata: ?*anyopaque, | 972 | userdata: ?*anyopaque, |
| 972 | dir: Io.Dir, | 973 | dir: Io.Dir, |
| 973 | sub_path: []const u8, | 974 | sub_path: []const u8, |
| ... | @@ -1003,8 +1004,6 @@ fn createFilePosix( | ... | @@ -1003,8 +1004,6 @@ fn createFilePosix( |
| 1003 | }, | 1004 | }, |
| 1004 | }; | 1005 | }; |
| 1005 | 1006 | ||
| 1006 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; | ||
| 1007 | |||
| 1008 | const fd: posix.fd_t = while (true) { | 1007 | const fd: posix.fd_t = while (true) { |
| 1009 | try pool.checkCancel(); | 1008 | try pool.checkCancel(); |
| 1010 | const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode); | 1009 | const rc = openat_sym(dir.handle, sub_path_posix, os_flags, flags.mode); |
| ... | @@ -1088,24 +1087,139 @@ fn createFilePosix( | ... | @@ -1088,24 +1087,139 @@ fn createFilePosix( |
| 1088 | return .{ .handle = fd }; | 1087 | return .{ .handle = fd }; |
| 1089 | } | 1088 | } |
| 1090 | 1089 | ||
| 1091 | fn fileOpen( | 1090 | fn dirOpenFile( |
| 1092 | userdata: ?*anyopaque, | 1091 | userdata: ?*anyopaque, |
| 1093 | dir: Io.Dir, | 1092 | dir: Io.Dir, |
| 1094 | sub_path: []const u8, | 1093 | sub_path: []const u8, |
| 1095 | flags: Io.File.OpenFlags, | 1094 | flags: Io.File.OpenFlags, |
| 1096 | ) Io.File.OpenError!Io.File { | 1095 | ) Io.File.OpenError!Io.File { |
| 1097 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1096 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1098 | try pool.checkCancel(); | 1097 | |
| 1099 | const fs_dir: std.fs.Dir = .{ .fd = dir.handle }; | 1098 | var path_buffer: [posix.PATH_MAX]u8 = undefined; |
| 1100 | const fs_file = try fs_dir.openFile(sub_path, flags); | 1099 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 1101 | return .{ .handle = fs_file.handle }; | 1100 | |
| 1101 | var os_flags: posix.O = switch (native_os) { | ||
| 1102 | .wasi => .{ | ||
| 1103 | .read = flags.mode != .write_only, | ||
| 1104 | .write = flags.mode != .read_only, | ||
| 1105 | }, | ||
| 1106 | else => .{ | ||
| 1107 | .ACCMODE = switch (flags.mode) { | ||
| 1108 | .read_only => .RDONLY, | ||
| 1109 | .write_only => .WRONLY, | ||
| 1110 | .read_write => .RDWR, | ||
| 1111 | }, | ||
| 1112 | }, | ||
| 1113 | }; | ||
| 1114 | if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true; | ||
| 1115 | if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true; | ||
| 1116 | if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty; | ||
| 1117 | |||
| 1118 | // Use the O locking flags if the os supports them to acquire the lock | ||
| 1119 | // atomically. | ||
| 1120 | const has_flock_open_flags = @hasField(posix.O, "EXLOCK"); | ||
| 1121 | if (has_flock_open_flags) { | ||
| 1122 | // Note that the NONBLOCK flag is removed after the openat() call | ||
| 1123 | // is successful. | ||
| 1124 | switch (flags.lock) { | ||
| 1125 | .none => {}, | ||
| 1126 | .shared => { | ||
| 1127 | os_flags.SHLOCK = true; | ||
| 1128 | os_flags.NONBLOCK = flags.lock_nonblocking; | ||
| 1129 | }, | ||
| 1130 | .exclusive => { | ||
| 1131 | os_flags.EXLOCK = true; | ||
| 1132 | os_flags.NONBLOCK = flags.lock_nonblocking; | ||
| 1133 | }, | ||
| 1134 | } | ||
| 1135 | } | ||
| 1136 | const fd: posix.fd_t = while (true) { | ||
| 1137 | try pool.checkCancel(); | ||
| 1138 | const rc = openat_sym(dir.handle, sub_path_posix, os_flags, 0); | ||
| 1139 | switch (posix.errno(rc)) { | ||
| 1140 | .SUCCESS => break @intCast(rc), | ||
| 1141 | .INTR => continue, | ||
| 1142 | |||
| 1143 | .FAULT => |err| return errnoBug(err), | ||
| 1144 | .INVAL => return error.BadPathName, | ||
| 1145 | .BADF => |err| return errnoBug(err), | ||
| 1146 | .ACCES => return error.AccessDenied, | ||
| 1147 | .FBIG => return error.FileTooBig, | ||
| 1148 | .OVERFLOW => return error.FileTooBig, | ||
| 1149 | .ISDIR => return error.IsDir, | ||
| 1150 | .LOOP => return error.SymLinkLoop, | ||
| 1151 | .MFILE => return error.ProcessFdQuotaExceeded, | ||
| 1152 | .NAMETOOLONG => return error.NameTooLong, | ||
| 1153 | .NFILE => return error.SystemFdQuotaExceeded, | ||
| 1154 | .NODEV => return error.NoDevice, | ||
| 1155 | .NOENT => return error.FileNotFound, | ||
| 1156 | .SRCH => return error.ProcessNotFound, | ||
| 1157 | .NOMEM => return error.SystemResources, | ||
| 1158 | .NOSPC => return error.NoSpaceLeft, | ||
| 1159 | .NOTDIR => return error.NotDir, | ||
| 1160 | .PERM => return error.PermissionDenied, | ||
| 1161 | .EXIST => return error.PathAlreadyExists, | ||
| 1162 | .BUSY => return error.DeviceBusy, | ||
| 1163 | .OPNOTSUPP => return error.FileLocksNotSupported, | ||
| 1164 | //.AGAIN => return error.WouldBlock, | ||
| 1165 | .TXTBSY => return error.FileBusy, | ||
| 1166 | .NXIO => return error.NoDevice, | ||
| 1167 | .ILSEQ => return error.BadPathName, | ||
| 1168 | else => |err| return posix.unexpectedErrno(err), | ||
| 1169 | } | ||
| 1170 | }; | ||
| 1171 | errdefer posix.close(fd); | ||
| 1172 | |||
| 1173 | if (have_flock and !has_flock_open_flags and flags.lock != .none) { | ||
| 1174 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; | ||
| 1175 | const lock_flags = switch (flags.lock) { | ||
| 1176 | .none => unreachable, | ||
| 1177 | .shared => posix.LOCK.SH | lock_nonblocking, | ||
| 1178 | .exclusive => posix.LOCK.EX | lock_nonblocking, | ||
| 1179 | }; | ||
| 1180 | while (true) { | ||
| 1181 | try pool.checkCancel(); | ||
| 1182 | switch (posix.errno(posix.system.flock(fd, lock_flags))) { | ||
| 1183 | .SUCCESS => break, | ||
| 1184 | .INTR => continue, | ||
| 1185 | |||
| 1186 | .BADF => |err| return errnoBug(err), | ||
| 1187 | .INVAL => |err| return errnoBug(err), // invalid parameters | ||
| 1188 | .NOLCK => return error.SystemResources, | ||
| 1189 | //.AGAIN => return error.WouldBlock, | ||
| 1190 | .OPNOTSUPP => return error.FileLocksNotSupported, | ||
| 1191 | else => |err| return posix.unexpectedErrno(err), | ||
| 1192 | } | ||
| 1193 | } | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | if (has_flock_open_flags and flags.lock_nonblocking) { | ||
| 1197 | var fl_flags: usize = while (true) { | ||
| 1198 | try pool.checkCancel(); | ||
| 1199 | switch (posix.errno(posix.system.fcntl(fd, posix.F.GETFL, 0))) { | ||
| 1200 | .SUCCESS => break, | ||
| 1201 | .INTR => continue, | ||
| 1202 | else => |err| return posix.unexpectedErrno(err), | ||
| 1203 | } | ||
| 1204 | }; | ||
| 1205 | fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK")); | ||
| 1206 | while (true) { | ||
| 1207 | try pool.checkCancel(); | ||
| 1208 | switch (posix.errno(posix.fcntl(fd, posix.F.SETFL, fl_flags))) { | ||
| 1209 | .SUCCESS => break, | ||
| 1210 | .INTR => continue, | ||
| 1211 | else => |err| return posix.unexpectedErrno(err), | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | return .{ .handle = fd }; | ||
| 1102 | } | 1217 | } |
| 1103 | 1218 | ||
| 1104 | fn fileClose(userdata: ?*anyopaque, file: Io.File) void { | 1219 | fn fileClose(userdata: ?*anyopaque, file: Io.File) void { |
| 1105 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1220 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1106 | _ = pool; | 1221 | _ = pool; |
| 1107 | const fs_file: std.fs.File = .{ .handle = file.handle }; | 1222 | posix.close(file.handle); |
| 1108 | return fs_file.close(); | ||
| 1109 | } | 1223 | } |
| 1110 | 1224 | ||
| 1111 | fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.ReadStreamingError!usize { | 1225 | fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File.ReadStreamingError!usize { |
lib/std/fs.zig+2-48| ... | @@ -260,12 +260,6 @@ pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.O | ... | @@ -260,12 +260,6 @@ pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.O |
| 260 | return cwd().openFile(absolute_path, flags); | 260 | return cwd().openFile(absolute_path, flags); |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | /// Same as `openFileAbsolute` but the path parameter is null-terminated. | ||
| 264 | pub fn openFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 265 | assert(path.isAbsoluteZ(absolute_path_c)); | ||
| 266 | return cwd().openFileZ(absolute_path_c, flags); | ||
| 267 | } | ||
| 268 | |||
| 269 | /// Same as `openFileAbsolute` but the path parameter is WTF-16-encoded. | 263 | /// Same as `openFileAbsolute` but the path parameter is WTF-16-encoded. |
| 270 | pub fn openFileAbsoluteW(absolute_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File { | 264 | pub fn openFileAbsoluteW(absolute_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File { |
| 271 | assert(path.isAbsoluteWindowsWTF16(absolute_path_w)); | 265 | assert(path.isAbsoluteWindowsWTF16(absolute_path_w)); |
| ... | @@ -284,11 +278,6 @@ pub fn accessAbsolute(absolute_path: []const u8, flags: File.OpenFlags) Dir.Acce | ... | @@ -284,11 +278,6 @@ pub fn accessAbsolute(absolute_path: []const u8, flags: File.OpenFlags) Dir.Acce |
| 284 | assert(path.isAbsolute(absolute_path)); | 278 | assert(path.isAbsolute(absolute_path)); |
| 285 | try cwd().access(absolute_path, flags); | 279 | try cwd().access(absolute_path, flags); |
| 286 | } | 280 | } |
| 287 | /// Same as `accessAbsolute` but the path parameter is null-terminated. | ||
| 288 | pub fn accessAbsoluteZ(absolute_path: [*:0]const u8, flags: File.OpenFlags) Dir.AccessError!void { | ||
| 289 | assert(path.isAbsoluteZ(absolute_path)); | ||
| 290 | try cwd().accessZ(absolute_path, flags); | ||
| 291 | } | ||
| 292 | /// Same as `accessAbsolute` but the path parameter is WTF-16 encoded. | 281 | /// Same as `accessAbsolute` but the path parameter is WTF-16 encoded. |
| 293 | pub fn accessAbsoluteW(absolute_path: [*:0]const u16, flags: File.OpenFlags) Dir.AccessError!void { | 282 | pub fn accessAbsoluteW(absolute_path: [*:0]const u16, flags: File.OpenFlags) Dir.AccessError!void { |
| 294 | assert(path.isAbsoluteWindowsW(absolute_path)); | 283 | assert(path.isAbsoluteWindowsW(absolute_path)); |
| ... | @@ -309,12 +298,6 @@ pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) Fi | ... | @@ -309,12 +298,6 @@ pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) Fi |
| 309 | return cwd().createFile(absolute_path, flags); | 298 | return cwd().createFile(absolute_path, flags); |
| 310 | } | 299 | } |
| 311 | 300 | ||
| 312 | /// Same as `createFileAbsolute` but the path parameter is null-terminated. | ||
| 313 | pub fn createFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 314 | assert(path.isAbsoluteZ(absolute_path_c)); | ||
| 315 | return cwd().createFileZ(absolute_path_c, flags); | ||
| 316 | } | ||
| 317 | |||
| 318 | /// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded. | 301 | /// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded. |
| 319 | pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File { | 302 | pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File { |
| 320 | assert(path.isAbsoluteWindowsW(absolute_path_w)); | 303 | assert(path.isAbsoluteWindowsW(absolute_path_w)); |
| ... | @@ -333,12 +316,6 @@ pub fn deleteFileAbsolute(absolute_path: []const u8) Dir.DeleteFileError!void { | ... | @@ -333,12 +316,6 @@ pub fn deleteFileAbsolute(absolute_path: []const u8) Dir.DeleteFileError!void { |
| 333 | return cwd().deleteFile(absolute_path); | 316 | return cwd().deleteFile(absolute_path); |
| 334 | } | 317 | } |
| 335 | 318 | ||
| 336 | /// Same as `deleteFileAbsolute` except the parameter is null-terminated. | ||
| 337 | pub fn deleteFileAbsoluteZ(absolute_path_c: [*:0]const u8) Dir.DeleteFileError!void { | ||
| 338 | assert(path.isAbsoluteZ(absolute_path_c)); | ||
| 339 | return cwd().deleteFileZ(absolute_path_c); | ||
| 340 | } | ||
| 341 | |||
| 342 | /// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded. | 319 | /// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded. |
| 343 | pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) Dir.DeleteFileError!void { | 320 | pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) Dir.DeleteFileError!void { |
| 344 | assert(path.isAbsoluteWindowsW(absolute_path_w)); | 321 | assert(path.isAbsoluteWindowsW(absolute_path_w)); |
| ... | @@ -383,12 +360,6 @@ pub fn readlinkAbsoluteW(pathname_w: [*:0]const u16, buffer: *[max_path_bytes]u8 | ... | @@ -383,12 +360,6 @@ pub fn readlinkAbsoluteW(pathname_w: [*:0]const u16, buffer: *[max_path_bytes]u8 |
| 383 | return posix.readlinkW(mem.span(pathname_w), buffer); | 360 | return posix.readlinkW(mem.span(pathname_w), buffer); |
| 384 | } | 361 | } |
| 385 | 362 | ||
| 386 | /// Same as `readLink`, except the path parameter is null-terminated. | ||
| 387 | pub fn readLinkAbsoluteZ(pathname_c: [*:0]const u8, buffer: *[max_path_bytes]u8) ![]u8 { | ||
| 388 | assert(path.isAbsoluteZ(pathname_c)); | ||
| 389 | return posix.readlinkZ(pathname_c, buffer); | ||
| 390 | } | ||
| 391 | |||
| 392 | /// Creates a symbolic link named `sym_link_path` which contains the string `target_path`. | 363 | /// Creates a symbolic link named `sym_link_path` which contains the string `target_path`. |
| 393 | /// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent | 364 | /// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent |
| 394 | /// one; the latter case is known as a dangling link. | 365 | /// one; the latter case is known as a dangling link. |
| ... | @@ -426,28 +397,11 @@ pub fn symLinkAbsoluteW( | ... | @@ -426,28 +397,11 @@ pub fn symLinkAbsoluteW( |
| 426 | return windows.CreateSymbolicLink(null, mem.span(sym_link_path_w), mem.span(target_path_w), flags.is_directory); | 397 | return windows.CreateSymbolicLink(null, mem.span(sym_link_path_w), mem.span(target_path_w), flags.is_directory); |
| 427 | } | 398 | } |
| 428 | 399 | ||
| 429 | /// Same as `symLinkAbsolute` except the parameters are null-terminated pointers. | ||
| 430 | /// See also `symLinkAbsolute`. | ||
| 431 | pub fn symLinkAbsoluteZ( | ||
| 432 | target_path_c: [*:0]const u8, | ||
| 433 | sym_link_path_c: [*:0]const u8, | ||
| 434 | flags: Dir.SymLinkFlags, | ||
| 435 | ) !void { | ||
| 436 | assert(path.isAbsoluteZ(target_path_c)); | ||
| 437 | assert(path.isAbsoluteZ(sym_link_path_c)); | ||
| 438 | if (native_os == .windows) { | ||
| 439 | const target_path_w = try windows.cStrToPrefixedFileW(null, target_path_c); | ||
| 440 | const sym_link_path_w = try windows.cStrToPrefixedFileW(null, sym_link_path_c); | ||
| 441 | return windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory); | ||
| 442 | } | ||
| 443 | return posix.symlinkZ(target_path_c, sym_link_path_c); | ||
| 444 | } | ||
| 445 | |||
| 446 | pub const OpenSelfExeError = posix.OpenError || SelfExePathError || posix.FlockError; | 400 | pub const OpenSelfExeError = posix.OpenError || SelfExePathError || posix.FlockError; |
| 447 | 401 | ||
| 448 | pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { | 402 | pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { |
| 449 | if (native_os == .linux or native_os == .serenity) { | 403 | if (native_os == .linux or native_os == .serenity) { |
| 450 | return openFileAbsoluteZ("/proc/self/exe", flags); | 404 | return openFileAbsolute("/proc/self/exe", flags); |
| 451 | } | 405 | } |
| 452 | if (native_os == .windows) { | 406 | if (native_os == .windows) { |
| 453 | // If ImagePathName is a symlink, then it will contain the path of the symlink, | 407 | // 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 { | ... | @@ -463,7 +417,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { |
| 463 | var buf: [max_path_bytes]u8 = undefined; | 417 | var buf: [max_path_bytes]u8 = undefined; |
| 464 | const self_exe_path = try selfExePath(&buf); | 418 | const self_exe_path = try selfExePath(&buf); |
| 465 | buf[self_exe_path.len] = 0; | 419 | buf[self_exe_path.len] = 0; |
| 466 | return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags); | 420 | return openFileAbsolute(buf[0..self_exe_path.len :0], flags); |
| 467 | } | 421 | } |
| 468 | 422 | ||
| 469 | // This is `posix.ReadLinkError || posix.RealPathError` with impossible errors excluded | 423 | // This is `posix.ReadLinkError || posix.RealPathError` with impossible errors excluded |
lib/std/fs/Dir.zig+7-164| ... | @@ -885,94 +885,9 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope | ... | @@ -885,94 +885,9 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope |
| 885 | const fd = try posix.openatWasi(self.fd, sub_path, .{}, .{}, .{}, base, .{}); | 885 | const fd = try posix.openatWasi(self.fd, sub_path, .{}, .{}, .{}, base, .{}); |
| 886 | return .{ .handle = fd }; | 886 | return .{ .handle = fd }; |
| 887 | } | 887 | } |
| 888 | const path_c = try posix.toPosixPath(sub_path); | 888 | var threaded: Io.Threaded = .init_single_threaded; |
| 889 | return self.openFileZ(&path_c, flags); | 889 | const io = threaded.io(); |
| 890 | } | 890 | return .adaptFromNewApi(try Io.Dir.openFile(self.adaptToNewApi(), io, sub_path, flags)); |
| 891 | |||
| 892 | /// Same as `openFile` but the path parameter is null-terminated. | ||
| 893 | pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 894 | switch (native_os) { | ||
| 895 | .windows => { | ||
| 896 | const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path); | ||
| 897 | return self.openFileW(path_w.span(), flags); | ||
| 898 | }, | ||
| 899 | // Use the libc API when libc is linked because it implements things | ||
| 900 | // such as opening absolute file paths. | ||
| 901 | .wasi => if (!builtin.link_libc) { | ||
| 902 | return openFile(self, mem.sliceTo(sub_path, 0), flags); | ||
| 903 | }, | ||
| 904 | else => {}, | ||
| 905 | } | ||
| 906 | |||
| 907 | var os_flags: posix.O = switch (native_os) { | ||
| 908 | .wasi => .{ | ||
| 909 | .read = flags.mode != .write_only, | ||
| 910 | .write = flags.mode != .read_only, | ||
| 911 | }, | ||
| 912 | else => .{ | ||
| 913 | .ACCMODE = switch (flags.mode) { | ||
| 914 | .read_only => .RDONLY, | ||
| 915 | .write_only => .WRONLY, | ||
| 916 | .read_write => .RDWR, | ||
| 917 | }, | ||
| 918 | }, | ||
| 919 | }; | ||
| 920 | if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true; | ||
| 921 | if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true; | ||
| 922 | if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty; | ||
| 923 | |||
| 924 | // Use the O locking flags if the os supports them to acquire the lock | ||
| 925 | // atomically. | ||
| 926 | const has_flock_open_flags = @hasField(posix.O, "EXLOCK"); | ||
| 927 | if (has_flock_open_flags) { | ||
| 928 | // Note that the NONBLOCK flag is removed after the openat() call | ||
| 929 | // is successful. | ||
| 930 | switch (flags.lock) { | ||
| 931 | .none => {}, | ||
| 932 | .shared => { | ||
| 933 | os_flags.SHLOCK = true; | ||
| 934 | os_flags.NONBLOCK = flags.lock_nonblocking; | ||
| 935 | }, | ||
| 936 | .exclusive => { | ||
| 937 | os_flags.EXLOCK = true; | ||
| 938 | os_flags.NONBLOCK = flags.lock_nonblocking; | ||
| 939 | }, | ||
| 940 | } | ||
| 941 | } | ||
| 942 | const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0); | ||
| 943 | errdefer posix.close(fd); | ||
| 944 | |||
| 945 | if (have_flock and !has_flock_open_flags and flags.lock != .none) { | ||
| 946 | // TODO: integrate async I/O | ||
| 947 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; | ||
| 948 | try posix.flock(fd, switch (flags.lock) { | ||
| 949 | .none => unreachable, | ||
| 950 | .shared => posix.LOCK.SH | lock_nonblocking, | ||
| 951 | .exclusive => posix.LOCK.EX | lock_nonblocking, | ||
| 952 | }); | ||
| 953 | } | ||
| 954 | |||
| 955 | if (has_flock_open_flags and flags.lock_nonblocking) { | ||
| 956 | var fl_flags = posix.fcntl(fd, posix.F.GETFL, 0) catch |err| switch (err) { | ||
| 957 | error.FileBusy => unreachable, | ||
| 958 | error.Locked => unreachable, | ||
| 959 | error.PermissionDenied => unreachable, | ||
| 960 | error.DeadLock => unreachable, | ||
| 961 | error.LockedRegionLimitExceeded => unreachable, | ||
| 962 | else => |e| return e, | ||
| 963 | }; | ||
| 964 | fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK")); | ||
| 965 | _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) { | ||
| 966 | error.FileBusy => unreachable, | ||
| 967 | error.Locked => unreachable, | ||
| 968 | error.PermissionDenied => unreachable, | ||
| 969 | error.DeadLock => unreachable, | ||
| 970 | error.LockedRegionLimitExceeded => unreachable, | ||
| 971 | else => |e| return e, | ||
| 972 | }; | ||
| 973 | } | ||
| 974 | |||
| 975 | return .{ .handle = fd }; | ||
| 976 | } | 891 | } |
| 977 | 892 | ||
| 978 | /// Same as `openFile` but Windows-only and the path parameter is | 893 | /// 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 | ... | @@ -1048,82 +963,10 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File |
| 1048 | }, .{}), | 963 | }, .{}), |
| 1049 | }; | 964 | }; |
| 1050 | } | 965 | } |
| 1051 | const path_c = try posix.toPosixPath(sub_path); | 966 | var threaded: Io.Threaded = .init_single_threaded; |
| 1052 | return self.createFileZ(&path_c, flags); | 967 | const io = threaded.io(); |
| 1053 | } | 968 | const new_file = try Io.Dir.createFile(self.adaptToNewApi(), io, sub_path, flags); |
| 1054 | 969 | return .adaptFromNewApi(new_file); | |
| 1055 | /// Same as `createFile` but the path parameter is null-terminated. | ||
| 1056 | pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 1057 | switch (native_os) { | ||
| 1058 | .windows => { | ||
| 1059 | const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path_c); | ||
| 1060 | return self.createFileW(path_w.span(), flags); | ||
| 1061 | }, | ||
| 1062 | .wasi => { | ||
| 1063 | return createFile(self, mem.sliceTo(sub_path_c, 0), flags); | ||
| 1064 | }, | ||
| 1065 | else => {}, | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | var os_flags: posix.O = .{ | ||
| 1069 | .ACCMODE = if (flags.read) .RDWR else .WRONLY, | ||
| 1070 | .CREAT = true, | ||
| 1071 | .TRUNC = flags.truncate, | ||
| 1072 | .EXCL = flags.exclusive, | ||
| 1073 | }; | ||
| 1074 | if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true; | ||
| 1075 | if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true; | ||
| 1076 | |||
| 1077 | // Use the O locking flags if the os supports them to acquire the lock | ||
| 1078 | // atomically. Note that the NONBLOCK flag is removed after the openat() | ||
| 1079 | // call is successful. | ||
| 1080 | const has_flock_open_flags = @hasField(posix.O, "EXLOCK"); | ||
| 1081 | if (has_flock_open_flags) switch (flags.lock) { | ||
| 1082 | .none => {}, | ||
| 1083 | .shared => { | ||
| 1084 | os_flags.SHLOCK = true; | ||
| 1085 | os_flags.NONBLOCK = flags.lock_nonblocking; | ||
| 1086 | }, | ||
| 1087 | .exclusive => { | ||
| 1088 | os_flags.EXLOCK = true; | ||
| 1089 | os_flags.NONBLOCK = flags.lock_nonblocking; | ||
| 1090 | }, | ||
| 1091 | }; | ||
| 1092 | |||
| 1093 | const fd = try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode); | ||
| 1094 | errdefer posix.close(fd); | ||
| 1095 | |||
| 1096 | if (have_flock and !has_flock_open_flags and flags.lock != .none) { | ||
| 1097 | // TODO: integrate async I/O | ||
| 1098 | const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0; | ||
| 1099 | try posix.flock(fd, switch (flags.lock) { | ||
| 1100 | .none => unreachable, | ||
| 1101 | .shared => posix.LOCK.SH | lock_nonblocking, | ||
| 1102 | .exclusive => posix.LOCK.EX | lock_nonblocking, | ||
| 1103 | }); | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | if (has_flock_open_flags and flags.lock_nonblocking) { | ||
| 1107 | var fl_flags = posix.fcntl(fd, posix.F.GETFL, 0) catch |err| switch (err) { | ||
| 1108 | error.FileBusy => unreachable, | ||
| 1109 | error.Locked => unreachable, | ||
| 1110 | error.PermissionDenied => unreachable, | ||
| 1111 | error.DeadLock => unreachable, | ||
| 1112 | error.LockedRegionLimitExceeded => unreachable, | ||
| 1113 | else => |e| return e, | ||
| 1114 | }; | ||
| 1115 | fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK")); | ||
| 1116 | _ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) { | ||
| 1117 | error.FileBusy => unreachable, | ||
| 1118 | error.Locked => unreachable, | ||
| 1119 | error.PermissionDenied => unreachable, | ||
| 1120 | error.DeadLock => unreachable, | ||
| 1121 | error.LockedRegionLimitExceeded => unreachable, | ||
| 1122 | else => |e| return e, | ||
| 1123 | }; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | return .{ .handle = fd }; | ||
| 1127 | } | 970 | } |
| 1128 | 971 | ||
| 1129 | /// Same as `createFile` but Windows-only and the path parameter is | 972 | /// Same as `createFile` but Windows-only and the path parameter is |