mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 23:18:47 +00:00
Compare commits
1 Commits
fix-7823
...
jarred/wip
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8755c8aca9 |
@@ -282,15 +282,15 @@ pub fn NewIterator(comptime use_windows_ospath: bool) type {
|
||||
if (mem.eql(u16, dir_info_name, &[_]u16{'.'}) or mem.eql(u16, dir_info_name, &[_]u16{ '.', '.' }))
|
||||
continue;
|
||||
|
||||
const kind = blk: {
|
||||
const kind: Entry.Kind = blk: {
|
||||
const attrs = dir_info.FileAttributes;
|
||||
if (attrs == w.INVALID_FILE_ATTRIBUTES) break :blk .unknown;
|
||||
const isdir = attrs & w.FILE_ATTRIBUTE_DIRECTORY != 0;
|
||||
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
|
||||
if (islink) break :blk Entry.Kind.sym_link;
|
||||
if (isdir) break :blk Entry.Kind.directory;
|
||||
break :blk Entry.Kind.file;
|
||||
if (islink and isdir) break :blk .sym_link_directory;
|
||||
if (islink) break :blk .sym_link;
|
||||
if (isdir) break :blk .directory;
|
||||
break :blk .file;
|
||||
};
|
||||
|
||||
if (use_windows_ospath) {
|
||||
|
||||
@@ -1753,7 +1753,7 @@ pub const Dirent = struct {
|
||||
// not publicly exposed
|
||||
kind: Kind,
|
||||
|
||||
pub const Kind = std.fs.File.Kind;
|
||||
pub const Kind = bun.sys.File.Kind;
|
||||
pub usingnamespace JSC.Codegen.JSDirent;
|
||||
|
||||
pub fn constructor(globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) ?*Dirent {
|
||||
@@ -1775,49 +1775,49 @@ pub const Dirent = struct {
|
||||
_: *JSC.JSGlobalObject,
|
||||
_: *JSC.CallFrame,
|
||||
) callconv(.C) JSC.JSValue {
|
||||
return JSC.JSValue.jsBoolean(this.kind == std.fs.File.Kind.block_device);
|
||||
return JSC.JSValue.jsBoolean(this.kind == .block_device);
|
||||
}
|
||||
pub fn isCharacterDevice(
|
||||
this: *Dirent,
|
||||
_: *JSC.JSGlobalObject,
|
||||
_: *JSC.CallFrame,
|
||||
) callconv(.C) JSC.JSValue {
|
||||
return JSC.JSValue.jsBoolean(this.kind == std.fs.File.Kind.character_device);
|
||||
return JSC.JSValue.jsBoolean(this.kind == .character_device);
|
||||
}
|
||||
pub fn isDirectory(
|
||||
this: *Dirent,
|
||||
_: *JSC.JSGlobalObject,
|
||||
_: *JSC.CallFrame,
|
||||
) callconv(.C) JSC.JSValue {
|
||||
return JSC.JSValue.jsBoolean(this.kind == std.fs.File.Kind.directory);
|
||||
return JSC.JSValue.jsBoolean(this.kind == .directory);
|
||||
}
|
||||
pub fn isFIFO(
|
||||
this: *Dirent,
|
||||
_: *JSC.JSGlobalObject,
|
||||
_: *JSC.CallFrame,
|
||||
) callconv(.C) JSC.JSValue {
|
||||
return JSC.JSValue.jsBoolean(this.kind == std.fs.File.Kind.named_pipe or this.kind == std.fs.File.Kind.event_port);
|
||||
return JSC.JSValue.jsBoolean(this.kind == .named_pipe or this.kind == .event_port);
|
||||
}
|
||||
pub fn isFile(
|
||||
this: *Dirent,
|
||||
_: *JSC.JSGlobalObject,
|
||||
_: *JSC.CallFrame,
|
||||
) callconv(.C) JSC.JSValue {
|
||||
return JSC.JSValue.jsBoolean(this.kind == std.fs.File.Kind.file);
|
||||
return JSC.JSValue.jsBoolean(this.kind == .file);
|
||||
}
|
||||
pub fn isSocket(
|
||||
this: *Dirent,
|
||||
_: *JSC.JSGlobalObject,
|
||||
_: *JSC.CallFrame,
|
||||
) callconv(.C) JSC.JSValue {
|
||||
return JSC.JSValue.jsBoolean(this.kind == std.fs.File.Kind.unix_domain_socket);
|
||||
return JSC.JSValue.jsBoolean(this.kind == .unix_domain_socket);
|
||||
}
|
||||
pub fn isSymbolicLink(
|
||||
this: *Dirent,
|
||||
_: *JSC.JSGlobalObject,
|
||||
_: *JSC.CallFrame,
|
||||
) callconv(.C) JSC.JSValue {
|
||||
return JSC.JSValue.jsBoolean(this.kind == std.fs.File.Kind.sym_link);
|
||||
return JSC.JSValue.jsBoolean(this.kind == .sym_link or this.kind == .sym_link_directory);
|
||||
}
|
||||
|
||||
pub fn finalize(this: *Dirent) callconv(.C) void {
|
||||
|
||||
19
src/c.zig
19
src/c.zig
@@ -15,7 +15,8 @@ const builtin = @import("builtin");
|
||||
const os = std.os;
|
||||
const mem = std.mem;
|
||||
const Stat = std.fs.File.Stat;
|
||||
const Kind = std.fs.File.Kind;
|
||||
|
||||
const Kind = bun.sys.File.Kind;
|
||||
const StatError = std.fs.File.StatError;
|
||||
const errno = os.errno;
|
||||
const mode_t = bun.Mode;
|
||||
@@ -187,15 +188,15 @@ pub fn copyFileZSlowWithHandle(in_handle: bun.FileDescriptor, to_dir: bun.FileDe
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kindFromMode(mode: mode_t) std.fs.File.Kind {
|
||||
pub fn kindFromMode(mode: mode_t) bun.sys.File.Kind {
|
||||
return switch (mode & bun.S.IFMT) {
|
||||
bun.S.IFBLK => std.fs.File.Kind.block_device,
|
||||
bun.S.IFCHR => std.fs.File.Kind.character_device,
|
||||
bun.S.IFDIR => std.fs.File.Kind.directory,
|
||||
bun.S.IFIFO => std.fs.File.Kind.named_pipe,
|
||||
bun.S.IFLNK => std.fs.File.Kind.sym_link,
|
||||
bun.S.IFREG => std.fs.File.Kind.file,
|
||||
bun.S.IFSOCK => std.fs.File.Kind.unix_domain_socket,
|
||||
bun.S.IFBLK => .block_device,
|
||||
bun.S.IFCHR => .character_device,
|
||||
bun.S.IFDIR => .directory,
|
||||
bun.S.IFIFO => .named_pipe,
|
||||
bun.S.IFLNK => .sym_link,
|
||||
bun.S.IFREG => .file,
|
||||
bun.S.IFSOCK => .unix_domain_socket,
|
||||
else => .unknown,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ const builtin = @import("builtin");
|
||||
const os = std.os;
|
||||
const mem = std.mem;
|
||||
const Stat = std.fs.File.Stat;
|
||||
const Kind = std.fs.File.Kind;
|
||||
const Kind = bun.sys.File.Kind;
|
||||
const StatError = std.fs.File.StatError;
|
||||
const off_t = std.c.off_t;
|
||||
const errno = os.errno;
|
||||
|
||||
181
src/fs.zig
181
src/fs.zig
@@ -158,7 +158,7 @@ pub const FileSystem = struct {
|
||||
pub fn addEntry(dir: *DirEntry, prev_map: ?*EntryMap, entry: *const bun.DirIterator.IteratorResult, allocator: std.mem.Allocator, comptime Iterator: type, iterator: Iterator) !void {
|
||||
const name_slice = entry.name.slice();
|
||||
const _kind: Entry.Kind = switch (entry.kind) {
|
||||
.directory => .dir,
|
||||
.sym_link_directory, .directory => .dir,
|
||||
// This might be wrong!
|
||||
.sym_link => .file,
|
||||
.file => .file,
|
||||
@@ -208,7 +208,7 @@ pub const FileSystem = struct {
|
||||
// Call "stat" lazily for performance. The "@material-ui/icons" package
|
||||
// contains a directory with over 11,000 entries in it and running "stat"
|
||||
// for each entry was a big performance issue for that package.
|
||||
.need_stat = entry.kind == .sym_link,
|
||||
.need_stat = entry.kind == .sym_link or entry.kind == .sym_link_directory,
|
||||
.cache = .{
|
||||
.symlink = PathString.empty,
|
||||
.kind = _kind,
|
||||
@@ -1136,19 +1136,21 @@ pub const FileSystem = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
path: string,
|
||||
_size: ?usize,
|
||||
file: std.fs.File,
|
||||
file_: std.fs.File,
|
||||
comptime use_shared_buffer: bool,
|
||||
shared_buffer: *MutableString,
|
||||
comptime stream: bool,
|
||||
) !PathContentsPair {
|
||||
FileSystem.setMaxFd(file.handle);
|
||||
_ = stream; // autofix
|
||||
FileSystem.setMaxFd(file_.handle);
|
||||
const file = bun.sys.File.from(file_);
|
||||
|
||||
// Skip the extra file.stat() call when possible
|
||||
var size = _size orelse (file.getEndPos() catch |err| {
|
||||
const size = _size orelse (file.getEndPos().unwrap() catch |err| {
|
||||
fs.readFileError(path, err);
|
||||
return err;
|
||||
});
|
||||
debug("stat({d}) = {d}", .{ file.handle, size });
|
||||
debug("stat({}) = {d}", .{ file.handle, size });
|
||||
|
||||
// Skip the pread call for empty files
|
||||
// Otherwise will get out of bounds errors
|
||||
@@ -1170,52 +1172,19 @@ pub const FileSystem = struct {
|
||||
// As a mitigation, we can just keep one buffer forever and re-use it for the parsed files
|
||||
if (use_shared_buffer) {
|
||||
shared_buffer.reset();
|
||||
var offset: u64 = 0;
|
||||
try shared_buffer.growBy(size + 1);
|
||||
shared_buffer.list.expandToCapacity();
|
||||
{
|
||||
var list = shared_buffer.list.toManaged(bun.default_allocator);
|
||||
defer shared_buffer.list = list.moveToUnmanaged();
|
||||
const rc = file.readToEndWithArrayListAndSize(&list, size);
|
||||
|
||||
// if you press save on a large file we might not read all the
|
||||
// bytes in the first few pread() calls. we only handle this on
|
||||
// stream because we assume that this only realistically happens
|
||||
// during HMR
|
||||
while (true) {
|
||||
|
||||
// We use pread to ensure if the file handle was open, it doesn't seek from the last position
|
||||
const prev_file_pos = if (comptime Environment.isWindows) try file.getPos() else 0;
|
||||
const read_count = file.preadAll(shared_buffer.list.items[offset..], offset) catch |err| {
|
||||
fs.readFileError(path, err);
|
||||
return err;
|
||||
};
|
||||
if (comptime Environment.isWindows) try file.seekTo(prev_file_pos);
|
||||
shared_buffer.list.items = shared_buffer.list.items[0 .. read_count + offset];
|
||||
file_contents = shared_buffer.list.items;
|
||||
debug("pread({d}, {d}) = {d}", .{ file.handle, size, read_count });
|
||||
|
||||
if (comptime stream) {
|
||||
// check again that stat() didn't change the file size
|
||||
// another reason to only do this when stream
|
||||
const new_size = file.getEndPos() catch |err| {
|
||||
fs.readFileError(path, err);
|
||||
return err;
|
||||
};
|
||||
|
||||
offset += read_count;
|
||||
|
||||
// don't infinite loop is we're still not reading more
|
||||
if (read_count == 0) break;
|
||||
|
||||
if (offset < new_size) {
|
||||
try shared_buffer.growBy(new_size - size);
|
||||
shared_buffer.list.expandToCapacity();
|
||||
size = new_size;
|
||||
continue;
|
||||
}
|
||||
switch (rc) {
|
||||
.result => {
|
||||
file_contents = list.items;
|
||||
},
|
||||
.err => {
|
||||
return bun.errnoToZigErr(rc.err.getErrno());
|
||||
},
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (shared_buffer.list.capacity > file_contents.len) {
|
||||
file_contents.ptr[file_contents.len] = 0;
|
||||
}
|
||||
|
||||
if (strings.BOM.detect(file_contents)) |bom| {
|
||||
@@ -1223,20 +1192,14 @@ pub const FileSystem = struct {
|
||||
file_contents = try bom.removeAndConvertToUTF8WithoutDealloc(allocator, &shared_buffer.list);
|
||||
}
|
||||
} else {
|
||||
// We use pread to ensure if the file handle was open, it doesn't seek from the last position
|
||||
var buf = try allocator.alloc(u8, size + 1);
|
||||
const result = file.readToEnd(allocator);
|
||||
if (comptime Environment.isWindows) _ = file.resetPosition();
|
||||
file_contents = result.bytes.items;
|
||||
|
||||
// stick a zero at the end
|
||||
buf[size] = 0;
|
||||
|
||||
const prev_file_pos = if (comptime Environment.isWindows) try file.getPos() else 0;
|
||||
const read_count = file.preadAll(buf, 0) catch |err| {
|
||||
fs.readFileError(path, err);
|
||||
return err;
|
||||
};
|
||||
if (comptime Environment.isWindows) try file.seekTo(prev_file_pos);
|
||||
file_contents = buf[0..read_count];
|
||||
debug("pread({d}, {d}) = {d}", .{ file.handle, size, read_count });
|
||||
if (result.err) |err| {
|
||||
allocator.free(file_contents);
|
||||
return bun.errnoToZigErr(err.getErrno());
|
||||
}
|
||||
|
||||
if (strings.BOM.detect(file_contents)) |bom| {
|
||||
debug("Convert {s} BOM", .{@tagName(bom)});
|
||||
@@ -1247,60 +1210,6 @@ pub const FileSystem = struct {
|
||||
return PathContentsPair{ .path = Path.init(path), .contents = file_contents };
|
||||
}
|
||||
|
||||
pub fn kindFromAbsolute(
|
||||
fs: *RealFS,
|
||||
absolute_path: [:0]const u8,
|
||||
existing_fd: StoredFileDescriptorType,
|
||||
store_fd: bool,
|
||||
) !Entry.Cache {
|
||||
var outpath: [bun.MAX_PATH_BYTES]u8 = undefined;
|
||||
|
||||
const stat = try C.lstat_absolute(absolute_path);
|
||||
const is_symlink = stat.kind == std.fs.File.Kind.SymLink;
|
||||
var _kind = stat.kind;
|
||||
var cache = Entry.Cache{
|
||||
.kind = Entry.Kind.file,
|
||||
.symlink = PathString.empty,
|
||||
};
|
||||
var symlink: []const u8 = "";
|
||||
|
||||
if (is_symlink) {
|
||||
var file = try if (existing_fd != 0)
|
||||
std.fs.File{ .handle = existing_fd }
|
||||
else if (store_fd)
|
||||
std.fs.openFileAbsoluteZ(absolute_path, .{ .mode = .read_only })
|
||||
else
|
||||
bun.openFileForPath(absolute_path);
|
||||
setMaxFd(file.handle);
|
||||
|
||||
defer {
|
||||
if ((!store_fd or fs.needToCloseFiles()) and existing_fd == 0) {
|
||||
file.close();
|
||||
} else if (comptime FeatureFlags.store_file_descriptors) {
|
||||
cache.fd = file.handle;
|
||||
}
|
||||
}
|
||||
const _stat = try file.stat();
|
||||
|
||||
symlink = try bun.getFdPath(file.handle, &outpath);
|
||||
|
||||
_kind = _stat.kind;
|
||||
}
|
||||
|
||||
std.debug.assert(_kind != .SymLink);
|
||||
|
||||
if (_kind == .Directory) {
|
||||
cache.kind = .dir;
|
||||
} else {
|
||||
cache.kind = .file;
|
||||
}
|
||||
if (symlink.len > 0) {
|
||||
cache.symlink = PathString.init(try FilenameStore.instance.append([]const u8, symlink));
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
pub fn kind(
|
||||
fs: *RealFS,
|
||||
_dir: string,
|
||||
@@ -1324,19 +1233,39 @@ pub const FileSystem = struct {
|
||||
const 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 wbuf: bun.WPathBuffer = undefined;
|
||||
const wpath = bun.strings.toNTPath(&wbuf, absolute_path_c);
|
||||
const attr = bun.windows.GetFileAttributesW(wpath);
|
||||
if (attr == bun.windows.INVALID_FILE_ATTRIBUTES) {
|
||||
return error.FileNotFound;
|
||||
}
|
||||
|
||||
const is_dir = (attr & bun.windows.FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
const is_link = (attr & bun.windows.FILE_ATTRIBUTE_REPARSE_POINT) == 0;
|
||||
|
||||
if (is_dir) {
|
||||
cache.kind = .dir;
|
||||
} else {
|
||||
cache.kind = .file;
|
||||
}
|
||||
|
||||
if (is_link) {
|
||||
const fd = switch (bun.sys.openatWindows(std.fs.cwd(), wpath, 0)) {
|
||||
.err => {
|
||||
return cache;
|
||||
},
|
||||
.result => |rc| rc,
|
||||
};
|
||||
defer _ = bun.sys.close(fd);
|
||||
const symlink_path = try bun.getFdPath(fd, &outpath);
|
||||
cache.symlink = PathString.init(try FilenameStore.instance.append([]const u8, symlink_path));
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
const stat = try C.lstat_absolute(absolute_path_c);
|
||||
const is_symlink = stat.kind == std.fs.File.Kind.sym_link;
|
||||
const is_symlink = stat.kind == .sym_link;
|
||||
var _kind = stat.kind;
|
||||
|
||||
var symlink: []const u8 = "";
|
||||
|
||||
@@ -348,7 +348,7 @@ pub const BufferReadStream = struct {
|
||||
// }
|
||||
};
|
||||
|
||||
const Kind = std.fs.File.Kind;
|
||||
const Kind = bun.sys.File.Kind;
|
||||
|
||||
pub const Archive = struct {
|
||||
// impl: *lib.archive = undefined,
|
||||
|
||||
@@ -600,7 +600,7 @@ pub const PackageJSON = struct {
|
||||
false,
|
||||
null,
|
||||
) catch |err| {
|
||||
if (err != error.IsDir) {
|
||||
if (err != error.IsDir and err != error.EISDIR) {
|
||||
r.log.addErrorFmt(null, logger.Loc.Empty, allocator, "Cannot read file \"{s}\": {s}", .{ r.prettyPath(fs.Path.init(input_path)), @errorName(err) }) catch unreachable;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ seed: u64 = 0,
|
||||
const NameBufferList = std.ArrayList(bun.OSPathChar);
|
||||
|
||||
const Dir = std.fs.Dir;
|
||||
const Kind = bun.sys.File.Kind;
|
||||
const WrappedIterator = DirIterator.NewWrappedIterator(if (Environment.isWindows) .u16 else .u8);
|
||||
|
||||
pub const WalkerEntry = struct {
|
||||
@@ -26,7 +27,7 @@ pub const WalkerEntry = struct {
|
||||
dir: Dir,
|
||||
basename: OSPathSlice,
|
||||
path: OSPathSlice,
|
||||
kind: Dir.Entry.Kind,
|
||||
kind: Kind,
|
||||
};
|
||||
|
||||
const StackItem = struct {
|
||||
@@ -65,7 +66,7 @@ pub fn next(self: *Walker) !?WalkerEntry {
|
||||
},
|
||||
|
||||
// we don't know what it is for a symlink
|
||||
.sym_link => {
|
||||
.sym_link_directory, .sym_link => {
|
||||
if (std.mem.indexOfScalar(
|
||||
u64,
|
||||
self.skip_all,
|
||||
|
||||
@@ -5,7 +5,7 @@ const win32 = std.os.windows;
|
||||
const os = std.os;
|
||||
const mem = std.mem;
|
||||
const Stat = std.fs.File.Stat;
|
||||
const Kind = std.fs.File.Kind;
|
||||
const Kind = bun.sys.File.Kind;
|
||||
const StatError = std.fs.File.StatError;
|
||||
|
||||
pub fn getTotalMemory() usize {
|
||||
|
||||
Reference in New Issue
Block a user