diff options
| author | Loris Cro <kappaloris@gmail.com> | 2023-06-18 09:06:40 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-06-18 09:06:40 +0200 |
| commit | 216ef10dc471e4db60a30208be178d6c59efeaaf (patch) | |
| tree | 8c239dab283ae9cb3b7fe099bae240bcc53f894e /lib/std/fs.zig | |
| parent | 0fc1d396495c1ab482197021dedac8bea3f9401c (diff) | |
| parent | 729a051e9e38674233190aea23c0ac8c134f2d67 (diff) | |
| download | zig-216ef10dc471e4db60a30208be178d6c59efeaaf.tar.gz zig-216ef10dc471e4db60a30208be178d6c59efeaaf.zip | |
Merge branch 'master' into autodoc-searchkey
Diffstat (limited to 'lib/std/fs.zig')
| -rw-r--r-- | lib/std/fs.zig | 207 |
1 files changed, 110 insertions, 97 deletions
diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 9f64387bd8..bb0890be4b 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -385,16 +385,16 @@ pub const IterableDir = struct { continue :start_over; } - const entry_kind = switch (darwin_entry.d_type) { - os.DT.BLK => Entry.Kind.BlockDevice, - os.DT.CHR => Entry.Kind.CharacterDevice, - os.DT.DIR => Entry.Kind.Directory, - os.DT.FIFO => Entry.Kind.NamedPipe, - os.DT.LNK => Entry.Kind.SymLink, - os.DT.REG => Entry.Kind.File, - os.DT.SOCK => Entry.Kind.UnixDomainSocket, - os.DT.WHT => Entry.Kind.Whiteout, - else => Entry.Kind.Unknown, + const entry_kind: Entry.Kind = switch (darwin_entry.d_type) { + os.DT.BLK => .block_device, + os.DT.CHR => .character_device, + os.DT.DIR => .directory, + os.DT.FIFO => .named_pipe, + os.DT.LNK => .sym_link, + os.DT.REG => .file, + os.DT.SOCK => .unix_domain_socket, + os.DT.WHT => .whiteout, + else => .unknown, }; return Entry{ .name = name, @@ -442,17 +442,17 @@ pub const IterableDir = struct { error.FileNotFound => unreachable, // lost the race else => |e| return e, }; - const entry_kind = switch (stat_info.mode & os.S.IFMT) { - os.S.IFIFO => Entry.Kind.NamedPipe, - os.S.IFCHR => Entry.Kind.CharacterDevice, - os.S.IFDIR => Entry.Kind.Directory, - os.S.IFBLK => Entry.Kind.BlockDevice, - os.S.IFREG => Entry.Kind.File, - os.S.IFLNK => Entry.Kind.SymLink, - os.S.IFSOCK => Entry.Kind.UnixDomainSocket, - os.S.IFDOOR => Entry.Kind.Door, - os.S.IFPORT => Entry.Kind.EventPort, - else => Entry.Kind.Unknown, + const entry_kind: Entry.Kind = switch (stat_info.mode & os.S.IFMT) { + os.S.IFIFO => .named_pipe, + os.S.IFCHR => .character_device, + os.S.IFDIR => .directory, + os.S.IFBLK => .block_device, + os.S.IFREG => .file, + os.S.IFLNK => .sym_link, + os.S.IFSOCK => .unix_domain_socket, + os.S.IFDOOR => .door, + os.S.IFPORT => .event_port, + else => .unknown, }; return Entry{ .name = name, @@ -478,6 +478,9 @@ pub const IterableDir = struct { .FAULT => unreachable, .NOTDIR => unreachable, .INVAL => unreachable, + // Introduced in freebsd 13.2: directory unlinked but still open. + // To be consistent, iteration ends if the directory being iterated is deleted during iteration. + .NOENT => return null, else => |err| return os.unexpectedErrno(err), } if (rc == 0) return null; @@ -501,16 +504,16 @@ pub const IterableDir = struct { continue :start_over; } - const entry_kind = switch (bsd_entry.d_type) { - os.DT.BLK => Entry.Kind.BlockDevice, - os.DT.CHR => Entry.Kind.CharacterDevice, - os.DT.DIR => Entry.Kind.Directory, - os.DT.FIFO => Entry.Kind.NamedPipe, - os.DT.LNK => Entry.Kind.SymLink, - os.DT.REG => Entry.Kind.File, - os.DT.SOCK => Entry.Kind.UnixDomainSocket, - os.DT.WHT => Entry.Kind.Whiteout, - else => Entry.Kind.Unknown, + const entry_kind: Entry.Kind = switch (bsd_entry.d_type) { + os.DT.BLK => .block_device, + os.DT.CHR => .character_device, + os.DT.DIR => .directory, + os.DT.FIFO => .named_pipe, + os.DT.LNK => .sym_link, + os.DT.REG => .file, + os.DT.SOCK => .unix_domain_socket, + os.DT.WHT => .whiteout, + else => .unknown, }; return Entry{ .name = name, @@ -595,14 +598,14 @@ pub const IterableDir = struct { } const statmode = stat_info.mode & os.S.IFMT; - const entry_kind = switch (statmode) { - os.S.IFDIR => Entry.Kind.Directory, - os.S.IFBLK => Entry.Kind.BlockDevice, - os.S.IFCHR => Entry.Kind.CharacterDevice, - os.S.IFLNK => Entry.Kind.SymLink, - os.S.IFREG => Entry.Kind.File, - os.S.IFIFO => Entry.Kind.NamedPipe, - else => Entry.Kind.Unknown, + const entry_kind: Entry.Kind = switch (statmode) { + os.S.IFDIR => .directory, + os.S.IFBLK => .block_device, + os.S.IFCHR => .character_device, + os.S.IFLNK => .sym_link, + os.S.IFREG => .file, + os.S.IFIFO => .named_pipe, + else => .unknown, }; return Entry{ @@ -662,6 +665,7 @@ pub const IterableDir = struct { .NOTDIR => unreachable, .NOENT => return error.DirNotFound, // The directory being iterated was deleted during iteration. .INVAL => return error.Unexpected, // Linux may in some cases return EINVAL when reading /proc/$PID/net. + .ACCES => return error.AccessDenied, // Do not have permission to iterate this directory. else => |err| return os.unexpectedErrno(err), } if (rc == 0) return null; @@ -679,15 +683,15 @@ pub const IterableDir = struct { continue :start_over; } - const entry_kind = switch (linux_entry.d_type) { - linux.DT.BLK => Entry.Kind.BlockDevice, - linux.DT.CHR => Entry.Kind.CharacterDevice, - linux.DT.DIR => Entry.Kind.Directory, - linux.DT.FIFO => Entry.Kind.NamedPipe, - linux.DT.LNK => Entry.Kind.SymLink, - linux.DT.REG => Entry.Kind.File, - linux.DT.SOCK => Entry.Kind.UnixDomainSocket, - else => Entry.Kind.Unknown, + const entry_kind: Entry.Kind = switch (linux_entry.d_type) { + linux.DT.BLK => .block_device, + linux.DT.CHR => .character_device, + linux.DT.DIR => .directory, + linux.DT.FIFO => .named_pipe, + linux.DT.LNK => .sym_link, + linux.DT.REG => .file, + linux.DT.SOCK => .unix_domain_socket, + else => .unknown, }; return Entry{ .name = name, @@ -761,11 +765,11 @@ pub const IterableDir = struct { // Trust that Windows gives us valid UTF-16LE const name_utf8_len = std.unicode.utf16leToUtf8(self.name_data[0..], name_utf16le) catch unreachable; const name_utf8 = self.name_data[0..name_utf8_len]; - const kind = blk: { + const kind: Entry.Kind = blk: { const attrs = dir_info.FileAttributes; - if (attrs & w.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory; - if (attrs & w.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink; - break :blk Entry.Kind.File; + if (attrs & w.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk .directory; + if (attrs & w.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk .sym_link; + break :blk .file; }; return Entry{ .name = name_utf8, @@ -850,14 +854,14 @@ pub const IterableDir = struct { continue :start_over; } - const entry_kind = switch (entry.d_type) { - .BLOCK_DEVICE => Entry.Kind.BlockDevice, - .CHARACTER_DEVICE => Entry.Kind.CharacterDevice, - .DIRECTORY => Entry.Kind.Directory, - .SYMBOLIC_LINK => Entry.Kind.SymLink, - .REGULAR_FILE => Entry.Kind.File, - .SOCKET_STREAM, .SOCKET_DGRAM => Entry.Kind.UnixDomainSocket, - else => Entry.Kind.Unknown, + const entry_kind: Entry.Kind = switch (entry.d_type) { + .BLOCK_DEVICE => .block_device, + .CHARACTER_DEVICE => .character_device, + .DIRECTORY => .directory, + .SYMBOLIC_LINK => .sym_link, + .REGULAR_FILE => .file, + .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket, + else => .unknown, }; return Entry{ .name = name, @@ -957,14 +961,24 @@ pub const IterableDir = struct { var top = &self.stack.items[self.stack.items.len - 1]; var containing = top; var dirname_len = top.dirname_len; - if (try top.iter.next()) |base| { + if (top.iter.next() catch |err| { + // If we get an error, then we want the user to be able to continue + // walking if they want, which means that we need to pop the directory + // that errored from the stack. Otherwise, all future `next` calls would + // likely just fail with the same error. + var item = self.stack.pop(); + if (self.stack.items.len != 0) { + item.iter.dir.close(); + } + return err; + }) |base| { self.name_buffer.shrinkRetainingCapacity(dirname_len); if (self.name_buffer.items.len != 0) { try self.name_buffer.append(path.sep); dirname_len += 1; } try self.name_buffer.appendSlice(base.name); - if (base.kind == .Directory) { + if (base.kind == .directory) { var new_dir = top.iter.dir.openIterableDir(base.name, .{}) catch |err| switch (err) { error.NameTooLong => unreachable, // no path sep in base.name else => |e| return e, @@ -972,7 +986,7 @@ pub const IterableDir = struct { { errdefer new_dir.close(); try self.stack.append(StackItem{ - .iter = new_dir.iterate(), + .iter = new_dir.iterateAssumeFirstIteration(), .dirname_len = self.name_buffer.items.len, }); top = &self.stack.items[self.stack.items.len - 1]; @@ -1157,9 +1171,9 @@ pub const Dir = struct { else 0; os_flags |= switch (flags.lock) { - .None => @as(u32, 0), - .Shared => os.O.SHLOCK | nonblocking_lock_flag, - .Exclusive => os.O.EXLOCK | nonblocking_lock_flag, + .none => @as(u32, 0), + .shared => os.O.SHLOCK | nonblocking_lock_flag, + .exclusive => os.O.EXLOCK | nonblocking_lock_flag, }; } if (@hasDecl(os.O, "LARGEFILE")) { @@ -1182,13 +1196,13 @@ pub const Dir = struct { // WASI doesn't have os.flock so we intetinally check OS prior to the inner if block // since it is not compiltime-known and we need to avoid undefined symbol in Wasm. if (builtin.target.os.tag != .wasi) { - if (!has_flock_open_flags and flags.lock != .None) { + if (!has_flock_open_flags and flags.lock != .none) { // TODO: integrate async I/O const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0); try os.flock(fd, switch (flags.lock) { - .None => unreachable, - .Shared => os.LOCK.SH | lock_nonblocking, - .Exclusive => os.LOCK.EX | lock_nonblocking, + .none => unreachable, + .shared => os.LOCK.SH | lock_nonblocking, + .exclusive => os.LOCK.EX | lock_nonblocking, }); } } @@ -1241,9 +1255,9 @@ pub const Dir = struct { const range_off: w.LARGE_INTEGER = 0; const range_len: w.LARGE_INTEGER = 1; const exclusive = switch (flags.lock) { - .None => return file, - .Shared => false, - .Exclusive => true, + .none => return file, + .shared => false, + .exclusive => true, }; try w.LockFile( file.handle, @@ -1320,9 +1334,9 @@ pub const Dir = struct { else 0; const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { - .None => @as(u32, 0), - .Shared => os.O.SHLOCK | nonblocking_lock_flag, - .Exclusive => os.O.EXLOCK | nonblocking_lock_flag, + .none => @as(u32, 0), + .shared => os.O.SHLOCK | nonblocking_lock_flag, + .exclusive => os.O.EXLOCK | nonblocking_lock_flag, } else 0; const O_LARGEFILE = if (@hasDecl(os.O, "LARGEFILE")) os.O.LARGEFILE else 0; @@ -1339,13 +1353,13 @@ pub const Dir = struct { // WASI doesn't have os.flock so we intetinally check OS prior to the inner if block // since it is not compiltime-known and we need to avoid undefined symbol in Wasm. if (builtin.target.os.tag != .wasi) { - if (!has_flock_open_flags and flags.lock != .None) { + if (!has_flock_open_flags and flags.lock != .none) { // TODO: integrate async I/O const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0); try os.flock(fd, switch (flags.lock) { - .None => unreachable, - .Shared => os.LOCK.SH | lock_nonblocking, - .Exclusive => os.LOCK.EX | lock_nonblocking, + .none => unreachable, + .shared => os.LOCK.SH | lock_nonblocking, + .exclusive => os.LOCK.EX | lock_nonblocking, }); } } @@ -1402,9 +1416,9 @@ pub const Dir = struct { const range_off: w.LARGE_INTEGER = 0; const range_len: w.LARGE_INTEGER = 1; const exclusive = switch (flags.lock) { - .None => return file, - .Shared => false, - .Exclusive => true, + .none => return file, + .shared => false, + .exclusive => true, }; try w.LockFile( file.handle, @@ -2106,7 +2120,7 @@ pub const Dir = struct { /// this function recursively removes its entries and then tries again. /// This operation is not atomic on most file systems. pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { - var initial_iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, .File)) orelse return; + var initial_iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, .file)) orelse return; const StackItem = struct { name: []const u8, @@ -2130,7 +2144,7 @@ pub const Dir = struct { process_stack: while (stack.len != 0) { var top = &(stack.slice()[stack.len - 1]); while (try top.iter.next()) |entry| { - var treat_as_dir = entry.kind == .Directory; + var treat_as_dir = entry.kind == .directory; handle_entry: while (true) { if (treat_as_dir) { if (stack.ensureUnusedCapacity(1)) { @@ -2291,7 +2305,7 @@ pub const Dir = struct { /// Like `deleteTree`, but only keeps one `Iterator` active at a time to minimize the function's stack size. /// This is slower than `deleteTree` but uses less stack space. pub fn deleteTreeMinStackSize(self: Dir, sub_path: []const u8) DeleteTreeError!void { - return self.deleteTreeMinStackSizeWithKindHint(sub_path, .File); + return self.deleteTreeMinStackSizeWithKindHint(sub_path, .file); } fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint: File.Kind) DeleteTreeError!void { @@ -2316,7 +2330,7 @@ pub const Dir = struct { scan_dir: while (true) { var dir_it = iterable_dir.iterateAssumeFirstIteration(); dir_it: while (try dir_it.next()) |entry| { - var treat_as_dir = entry.kind == .Directory; + var treat_as_dir = entry.kind == .directory; handle_entry: while (true) { if (treat_as_dir) { const new_dir = iterable_dir.dir.openIterableDir(entry.name, .{ .no_follow = true }) catch |err| switch (err) { @@ -2407,7 +2421,7 @@ pub const Dir = struct { fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File.Kind) !?IterableDir { return iterable_dir: { // Treat as a file by default - var treat_as_dir = kind_hint == .Directory; + var treat_as_dir = kind_hint == .directory; handle_entry: while (true) { if (treat_as_dir) { @@ -2999,8 +3013,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { .haiku => { // The only possible issue when looking for the self image path is // when the buffer is too short. - // TODO replace with proper constants - if (os.find_path(null, 1000, null, out_buffer.ptr, out_buffer.len) != 0) + if (os.find_path(os.B_APP_IMAGE_SYMBOL, os.path_base_directory.B_FIND_IMAGE_PATH, null, out_buffer.ptr, out_buffer.len) != 0) return error.Overflow; return mem.sliceTo(out_buffer, 0); }, @@ -3022,7 +3035,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { } else if (argv0.len != 0) { // argv[0] is not empty (and not a path): search it inside PATH const PATH = std.os.getenvZ("PATH") orelse return error.FileNotFound; - var path_it = mem.tokenize(u8, PATH, &[_]u8{path.delimiter}); + var path_it = mem.tokenizeScalar(u8, PATH, path.delimiter); while (path_it.next()) |a_path| { var resolved_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined; const resolved_path = std.fmt.bufPrintZ(&resolved_path_buf, "{s}/{s}", .{ @@ -3103,7 +3116,7 @@ const CopyFileRawError = error{SystemResources} || os.CopyFileRangeError || os.S // No metadata is transferred over. fn copy_file(fd_in: os.fd_t, fd_out: os.fd_t, maybe_size: ?u64) CopyFileRawError!void { if (comptime builtin.target.isDarwin()) { - const rc = os.system.fcopyfile(fd_in, fd_out, null, os.system.COPYFILE_DATA); + const rc = os.system.fcopyfile(fd_in, fd_out, null, os.system.COPYFILE.DATA); switch (os.errno(rc)) { .SUCCESS => return, .INVAL => unreachable, @@ -3151,12 +3164,12 @@ fn copy_file(fd_in: os.fd_t, fd_out: os.fd_t, maybe_size: ?u64) CopyFileRawError test { if (builtin.os.tag != .wasi) { - _ = makeDirAbsolute; - _ = makeDirAbsoluteZ; - _ = copyFileAbsolute; - _ = updateFileAbsolute; + _ = &makeDirAbsolute; + _ = &makeDirAbsoluteZ; + _ = ©FileAbsolute; + _ = &updateFileAbsolute; } - _ = Dir.copyFile; + _ = &Dir.copyFile; _ = @import("fs/test.zig"); _ = @import("fs/path.zig"); _ = @import("fs/file.zig"); |
