| author | |
| committer | |
| log | 68621afd2e203d82b6f53bf4ede951827fa98db8 |
| tree | 60899decd0062ce7786592e49ca77ab6f80d22fd |
| parent | 0e230993d51d0ecded40d5235ada4f2f64036b26 |
15 files changed, 110 insertions(+), 110 deletions(-)
lib/compiler/aro/aro/Compilation.zig+2-1| ... | ... | @@ -2162,8 +2162,9 @@ pub fn locSlice(comp: *const Compilation, loc: Source.Location) []const u8 { |
| 2162 | 2162 | } |
| 2163 | 2163 | |
| 2164 | 2164 | pub fn getSourceMTimeUncached(comp: *const Compilation, source_id: Source.Id) ?u64 { |
| 2165 | const io = comp.io; | |
| 2165 | 2166 | const source = comp.getSource(source_id); |
| 2166 | if (comp.cwd.statFile(source.path)) |stat| { | |
| 2167 | if (comp.cwd.statFile(io, source.path, .{})) |stat| { | |
| 2167 | 2168 | return std.math.cast(u64, stat.mtime.toSeconds()); |
| 2168 | 2169 | } else |_| { |
| 2169 | 2170 | return null; |
lib/std/Build/Cache/Path.zig+2-2| ... | ... | @@ -94,14 +94,14 @@ pub fn makeOpenPath(p: Path, sub_path: []const u8, opts: Io.Dir.OpenOptions) !Io |
| 94 | 94 | return p.root_dir.handle.makeOpenPath(joined_path, opts); |
| 95 | 95 | } |
| 96 | 96 | |
| 97 | pub fn statFile(p: Path, sub_path: []const u8) !Io.Dir.Stat { | |
| 97 | pub fn statFile(p: Path, io: Io, sub_path: []const u8) !Io.Dir.Stat { | |
| 98 | 98 | var buf: [fs.max_path_bytes]u8 = undefined; |
| 99 | 99 | const joined_path = if (p.sub_path.len == 0) sub_path else p: { |
| 100 | 100 | break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{ |
| 101 | 101 | p.sub_path, sub_path, |
| 102 | 102 | }) catch return error.NameTooLong; |
| 103 | 103 | }; |
| 104 | return p.root_dir.handle.statFile(joined_path); | |
| 104 | return p.root_dir.handle.statFile(io, joined_path, .{}); | |
| 105 | 105 | } |
| 106 | 106 | |
| 107 | 107 | pub fn atomicFile( |
lib/std/Io.zig+1-1| ... | ... | @@ -671,7 +671,7 @@ pub const VTable = struct { |
| 671 | 671 | dirMakeOpenPath: *const fn (?*anyopaque, Dir, []const u8, Dir.Permissions, Dir.OpenOptions) Dir.MakeOpenPathError!Dir, |
| 672 | 672 | dirOpenDir: *const fn (?*anyopaque, Dir, []const u8, Dir.OpenOptions) Dir.OpenError!Dir, |
| 673 | 673 | dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat, |
| 674 | dirStatPath: *const fn (?*anyopaque, Dir, []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat, | |
| 674 | dirStatFile: *const fn (?*anyopaque, Dir, []const u8, Dir.StatFileOptions) Dir.StatFileError!File.Stat, | |
| 675 | 675 | dirAccess: *const fn (?*anyopaque, Dir, []const u8, Dir.AccessOptions) Dir.AccessError!void, |
| 676 | 676 | dirCreateFile: *const fn (?*anyopaque, Dir, []const u8, File.CreateFlags) File.OpenError!File, |
| 677 | 677 | dirOpenFile: *const fn (?*anyopaque, Dir, []const u8, File.OpenFlags) File.OpenError!File, |
lib/std/Io/Dir.zig+6-6| ... | ... | @@ -669,7 +669,7 @@ pub fn makeDirAbsolute(io: Io, absolute_path: []const u8, permissions: Permissio |
| 669 | 669 | |
| 670 | 670 | test makeDirAbsolute {} |
| 671 | 671 | |
| 672 | pub const MakePathError = MakeError || StatPathError; | |
| 672 | pub const MakePathError = MakeError || StatFileError; | |
| 673 | 673 | |
| 674 | 674 | /// Creates parent directories with default permissions as necessary to ensure |
| 675 | 675 | /// `sub_path` exists as a directory. |
| ... | ... | @@ -708,7 +708,7 @@ pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8, permissions: Permi |
| 708 | 708 | return io.vtable.dirMakePath(io.userdata, dir, sub_path, permissions); |
| 709 | 709 | } |
| 710 | 710 | |
| 711 | pub const MakeOpenPathError = MakeError || OpenError || StatPathError; | |
| 711 | pub const MakeOpenPathError = MakeError || OpenError || StatFileError; | |
| 712 | 712 | |
| 713 | 713 | pub const MakeOpenPathOptions = struct { |
| 714 | 714 | open_options: OpenOptions = .{}, |
| ... | ... | @@ -734,9 +734,9 @@ pub fn stat(dir: Dir, io: Io) StatError!Stat { |
| 734 | 734 | return io.vtable.dirStat(io.userdata, dir); |
| 735 | 735 | } |
| 736 | 736 | |
| 737 | pub const StatPathError = File.OpenError || File.StatError; | |
| 737 | pub const StatFileError = File.OpenError || File.StatError; | |
| 738 | 738 | |
| 739 | pub const StatPathOptions = struct { | |
| 739 | pub const StatFileOptions = struct { | |
| 740 | 740 | follow_symlinks: bool = true, |
| 741 | 741 | }; |
| 742 | 742 | |
| ... | ... | @@ -752,8 +752,8 @@ pub const StatPathOptions = struct { |
| 752 | 752 | /// * On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). |
| 753 | 753 | /// * On WASI, `sub_path` should be encoded as valid UTF-8. |
| 754 | 754 | /// * On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. |
| 755 | pub fn statPath(dir: Dir, io: Io, sub_path: []const u8, options: StatPathOptions) StatPathError!Stat { | |
| 756 | return io.vtable.dirStatPath(io.userdata, dir, sub_path, options); | |
| 755 | pub fn statFile(dir: Dir, io: Io, sub_path: []const u8, options: StatFileOptions) StatFileError!Stat { | |
| 756 | return io.vtable.dirStatFile(io.userdata, dir, sub_path, options); | |
| 757 | 757 | } |
| 758 | 758 | |
| 759 | 759 | pub const RealPathError = error{ |
lib/std/Io/File.zig+3| ... | ... | @@ -372,6 +372,7 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum( |
| 372 | 372 | _, |
| 373 | 373 | |
| 374 | 374 | pub const default_dir: @This() = .default_file; |
| 375 | pub const executable_file: @This() = .default_file; | |
| 375 | 376 | pub const has_executable_bit = false; |
| 376 | 377 | |
| 377 | 378 | const windows = std.os.windows; |
| ... | ... | @@ -401,6 +402,7 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum( |
| 401 | 402 | /// process-scoped "umask" setting to adjust this number for file creation. |
| 402 | 403 | default_file = 0o666, |
| 403 | 404 | default_dir = 0o755, |
| 405 | executable_file = 0o777, | |
| 404 | 406 | _, |
| 405 | 407 | |
| 406 | 408 | pub const has_executable_bit = true; |
| ... | ... | @@ -428,6 +430,7 @@ pub const Permissions = std.options.FilePermissions orelse if (is_windows) enum( |
| 428 | 430 | } else enum(u0) { |
| 429 | 431 | default_file = 0, |
| 430 | 432 | pub const default_dir: @This() = .default_file; |
| 433 | pub const executable_file: @This() = .default_file; | |
| 431 | 434 | pub const has_executable_bit = false; |
| 432 | 435 | }; |
| 433 | 436 |
lib/std/Io/Threaded.zig+25-25| ... | ... | @@ -708,7 +708,7 @@ pub fn io(t: *Threaded) Io { |
| 708 | 708 | .dirMakePath = dirMakePath, |
| 709 | 709 | .dirMakeOpenPath = dirMakeOpenPath, |
| 710 | 710 | .dirStat = dirStat, |
| 711 | .dirStatPath = dirStatPath, | |
| 711 | .dirStatFile = dirStatFile, | |
| 712 | 712 | .dirAccess = dirAccess, |
| 713 | 713 | .dirCreateFile = dirCreateFile, |
| 714 | 714 | .dirOpenFile = dirOpenFile, |
| ... | ... | @@ -840,7 +840,7 @@ pub fn ioBasic(t: *Threaded) Io { |
| 840 | 840 | .dirMakePath = dirMakePath, |
| 841 | 841 | .dirMakeOpenPath = dirMakeOpenPath, |
| 842 | 842 | .dirStat = dirStat, |
| 843 | .dirStatPath = dirStatPath, | |
| 843 | .dirStatFile = dirStatFile, | |
| 844 | 844 | .dirAccess = dirAccess, |
| 845 | 845 | .dirCreateFile = dirCreateFile, |
| 846 | 846 | .dirOpenFile = dirOpenFile, |
| ... | ... | @@ -1623,7 +1623,7 @@ fn dirMakePath( |
| 1623 | 1623 | // could cause an infinite loop |
| 1624 | 1624 | check_dir: { |
| 1625 | 1625 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 |
| 1626 | const fstat = dirStatPath(t, dir, component.path, .{}) catch |stat_err| switch (stat_err) { | |
| 1626 | const fstat = dirStatFile(t, dir, component.path, .{}) catch |stat_err| switch (stat_err) { | |
| 1627 | 1627 | error.IsDir => break :check_dir, |
| 1628 | 1628 | else => |e| return e, |
| 1629 | 1629 | }; |
| ... | ... | @@ -1752,7 +1752,7 @@ fn dirMakeOpenPathWindows( |
| 1752 | 1752 | // could cause an infinite loop |
| 1753 | 1753 | check_dir: { |
| 1754 | 1754 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 |
| 1755 | const fstat = dirStatPathWindows(t, dir, component.path, .{ | |
| 1755 | const fstat = dirStatFileWindows(t, dir, component.path, .{ | |
| 1756 | 1756 | .follow_symlinks = options.follow_symlinks, |
| 1757 | 1757 | }) catch |stat_err| switch (stat_err) { |
| 1758 | 1758 | error.IsDir => break :check_dir, |
| ... | ... | @@ -1806,19 +1806,19 @@ fn dirStat(userdata: ?*anyopaque, dir: Dir) Dir.StatError!Dir.Stat { |
| 1806 | 1806 | return fileStat(t, file); |
| 1807 | 1807 | } |
| 1808 | 1808 | |
| 1809 | const dirStatPath = switch (native_os) { | |
| 1810 | .linux => dirStatPathLinux, | |
| 1811 | .windows => dirStatPathWindows, | |
| 1812 | .wasi => dirStatPathWasi, | |
| 1813 | else => dirStatPathPosix, | |
| 1809 | const dirStatFile = switch (native_os) { | |
| 1810 | .linux => dirStatFileLinux, | |
| 1811 | .windows => dirStatFileWindows, | |
| 1812 | .wasi => dirStatFileWasi, | |
| 1813 | else => dirStatFilePosix, | |
| 1814 | 1814 | }; |
| 1815 | 1815 | |
| 1816 | fn dirStatPathLinux( | |
| 1816 | fn dirStatFileLinux( | |
| 1817 | 1817 | userdata: ?*anyopaque, |
| 1818 | 1818 | dir: Dir, |
| 1819 | 1819 | sub_path: []const u8, |
| 1820 | options: Dir.StatPathOptions, | |
| 1821 | ) Dir.StatPathError!File.Stat { | |
| 1820 | options: Dir.StatFileOptions, | |
| 1821 | ) Dir.StatFileError!File.Stat { | |
| 1822 | 1822 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1823 | 1823 | const current_thread = Thread.getCurrent(t); |
| 1824 | 1824 | const linux = std.os.linux; |
| ... | ... | @@ -1875,12 +1875,12 @@ fn dirStatPathLinux( |
| 1875 | 1875 | } |
| 1876 | 1876 | } |
| 1877 | 1877 | |
| 1878 | fn dirStatPathPosix( | |
| 1878 | fn dirStatFilePosix( | |
| 1879 | 1879 | userdata: ?*anyopaque, |
| 1880 | 1880 | dir: Dir, |
| 1881 | 1881 | sub_path: []const u8, |
| 1882 | options: Dir.StatPathOptions, | |
| 1883 | ) Dir.StatPathError!File.Stat { | |
| 1882 | options: Dir.StatFileOptions, | |
| 1883 | ) Dir.StatFileError!File.Stat { | |
| 1884 | 1884 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1885 | 1885 | const current_thread = Thread.getCurrent(t); |
| 1886 | 1886 | |
| ... | ... | @@ -1889,10 +1889,10 @@ fn dirStatPathPosix( |
| 1889 | 1889 | |
| 1890 | 1890 | const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0; |
| 1891 | 1891 | |
| 1892 | return posixStatPath(current_thread, dir.handle, sub_path_posix, flags); | |
| 1892 | return posixStatFile(current_thread, dir.handle, sub_path_posix, flags); | |
| 1893 | 1893 | } |
| 1894 | 1894 | |
| 1895 | fn posixStatPath(current_thread: *Thread, dir_fd: posix.fd_t, sub_path: [:0]const u8, flags: u32) Dir.StatPathError!File.Stat { | |
| 1895 | fn posixStatFile(current_thread: *Thread, dir_fd: posix.fd_t, sub_path: [:0]const u8, flags: u32) Dir.StatFileError!File.Stat { | |
| 1896 | 1896 | try current_thread.beginSyscall(); |
| 1897 | 1897 | while (true) { |
| 1898 | 1898 | var stat = std.mem.zeroes(posix.Stat); |
| ... | ... | @@ -1927,12 +1927,12 @@ fn posixStatPath(current_thread: *Thread, dir_fd: posix.fd_t, sub_path: [:0]cons |
| 1927 | 1927 | } |
| 1928 | 1928 | } |
| 1929 | 1929 | |
| 1930 | fn dirStatPathWindows( | |
| 1930 | fn dirStatFileWindows( | |
| 1931 | 1931 | userdata: ?*anyopaque, |
| 1932 | 1932 | dir: Dir, |
| 1933 | 1933 | sub_path: []const u8, |
| 1934 | options: Dir.StatPathOptions, | |
| 1935 | ) Dir.StatPathError!File.Stat { | |
| 1934 | options: Dir.StatFileOptions, | |
| 1935 | ) Dir.StatFileError!File.Stat { | |
| 1936 | 1936 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1937 | 1937 | const file = try dirOpenFileWindows(t, dir, sub_path, .{ |
| 1938 | 1938 | .follow_symlinks = options.follow_symlinks, |
| ... | ... | @@ -1941,13 +1941,13 @@ fn dirStatPathWindows( |
| 1941 | 1941 | return fileStatWindows(t, file); |
| 1942 | 1942 | } |
| 1943 | 1943 | |
| 1944 | fn dirStatPathWasi( | |
| 1944 | fn dirStatFileWasi( | |
| 1945 | 1945 | userdata: ?*anyopaque, |
| 1946 | 1946 | dir: Dir, |
| 1947 | 1947 | sub_path: []const u8, |
| 1948 | options: Dir.StatPathOptions, | |
| 1949 | ) Dir.StatPathError!File.Stat { | |
| 1950 | if (builtin.link_libc) return dirStatPathPosix(userdata, dir, sub_path, options); | |
| 1948 | options: Dir.StatFileOptions, | |
| 1949 | ) Dir.StatFileError!File.Stat { | |
| 1950 | if (builtin.link_libc) return dirStatFilePosix(userdata, dir, sub_path, options); | |
| 1951 | 1951 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1952 | 1952 | const current_thread = Thread.getCurrent(t); |
| 1953 | 1953 | const wasi = std.os.wasi; |
| ... | ... | @@ -3629,7 +3629,7 @@ fn dirReadIllumos(userdata: ?*anyopaque, dr: *Dir.Reader, buffer: []Dir.Entry) D |
| 3629 | 3629 | if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, "..")) continue; |
| 3630 | 3630 | |
| 3631 | 3631 | // illumos dirent doesn't expose type, so we have to call stat to get it. |
| 3632 | const stat = try posixStatPath(current_thread, dr.dir.handle, name, posix.AT.SYMLINK_NOFOLLOW); | |
| 3632 | const stat = try posixStatFile(current_thread, dr.dir.handle, name, posix.AT.SYMLINK_NOFOLLOW); | |
| 3633 | 3633 | |
| 3634 | 3634 | buffer[buffer_index] = .{ |
| 3635 | 3635 | .name = name, |
lib/std/fs/test.zig+30-27| ... | ... | @@ -160,8 +160,8 @@ fn testWithPathTypeIfSupported(comptime path_type: PathType, comptime path_sep: |
| 160 | 160 | |
| 161 | 161 | // For use in test setup. If the symlink creation fails on Windows with |
| 162 | 162 | // AccessDenied, then make the test failure silent (it is not a Zig failure). |
| 163 | fn setupSymlink(dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void { | |
| 164 | return dir.symLink(target, link, flags) catch |err| switch (err) { | |
| 163 | fn setupSymlink(io: Io, dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void { | |
| 164 | return dir.symLink(io, target, link, flags) catch |err| switch (err) { | |
| 165 | 165 | // Symlink requires admin privileges on windows, so this test can legitimately fail. |
| 166 | 166 | error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err, |
| 167 | 167 | else => return err, |
| ... | ... | @@ -193,15 +193,15 @@ test "Dir.readLink" { |
| 193 | 193 | const canonical_dir_target_path = try ctx.toCanonicalPathSep(dir_target_path); |
| 194 | 194 | |
| 195 | 195 | // test 1: symlink to a file |
| 196 | try setupSymlink(ctx.dir, file_target_path, "symlink1", .{}); | |
| 197 | try testReadLink(ctx.dir, canonical_file_target_path, "symlink1"); | |
| 196 | try setupSymlink(io, ctx.dir, file_target_path, "symlink1", .{}); | |
| 197 | try testReadLink(io, ctx.dir, canonical_file_target_path, "symlink1"); | |
| 198 | 198 | if (builtin.os.tag == .windows) { |
| 199 | 199 | try testReadLinkW(testing.allocator, ctx.dir, canonical_file_target_path, "symlink1"); |
| 200 | 200 | } |
| 201 | 201 | |
| 202 | 202 | // test 2: symlink to a directory (can be different on Windows) |
| 203 | try setupSymlink(ctx.dir, dir_target_path, "symlink2", .{ .is_directory = true }); | |
| 204 | try testReadLink(ctx.dir, canonical_dir_target_path, "symlink2"); | |
| 203 | try setupSymlink(io, ctx.dir, dir_target_path, "symlink2", .{ .is_directory = true }); | |
| 204 | try testReadLink(io, ctx.dir, canonical_dir_target_path, "symlink2"); | |
| 205 | 205 | if (builtin.os.tag == .windows) { |
| 206 | 206 | try testReadLinkW(testing.allocator, ctx.dir, canonical_dir_target_path, "symlink2"); |
| 207 | 207 | } |
| ... | ... | @@ -211,8 +211,8 @@ test "Dir.readLink" { |
| 211 | 211 | const canonical_parent_file = try ctx.toCanonicalPathSep(parent_file); |
| 212 | 212 | var subdir = try ctx.dir.makeOpenPath("subdir", .{}); |
| 213 | 213 | defer subdir.close(io); |
| 214 | try setupSymlink(subdir, canonical_parent_file, "relative-link.txt", .{}); | |
| 215 | try testReadLink(subdir, canonical_parent_file, "relative-link.txt"); | |
| 214 | try setupSymlink(io, subdir, canonical_parent_file, "relative-link.txt", .{}); | |
| 215 | try testReadLink(io, subdir, canonical_parent_file, "relative-link.txt"); | |
| 216 | 216 | if (builtin.os.tag == .windows) { |
| 217 | 217 | try testReadLinkW(testing.allocator, subdir, canonical_parent_file, "relative-link.txt"); |
| 218 | 218 | } |
| ... | ... | @@ -246,9 +246,9 @@ test "Dir.readLink on non-symlinks" { |
| 246 | 246 | }.impl); |
| 247 | 247 | } |
| 248 | 248 | |
| 249 | fn testReadLink(dir: Dir, target_path: []const u8, symlink_path: []const u8) !void { | |
| 249 | fn testReadLink(io: Io, dir: Dir, target_path: []const u8, symlink_path: []const u8) !void { | |
| 250 | 250 | var buffer: [fs.max_path_bytes]u8 = undefined; |
| 251 | const actual = try dir.readLink(symlink_path, buffer[0..]); | |
| 251 | const actual = try dir.readLink(io, symlink_path, &buffer); | |
| 252 | 252 | try testing.expectEqualStrings(target_path, actual); |
| 253 | 253 | } |
| 254 | 254 | |
| ... | ... | @@ -284,7 +284,7 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" { |
| 284 | 284 | const dir_target_path = try ctx.transformPath("subdir"); |
| 285 | 285 | try ctx.dir.makeDir(io, dir_target_path, .default_dir); |
| 286 | 286 | |
| 287 | try setupSymlink(ctx.dir, dir_target_path, "symlink", .{ .is_directory = true }); | |
| 287 | try setupSymlink(io, ctx.dir, dir_target_path, "symlink", .{ .is_directory = true }); | |
| 288 | 288 | |
| 289 | 289 | var symlink: Dir = switch (builtin.target.os.tag) { |
| 290 | 290 | .windows => windows_symlink: { |
| ... | ... | @@ -809,11 +809,11 @@ test "Dir.statFile" { |
| 809 | 809 | const io = ctx.io; |
| 810 | 810 | const test_file_name = try ctx.transformPath("test_file"); |
| 811 | 811 | |
| 812 | try testing.expectError(error.FileNotFound, ctx.dir.statFile(test_file_name)); | |
| 812 | try testing.expectError(error.FileNotFound, ctx.dir.statFile(io, test_file_name, .{})); | |
| 813 | 813 | |
| 814 | 814 | try ctx.dir.writeFile(io, .{ .sub_path = test_file_name, .data = "" }); |
| 815 | 815 | |
| 816 | const stat = try ctx.dir.statFile(test_file_name); | |
| 816 | const stat = try ctx.dir.statFile(io, test_file_name, .{}); | |
| 817 | 817 | try testing.expectEqual(File.Kind.file, stat.kind); |
| 818 | 818 | } |
| 819 | 819 | }.impl); |
| ... | ... | @@ -822,12 +822,13 @@ test "Dir.statFile" { |
| 822 | 822 | test "statFile on dangling symlink" { |
| 823 | 823 | try testWithAllSupportedPathTypes(struct { |
| 824 | 824 | fn impl(ctx: *TestContext) !void { |
| 825 | const io = ctx.io; | |
| 825 | 826 | const symlink_name = try ctx.transformPath("dangling-symlink"); |
| 826 | 827 | const symlink_target = "." ++ fs.path.sep_str ++ "doesnotexist"; |
| 827 | 828 | |
| 828 | try setupSymlink(ctx.dir, symlink_target, symlink_name, .{}); | |
| 829 | try setupSymlink(io, ctx.dir, symlink_target, symlink_name, .{}); | |
| 829 | 830 | |
| 830 | try std.testing.expectError(error.FileNotFound, ctx.dir.statFile(symlink_name)); | |
| 831 | try std.testing.expectError(error.FileNotFound, ctx.dir.statFile(io, symlink_name, .{})); | |
| 831 | 832 | } |
| 832 | 833 | }.impl); |
| 833 | 834 | } |
| ... | ... | @@ -1206,7 +1207,7 @@ test "deleteTree does not follow symlinks" { |
| 1206 | 1207 | var a = try tmp.dir.makeOpenPath("a", .{}); |
| 1207 | 1208 | defer a.close(io); |
| 1208 | 1209 | |
| 1209 | try setupSymlink(a, "../b", "b", .{ .is_directory = true }); | |
| 1210 | try setupSymlink(io, a, "../b", "b", .{ .is_directory = true }); | |
| 1210 | 1211 | } |
| 1211 | 1212 | |
| 1212 | 1213 | try tmp.dir.deleteTree(io, "a"); |
| ... | ... | @@ -1223,7 +1224,7 @@ test "deleteTree on a symlink" { |
| 1223 | 1224 | |
| 1224 | 1225 | // Symlink to a file |
| 1225 | 1226 | try tmp.dir.writeFile(io, .{ .sub_path = "file", .data = "" }); |
| 1226 | try setupSymlink(tmp.dir, "file", "filelink", .{}); | |
| 1227 | try setupSymlink(io, tmp.dir, "file", "filelink", .{}); | |
| 1227 | 1228 | |
| 1228 | 1229 | try tmp.dir.deleteTree(io, "filelink"); |
| 1229 | 1230 | try testing.expectError(error.FileNotFound, tmp.dir.access(io, "filelink", .{})); |
| ... | ... | @@ -1231,7 +1232,7 @@ test "deleteTree on a symlink" { |
| 1231 | 1232 | |
| 1232 | 1233 | // Symlink to a directory |
| 1233 | 1234 | try tmp.dir.makePath(io, "dir"); |
| 1234 | try setupSymlink(tmp.dir, "dir", "dirlink", .{ .is_directory = true }); | |
| 1235 | try setupSymlink(io, tmp.dir, "dir", "dirlink", .{ .is_directory = true }); | |
| 1235 | 1236 | |
| 1236 | 1237 | try tmp.dir.deleteTree(io, "dirlink"); |
| 1237 | 1238 | try testing.expectError(error.FileNotFound, tmp.dir.access(io, "dirlink", .{})); |
| ... | ... | @@ -1337,7 +1338,7 @@ test "makepath through existing valid symlink" { |
| 1337 | 1338 | defer tmp.cleanup(); |
| 1338 | 1339 | |
| 1339 | 1340 | try tmp.dir.makeDir(io, "realfolder", .default_dir); |
| 1340 | try setupSymlink(tmp.dir, "." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{}); | |
| 1341 | try setupSymlink(io, tmp.dir, "." ++ fs.path.sep_str ++ "realfolder", "working-symlink", .{}); | |
| 1341 | 1342 | |
| 1342 | 1343 | try tmp.dir.makePath(io, "working-symlink" ++ fs.path.sep_str ++ "in-realfolder"); |
| 1343 | 1344 | |
| ... | ... | @@ -2178,12 +2179,12 @@ test "invalid UTF-8/WTF-8 paths" { |
| 2178 | 2179 | |
| 2179 | 2180 | try testing.expectError(expected_err, ctx.dir.rename(invalid_path, ctx.dir, invalid_path, io)); |
| 2180 | 2181 | |
| 2181 | try testing.expectError(expected_err, ctx.dir.symLink(invalid_path, invalid_path, .{})); | |
| 2182 | try testing.expectError(expected_err, ctx.dir.symLink(io, invalid_path, invalid_path, .{})); | |
| 2182 | 2183 | if (native_os == .wasi) { |
| 2183 | 2184 | try testing.expectError(expected_err, ctx.dir.symLinkWasi(invalid_path, invalid_path, .{})); |
| 2184 | 2185 | } |
| 2185 | 2186 | |
| 2186 | try testing.expectError(expected_err, ctx.dir.readLink(invalid_path, &[_]u8{})); | |
| 2187 | try testing.expectError(expected_err, ctx.dir.readLink(io, invalid_path, &[_]u8{})); | |
| 2187 | 2188 | if (native_os == .wasi) { |
| 2188 | 2189 | try testing.expectError(expected_err, ctx.dir.readLinkWasi(invalid_path, &[_]u8{})); |
| 2189 | 2190 | } |
| ... | ... | @@ -2386,14 +2387,16 @@ test "File.Writer sendfile with buffered contents" { |
| 2386 | 2387 | test "readlink on Windows" { |
| 2387 | 2388 | if (native_os != .windows) return error.SkipZigTest; |
| 2388 | 2389 | |
| 2389 | try testReadlink("C:\\ProgramData", "C:\\Users\\All Users"); | |
| 2390 | try testReadlink("C:\\Users\\Default", "C:\\Users\\Default User"); | |
| 2391 | try testReadlink("C:\\Users", "C:\\Documents and Settings"); | |
| 2390 | const io = testing.io; | |
| 2391 | ||
| 2392 | try testReadLinkWindows(io, "C:\\ProgramData", "C:\\Users\\All Users"); | |
| 2393 | try testReadLinkWindows(io, "C:\\Users\\Default", "C:\\Users\\Default User"); | |
| 2394 | try testReadLinkWindows(io, "C:\\Users", "C:\\Documents and Settings"); | |
| 2392 | 2395 | } |
| 2393 | 2396 | |
| 2394 | fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void { | |
| 2397 | fn testReadLinkWindows(io: Io, target_path: []const u8, symlink_path: []const u8) !void { | |
| 2395 | 2398 | var buffer: [fs.max_path_bytes]u8 = undefined; |
| 2396 | const given = try Dir.readLinkAbsolute(symlink_path, buffer[0..]); | |
| 2399 | const given = try Dir.readLinkAbsolute(io, symlink_path, &buffer); | |
| 2397 | 2400 | try expect(mem.eql(u8, target_path, given)); |
| 2398 | 2401 | } |
| 2399 | 2402 | |
| ... | ... | @@ -2424,6 +2427,6 @@ test "readlinkat" { |
| 2424 | 2427 | |
| 2425 | 2428 | // read the link |
| 2426 | 2429 | var buffer: [fs.max_path_bytes]u8 = undefined; |
| 2427 | const read_link = try tmp.dir.readLink("link", &buffer); | |
| 2430 | const read_link = try tmp.dir.readLink(io, "link", &buffer); | |
| 2428 | 2431 | try expect(mem.eql(u8, "file.txt", read_link)); |
| 2429 | 2432 | } |
lib/std/tar.zig+23-31| ... | ... | @@ -653,11 +653,11 @@ fn createDirAndFile(io: Io, dir: Io.Dir, file_name: []const u8, permissions: Io. |
| 653 | 653 | |
| 654 | 654 | // Creates a symbolic link at path `file_name` which points to `link_name`. |
| 655 | 655 | fn createDirAndSymlink(io: Io, dir: Io.Dir, link_name: []const u8, file_name: []const u8) !void { |
| 656 | dir.symLink(link_name, file_name, .{}) catch |err| { | |
| 656 | dir.symLink(io, link_name, file_name, .{}) catch |err| { | |
| 657 | 657 | if (err == error.FileNotFound) { |
| 658 | 658 | if (std.fs.path.dirname(file_name)) |dir_name| { |
| 659 | 659 | try dir.makePath(io, dir_name); |
| 660 | return try dir.symLink(link_name, file_name, .{}); | |
| 660 | return try dir.symLink(io, link_name, file_name, .{}); | |
| 661 | 661 | } |
| 662 | 662 | } |
| 663 | 663 | return err; |
| ... | ... | @@ -996,15 +996,15 @@ test pipeToFileSystem { |
| 996 | 996 | return err; |
| 997 | 997 | }; |
| 998 | 998 | |
| 999 | try testing.expectError(error.FileNotFound, dir.statFile("empty")); | |
| 1000 | try testing.expect((try dir.statFile("a/file")).kind == .file); | |
| 1001 | try testing.expect((try dir.statFile("b/symlink")).kind == .file); // statFile follows symlink | |
| 999 | try testing.expectError(error.FileNotFound, dir.statFile(io, "empty", .{})); | |
| 1000 | try testing.expect((try dir.statFile(io, "a/file", .{})).kind == .file); | |
| 1001 | try testing.expect((try dir.statFile(io, "b/symlink", .{})).kind == .file); // statFile follows symlink | |
| 1002 | 1002 | |
| 1003 | 1003 | var buf: [32]u8 = undefined; |
| 1004 | 1004 | try testing.expectEqualSlices( |
| 1005 | 1005 | u8, |
| 1006 | 1006 | "../a/file", |
| 1007 | normalizePath(try dir.readLink("b/symlink", &buf)), | |
| 1007 | normalizePath(buf[0..try dir.readLink(io, "b/symlink", &buf)]), | |
| 1008 | 1008 | ); |
| 1009 | 1009 | } |
| 1010 | 1010 | |
| ... | ... | @@ -1120,28 +1120,18 @@ fn normalizePath(bytes: []u8) []u8 { |
| 1120 | 1120 | |
| 1121 | 1121 | // File system mode based on tar header mode and mode_mode options. |
| 1122 | 1122 | fn filePermissions(mode: u32, options: PipeOptions) Io.File.Permissions { |
| 1123 | const default_mode = 0o666; | |
| 1124 | ||
| 1125 | if (!Io.File.Permissions.has_executable_bit or options.mode_mode == .ignore) | |
| 1126 | return .fromMode(default_mode); | |
| 1127 | ||
| 1128 | const S = std.posix.S; | |
| 1129 | ||
| 1130 | // The mode from the tar file is inspected for the owner executable bit. | |
| 1131 | if (mode & S.IXUSR == 0) | |
| 1132 | return .fromMode(default_mode); | |
| 1133 | ||
| 1134 | // This bit is copied to the group and other executable bits. | |
| 1135 | // Other bits of the mode are left as the default when creating files. | |
| 1136 | return .fromMode(default_mode | S.IXUSR | S.IXGRP | S.IXOTH); | |
| 1123 | return if (!Io.File.Permissions.has_executable_bit or options.mode_mode == .ignore or (mode & 0o100) == 0) | |
| 1124 | .default_file | |
| 1125 | else | |
| 1126 | .executable_file; | |
| 1137 | 1127 | } |
| 1138 | 1128 | |
| 1139 | 1129 | test filePermissions { |
| 1140 | 1130 | if (!Io.File.Permissions.has_executable_bit) return error.SkipZigTest; |
| 1141 | try testing.expectEqual(0o666, filePermissions(0o744, PipeOptions{ .mode_mode = .ignore })); | |
| 1142 | try testing.expectEqual(0o777, filePermissions(0o744, PipeOptions{})); | |
| 1143 | try testing.expectEqual(0o666, filePermissions(0o644, PipeOptions{})); | |
| 1144 | try testing.expectEqual(0o666, filePermissions(0o655, PipeOptions{})); | |
| 1131 | try testing.expectEqual(.default_file, filePermissions(0o744, .{ .mode_mode = .ignore })); | |
| 1132 | try testing.expectEqual(.executable_file, filePermissions(0o744, .{})); | |
| 1133 | try testing.expectEqual(.default_file, filePermissions(0o644, .{})); | |
| 1134 | try testing.expectEqual(.default_file, filePermissions(0o655, .{})); | |
| 1145 | 1135 | } |
| 1146 | 1136 | |
| 1147 | 1137 | test "executable bit" { |
| ... | ... | @@ -1167,19 +1157,21 @@ test "executable bit" { |
| 1167 | 1157 | return err; |
| 1168 | 1158 | }; |
| 1169 | 1159 | |
| 1170 | const fs = try tmp.dir.statFile("a/file"); | |
| 1160 | const fs = try tmp.dir.statFile(io, "a/file", .{}); | |
| 1171 | 1161 | try testing.expect(fs.kind == .file); |
| 1172 | 1162 | |
| 1163 | const mode = fs.permissions.toMode(); | |
| 1164 | ||
| 1173 | 1165 | if (opt == .executable_bit_only) { |
| 1174 | 1166 | // Executable bit is set for user, group and others |
| 1175 | try testing.expect(fs.mode & S.IXUSR > 0); | |
| 1176 | try testing.expect(fs.mode & S.IXGRP > 0); | |
| 1177 | try testing.expect(fs.mode & S.IXOTH > 0); | |
| 1167 | try testing.expect(mode & S.IXUSR > 0); | |
| 1168 | try testing.expect(mode & S.IXGRP > 0); | |
| 1169 | try testing.expect(mode & S.IXOTH > 0); | |
| 1178 | 1170 | } |
| 1179 | 1171 | if (opt == .ignore) { |
| 1180 | try testing.expect(fs.mode & S.IXUSR == 0); | |
| 1181 | try testing.expect(fs.mode & S.IXGRP == 0); | |
| 1182 | try testing.expect(fs.mode & S.IXOTH == 0); | |
| 1172 | try testing.expect(mode & S.IXUSR == 0); | |
| 1173 | try testing.expect(mode & S.IXGRP == 0); | |
| 1174 | try testing.expect(mode & S.IXOTH == 0); | |
| 1183 | 1175 | } |
| 1184 | 1176 | } |
| 1185 | 1177 | } |
lib/std/tar/test.zig+2-2| ... | ... | @@ -504,6 +504,6 @@ test "case sensitivity" { |
| 504 | 504 | }; |
| 505 | 505 | |
| 506 | 506 | // on case sensitive os both files are created |
| 507 | try testing.expect((try root.dir.statFile("alacritty/darkermatrix.yml")).kind == .file); | |
| 508 | try testing.expect((try root.dir.statFile("alacritty/Darkermatrix.yml")).kind == .file); | |
| 507 | try testing.expect((try root.dir.statFile(io, "alacritty/darkermatrix.yml", .{})).kind == .file); | |
| 508 | try testing.expect((try root.dir.statFile(io, "alacritty/Darkermatrix.yml", .{})).kind == .file); | |
| 509 | 509 | } |
lib/std/zig/WindowsSdk.zig+1-1| ... | ... | @@ -1012,7 +1012,7 @@ const MsvcLibDir = struct { |
| 1012 | 1012 | var dir = std.fs.openDirAbsolute(lib_dir_path, .{}) catch return false; |
| 1013 | 1013 | defer dir.close(io); |
| 1014 | 1014 | |
| 1015 | const stat = dir.statFile("vcruntime.lib") catch return false; | |
| 1015 | const stat = dir.statFile(io, "vcruntime.lib", .{}) catch return false; | |
| 1016 | 1016 | if (stat.kind != .file) |
| 1017 | 1017 | return false; |
| 1018 | 1018 |
lib/std/zig/parser_test.zig+1-1| ... | ... | @@ -4539,7 +4539,7 @@ test "zig fmt: Only indent multiline string literals in function calls" { |
| 4539 | 4539 | test "zig fmt: Don't add extra newline after if" { |
| 4540 | 4540 | try testCanonical( |
| 4541 | 4541 | \\pub fn atomicSymLink(allocator: Allocator, existing_path: []const u8, new_path: []const u8) !void { |
| 4542 | \\ if (cwd().symLink(existing_path, new_path, .{})) { | |
| 4542 | \\ if (foo().bar(existing_path, new_path, .{})) { | |
| 4543 | 4543 | \\ return; |
| 4544 | 4544 | \\ } |
| 4545 | 4545 | \\} |
src/Builtin.zig+2-1| ... | ... | @@ -313,8 +313,9 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void { |
| 313 | 313 | assert(file.source != null); |
| 314 | 314 | |
| 315 | 315 | const root_dir, const sub_path = file.path.openInfo(comp.dirs); |
| 316 | const io = comp.io; | |
| 316 | 317 | |
| 317 | if (root_dir.statFile(sub_path)) |stat| { | |
| 318 | if (root_dir.statFile(io, sub_path, .{})) |stat| { | |
| 318 | 319 | if (stat.size != file.source.?.len) { |
| 319 | 320 | std.log.warn( |
| 320 | 321 | "the cached file '{f}' had the wrong size. Expected {d}, found {d}. " ++ |
src/Package/Fetch.zig+10-10| ... | ... | @@ -1440,13 +1440,13 @@ fn recursiveDirectoryCopy(f: *Fetch, dir: Io.Dir, tmp_dir: Io.Dir) anyerror!void |
| 1440 | 1440 | }, |
| 1441 | 1441 | .sym_link => { |
| 1442 | 1442 | var buf: [fs.max_path_bytes]u8 = undefined; |
| 1443 | const link_name = try dir.readLink(entry.path, &buf); | |
| 1443 | const link_name = try dir.readLink(io, entry.path, &buf); | |
| 1444 | 1444 | // TODO: if this would create a symlink to outside |
| 1445 | 1445 | // the destination directory, fail with an error instead. |
| 1446 | tmp_dir.symLink(link_name, entry.path, .{}) catch |err| switch (err) { | |
| 1446 | tmp_dir.symLink(io, link_name, entry.path, .{}) catch |err| switch (err) { | |
| 1447 | 1447 | error.FileNotFound => { |
| 1448 | 1448 | if (fs.path.dirname(entry.path)) |dirname| try tmp_dir.makePath(io, dirname); |
| 1449 | try tmp_dir.symLink(link_name, entry.path, .{}); | |
| 1449 | try tmp_dir.symLink(io, link_name, entry.path, .{}); | |
| 1450 | 1450 | }, |
| 1451 | 1451 | else => |e| return e, |
| 1452 | 1452 | }; |
| ... | ... | @@ -1698,7 +1698,7 @@ fn hashFileFallible(io: Io, dir: Io.Dir, hashed_file: *HashedFile) HashedFile.Er |
| 1698 | 1698 | } |
| 1699 | 1699 | }, |
| 1700 | 1700 | .link => { |
| 1701 | const link_name = try dir.readLink(hashed_file.fs_path, &buf); | |
| 1701 | const link_name = try dir.readLink(io, hashed_file.fs_path, &buf); | |
| 1702 | 1702 | if (fs.path.sep != canonical_sep) { |
| 1703 | 1703 | // Package hashes are intended to be consistent across |
| 1704 | 1704 | // platforms which means we must normalize path separators |
| ... | ... | @@ -2218,13 +2218,13 @@ test "set executable bit based on file content" { |
| 2218 | 2218 | defer out.close(io); |
| 2219 | 2219 | const S = std.posix.S; |
| 2220 | 2220 | // expect executable bit not set |
| 2221 | try std.testing.expect((try out.statFile("file1")).mode & S.IXUSR == 0); | |
| 2222 | try std.testing.expect((try out.statFile("script_without_shebang")).mode & S.IXUSR == 0); | |
| 2221 | try std.testing.expect((try out.statFile(io, "file1", .{})).mode & S.IXUSR == 0); | |
| 2222 | try std.testing.expect((try out.statFile(io, "script_without_shebang", .{})).mode & S.IXUSR == 0); | |
| 2223 | 2223 | // expect executable bit set |
| 2224 | try std.testing.expect((try out.statFile("hello")).mode & S.IXUSR != 0); | |
| 2225 | try std.testing.expect((try out.statFile("script")).mode & S.IXUSR != 0); | |
| 2226 | try std.testing.expect((try out.statFile("script_with_shebang_without_exec_bit")).mode & S.IXUSR != 0); | |
| 2227 | try std.testing.expect((try out.statFile("hello_ln")).mode & S.IXUSR != 0); | |
| 2224 | try std.testing.expect((try out.statFile(io, "hello", .{})).mode & S.IXUSR != 0); | |
| 2225 | try std.testing.expect((try out.statFile(io, "script", .{})).mode & S.IXUSR != 0); | |
| 2226 | try std.testing.expect((try out.statFile(io, "script_with_shebang_without_exec_bit", .{})).mode & S.IXUSR != 0); | |
| 2227 | try std.testing.expect((try out.statFile(io, "hello_ln", .{})).mode & S.IXUSR != 0); | |
| 2228 | 2228 | |
| 2229 | 2229 | // |
| 2230 | 2230 | // $ ls -al zig-cache/tmp/OCz9ovUcstDjTC_U/zig-global-cache/p/1220fecb4c06a9da8673c87fe8810e15785f1699212f01728eadce094d21effeeef3 |
src/Package/Fetch/git.zig+1-1| ... | ... | @@ -281,7 +281,7 @@ pub const Repository = struct { |
| 281 | 281 | const symlink_object = try repository.odb.readObject(); |
| 282 | 282 | if (symlink_object.type != .blob) return error.InvalidFile; |
| 283 | 283 | const link_name = symlink_object.data; |
| 284 | dir.symLink(link_name, entry.name, .{}) catch |e| { | |
| 284 | dir.symLink(io, link_name, entry.name, .{}) catch |e| { | |
| 285 | 285 | const file_name = try std.fs.path.join(diagnostics.allocator, &.{ current_path, entry.name }); |
| 286 | 286 | errdefer diagnostics.allocator.free(file_name); |
| 287 | 287 | const link_name_dup = try diagnostics.allocator.dupe(u8, link_name); |
src/fmt.zig+1-1| ... | ... | @@ -182,7 +182,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! |
| 182 | 182 | // Mark any excluded files/directories as already seen, |
| 183 | 183 | // so that they are skipped later during actual processing |
| 184 | 184 | for (excluded_files.items) |file_path| { |
| 185 | const stat = Io.Dir.cwd().statFile(file_path) catch |err| switch (err) { | |
| 185 | const stat = Io.Dir.cwd().statFile(io, file_path, .{}) catch |err| switch (err) { | |
| 186 | 186 | error.FileNotFound => continue, |
| 187 | 187 | // On Windows, statFile does not work for directories |
| 188 | 188 | error.IsDir => dir: { |