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
This commit is contained in:
daurnimator 2020-01-15 18:17:14 +10:00 committed by Andrew Kelley
parent bfc569bc98
commit d8f966a04b
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9

View File

@ -301,35 +301,32 @@ pub fn makeDirW(dir_path: [*:0]const u16) !void {
/// already exists and is a directory. /// already exists and is a directory.
/// This function is not atomic, and if it returns an error, the file system may /// This function is not atomic, and if it returns an error, the file system may
/// have been modified regardless. /// have been modified regardless.
/// TODO determine if we can remove the allocator requirement from this function pub fn makePath(full_path: []const u8) !void {
pub fn makePath(allocator: *Allocator, full_path: []const u8) !void { var end_index: usize = full_path.len;
const resolved_path = try path.resolve(allocator, &[_][]const u8{full_path});
defer allocator.free(resolved_path);
var end_index: usize = resolved_path.len;
while (true) { while (true) {
makeDir(resolved_path[0..end_index]) catch |err| switch (err) { cwd().makeDir(full_path[0..end_index]) catch |err| switch (err) {
error.PathAlreadyExists => { error.PathAlreadyExists => {
// TODO stat the file and return an error if it's not a directory // TODO stat the file and return an error if it's not a directory
// this is important because otherwise a dangling symlink // this is important because otherwise a dangling symlink
// could cause an infinite loop // could cause an infinite loop
if (end_index == resolved_path.len) return; if (end_index == full_path.len) return;
}, },
error.FileNotFound => { error.FileNotFound => {
if (end_index == 0) return err;
// march end_index backward until next path component // march end_index backward until next path component
while (true) { while (true) {
end_index -= 1; end_index -= 1;
if (path.isSep(resolved_path[end_index])) break; if (path.isSep(full_path[end_index])) break;
} }
continue; continue;
}, },
else => return err, else => return err,
}; };
if (end_index == resolved_path.len) return; if (end_index == full_path.len) return;
// march end_index forward until next path component // march end_index forward until next path component
while (true) { while (true) {
end_index += 1; end_index += 1;
if (end_index == resolved_path.len or path.isSep(resolved_path[end_index])) break; if (end_index == full_path.len or path.isSep(full_path[end_index])) break;
} }
} }
} }