Compare commits

...

3 Commits

Author SHA1 Message Date
Jarred Sumner
9f6fa0f699 Update fs.zig 2025-03-09 00:21:44 -08:00
Jarred-Sumner
e99c142d5b bun run zig-format 2025-03-09 08:09:06 +00:00
Jarred Sumner
8a1550af23 use bun.sys instead of std.fs more 2025-03-08 23:43:02 -08:00
4 changed files with 122 additions and 55 deletions

View File

@@ -129,10 +129,10 @@ pub const Fs = struct {
) !Entry {
var rfs = _fs.fs;
const file_handle: std.fs.File = if (_file_handle) |__file|
std.fs.File{ .handle = __file }
const file_handle: bun.sys.File = if (_file_handle) |__file|
bun.sys.File{ .handle = __file }
else
try std.fs.openFileAbsoluteZ(path, .{ .mode = .read_only });
try bun.sys.File.open(path, bun.sys.O.RDONLY, 0).unwrap();
defer {
if (rfs.needToCloseFiles() and _file_handle == null) {
@@ -157,7 +157,7 @@ pub const Fs = struct {
return Entry{
.contents = file.contents,
.fd = if (FeatureFlags.store_file_descriptors) file_handle.handle else 0,
.fd = if (FeatureFlags.store_file_descriptors) file_handle.handle.int() else 0,
};
}
@@ -183,11 +183,11 @@ pub const Fs = struct {
) !Entry {
var rfs = _fs.fs;
var file_handle: std.fs.File = if (_file_handle) |__file| __file.asFile() else undefined;
var file_handle: bun.sys.File = if (_file_handle) |__file| bun.sys.File{ .handle = __file } else undefined;
if (_file_handle == null) {
if (FeatureFlags.store_file_descriptors and dirname_fd != bun.invalid_fd and dirname_fd != .zero) {
file_handle = (bun.sys.openatA(dirname_fd, std.fs.path.basename(path), bun.O.RDONLY, 0).unwrap() catch |err| brk: {
file_handle = .{ .handle = (bun.sys.openatA(dirname_fd, std.fs.path.basename(path), bun.O.RDONLY, 0).unwrap() catch |err| brk: {
switch (err) {
error.ENOENT => {
const handle = try bun.openFile(path, .{ .mode = .read_only });
@@ -199,19 +199,18 @@ pub const Fs = struct {
},
else => return err,
}
}).asFile();
}) };
} else {
file_handle = try bun.openFile(path, .{ .mode = .read_only });
file_handle = .{ .handle = try bun.sys.openA(path, bun.sys.O.RDONLY, 0).unwrap() };
}
}
if (comptime !Environment.isWindows) // skip on Windows because NTCreateFile will do it.
debug("openat({}, {s}) = {}", .{ dirname_fd, path, bun.toFD(file_handle.handle) });
debug("openat({}, {s}) = {}", .{ dirname_fd, path, file_handle.handle });
const will_close = rfs.needToCloseFiles() and _file_handle == null;
defer {
if (will_close) {
debug("readFileWithAllocator close({d})", .{file_handle.handle});
file_handle.close();
}
}
@@ -233,7 +232,7 @@ pub const Fs = struct {
return Entry{
.contents = file.contents,
.fd = if (FeatureFlags.store_file_descriptors and !will_close) bun.toFD(file_handle.handle) else bun.invalid_fd,
.fd = if (FeatureFlags.store_file_descriptors and !will_close) file_handle.handle else bun.invalid_fd,
};
}
};

View File

@@ -1129,13 +1129,11 @@ pub const FileSystem = struct {
return &temp_entries_option;
}
fn readFileError(_: *RealFS, _: string, _: anyerror) void {}
pub fn readFileWithHandle(
fs: *RealFS,
path: string,
_size: ?usize,
file: std.fs.File,
file: bun.sys.File,
comptime use_shared_buffer: bool,
shared_buffer: *MutableString,
comptime stream: bool,
@@ -1153,16 +1151,18 @@ pub const FileSystem = struct {
}
pub fn readFileWithHandleAndAllocator(
fs: *RealFS,
_: *RealFS,
allocator: std.mem.Allocator,
path: string,
_size: ?usize,
file: std.fs.File,
file: bun.sys.File,
comptime use_shared_buffer: bool,
shared_buffer: *MutableString,
comptime stream: bool,
) !PathContentsPair {
FileSystem.setMaxFd(file.handle);
if (comptime Environment.isPosix) {
FileSystem.setMaxFd(file.handle.int());
}
var file_contents: []u8 = undefined;
@@ -1174,11 +1174,8 @@ pub const FileSystem = struct {
shared_buffer.reset();
// Skip the extra file.stat() call when possible
var size = _size orelse (file.getEndPos() catch |err| {
fs.readFileError(path, err);
return err;
});
debug("stat({d}) = {d}", .{ file.handle, size });
var size = _size orelse try file.getEndPos().unwrap();
debug("stat({}) = {d}", .{ file.handle, size });
// Skip the pread call for empty files
// Otherwise will get out of bounds errors
@@ -1203,28 +1200,21 @@ pub const FileSystem = struct {
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];
const win_prev_file_pos = if (comptime Environment.isWindows) try file.getPos().unwrap() else 0;
const read_amount = try file.preadAll(shared_buffer.list.items[offset..], offset).unwrap();
if (comptime Environment.isWindows) try file.seekTo(@intCast(win_prev_file_pos)).unwrap();
shared_buffer.list.items = shared_buffer.list.items[0 .. read_amount + 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;
};
const new_size = try file.getEndPos().unwrap();
offset += read_count;
offset += read_amount;
// don't infinite loop is we're still not reading more
if (read_count == 0) break;
if (read_amount == 0) break;
if (offset < new_size) {
try shared_buffer.growBy(new_size - size);
@@ -1252,11 +1242,11 @@ pub const FileSystem = struct {
// that we need to dynamically allocate memory to read it.
const initial_read = if (_size == null) brk: {
var buf: []u8 = &initial_buf;
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;
};
prev_file_pos = if (comptime Environment.isWindows)
try file.getPos().unwrap()
else
0;
const read_count = try file.preadAll(buf, 0).unwrap();
if (read_count + 1 < buf.len) {
var allocation = try allocator.alloc(u8, read_count + 1);
@memcpy(allocation[0..read_count], buf[0..read_count]);
@@ -1267,7 +1257,7 @@ pub const FileSystem = struct {
debug("Convert {s} BOM", .{@tagName(bom)});
file_contents = try bom.removeAndConvertToUTF8AndFree(allocator, file_contents);
}
if (comptime Environment.isWindows) try file.seekTo(prev_file_pos.?);
if (comptime Environment.isWindows) try file.seekTo(@intCast(prev_file_pos.?)).unwrap();
return PathContentsPair{ .path = Path.init(path), .contents = file_contents };
}
@@ -1277,16 +1267,13 @@ pub const FileSystem = struct {
if (comptime Environment.isWindows) {
if (prev_file_pos == null) {
prev_file_pos = try file.getPos();
prev_file_pos = try file.getPos().unwrap();
}
}
// Skip the extra file.stat() call when possible
const size = _size orelse (file.getEndPos() catch |err| {
fs.readFileError(path, err);
return err;
});
debug("stat({d}) = {d}", .{ file.handle, size });
const size = _size orelse try file.getEndPos().unwrap();
debug("stat({}) = {d}", .{ file.handle, size });
var buf = try allocator.alloc(u8, size + 1);
@memcpy(buf[0..initial_read.len], initial_read);
@@ -1298,13 +1285,12 @@ pub const FileSystem = struct {
// stick a zero at the end
buf[size] = 0;
const read_count = file.preadAll(buf[initial_read.len..], initial_read.len) catch |err| {
fs.readFileError(path, err);
return err;
};
if (comptime Environment.isWindows) try file.seekTo(prev_file_pos.?);
file_contents = buf[0 .. read_count + initial_read.len];
debug("pread({d}, {d}) = {d}", .{ file.handle, size, read_count });
const read_buf = try file.preadAll(buf[initial_read.len..], initial_read.len).unwrap();
if (comptime Environment.isWindows) {
try file.seekTo(@intCast(prev_file_pos.?)).unwrap();
}
file_contents = buf[0 .. read_buf + initial_read.len];
if (strings.BOM.detect(file_contents)) |bom| {
debug("Convert {s} BOM", .{@tagName(bom)});

View File

@@ -2101,6 +2101,14 @@ pub fn pread(fd: bun.FileDescriptor, buf: []u8, offset: i64) Maybe(usize) {
}
}
if (comptime Environment.isWindows) {
if (bun.FDImpl.decode(fd).kind == .uv) {
return sys_uv.pread(fd, buf, offset);
}
return bun.C.readFile(fd, buf, @as(u64, @intCast(offset)));
}
const ioffset = @as(i64, @bitCast(offset)); // the OS treats this as unsigned
while (true) {
const rc = pread_sym(fd.cast(), buf.ptr, adjusted_len, ioffset);
@@ -3771,6 +3779,54 @@ pub const File = struct {
// "handle" matches std.fs.File
handle: bun.FileDescriptor,
pub fn pread(this: File, buf: []u8, offset: usize) Maybe(usize) {
return bun.sys.pread(this.handle, buf, @intCast(offset));
}
pub fn seekTo(this: File, offset: i64) Maybe(void) {
if (comptime Environment.isWindows) {
const rc = std.os.windows.kernel32.SetFilePointerEx(this.handle.cast(), offset, null, std.os.windows.FILE_BEGIN);
if (Maybe(void).errnoSys(rc, .lseek)) |err| {
return err;
}
return .{ .result = {} };
}
return bun.sys.lseek(this.handle, offset, std.posix.SEEK.SET);
}
pub fn getPos(this: File) Maybe(usize) {
if (comptime Environment.isWindows) {
const rc = std.os.windows.kernel32.SetFilePointerEx(this.handle.cast(), 0, null, std.os.windows.FILE_CURRENT);
if (Maybe(usize).errnoSys(rc, .lseek)) |err| {
return err;
}
// Windows casts as unsigned
return .{ .result = @as(u32, @bitCast(rc)) };
}
return bun.sys.lseek(this.handle, 0, std.posix.SEEK.CUR);
}
pub fn preadAll(this: File, buf: []u8, offset: usize) Maybe(usize) {
var total: usize = 0;
while (true) {
const read_amount = switch (this.pread(buf[total..], offset + total)) {
.err => |err| return .{ .err = err },
.result => |amt| amt,
};
if (read_amount == 0) {
break;
}
total += read_amount;
}
return .{ .result = total };
}
pub fn openat(other: anytype, path: [:0]const u8, flags: i32, mode: bun.Mode) Maybe(File) {
return switch (This.openat(bun.toFD(other), path, flags, mode)) {
.result => |fd| .{ .result = .{ .handle = fd } },

View File

@@ -1399,4 +1399,30 @@ pub fn deleteOpenedFile(fd: bun.FileDescriptor) Maybe(void) {
pub extern fn windows_enable_stdio_inheritance() void;
/// If buffer's length exceeds what a Windows DWORD integer can hold, it will be broken into
/// multiple non-atomic reads.
pub fn readFile(in_hFile: bun.FileDescriptor, buffer: []u8, offset: ?u64) Maybe(usize) {
const want_read_count: w.DWORD = @min(@as(w.DWORD, std.math.maxInt(w.DWORD)), buffer.len);
var amt_read: w.DWORD = undefined;
var overlapped_data: w.OVERLAPPED = undefined;
const overlapped: ?*w.OVERLAPPED = if (offset) |off| blk: {
overlapped_data = .{
.Internal = 0,
.InternalHigh = 0,
.DUMMYUNIONNAME = .{
.DUMMYSTRUCTNAME = .{
.Offset = @as(u32, @truncate(off)),
.OffsetHigh = @as(u32, @truncate(off >> 32)),
},
},
.hEvent = null,
};
break :blk &overlapped_data;
} else null;
if (w.kernel32.ReadFile(in_hFile.cast(), buffer.ptr, want_read_count, &amt_read, overlapped) == 0) {
return .{ .err = bun.sys.Error.fromCode(bun.windows.getLastErrno(), .read) };
}
return .{ .result = amt_read };
}
pub extern "c" fn quick_exit(code: c_int) noreturn;