Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/js/node/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,11 @@ var access = function access(path, mode, callback?) {
offset: offsetOrOptions = 0,
length = buffer.byteLength - offsetOrOptions,
position = null,
} = offsetOrOptions ?? {});
} = offsetOrOptions ?? kEmptyObject);
}
if (typeof offsetOrOptions === "function") {
// fs.write(fd, buffer, callback)
offsetOrOptions = 0;
}

fs.writeCb(onWritten, fd, buffer, offsetOrOptions, length, position);
Expand Down Expand Up @@ -511,8 +515,9 @@ var access = function access(path, mode, callback?) {
try {
if (types.isArrayBufferView(buffer)) {
let offset = offsetOrOptions;
if (typeof offset === "object" && offset !== null) {
({ offset = 0, length = buffer.byteLength - offset, position = null } = offsetOrOptions);
// `null` is an empty options object, as in Node.
if (typeof offset === "object") {
({ offset = 0, length = buffer.byteLength - offset, position = null } = offsetOrOptions ?? kEmptyObject);
return fs.writeSync(fd, buffer, offset, length, position);
}
return arguments.length <= 2 ? fs.writeSync(fd, buffer) : fs.writeSync(fd, buffer, offset, length, position);
Expand Down
149 changes: 73 additions & 76 deletions src/runtime/node/node_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3777,104 +3777,101 @@ pub(crate) mod args {
..Default::default()
};
arguments.eat();
'parse: {
let Some(mut current) = arguments.next() else {
break 'parse;
};
match &args.buffer {
// fs.write(fd, buffer[, offset[, length[, position]]], callback)
StringOrBuffer::Buffer(_) | StringOrBuffer::PinnedBuffer(_) => {
if current.is_undefined_or_null() || current.is_function() {
break 'parse;
}
match &args.buffer {
// fs.write(fd, buffer[, offset[, length[, position]]], callback)
// Each slot takes its default on its own, as in Node's writeSync.
Comment thread
robobun marked this conversation as resolved.
Resolved
StringOrBuffer::Buffer(_) | StringOrBuffer::PinnedBuffer(_) => 'buffer: {
let buf_len = args.buffer.slice().len() as u64;
let Some(offset) = arguments.next_eat() else {
break 'buffer;
};
if !offset.is_undefined_or_null() {
args.offset = u64::try_from(validators::validate_integer(
ctx,
current,
offset,
"offset",
Some(0),
Some(9007199254740991),
Some(bun_jsc::MAX_SAFE_INTEGER),
)?)
.expect("infallible: validated range");
arguments.eat();
// Node bounds `offset` by the buffer whether or not a
// `length` follows (`length` defaults to the rest).
let buf_len = args.buffer.slice().len();
let max_offset = buf_len as i64;
if args.offset as i64 > max_offset {
}
if args.offset > buf_len {
return Err(ctx.throw_range_error(
args.offset as f64,
bun_jsc::RangeErrorOptions {
field_name: b"offset",
max: buf_len as i64,
..Default::default()
},
));
}
let Some(length) = arguments.next_eat() else {
break 'buffer;
};
// validateOffsetLengthWrite, in Node's order.
if length.is_number() {
let length_float = length.as_number();
let max_len = (buf_len - args.offset).min(i32::MAX as u64) as i64;
if length_float > max_len as f64 {
return Err(ctx.throw_range_error(
args.offset as f64,
length_float,
bun_jsc::RangeErrorOptions {
Comment thread
robobun marked this conversation as resolved.
Resolved
field_name: b"offset",
max: max_offset,
field_name: b"length",
max: max_len,
..Default::default()
},
));
}
let Some(next) = arguments.next() else {
break 'parse;
};
current = next;
if !(current.is_number() || current.is_big_int()) {
break 'parse;
}
let length = current.to_int64();
let max_len = ((buf_len as u64 - args.offset) as i64).min(i32::MAX as i64);
if length > max_len || length < 0 {
if length_float < 0.0 {
return Err(ctx.throw_range_error(
length as f64,
length_float,
bun_jsc::RangeErrorOptions {
field_name: b"length",
min: 0,
max: max_len,
..Default::default()
},
));
}
args.length = u64::try_from(length).expect("int cast");
arguments.eat();
let Some(next) = arguments.next() else {
break 'parse;
};
current = next;
if !(current.is_number() || current.is_big_int()) {
break 'parse;
}
if let Some(position @ 0..) = i52::offset_from_js(current) {
args.position = Some(position);
if length_float % 1.0 != 0.0 {
return Err(ctx.throw_range_error(
length_float,
bun_jsc::RangeErrorOptions {
field_name: b"length",
msg: b"an integer",
..Default::default()
},
));
}
arguments.eat();
args.length = length_float as u64;
}
// fs.write(fd, string[, position[, encoding]], callback)
_ => {
if let Some(position @ 0..) = i52::offset_from_js(current) {
args.position = Some(position);
}
// Node consumes the position slot whatever its type
// (null, undefined, a non-number); the encoding is
// strictly the next argument.
arguments.eat();
let Some(next) = arguments.next() else {
break 'parse;
};
current = next;
if current.is_string() {
args.encoding = Encoding::assert(current, ctx, args.encoding)?;
arguments.eat();
// `bv` was converted to UTF-8 before the encoding
// argument was parsed; re-encode it now. Node
// treats the "buffer" encoding name as UTF-8 here.
if !matches!(args.encoding, Encoding::Utf8 | Encoding::Buffer) {
if let Some(encoded) =
StringOrBuffer::from_js_with_encoding_maybe_async(
ctx,
bv,
args.encoding,
flavor,
StringObjects::Allow,
)?
{
args.buffer = encoded;
}
if let Some(position @ 0..) = arguments.next_eat().and_then(i52::offset_from_js)
{
args.position = Some(position);
}
}
// fs.write(fd, string[, position[, encoding]], callback)
_ => {
if let Some(position @ 0..) = arguments.next_eat().and_then(i52::offset_from_js)
{
args.position = Some(position);
}
let encoding = arguments.next_eat().unwrap_or(JSValue::UNDEFINED);
if encoding.is_string() {
args.encoding = Encoding::assert(encoding, ctx, args.encoding)?;
// `bv` was converted to UTF-8 before the encoding
// argument was parsed; re-encode it now. Node
// treats the "buffer" encoding name as UTF-8 here.
Comment thread
robobun marked this conversation as resolved.
Resolved
if !matches!(args.encoding, Encoding::Utf8 | Encoding::Buffer) {
if let Some(encoded) =
StringOrBuffer::from_js_with_encoding_maybe_async(
ctx,
bv,
args.encoding,
flavor,
StringObjects::Allow,
)?
{
args.buffer = encoded;
}
}
}
Expand Down
Loading
Loading