src: report libuv error when openAsBlob cannot stat

`FdEntry::Create()` returned nullptr for any failed `uv_fs_stat()`,
discarding the status, and `BlobFromFilePath()` turned that into
`ERR_INVALID_ARG_VALUE: Unable to open file as blob`. A missing file is
not a malformed argument, and the resulting `TypeError` carried no
`errno`, `syscall`, or `path`, so ENOENT could not be told apart from
any other reason the path was unusable.

Thread the libuv status out of `CreateFdEntry()` and throw a
`UVException` instead, so `fs.openAsBlob()` reports the same error
`fs.stat()` does for the same path.

Fixes: https://github.com/nodejs/node/issues/65514
Signed-off-by: Paul Bouchon <mail@bitpshr.net>
PR-URL: https://github.com/nodejs/node/pull/65517
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
Paul Bouchon authored and GitHub committed 2026-08-28 13:31:48 +00:00
1 parent e5a1ce2125
commit 05447419fb
4 files changed
+33 -7

No files matched your search

+11 -4
View File
@@ -868,13 +868,19 @@ class FdEntry final : public EntryImpl {
// the race
// condition described in the comment above.
public:
static std::unique_ptr<FdEntry> Create(Environment* env, Local<Value> path) {
static std::unique_ptr<FdEntry> Create(Environment* env,
Local<Value> path,
int* status) {
// We're only going to create the FdEntry if the file exists.
uv_fs_t req = uv_fs_t();
auto cleanup = OnScopeLeave([&] { uv_fs_req_cleanup(&req); });
auto buf = std::make_shared<BufferValue>(env->isolate(), path);
if (uv_fs_stat(nullptr, &req, buf->out(), nullptr) < 0) return nullptr;
int err = uv_fs_stat(nullptr, &req, buf->out(), nullptr);
if (err < 0) {
if (status != nullptr) *status = err;
return nullptr;
}
return std::make_unique<FdEntry>(
env, std::move(buf), req.statbuf, 0, req.statbuf.st_size);
@@ -1183,8 +1189,9 @@ std::unique_ptr<DataQueue::Entry> DataQueue::CreateDataQueueEntry(
}
std::unique_ptr<DataQueue::Entry> DataQueue::CreateFdEntry(Environment* env,
Local<Value> path) {
return FdEntry::Create(env, path);
Local<Value> path,
int* status) {
return FdEntry::Create(env, path, status);
}
void DataQueue::Initialize(Environment* env, v8::Local<v8::Object> target) {
+4 -1
View File
@@ -226,8 +226,11 @@ class DataQueue : public MemoryRetainer {
static std::unique_ptr<Entry> CreateDataQueueEntry(
std::shared_ptr<DataQueue> data_queue);
// Returns nullptr if the file cannot be stat'd. When `status` is given, it
// is set to the libuv error code so callers can report why.
static std::unique_ptr<Entry> CreateFdEntry(Environment* env,
v8::Local<v8::Value> path);
v8::Local<v8::Value> path,
int* status = nullptr);
// Creates a Reader for the given queue. If the queue is idempotent,
// any number of readers can be created, all of which are guaranteed