| author | |
| committer | |
| log | 219acaa1d6ca4279085d7eb9449e7d0469a48432 |
| tree | 8d25f1122c8a168dc37177f82028b56307ba0a0d |
| parent | 4a77c7f2588ce42c10df53fc1242f684ff506720 |
Deprecates std.fs.atomicSymLink and removes the allocator requirement
from the new std.fs.Dir.atomicSymLink. Replaces the two usages of this
within std.
I did not include the TODOs from the original code that were based
off of `switch (err) { ..., else => return err }` not having correct
inference that cases handled in `...` are impossible in the error
union return type because these are not specified in many places but
I can add them back if wanted.
Thank you @squeek502 for help with fixing buffer overflows!3 files changed, 57 insertions(+), 38 deletions(-)
lib/std/Build/Step/Compile.zig+2-3| ... | @@ -1862,19 +1862,18 @@ pub fn doAtomicSymLinks( | ... | @@ -1862,19 +1862,18 @@ pub fn doAtomicSymLinks( |
| 1862 | filename_name_only: []const u8, | 1862 | filename_name_only: []const u8, |
| 1863 | ) !void { | 1863 | ) !void { |
| 1864 | const b = step.owner; | 1864 | const b = step.owner; |
| 1865 | const arena = b.allocator; | ||
| 1866 | const out_dir = fs.path.dirname(output_path) orelse "."; | 1865 | const out_dir = fs.path.dirname(output_path) orelse "."; |
| 1867 | const out_basename = fs.path.basename(output_path); | 1866 | const out_basename = fs.path.basename(output_path); |
| 1868 | // sym link for libfoo.so.1 to libfoo.so.1.2.3 | 1867 | // sym link for libfoo.so.1 to libfoo.so.1.2.3 |
| 1869 | const major_only_path = b.pathJoin(&.{ out_dir, filename_major_only }); | 1868 | const major_only_path = b.pathJoin(&.{ out_dir, filename_major_only }); |
| 1870 | fs.atomicSymLink(arena, out_basename, major_only_path) catch |err| { | 1869 | fs.cwd().atomicSymLink(out_basename, major_only_path, .{}) catch |err| { |
| 1871 | return step.fail("unable to symlink {s} -> {s}: {s}", .{ | 1870 | return step.fail("unable to symlink {s} -> {s}: {s}", .{ |
| 1872 | major_only_path, out_basename, @errorName(err), | 1871 | major_only_path, out_basename, @errorName(err), |
| 1873 | }); | 1872 | }); |
| 1874 | }; | 1873 | }; |
| 1875 | // sym link for libfoo.so to libfoo.so.1 | 1874 | // sym link for libfoo.so to libfoo.so.1 |
| 1876 | const name_only_path = b.pathJoin(&.{ out_dir, filename_name_only }); | 1875 | const name_only_path = b.pathJoin(&.{ out_dir, filename_name_only }); |
| 1877 | fs.atomicSymLink(arena, filename_major_only, name_only_path) catch |err| { | 1876 | fs.cwd().atomicSymLink(filename_major_only, name_only_path, .{}) catch |err| { |
| 1878 | return step.fail("Unable to symlink {s} -> {s}: {s}", .{ | 1877 | return step.fail("Unable to symlink {s} -> {s}: {s}", .{ |
| 1879 | name_only_path, filename_major_only, @errorName(err), | 1878 | name_only_path, filename_major_only, @errorName(err), |
| 1880 | }); | 1879 | }); |
lib/std/fs.zig+3-31| ... | @@ -101,37 +101,9 @@ pub const base64_encoder = base64.Base64Encoder.init(base64_alphabet, null); | ... | @@ -101,37 +101,9 @@ pub const base64_encoder = base64.Base64Encoder.init(base64_alphabet, null); |
| 101 | /// Base64 decoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem. | 101 | /// Base64 decoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem. |
| 102 | pub const base64_decoder = base64.Base64Decoder.init(base64_alphabet, null); | 102 | pub const base64_decoder = base64.Base64Decoder.init(base64_alphabet, null); |
| 103 | 103 | ||
| 104 | /// TODO remove the allocator requirement from this API | 104 | /// Deprecated. Use `cwd().atomicSymLink()` instead. |
| 105 | /// TODO move to Dir | 105 | pub fn atomicSymLink(_: Allocator, existing_path: []const u8, new_path: []const u8) !void { |
| 106 | /// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | 106 | try cwd().atomicSymLink(existing_path, new_path, .{}); |
| 107 | /// On WASI, both paths should be encoded as valid UTF-8. | ||
| 108 | /// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | ||
| 109 | pub fn atomicSymLink(allocator: Allocator, existing_path: []const u8, new_path: []const u8) !void { | ||
| 110 | if (cwd().symLink(existing_path, new_path, .{})) { | ||
| 111 | return; | ||
| 112 | } else |err| switch (err) { | ||
| 113 | error.PathAlreadyExists => {}, | ||
| 114 | else => return err, // TODO zig should know this set does not include PathAlreadyExists | ||
| 115 | } | ||
| 116 | |||
| 117 | const dirname = path.dirname(new_path) orelse "."; | ||
| 118 | |||
| 119 | var rand_buf: [AtomicFile.random_bytes_len]u8 = undefined; | ||
| 120 | const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64_encoder.calcSize(rand_buf.len)); | ||
| 121 | defer allocator.free(tmp_path); | ||
| 122 | @memcpy(tmp_path[0..dirname.len], dirname); | ||
| 123 | tmp_path[dirname.len] = path.sep; | ||
| 124 | while (true) { | ||
| 125 | crypto.random.bytes(rand_buf[0..]); | ||
| 126 | _ = base64_encoder.encode(tmp_path[dirname.len + 1 ..], &rand_buf); | ||
| 127 | |||
| 128 | if (cwd().symLink(existing_path, tmp_path, .{})) { | ||
| 129 | return cwd().rename(tmp_path, new_path); | ||
| 130 | } else |err| switch (err) { | ||
| 131 | error.PathAlreadyExists => continue, | ||
| 132 | else => return err, // TODO zig should know this set does not include PathAlreadyExists | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | 107 | } |
| 136 | 108 | ||
| 137 | /// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path` | 109 | /// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path` |
lib/std/fs/Dir.zig+52-4| ... | @@ -1758,10 +1758,11 @@ pub fn renameW(self: Dir, old_sub_path_w: []const u16, new_sub_path_w: []const u | ... | @@ -1758,10 +1758,11 @@ pub fn renameW(self: Dir, old_sub_path_w: []const u16, new_sub_path_w: []const u |
| 1758 | return posix.renameatW(self.fd, old_sub_path_w, self.fd, new_sub_path_w); | 1758 | return posix.renameatW(self.fd, old_sub_path_w, self.fd, new_sub_path_w); |
| 1759 | } | 1759 | } |
| 1760 | 1760 | ||
| 1761 | /// Use with `Dir.symLink` and `symLinkAbsolute` to specify whether the symlink | 1761 | /// Use with `Dir.symLink`, `Dir.atomicSymLink`, and `symLinkAbsolute` to |
| 1762 | /// will point to a file or a directory. This value is ignored on all hosts | 1762 | /// specify whether the symlink will point to a file or a directory. This value |
| 1763 | /// except Windows where creating symlinks to different resource types, requires | 1763 | /// is ignored on all hosts except Windows where creating symlinks to different |
| 1764 | /// different flags. By default, `symLinkAbsolute` is assumed to point to a file. | 1764 | /// resource types, requires different flags. By default, `symLinkAbsolute` is |
| 1765 | /// assumed to point to a file. | ||
| 1765 | pub const SymLinkFlags = struct { | 1766 | pub const SymLinkFlags = struct { |
| 1766 | is_directory: bool = false, | 1767 | is_directory: bool = false, |
| 1767 | }; | 1768 | }; |
| ... | @@ -1847,6 +1848,50 @@ pub fn symLinkW( | ... | @@ -1847,6 +1848,50 @@ pub fn symLinkW( |
| 1847 | return windows.CreateSymbolicLink(self.fd, sym_link_path_w, target_path_w, flags.is_directory); | 1848 | return windows.CreateSymbolicLink(self.fd, sym_link_path_w, target_path_w, flags.is_directory); |
| 1848 | } | 1849 | } |
| 1849 | 1850 | ||
| 1851 | /// Same as `symLink`, except tries to create the symbolic link until it | ||
| 1852 | /// succeeds or encounters an error other than `error.PathAlreadyExists`. | ||
| 1853 | /// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | ||
| 1854 | /// On WASI, both paths should be encoded as valid UTF-8. | ||
| 1855 | /// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | ||
| 1856 | pub fn atomicSymLink( | ||
| 1857 | dir: Dir, | ||
| 1858 | target_path: []const u8, | ||
| 1859 | sym_link_path: []const u8, | ||
| 1860 | flags: SymLinkFlags, | ||
| 1861 | ) !void { | ||
| 1862 | if (dir.symLink(target_path, sym_link_path, flags)) { | ||
| 1863 | return; | ||
| 1864 | } else |err| switch (err) { | ||
| 1865 | error.PathAlreadyExists => {}, | ||
| 1866 | else => |e| return e, | ||
| 1867 | } | ||
| 1868 | |||
| 1869 | const dirname = path.dirname(sym_link_path) orelse "."; | ||
| 1870 | |||
| 1871 | var rand_buf: [AtomicFile.random_bytes_len]u8 = undefined; | ||
| 1872 | |||
| 1873 | const temp_path_len = dirname.len + 1 + base64_encoder.calcSize(rand_buf.len); | ||
| 1874 | var temp_path_buf: [fs.max_path_bytes]u8 = undefined; | ||
| 1875 | |||
| 1876 | if (temp_path_len > temp_path_buf.len) return error.NameTooLong; | ||
| 1877 | @memcpy(temp_path_buf[0..dirname.len], dirname); | ||
| 1878 | temp_path_buf[dirname.len] = path.sep; | ||
| 1879 | |||
| 1880 | const temp_path = temp_path_buf[0..temp_path_len]; | ||
| 1881 | |||
| 1882 | while (true) { | ||
| 1883 | crypto.random.bytes(rand_buf[0..]); | ||
| 1884 | _ = base64_encoder.encode(temp_path[dirname.len + 1 ..], rand_buf[0..]); | ||
| 1885 | |||
| 1886 | if (dir.symLink(target_path, temp_path, flags)) { | ||
| 1887 | return dir.rename(temp_path, sym_link_path); | ||
| 1888 | } else |err| switch (err) { | ||
| 1889 | error.PathAlreadyExists => continue, | ||
| 1890 | else => |e| return e, | ||
| 1891 | } | ||
| 1892 | } | ||
| 1893 | } | ||
| 1894 | |||
| 1850 | pub const ReadLinkError = posix.ReadLinkError; | 1895 | pub const ReadLinkError = posix.ReadLinkError; |
| 1851 | 1896 | ||
| 1852 | /// Read value of a symbolic link. | 1897 | /// Read value of a symbolic link. |
| ... | @@ -2695,8 +2740,11 @@ const builtin = @import("builtin"); | ... | @@ -2695,8 +2740,11 @@ const builtin = @import("builtin"); |
| 2695 | const std = @import("../std.zig"); | 2740 | const std = @import("../std.zig"); |
| 2696 | const File = std.fs.File; | 2741 | const File = std.fs.File; |
| 2697 | const AtomicFile = std.fs.AtomicFile; | 2742 | const AtomicFile = std.fs.AtomicFile; |
| 2743 | const base64_encoder = fs.base64_encoder; | ||
| 2744 | const crypto = std.crypto; | ||
| 2698 | const posix = std.posix; | 2745 | const posix = std.posix; |
| 2699 | const mem = std.mem; | 2746 | const mem = std.mem; |
| 2747 | const path = fs.path; | ||
| 2700 | const fs = std.fs; | 2748 | const fs = std.fs; |
| 2701 | const Allocator = std.mem.Allocator; | 2749 | const Allocator = std.mem.Allocator; |
| 2702 | const assert = std.debug.assert; | 2750 | const assert = std.debug.assert; |