authorgravatar for quae@daurnimator.comdaurnimator <quae@daurnimator.com> 2020-01-15 18:17:14+10:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-03 13:25:43-05:00
logd8f966a04b09ede06840b5fdd42b7d8e65b0cb25
tree4432ed7e3f253bd2f02c016f41f2dba37f77f3ed
parentbfc569bc9877a4f305080bc6cde0e42fed7433e0
signature Commit is signed but in an unrecognized format.

std: fix fs.makePath

The previous behaviour of using path.resolve has unexpected behaviour around symlinks. This more simple implementation is more correct and doesn't require an allocator

1 files changed, 8 insertions(+), 11 deletions(-)

lib/std/fs.zig+8-11
...@@ -301,35 +301,32 @@ pub fn makeDirW(dir_path: [*:0]const u16) !void {...@@ -301,35 +301,32 @@ pub fn makeDirW(dir_path: [*:0]const u16) !void {
301/// already exists and is a directory.301/// already exists and is a directory.
302/// This function is not atomic, and if it returns an error, the file system may302/// This function is not atomic, and if it returns an error, the file system may
303/// have been modified regardless.303/// have been modified regardless.
304/// TODO determine if we can remove the allocator requirement from this function304pub fn makePath(full_path: []const u8) !void {
305pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {305 var end_index: usize = full_path.len;
306 const resolved_path = try path.resolve(allocator, &[_][]const u8{full_path});
307 defer allocator.free(resolved_path);
308
309 var end_index: usize = resolved_path.len;
310 while (true) {306 while (true) {
311 makeDir(resolved_path[0..end_index]) catch |err| switch (err) {307 cwd().makeDir(full_path[0..end_index]) catch |err| switch (err) {
312 error.PathAlreadyExists => {308 error.PathAlreadyExists => {
313 // TODO stat the file and return an error if it's not a directory309 // TODO stat the file and return an error if it's not a directory
314 // this is important because otherwise a dangling symlink310 // this is important because otherwise a dangling symlink
315 // could cause an infinite loop311 // could cause an infinite loop
316 if (end_index == resolved_path.len) return;312 if (end_index == full_path.len) return;
317 },313 },
318 error.FileNotFound => {314 error.FileNotFound => {
315 if (end_index == 0) return err;
319 // march end_index backward until next path component316 // march end_index backward until next path component
320 while (true) {317 while (true) {
321 end_index -= 1;318 end_index -= 1;
322 if (path.isSep(resolved_path[end_index])) break;319 if (path.isSep(full_path[end_index])) break;
323 }320 }
324 continue;321 continue;
325 },322 },
326 else => return err,323 else => return err,
327 };324 };
328 if (end_index == resolved_path.len) return;325 if (end_index == full_path.len) return;
329 // march end_index forward until next path component326 // march end_index forward until next path component
330 while (true) {327 while (true) {
331 end_index += 1;328 end_index += 1;
332 if (end_index == resolved_path.len or path.isSep(resolved_path[end_index])) break;329 if (end_index == full_path.len or path.isSep(full_path[end_index])) break;
333 }330 }
334 }331 }
335}332}