| ... | @@ -86,51 +86,33 @@ pub const PrevStatus = enum { | ... | @@ -86,51 +86,33 @@ pub const PrevStatus = enum { |
| 86 | fresh, | 86 | fresh, |
| 87 | }; | 87 | }; |
| 88 | | 88 | |
| 89 | /// Deprecated; use `Dir.updateFile`. | 89 | pub const CopyFileOptions = struct { |
| 90 | pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { | 90 | /// When this is `null` the mode is copied from the source file. |
| 91 | const my_cwd = cwd(); | 91 | override_mode: ?File.Mode = null, |
| 92 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{}); | 92 | }; |
| 93 | } | | |
| 94 | | 93 | |
| 95 | /// Deprecated; use `Dir.updateFile`. | 94 | /// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path` |
| 96 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !Dir.PrevStatus { | 95 | /// are absolute. See `Dir.updateFile` for a function that operates on both |
| | 96 | /// absolute and relative paths. |
| | 97 | pub fn updateFileAbsolute( |
| | 98 | source_path: []const u8, |
| | 99 | dest_path: []const u8, |
| | 100 | args: CopyFileOptions, |
| | 101 | ) !PrevStatus { |
| | 102 | assert(path.isAbsolute(source_path)); |
| | 103 | assert(path.isAbsolute(dest_path)); |
| 97 | const my_cwd = cwd(); | 104 | const my_cwd = cwd(); |
| 98 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{ .override_mode = mode }); | 105 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); |
| 99 | } | | |
| 100 | | | |
| 101 | /// Guaranteed to be atomic. | | |
| 102 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, | | |
| 103 | /// there is a possibility of power loss or application termination leaving temporary files present | | |
| 104 | /// in the same directory as dest_path. | | |
| 105 | /// Destination file will have the same mode as the source file. | | |
| 106 | /// TODO rework this to integrate with Dir | | |
| 107 | pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { | | |
| 108 | var in_file = try cwd().openFile(source_path, .{}); | | |
| 109 | defer in_file.close(); | | |
| 110 | | | |
| 111 | const stat = try in_file.stat(); | | |
| 112 | | | |
| 113 | var atomic_file = try AtomicFile.init(dest_path, stat.mode); | | |
| 114 | defer atomic_file.deinit(); | | |
| 115 | | | |
| 116 | try atomic_file.file.writeFileAll(in_file, .{ .in_len = stat.size }); | | |
| 117 | return atomic_file.finish(); | | |
| 118 | } | 106 | } |
| 119 | | 107 | |
| 120 | /// Guaranteed to be atomic. | 108 | /// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` |
| 121 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, | 109 | /// are absolute. See `Dir.copyFile` for a function that operates on both |
| 122 | /// there is a possibility of power loss or application termination leaving temporary files present | 110 | /// absolute and relative paths. |
| 123 | /// in the same directory as dest_path. | 111 | pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: CopyFileOptions) !void { |
| 124 | /// TODO rework this to integrate with Dir | 112 | assert(path.isAbsolute(source_path)); |
| 125 | pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { | 113 | assert(path.isAbsolute(dest_path)); |
| 126 | var in_file = try cwd().openFile(source_path, .{}); | 114 | const my_cwd = cwd(); |
| 127 | defer in_file.close(); | 115 | return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); |
| 128 | | | |
| 129 | var atomic_file = try AtomicFile.init(dest_path, mode); | | |
| 130 | defer atomic_file.deinit(); | | |
| 131 | | | |
| 132 | try atomic_file.file.writeFileAll(in_file, .{}); | | |
| 133 | return atomic_file.finish(); | | |
| 134 | } | 116 | } |
| 135 | | 117 | |
| 136 | /// TODO update this API to avoid a getrandom syscall for every operation. | 118 | /// TODO update this API to avoid a getrandom syscall for every operation. |
| ... | @@ -245,18 +227,17 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { | ... | @@ -245,18 +227,17 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { |
| 245 | os.windows.CloseHandle(handle); | 227 | os.windows.CloseHandle(handle); |
| 246 | } | 228 | } |
| 247 | | 229 | |
| 248 | /// Returns `error.DirNotEmpty` if the directory is not empty. | 230 | /// Deprecated; use `Dir.deleteDir`. |
| 249 | /// To delete a directory recursively, see `deleteTree`. | | |
| 250 | pub fn deleteDir(dir_path: []const u8) !void { | 231 | pub fn deleteDir(dir_path: []const u8) !void { |
| 251 | return os.rmdir(dir_path); | 232 | return os.rmdir(dir_path); |
| 252 | } | 233 | } |
| 253 | | 234 | |
| 254 | /// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string. | 235 | /// Deprecated; use `Dir.deleteDirC`. |
| 255 | pub fn deleteDirC(dir_path: [*:0]const u8) !void { | 236 | pub fn deleteDirC(dir_path: [*:0]const u8) !void { |
| 256 | return os.rmdirC(dir_path); | 237 | return os.rmdirC(dir_path); |
| 257 | } | 238 | } |
| 258 | | 239 | |
| 259 | /// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string. | 240 | /// Deprecated; use `Dir.deleteDirW`. |
| 260 | pub fn deleteDirW(dir_path: [*:0]const u16) !void { | 241 | pub fn deleteDirW(dir_path: [*:0]const u16) !void { |
| 261 | return os.rmdirW(dir_path); | 242 | return os.rmdirW(dir_path); |
| 262 | } | 243 | } |
| ... | @@ -1218,22 +1199,17 @@ pub const Dir = struct { | ... | @@ -1218,22 +1199,17 @@ pub const Dir = struct { |
| 1218 | return os.faccessatW(self.fd, sub_path_w, 0, 0); | 1199 | return os.faccessatW(self.fd, sub_path_w, 0, 0); |
| 1219 | } | 1200 | } |
| 1220 | | 1201 | |
| 1221 | pub const UpdateFileOptions = struct { | | |
| 1222 | override_mode: ?File.Mode = null, | | |
| 1223 | }; | | |
| 1224 | | | |
| 1225 | /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. | 1202 | /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. |
| 1226 | /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, | 1203 | /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, |
| 1227 | /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. | 1204 | /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. |
| 1228 | /// Returns the previous status of the file before updating. | 1205 | /// Returns the previous status of the file before updating. |
| 1229 | /// If any of the directories do not exist for dest_path, they are created. | 1206 | /// If any of the directories do not exist for dest_path, they are created. |
| 1230 | /// If `override_mode` is provided, then that value is used rather than the source path's mode. | | |
| 1231 | pub fn updateFile( | 1207 | pub fn updateFile( |
| 1232 | source_dir: Dir, | 1208 | source_dir: Dir, |
| 1233 | source_path: []const u8, | 1209 | source_path: []const u8, |
| 1234 | dest_dir: Dir, | 1210 | dest_dir: Dir, |
| 1235 | dest_path: []const u8, | 1211 | dest_path: []const u8, |
| 1236 | options: UpdateFileOptions, | 1212 | options: CopyFileOptions, |
| 1237 | ) !PrevStatus { | 1213 | ) !PrevStatus { |
| 1238 | var src_file = try source_dir.openFile(source_path, .{}); | 1214 | var src_file = try source_dir.openFile(source_path, .{}); |
| 1239 | defer src_file.close(); | 1215 | defer src_file.close(); |
| ... | @@ -1272,6 +1248,34 @@ pub const Dir = struct { | ... | @@ -1272,6 +1248,34 @@ pub const Dir = struct { |
| 1272 | return PrevStatus.stale; | 1248 | return PrevStatus.stale; |
| 1273 | } | 1249 | } |
| 1274 | | 1250 | |
| | 1251 | /// Guaranteed to be atomic. |
| | 1252 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, |
| | 1253 | /// there is a possibility of power loss or application termination leaving temporary files present |
| | 1254 | /// in the same directory as dest_path. |
| | 1255 | pub fn copyFile( |
| | 1256 | source_dir: Dir, |
| | 1257 | source_path: []const u8, |
| | 1258 | dest_dir: Dir, |
| | 1259 | dest_path: []const u8, |
| | 1260 | options: CopyFileOptions, |
| | 1261 | ) !void { |
| | 1262 | var in_file = try source_dir.openFile(source_path, .{}); |
| | 1263 | defer in_file.close(); |
| | 1264 | |
| | 1265 | var size: ?u64 = null; |
| | 1266 | const mode = options.override_mode orelse blk: { |
| | 1267 | const stat = try in_file.stat(); |
| | 1268 | size = stat.size; |
| | 1269 | break :blk stat.mode; |
| | 1270 | }; |
| | 1271 | |
| | 1272 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); |
| | 1273 | defer atomic_file.deinit(); |
| | 1274 | |
| | 1275 | try atomic_file.file.writeFileAll(in_file, .{ .in_len = size }); |
| | 1276 | return atomic_file.finish(); |
| | 1277 | } |
| | 1278 | |
| 1275 | pub const AtomicFileOptions = struct { | 1279 | pub const AtomicFileOptions = struct { |
| 1276 | mode: File.Mode = File.default_mode, | 1280 | mode: File.Mode = File.default_mode, |
| 1277 | }; | 1281 | }; |
| ... | @@ -1471,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { | ... | @@ -1471,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1471 | return walker; | 1475 | return walker; |
| 1472 | } | 1476 | } |
| 1473 | | 1477 | |
| 1474 | /// Read value of a symbolic link. | 1478 | /// Deprecated; use `Dir.readLink`. |
| 1475 | /// The return value is a slice of buffer, from index `0`. | | |
| 1476 | pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { | 1479 | pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1477 | return os.readlink(pathname, buffer); | 1480 | return os.readlink(pathname, buffer); |
| 1478 | } | 1481 | } |
| 1479 | | 1482 | |
| 1480 | /// Same as `readLink`, except the parameter is null-terminated. | 1483 | /// Deprecated; use `Dir.readLinkC`. |
| 1481 | pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { | 1484 | pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1482 | return os.readlinkC(pathname_c, buffer); | 1485 | return os.readlinkC(pathname_c, buffer); |
| 1483 | } | 1486 | } |
| ... | @@ -1584,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const | ... | @@ -1584,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const |
| 1584 | } | 1587 | } |
| 1585 | | 1588 | |
| 1586 | /// `realpath`, except caller must free the returned memory. | 1589 | /// `realpath`, except caller must free the returned memory. |
| | 1590 | /// TODO integrate with `Dir` |
| 1587 | pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { | 1591 | pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { |
| 1588 | var buf: [MAX_PATH_BYTES]u8 = undefined; | 1592 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1589 | return mem.dupe(allocator, u8, try os.realpath(pathname, &buf)); | 1593 | return mem.dupe(allocator, u8, try os.realpath(pathname, &buf)); |
| ... | @@ -1592,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { | ... | @@ -1592,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { |
| 1592 | test "" { | 1596 | test "" { |
| 1593 | _ = makeDirAbsolute; | 1597 | _ = makeDirAbsolute; |
| 1594 | _ = makeDirAbsoluteZ; | 1598 | _ = makeDirAbsoluteZ; |
| | 1599 | _ = copyFileAbsolute; |
| | 1600 | _ = updateFileAbsolute; |
| | 1601 | _ = Dir.copyFile; |
| 1595 | _ = @import("fs/path.zig"); | 1602 | _ = @import("fs/path.zig"); |
| 1596 | _ = @import("fs/file.zig"); | 1603 | _ = @import("fs/file.zig"); |
| 1597 | _ = @import("fs/get_app_data_dir.zig"); | 1604 | _ = @import("fs/get_app_data_dir.zig"); |