| ... | @@ -66,7 +66,15 @@ pub const need_async_thread = std.io.is_async and switch (builtin.os.tag) { | ... | @@ -66,7 +66,15 @@ pub const need_async_thread = std.io.is_async and switch (builtin.os.tag) { |
| 66 | | 66 | |
| 67 | /// TODO remove the allocator requirement from this API | 67 | /// TODO remove the allocator requirement from this API |
| 68 | pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void { | 68 | pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void { |
| 69 | if (symLinkAbsolute(existing_path, new_path, .{})) { | 69 | const res = blk: { |
| | 70 | // TODO this is just a temporary until Dir.symLink is implemented on Windows |
| | 71 | if (builtin.os.tag == .windows) { |
| | 72 | break :blk os.windows.CreateSymbolicLink(new_path, existing_path, false); |
| | 73 | } else { |
| | 74 | break :blk cwd().symLink(existing_path, new_path, .{}); |
| | 75 | } |
| | 76 | }; |
| | 77 | if (res) { |
| 70 | return; | 78 | return; |
| 71 | } else |err| switch (err) { | 79 | } else |err| switch (err) { |
| 72 | error.PathAlreadyExists => {}, | 80 | error.PathAlreadyExists => {}, |
| ... | @@ -84,7 +92,15 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: | ... | @@ -84,7 +92,15 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: |
| 84 | try crypto.randomBytes(rand_buf[0..]); | 92 | try crypto.randomBytes(rand_buf[0..]); |
| 85 | base64_encoder.encode(tmp_path[dirname.len + 1 ..], &rand_buf); | 93 | base64_encoder.encode(tmp_path[dirname.len + 1 ..], &rand_buf); |
| 86 | | 94 | |
| 87 | if (symLinkAbsolute(existing_path, tmp_path, .{})) { | 95 | const res2 = blk: { |
| | 96 | // TODO this is just a temporary until Dir.symLink is implemented on Windows |
| | 97 | if (builtin.os.tag == .windows) { |
| | 98 | break :blk os.windows.CreateSymbolicLink(tmp_path, existing_path, false); |
| | 99 | } else { |
| | 100 | break :blk cwd().symLink(existing_path, new_path, .{}); |
| | 101 | } |
| | 102 | }; |
| | 103 | if (res2) { |
| 88 | return rename(tmp_path, new_path); | 104 | return rename(tmp_path, new_path); |
| 89 | } else |err| switch (err) { | 105 | } else |err| switch (err) { |
| 90 | error.PathAlreadyExists => continue, | 106 | error.PathAlreadyExists => continue, |
| ... | @@ -669,7 +685,7 @@ pub const Dir = struct { | ... | @@ -669,7 +685,7 @@ pub const Dir = struct { |
| 669 | w.RIGHT_FD_FILESTAT_SET_TIMES | | 685 | w.RIGHT_FD_FILESTAT_SET_TIMES | |
| 670 | w.RIGHT_FD_FILESTAT_SET_SIZE; | 686 | w.RIGHT_FD_FILESTAT_SET_SIZE; |
| 671 | } | 687 | } |
| 672 | const fd = try os.openatWasi(self.fd, sub_path, 0x0, fdflags, base, 0x0); | 688 | const fd = try os.openatWasi(self.fd, sub_path, 0x0, 0x0, fdflags, base, 0x0); |
| 673 | return File{ .handle = fd }; | 689 | return File{ .handle = fd }; |
| 674 | } | 690 | } |
| 675 | | 691 | |
| ... | @@ -789,7 +805,7 @@ pub const Dir = struct { | ... | @@ -789,7 +805,7 @@ pub const Dir = struct { |
| 789 | if (flags.exclusive) { | 805 | if (flags.exclusive) { |
| 790 | oflags |= w.O_EXCL; | 806 | oflags |= w.O_EXCL; |
| 791 | } | 807 | } |
| 792 | const fd = try os.openatWasi(self.fd, sub_path, oflags, 0x0, base, 0x0); | 808 | const fd = try os.openatWasi(self.fd, sub_path, 0x0, oflags, 0x0, base, 0x0); |
| 793 | return File{ .handle = fd }; | 809 | return File{ .handle = fd }; |
| 794 | } | 810 | } |
| 795 | | 811 | |
| ... | @@ -952,7 +968,7 @@ pub const Dir = struct { | ... | @@ -952,7 +968,7 @@ pub const Dir = struct { |
| 952 | /// of the result. It means the `iterate` function can be called. | 968 | /// of the result. It means the `iterate` function can be called. |
| 953 | iterate: bool = false, | 969 | iterate: bool = false, |
| 954 | | 970 | |
| 955 | /// `true` means it won't dereference the symlink. | 971 | /// `true` means it won't dereference the symlinks. |
| 956 | no_follow: bool = false, | 972 | no_follow: bool = false, |
| 957 | }; | 973 | }; |
| 958 | | 974 | |
| ... | @@ -1001,7 +1017,7 @@ pub const Dir = struct { | ... | @@ -1001,7 +1017,7 @@ pub const Dir = struct { |
| 1001 | // TODO do we really need all the rights here? | 1017 | // TODO do we really need all the rights here? |
| 1002 | const inheriting: w.rights_t = w.RIGHT_ALL ^ w.RIGHT_SOCK_SHUTDOWN; | 1018 | const inheriting: w.rights_t = w.RIGHT_ALL ^ w.RIGHT_SOCK_SHUTDOWN; |
| 1003 | | 1019 | |
| 1004 | const result = os.openatWasi(self.fd, sub_path, w.O_DIRECTORY, symlink_flags, base, inheriting); | 1020 | const result = os.openatWasi(self.fd, sub_path, symlink_flags, w.O_DIRECTORY, 0x0, base, inheriting); |
| 1005 | const fd = result catch |err| switch (err) { | 1021 | const fd = result catch |err| switch (err) { |
| 1006 | error.FileTooBig => unreachable, // can't happen for directories | 1022 | error.FileTooBig => unreachable, // can't happen for directories |
| 1007 | error.IsDir => unreachable, // we're providing O_DIRECTORY | 1023 | error.IsDir => unreachable, // we're providing O_DIRECTORY |
| ... | @@ -1211,6 +1227,38 @@ pub const Dir = struct { | ... | @@ -1211,6 +1227,38 @@ pub const Dir = struct { |
| 1211 | }; | 1227 | }; |
| 1212 | } | 1228 | } |
| 1213 | | 1229 | |
| | 1230 | /// Creates a symbolic link named `sym_link_path` which contains the string `target_path`. |
| | 1231 | /// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent |
| | 1232 | /// one; the latter case is known as a dangling link. |
| | 1233 | /// If `sym_link_path` exists, it will not be overwritten. |
| | 1234 | /// TODO add Windows support |
| | 1235 | pub fn symLink( |
| | 1236 | self: Dir, |
| | 1237 | target_path: []const u8, |
| | 1238 | sym_link_path: []const u8, |
| | 1239 | flags: SymLinkFlags, |
| | 1240 | ) !void { |
| | 1241 | if (builtin.os.tag == .wasi) { |
| | 1242 | return self.symLinkWasi(target_path, sym_link_path); |
| | 1243 | } |
| | 1244 | if (builtin.os.tag == .windows) { |
| | 1245 | @compileError("TODO implement Dir.symLink on Windows"); |
| | 1246 | } |
| | 1247 | const target_path_c = try os.toPosixPath(target_path); |
| | 1248 | const sym_link_path_c = try os.toPosixPath(sym_link_path); |
| | 1249 | return self.symLinkZ(&target_path_c, &sym_link_path_c, flags); |
| | 1250 | } |
| | 1251 | |
| | 1252 | /// WASI-only. Same as `symLink` except targeting WASI. |
| | 1253 | pub fn symLinkWasi(self: Dir, target_path: []const u8, sym_link_path: []const u8, flags: SymLinkFlags) !void { |
| | 1254 | return os.symlinkatWasi(target_path, self.fd, sym_link_path); |
| | 1255 | } |
| | 1256 | |
| | 1257 | /// Same as `symLink`, except the pathname parameters are null-terminated. |
| | 1258 | pub fn symLinkZ(self: Dir, target_path_c: [*:0]const u8, sym_link_path_c: [*:0]const u8, flags: SymLinkFlags) !void { |
| | 1259 | return os.symlinkatZ(target_path_c, self.fd, sym_link_path_c); |
| | 1260 | } |
| | 1261 | |
| 1214 | /// Read value of a symbolic link. | 1262 | /// Read value of a symbolic link. |
| 1215 | /// The return value is a slice of `buffer`, from index `0`. | 1263 | /// The return value is a slice of `buffer`, from index `0`. |
| 1216 | /// Asserts that the path parameter has no null bytes. | 1264 | /// Asserts that the path parameter has no null bytes. |
| ... | @@ -1305,7 +1353,6 @@ pub const Dir = struct { | ... | @@ -1305,7 +1353,6 @@ pub const Dir = struct { |
| 1305 | error.Unexpected, | 1353 | error.Unexpected, |
| 1306 | => |e| return e, | 1354 | => |e| return e, |
| 1307 | } | 1355 | } |
| 1308 | | | |
| 1309 | var dir = self.openDir(sub_path, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) { | 1356 | var dir = self.openDir(sub_path, .{ .iterate = true, .no_follow = true }) catch |err| switch (err) { |
| 1310 | error.NotDir => { | 1357 | error.NotDir => { |
| 1311 | if (got_access_denied) { | 1358 | if (got_access_denied) { |
| ... | @@ -1718,7 +1765,7 @@ pub const readLinkC = @compileError("deprecated; use Dir.readLinkZ or readLinkAb | ... | @@ -1718,7 +1765,7 @@ pub const readLinkC = @compileError("deprecated; use Dir.readLinkZ or readLinkAb |
| 1718 | /// or a directory. This value is ignored on all hosts except Windows where | 1765 | /// or a directory. This value is ignored on all hosts except Windows where |
| 1719 | /// creating symlinks to different resource types, requires different flags. | 1766 | /// creating symlinks to different resource types, requires different flags. |
| 1720 | /// By default, `symLinkAbsolute` is assumed to point to a file. | 1767 | /// By default, `symLinkAbsolute` is assumed to point to a file. |
| 1721 | pub const SymlinkFlags = struct { | 1768 | pub const SymLinkFlags = struct { |
| 1722 | is_directory: bool = false, | 1769 | is_directory: bool = false, |
| 1723 | }; | 1770 | }; |
| 1724 | | 1771 | |
| ... | @@ -1727,9 +1774,9 @@ pub const SymlinkFlags = struct { | ... | @@ -1727,9 +1774,9 @@ pub const SymlinkFlags = struct { |
| 1727 | /// one; the latter case is known as a dangling link. | 1774 | /// one; the latter case is known as a dangling link. |
| 1728 | /// If `sym_link_path` exists, it will not be overwritten. | 1775 | /// If `sym_link_path` exists, it will not be overwritten. |
| 1729 | /// See also `symLinkAbsoluteZ` and `symLinkAbsoluteW`. | 1776 | /// See also `symLinkAbsoluteZ` and `symLinkAbsoluteW`. |
| 1730 | pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags: SymlinkFlags) !void { | 1777 | pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags: SymLinkFlags) !void { |
| 1731 | if (builtin.os.tag == .wasi) { | 1778 | if (builtin.os.tag == .wasi) { |
| 1732 | @compileError("symLinkAbsolute is not supported in WASI"); | 1779 | @compileError("symLinkAbsolute is not supported in WASI; use Dir.symLinkWasi instead"); |
| 1733 | } | 1780 | } |
| 1734 | assert(path.isAbsolute(target_path)); | 1781 | assert(path.isAbsolute(target_path)); |
| 1735 | assert(path.isAbsolute(sym_link_path)); | 1782 | assert(path.isAbsolute(sym_link_path)); |
| ... | @@ -1741,9 +1788,9 @@ pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags | ... | @@ -1741,9 +1788,9 @@ pub fn symLinkAbsolute(target_path: []const u8, sym_link_path: []const u8, flags |
| 1741 | | 1788 | |
| 1742 | /// Windows-only. Same as `symLinkAbsolute` except the parameters are null-terminated, WTF16 encoded. | 1789 | /// Windows-only. Same as `symLinkAbsolute` except the parameters are null-terminated, WTF16 encoded. |
| 1743 | /// Note that this function will by default try creating a symbolic link to a file. If you would | 1790 | /// Note that this function will by default try creating a symbolic link to a file. If you would |
| 1744 | /// like to create a symbolic link to a directory, specify this with `SymlinkFlags{ .is_directory = true }`. | 1791 | /// like to create a symbolic link to a directory, specify this with `SymLinkFlags{ .is_directory = true }`. |
| 1745 | /// See also `symLinkAbsolute`, `symLinkAbsoluteZ`. | 1792 | /// See also `symLinkAbsolute`, `symLinkAbsoluteZ`. |
| 1746 | pub fn symLinkAbsoluteW(target_path_w: [*:0]const u16, sym_link_path_w: [*:0]const u16, flags: SymlinkFlags) !void { | 1793 | pub fn symLinkAbsoluteW(target_path_w: [*:0]const u16, sym_link_path_w: [*:0]const u16, flags: SymLinkFlags) !void { |
| 1747 | assert(path.isAbsoluteWindowsW(target_path_w)); | 1794 | assert(path.isAbsoluteWindowsW(target_path_w)); |
| 1748 | assert(path.isAbsoluteWindowsW(sym_link_path_w)); | 1795 | assert(path.isAbsoluteWindowsW(sym_link_path_w)); |
| 1749 | return os.windows.CreateSymbolicLinkW(sym_link_path_w, target_path_w, flags.is_directory); | 1796 | return os.windows.CreateSymbolicLinkW(sym_link_path_w, target_path_w, flags.is_directory); |
| ... | @@ -1751,7 +1798,7 @@ pub fn symLinkAbsoluteW(target_path_w: [*:0]const u16, sym_link_path_w: [*:0]con | ... | @@ -1751,7 +1798,7 @@ pub fn symLinkAbsoluteW(target_path_w: [*:0]const u16, sym_link_path_w: [*:0]con |
| 1751 | | 1798 | |
| 1752 | /// Same as `symLinkAbsolute` except the parameters are null-terminated pointers. | 1799 | /// Same as `symLinkAbsolute` except the parameters are null-terminated pointers. |
| 1753 | /// See also `symLinkAbsolute`. | 1800 | /// See also `symLinkAbsolute`. |
| 1754 | pub fn symLinkAbsoluteZ(target_path_c: [*:0]const u8, sym_link_path_c: [*:0]const u8, flags: SymlinkFlags) !void { | 1801 | pub fn symLinkAbsoluteZ(target_path_c: [*:0]const u8, sym_link_path_c: [*:0]const u8, flags: SymLinkFlags) !void { |
| 1755 | assert(path.isAbsoluteZ(target_path_c)); | 1802 | assert(path.isAbsoluteZ(target_path_c)); |
| 1756 | assert(path.isAbsoluteZ(sym_link_path_c)); | 1803 | assert(path.isAbsoluteZ(sym_link_path_c)); |
| 1757 | if (builtin.os.tag == .windows) { | 1804 | if (builtin.os.tag == .windows) { |
| ... | @@ -1762,8 +1809,8 @@ pub fn symLinkAbsoluteZ(target_path_c: [*:0]const u8, sym_link_path_c: [*:0]cons | ... | @@ -1762,8 +1809,8 @@ pub fn symLinkAbsoluteZ(target_path_c: [*:0]const u8, sym_link_path_c: [*:0]cons |
| 1762 | return os.symlinkZ(target_path_c, sym_link_path_c); | 1809 | return os.symlinkZ(target_path_c, sym_link_path_c); |
| 1763 | } | 1810 | } |
| 1764 | | 1811 | |
| 1765 | pub const symLink = @compileError("deprecated: use symLinkAbsolute"); | 1812 | pub const symLink = @compileError("deprecated: use Dir.symLink or symLinkAbsolute"); |
| 1766 | pub const symLinkC = @compileError("deprecated: use symLinkAbsoluteC"); | 1813 | pub const symLinkC = @compileError("deprecated: use Dir.symLinkZ or symLinkAbsoluteZ"); |
| 1767 | | 1814 | |
| 1768 | pub const Walker = struct { | 1815 | pub const Walker = struct { |
| 1769 | stack: std.ArrayList(StackItem), | 1816 | stack: std.ArrayList(StackItem), |