Skip to content

Commit

Permalink
Merge branch 'main' into dylan/fix-libarchive-wide-char-bug
Browse files Browse the repository at this point in the history
  • Loading branch information
dylan-conway authored Feb 1, 2024
2 parents 5cb4af1 + 91cfd61 commit adc95a8
Show file tree
Hide file tree
Showing 18 changed files with 241 additions and 105 deletions.
2 changes: 1 addition & 1 deletion scripts/build.ps1
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
.\scripts\env.sh
.\scripts\env.ps1
ninja -Cbuild
43 changes: 41 additions & 2 deletions src/bun.js/node/node_fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5273,13 +5273,52 @@ pub const NodeFS = struct {

pub fn writeFileWithPathBuffer(pathbuf: *[bun.MAX_PATH_BYTES]u8, args: Arguments.WriteFile) Maybe(Return.WriteFile) {
var path: [:0]const u8 = undefined;
var pathbuf2: [bun.MAX_PATH_BYTES]u8 = undefined;

const fd = switch (args.file) {
.path => brk: {
path = args.file.path.sliceZ(pathbuf);
// On Windows, we potentially mutate the path in posixToPlatformInPlace
// We cannot mutate JavaScript strings in-place. That will break many things.
// So we must always copy the path string on Windows.
path = args.file.path.sliceZWithForceCopy(pathbuf, Environment.isWindows);
bun.path.posixToPlatformInPlace(u8, @constCast(path));

var is_dirfd_different = false;
var dirfd = args.dirfd;
if (Environment.isWindows) {
while (std.mem.startsWith(u8, path, "..\\")) {
is_dirfd_different = true;
var buffer: bun.WPathBuffer = undefined;
const dirfd_path_len = std.os.windows.kernel32.GetFinalPathNameByHandleW(args.dirfd.cast(), &buffer, buffer.len, 0);
const dirfd_path = buffer[0..dirfd_path_len];
const parent_path = bun.Dirname.dirname(u16, dirfd_path).?;
if (std.mem.startsWith(u16, parent_path, &bun.windows.nt_maxpath_prefix)) @constCast(parent_path)[1] = '?';
const newdirfd = switch (bun.sys.openDirAtWindows(bun.invalid_fd, parent_path, false, true)) {
.result => |fd| fd,
.err => |err| {
return .{ .err = err.withPath(path) };
},
};
path = path[3..];
dirfd = newdirfd;
}
}
defer if (is_dirfd_different) {
var d = dirfd.asDir();
d.close();
};
if (Environment.isWindows) {
// windows openat does not support path traversal, fix it here.
// use pathbuf2 here since without it 'panic: @memcpy arguments alias' triggers
if (std.mem.indexOf(u8, path, "\\.\\") != null or std.mem.indexOf(u8, path, "\\..\\") != null) {
const fixed_path = bun.path.normalizeStringWindows(path, &pathbuf2, false, false);
pathbuf2[fixed_path.len] = 0;
path = pathbuf2[0..fixed_path.len :0];
}
}

const open_result = Syscall.openat(
args.dirfd,
dirfd,
path,
@intFromEnum(args.flag) | os.O.NOCTTY,
args.mode,
Expand Down
16 changes: 7 additions & 9 deletions src/bun.js/node/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -657,12 +657,17 @@ pub const PathLike = union(enum) {
pub fn sliceZWithForceCopy(this: PathLike, buf: *[bun.MAX_PATH_BYTES]u8, comptime force: bool) [:0]const u8 {
const sliced = this.slice();

if (Environment.isWindows) {
if (std.fs.path.isAbsolute(sliced)) {
return resolve_path.PosixToWinNormalizer.resolveCWDWithExternalBufZ(buf, sliced) catch @panic("Error while resolving path.");
}
}

if (sliced.len == 0) return "";

if (comptime !force) {
if (sliced[sliced.len - 1] == 0) {
var sliced_ptr = sliced.ptr;
return sliced_ptr[0 .. sliced.len - 1 :0];
return sliced[0 .. sliced.len - 1 :0];
}
}

Expand All @@ -672,13 +677,6 @@ pub const PathLike = union(enum) {
}

pub inline fn sliceZ(this: PathLike, buf: *[bun.MAX_PATH_BYTES]u8) [:0]const u8 {
if (Environment.isWindows) {
const data = this.slice();
if (!std.fs.path.isAbsolute(data)) {
return sliceZWithForceCopy(this, buf, false);
}
return resolve_path.PosixToWinNormalizer.resolveCWDWithExternalBufZ(buf, data) catch @panic("Error while resolving path.");
}
return sliceZWithForceCopy(this, buf, false);
}

Expand Down
11 changes: 11 additions & 0 deletions src/bun.zig
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub const resolver = @import("./resolver//resolver.zig");
pub const DirIterator = @import("./bun.js/node/dir_iterator.zig");
pub const PackageJSON = @import("./resolver/package_json.zig").PackageJSON;
pub const fmt = @import("./fmt.zig");
pub const allocators = @import("./allocators.zig");

pub const shell = struct {
pub usingnamespace @import("./shell/shell.zig");
Expand Down Expand Up @@ -552,6 +553,16 @@ pub inline fn isSliceInBuffer(slice: []const u8, buffer: []const u8) bool {
return slice.len > 0 and @intFromPtr(buffer.ptr) <= @intFromPtr(slice.ptr) and ((@intFromPtr(slice.ptr) + slice.len) <= (@intFromPtr(buffer.ptr) + buffer.len));
}

pub inline fn sliceInBuffer(stable: string, value: string) string {
if (allocators.sliceRange(stable, value)) |_| {
return value;
}
if (strings.indexOf(stable, value)) |index| {
return stable[index..][0..value.len];
}
return value;
}

pub fn rangeOfSliceInBuffer(slice: []const u8, buffer: []const u8) ?[2]u32 {
if (!isSliceInBuffer(slice, buffer)) return null;
const r = [_]u32{
Expand Down
37 changes: 26 additions & 11 deletions src/bundler/bundle_v2.zig
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ pub const BundleV2 = struct {
}
_ = @atomicRmw(usize, &this.graph.parse_pending, .Add, 1, .Monotonic);
const source_index = Index.source(this.graph.input_files.len);

if (path.pretty.ptr == path.text.ptr) {
// TODO: outbase
const rel = bun.path.relative(this.bundler.fs.top_level_dir, path.text);
Expand All @@ -674,6 +675,8 @@ pub const BundleV2 = struct {
}
}
path.* = try path.dupeAlloc(this.graph.allocator);
// TODO: this shouldn't be necessary
path.pretty = bun.sliceInBuffer(path.text, path.pretty);
entry.value_ptr.* = source_index.get();
this.graph.ast.append(bun.default_allocator, JSAst.empty) catch unreachable;

Expand Down Expand Up @@ -1115,9 +1118,7 @@ pub const BundleV2 = struct {
},
},
.size = source.contents.len,
.output_path = std.fmt.allocPrint(bun.default_allocator, "{}", .{
template,
}) catch unreachable,
.output_path = std.fmt.allocPrint(bun.default_allocator, "{}", .{template}) catch unreachable,
.input_path = bun.default_allocator.dupe(u8, source.path.text) catch unreachable,
.input_loader = .file,
.output_kind = .asset,
Expand Down Expand Up @@ -2029,6 +2030,8 @@ pub const BundleV2 = struct {
}

path.* = path.dupeAlloc(this.graph.allocator) catch @panic("Ran out of memory");
// TODO: this shouldn't be necessary
path.pretty = bun.sliceInBuffer(path.text, path.pretty);
import_record.path = path.*;
debug("created ParseTask: {s}", .{path.text});

Expand Down Expand Up @@ -9027,11 +9030,20 @@ const LinkerContext = struct {
chunk.template.placeholder.hash = chunk.isolated_hash;

const rel_path = std.fmt.allocPrint(c.allocator, "{any}", .{chunk.template}) catch unreachable;
bun.path.platformToPosixInPlace(u8, rel_path);

if ((try path_names_map.getOrPut(rel_path)).found_existing) {
try c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "Multiple files share the same output path: {s}", .{rel_path});
return error.DuplicateOutputPath;
}

// resolve any /./ and /../ occurrences
// use resolvePosix since we asserted above all seps are '/'
if (Environment.isWindows and std.mem.indexOf(u8, rel_path, "/./") != null) {
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const rel_path_fixed = c.allocator.dupe(u8, bun.path.normalizeBuf(rel_path, &buf, .posix)) catch unreachable;
chunk.final_rel_path = rel_path_fixed;
continue;
}
chunk.final_rel_path = rel_path;
}
}
Expand Down Expand Up @@ -9377,7 +9389,7 @@ const LinkerContext = struct {
defer max_heap_allocator.reset();

const rel_path = chunk.final_rel_path;
if (std.fs.path.dirname(rel_path)) |rel_parent| {
if (std.fs.path.dirnamePosix(rel_path)) |rel_parent| {
if (rel_parent.len > 0) {
root_dir.makePath(rel_parent) catch |err| {
c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "{s} creating outdir {} while saving chunk {}", .{
Expand Down Expand Up @@ -11082,7 +11094,7 @@ pub const Chunk = struct {
shifts.appendAssumeCapacity(shift);

var count: usize = 0;
var from_chunk_dir = std.fs.path.dirname(chunk.final_rel_path) orelse "";
var from_chunk_dir = std.fs.path.dirnamePosix(chunk.final_rel_path) orelse "";
if (strings.eqlComptime(from_chunk_dir, "."))
from_chunk_dir = "";

Expand All @@ -11103,7 +11115,7 @@ pub const Chunk = struct {
if (from_chunk_dir.len == 0)
file_path
else
bun.path.relative(from_chunk_dir, file_path),
bun.path.relativePlatform(from_chunk_dir, file_path, .posix, false),
);
count += cheap_normalizer[0].len + cheap_normalizer[1].len;
},
Expand Down Expand Up @@ -11160,7 +11172,7 @@ pub const Chunk = struct {
if (from_chunk_dir.len == 0)
file_path
else
bun.path.relative(from_chunk_dir, file_path),
bun.path.relativePlatform(from_chunk_dir, file_path, .posix, false),
);

if (cheap_normalizer[0].len > 0) {
Expand Down Expand Up @@ -11250,7 +11262,7 @@ pub const Chunk = struct {
var count: usize = 0;
const file_path_buf: [4096]u8 = undefined;
_ = file_path_buf;
var from_chunk_dir = std.fs.path.dirname(chunk.final_rel_path) orelse "";
var from_chunk_dir = std.fs.path.dirnamePosix(chunk.final_rel_path) orelse "";
if (strings.eqlComptime(from_chunk_dir, "."))
from_chunk_dir = "";

Expand All @@ -11274,7 +11286,8 @@ pub const Chunk = struct {
.chunk => chunks[index].final_rel_path,
else => unreachable,
};

// normalize windows paths to '/'
bun.path.platformToPosixInPlace(u8, @constCast(file_path));
const cheap_normalizer = cheapPrefixNormalizer(
import_prefix,
if (from_chunk_dir.len == 0)
Expand Down Expand Up @@ -11315,12 +11328,14 @@ pub const Chunk = struct {
.chunk => chunks[index].final_rel_path,
else => unreachable,
};
// normalize windows paths to '/'
bun.path.platformToPosixInPlace(u8, @constCast(file_path));
const cheap_normalizer = cheapPrefixNormalizer(
import_prefix,
if (from_chunk_dir.len == 0)
file_path
else
bun.path.relative(from_chunk_dir, file_path),
bun.path.relativePlatform(from_chunk_dir, file_path, .posix, false),
);

if (cheap_normalizer[0].len > 0) {
Expand Down
Loading

0 comments on commit adc95a8

Please sign in to comment.