Skip to content

Commit

Permalink
fix junction/pnpm on window (#11157)
Browse files Browse the repository at this point in the history
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
  • Loading branch information
paperdave and Jarred-Sumner committed May 18, 2024
1 parent 38122a9 commit d0cacfc
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 35 deletions.
16 changes: 10 additions & 6 deletions .github/workflows/build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,17 @@ on:
type: boolean
no-cache:
type: boolean
bun-version:
type: string
default: 1.1.7

env:
# Must specify exact version of LLVM for Windows
LLVM_VERSION: 16.0.6
BUN_VERSION: 1.1.8
BUN_VERSION: ${{ inputs.bun-version }}
BUN_GARBAGE_COLLECTOR_LEVEL: 1
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: 1
CI: true

jobs:
build-submodules:
Expand Down Expand Up @@ -116,7 +122,7 @@ jobs:
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: ${{ env.BUN_VERSION }}
bun-version: ${{ inputs.bun-version }}
- name: Codegen
run: |
./scripts/cross-compile-codegen.sh win32 x64
Expand Down Expand Up @@ -154,7 +160,7 @@ jobs:
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: ${{ env.BUN_VERSION }}
bun-version: ${{ inputs.bun-version }}
- if: ${{ !inputs.no-cache }}
name: Restore Cache
uses: actions/cache@v4
Expand Down Expand Up @@ -233,7 +239,7 @@ jobs:
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: ${{ env.BUN_VERSION }}
bun-version: ${{ inputs.bun-version }}
- name: Download bun-${{ inputs.tag }}-deps
uses: actions/download-artifact@v4
with:
Expand Down Expand Up @@ -294,8 +300,6 @@ jobs:
cp -r build\bun.exe "$Dist\bun.exe"
cp -r build\bun.pdb "$Dist\bun.pdb"
Compress-Archive -Force "$Dist" "$Dist.zip"
$env:BUN_GARBAGE_COLLECTOR_LEVEL = "1"
$env:BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING = "1"
.\build\bun.exe --print "JSON.stringify(require('bun:internal-for-testing').crash_handler.getFeatureData())" > .\features.json
- name: Upload bun-${{ inputs.tag }}
uses: actions/upload-artifact@v4
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/node/dir_iterator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ pub fn NewIterator(comptime use_windows_ospath: bool) type {
const islink = attrs & w.FILE_ATTRIBUTE_REPARSE_POINT != 0;
// on windows symlinks can be directories, too. We prioritize the
// "sym_link" kind over the "directory" kind
// this will coerce into either .file or .directory later
// once the symlink is read
if (islink) break :blk Entry.Kind.sym_link;
if (isdir) break :blk Entry.Kind.directory;
break :blk Entry.Kind.file;
Expand Down
38 changes: 28 additions & 10 deletions src/fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1324,23 +1324,41 @@ pub const FileSystem = struct {

const dir = _dir;
var combo = [2]string{ dir, base };
var outpath: [bun.MAX_PATH_BYTES]u8 = undefined;
var outpath: bun.PathBuffer = undefined;
const entry_path = path_handler.joinAbsStringBuf(fs.cwd, &outpath, &combo, .auto);

outpath[entry_path.len + 1] = 0;
outpath[entry_path.len] = 0;

const absolute_path_c: [:0]const u8 = outpath[0..entry_path.len :0];
var absolute_path_c: [:0]const u8 = outpath[0..entry_path.len :0];

if (comptime bun.Environment.isWindows) {
var file = try std.fs.openFileAbsoluteZ(absolute_path_c, .{ .mode = .read_only });
defer file.close();
const metadata = try file.metadata();
cache.kind = switch (metadata.kind()) {
.directory => .dir,
.sym_link => .file,
else => .file,
};
var file = bun.sys.getFileAttributes(absolute_path_c) orelse return error.FileNotFound;
var depth: usize = 0;
var buf2: bun.PathBuffer = undefined;
var current_buf: *bun.PathBuffer = &buf2;
var other_buf: *bun.PathBuffer = &outpath;
while (file.isReparsePoint()) : (depth += 1) {
const read = try bun.sys.readlink(absolute_path_c, current_buf).unwrap();
std.mem.swap(*bun.PathBuffer, &current_buf, &other_buf);
file = bun.sys.getFileAttributes(read) orelse return error.FileNotFound;
absolute_path_c = read;

if (depth > 20) {
return error.TooManySymlinks;
}
}

if (depth > 0) {
cache.symlink = PathString.init(try FilenameStore.instance.append([]const u8, absolute_path_c));
}

if (file.isDirectory()) {
cache.kind = .dir;
} else {
cache.kind = .file;
}

return cache;
}

Expand Down
1 change: 0 additions & 1 deletion src/resolver/resolver.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3956,7 +3956,6 @@ pub const Resolver = struct {
// }

if (parent) |parent_| {

// Propagate the browser scope into child directories
info.enclosing_browser_scope = parent_.enclosing_browser_scope;
info.package_json_for_browser_field = parent_.package_json_for_browser_field;
Expand Down
9 changes: 4 additions & 5 deletions src/shell/interpreter.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10538,17 +10538,16 @@ pub const Interpreter = struct {

pub fn isDir(_: *ShellCpTask, path: [:0]const u8) Maybe(bool) {
if (bun.Environment.isWindows) {
var wpath: bun.OSPathBuffer = undefined;
const attributes = windows.GetFileAttributesW(bun.strings.toWPath(wpath[0..], path[0..path.len]));
if (attributes == windows.INVALID_FILE_ATTRIBUTES) {
const attributes = bun.sys.getFileAttributes(path[0..path.len]) orelse {
const err: Syscall.Error = .{
.errno = @intFromEnum(bun.C.SystemErrno.ENOENT),
.syscall = .copyfile,
.path = path,
};
return .{ .err = err };
}
return .{ .result = (attributes & windows.FILE_ATTRIBUTE_DIRECTORY) != 0 };
};

return .{ .result = attributes.isDirectory() };
}
const stat = switch (Syscall.lstat(path)) {
.result => |x| x,
Expand Down
128 changes: 115 additions & 13 deletions src/sys.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2096,23 +2096,128 @@ pub fn getMaxPipeSizeOnLinux() usize {
);
}

pub fn existsOSPath(path: bun.OSPathSliceZ, file_only: bool) bool {
if (comptime Environment.isPosix) {
return system.access(path, 0) == 0;
pub const WindowsFileAttributes = enum(windows.DWORD) {
invalid = windows.INVALID_FILE_ATTRIBUTES,
_,

pub fn isFile(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_NORMAL != 0;
}

if (comptime Environment.isWindows) {
pub fn isArchive(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_ARCHIVE != 0;
}
pub fn isCompressed(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_COMPRESSED != 0;
}
pub fn isDevice(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_DEVICE != 0;
}
pub fn isDirectory(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_DIRECTORY != 0;
}
pub fn isEncrypted(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_ENCRYPTED != 0;
}
pub fn isHidden(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_HIDDEN != 0;
}
pub fn isIntegrityStream(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_INTEGRITY_STREAM != 0;
}
pub fn isNormal(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_NORMAL != 0;
}
pub fn isNotContentIndexed(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED != 0;
}
pub fn isNoScrubData(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_NO_SCRUB_DATA != 0;
}
pub fn isOffline(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_OFFLINE != 0;
}
pub fn isReadonly(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_READONLY != 0;
}
pub fn isRecallOnDataAccess(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS != 0;
}
pub fn isRecallOnOpen(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_RECALL_ON_OPEN != 0;
}
pub fn isReparsePoint(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_REPARSE_POINT != 0;
}
pub fn isSparseFile(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_SPARSE_FILE != 0;
}
pub fn isSystem(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_SYSTEM != 0;
}
pub fn isTemporary(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_TEMPORARY != 0;
}
pub fn isVirtual(this: WindowsFileAttributes) bool {
return @intFromEnum(this) & FILE_ATTRIBUTE_VIRTUAL != 0;
}

const FILE_ATTRIBUTE_ARCHIVE = 0x20;
const FILE_ATTRIBUTE_COMPRESSED = 0x800;
const FILE_ATTRIBUTE_DEVICE = 0x40;
const FILE_ATTRIBUTE_DIRECTORY = 0x10;
const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
const FILE_ATTRIBUTE_HIDDEN = 0x2;
const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
const FILE_ATTRIBUTE_NORMAL = 0x80;
const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
const FILE_ATTRIBUTE_OFFLINE = 0x1000;
const FILE_ATTRIBUTE_READONLY = 0x1;
const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
const FILE_ATTRIBUTE_SYSTEM = 0x4;
const FILE_ATTRIBUTE_TEMPORARY = 0x100;
const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
};

pub fn getFileAttributes(path: anytype) ?WindowsFileAttributes {
if (comptime !Environment.isWindows) @compileError("Windows only");

const T = std.meta.Child(@TypeOf(path));
if (T == u16) {
assertIsValidWindowsPath(bun.OSPathChar, path);
const attributes = kernel32.GetFileAttributesW(path.ptr);
if (Environment.isDebug) {
const attributes: WindowsFileAttributes = @enumFromInt(kernel32.GetFileAttributesW(path.ptr));
if (comptime Environment.isDebug) {
log("GetFileAttributesW({}) = {d}", .{ bun.fmt.utf16(path), attributes });
}
if (attributes == windows.INVALID_FILE_ATTRIBUTES) {
return false;

if (attributes == .invalid) {
return null;
}
if (file_only and attributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0) {

return attributes;
} else {
var wbuf: bun.WPathBuffer = undefined;
const path_to_use = bun.strings.toWPath(&wbuf, path);
return getFileAttributes(path_to_use);
}
}

pub fn existsOSPath(path: bun.OSPathSliceZ, file_only: bool) bool {
if (comptime Environment.isPosix) {
return system.access(path, 0) == 0;
}

if (comptime Environment.isWindows) {
const attributes = getFileAttributes(path) orelse return false;

if (file_only and attributes.isDirectory()) {
return false;
}

return true;
}

Expand All @@ -2125,10 +2230,7 @@ pub fn exists(path: []const u8) bool {
}

if (comptime Environment.isWindows) {
var wbuf: bun.WPathBuffer = undefined;
const path_to_use = bun.strings.toWPath(&wbuf, path);
assertIsValidWindowsPath(u16, path_to_use);
return kernel32.GetFileAttributesW(path_to_use.ptr) != windows.INVALID_FILE_ATTRIBUTES;
return getFileAttributes(path) != null;
}

@compileError("TODO: existsOSPath");
Expand Down

0 comments on commit d0cacfc

Please sign in to comment.