From fdff381a5644d5e12519ca53012d7b00a33a33c4 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Thu, 5 Mar 2020 20:15:55 -0800 Subject: [PATCH 1/3] fmt: Fix relative paths with . and .. on Windows This is a band-aid fix due to NtCreateFile failing on paths with . or .. in them. --- src-self-hosted/stage2.zig | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 1f65efec8..5c469e4c8 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -318,11 +318,18 @@ const FmtError = error{ } || fs.File.OpenError; fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { - if (fmt.seen.exists(file_path)) return; - try fmt.seen.put(file_path); + // get the real path here to avoid Windows failing on relative file paths with . or .. in them + var real_path = fs.realpathAlloc(fmt.allocator, file_path) catch |err| { + try stderr.print("unable to open '{}': {}\n", .{ file_path, err }); + fmt.any_error = true; + return; + }; + defer fmt.allocator.free(real_path); - const max = std.math.maxInt(usize); - const source_code = fs.cwd().readFileAlloc(fmt.allocator, file_path, max) catch |err| switch (err) { + if (fmt.seen.exists(real_path)) return; + try fmt.seen.put(real_path); + + const source_code = fs.cwd().readFileAlloc(fmt.allocator, real_path, self_hosted_main.max_src_size) catch |err| switch (err) { error.IsDir, error.AccessDenied => { // TODO make event based (and dir.next()) var dir = try fs.cwd().openDir(file_path, .{ .iterate = true }); @@ -332,7 +339,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { while (try dir_it.next()) |entry| { if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) { - const full_path = try fs.path.join(fmt.allocator, &[_][]const u8{ file_path, entry.name }); + const full_path = try fs.path.join(fmt.allocator, &[_][]const u8{ real_path, entry.name }); try fmtPath(fmt, full_path, check_mode); } } @@ -370,7 +377,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { fmt.any_error = true; } } else { - const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path); + const baf = try io.BufferedAtomicFile.create(fmt.allocator, real_path); defer baf.destroy(); const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree); From 41e17106cdcb0bc19f26ef67ebe2d98d920ee21b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 27 Apr 2020 13:38:19 -0400 Subject: [PATCH 2/3] zig fmt: still print the relative path The previous commit made zig fmt print absolute paths; this commit keeps the absolute path resolution but still prints the relative paths to stdout. --- lib/std/io/buffered_atomic_file.zig | 10 +++++++--- src-self-hosted/stage2.zig | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/std/io/buffered_atomic_file.zig b/lib/std/io/buffered_atomic_file.zig index b450a578c..81c040da2 100644 --- a/lib/std/io/buffered_atomic_file.zig +++ b/lib/std/io/buffered_atomic_file.zig @@ -15,8 +15,12 @@ pub const BufferedAtomicFile = struct { /// TODO when https://github.com/ziglang/zig/issues/2761 is solved /// this API will not need an allocator - /// TODO integrate this with Dir API - pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile { + pub fn create( + allocator: *mem.Allocator, + dir: fs.Dir, + dest_path: []const u8, + atomic_file_options: fs.Dir.AtomicFileOptions, + ) !*BufferedAtomicFile { var self = try allocator.create(BufferedAtomicFile); self.* = BufferedAtomicFile{ .atomic_file = undefined, @@ -26,7 +30,7 @@ pub const BufferedAtomicFile = struct { }; errdefer allocator.destroy(self); - self.atomic_file = try fs.cwd().atomicFile(dest_path, .{}); + self.atomic_file = try dir.atomicFile(dest_path, atomic_file_options); errdefer self.atomic_file.deinit(); self.file_stream = self.atomic_file.file.outStream(); diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 5c469e4c8..38ab49ccc 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -339,7 +339,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { while (try dir_it.next()) |entry| { if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) { - const full_path = try fs.path.join(fmt.allocator, &[_][]const u8{ real_path, entry.name }); + const full_path = try fs.path.join(fmt.allocator, &[_][]const u8{ file_path, entry.name }); try fmtPath(fmt, full_path, check_mode); } } @@ -377,7 +377,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { fmt.any_error = true; } } else { - const baf = try io.BufferedAtomicFile.create(fmt.allocator, real_path); + const baf = try io.BufferedAtomicFile.create(fmt.allocator, fs.cwd(), real_path, .{}); defer baf.destroy(); const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree); From 1e04e852009b969741e2969f2aeedb72d73d326a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 27 Apr 2020 13:39:06 -0400 Subject: [PATCH 3/3] std: support `/` in Windows paths --- lib/std/os/windows.zig | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 9cf90efff..7118fabf7 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -1260,15 +1260,9 @@ pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE:0]u16 { pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len:0]u16 { // TODO https://github.com/ziglang/zig/issues/2765 var result: [PATH_MAX_WIDE + suffix.len:0]u16 = undefined; - // > File I/O functions in the Windows API convert "/" to "\" as part of - // > converting the name to an NT-style name, except when using the "\\?\" - // > prefix as detailed in the following sections. - // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation - // Because we want the larger maximum path length for absolute paths, we - // disallow forward slashes in zig std lib file functions on Windows. for (s) |byte| { switch (byte) { - '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName, + '*', '?', '"', '<', '>', '|' => return error.BadPathName, else => {}, } } @@ -1279,6 +1273,17 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) }; const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s); if (end_index + suffix.len > result.len) return error.NameTooLong; + // > File I/O functions in the Windows API convert "/" to "\" as part of + // > converting the name to an NT-style name, except when using the "\\?\" + // > prefix as detailed in the following sections. + // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation + // Because we want the larger maximum path length for absolute paths, we + // convert forward slashes to backward slashes here. + for (result[0..end_index]) |*elem| { + if (elem.* == '/') { + elem.* = '\\'; + } + } mem.copy(u16, result[end_index..], suffix); result[end_index + suffix.len] = 0; return result;