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
15 changes: 11 additions & 4 deletions src/dataqueue/queue.cc
Original file line number Diff line number Diff line change
Expand Up @@ -847,13 +847,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);
Expand Down Expand Up @@ -1162,8 +1168,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) {
Expand Down
5 changes: 4 additions & 1 deletion src/dataqueue/queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions src/node_blob.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,12 @@ void BlobFromFilePath(const FunctionCallbackInfo<Value>& args) {
ToNamespacedPath(env, &path);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
auto entry = DataQueue::CreateFdEntry(env, args[0]);
int status = 0;
auto entry = DataQueue::CreateFdEntry(env, args[0], &status);
if (entry == nullptr) {
return THROW_ERR_INVALID_ARG_VALUE(env, "Unable to open file as blob");
// The file could not be stat'd. Report the libuv error so callers can tell
// ENOENT apart from any other reason the path could not be used.
return env->ThrowUVException(status, "stat", nullptr, *path);
}

std::vector<std::unique_ptr<DataQueue::Entry>> entries;
Expand Down
13 changes: 13 additions & 0 deletions test/parallel/test-blob-file-backed.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,19 @@ writeFileSync(testfile5, '');
await unlink(testfile5);
})().then(common.mustCall());

(async () => {
// A path that cannot be stat'd reports the underlying libuv error rather
// than a generic argument error, so ENOENT can be told apart from any other
// reason the file could not be used.
// Refs: https://github.com/nodejs/node/issues/65514
const missing = tmpdir.resolve('does-not-exist.txt');
await assert.rejects(async () => openAsBlob(missing), {
code: 'ENOENT',
syscall: 'stat',
path: missing,
});
})().then(common.mustCall());

(async () => {
// We currently do not allow File-backed blobs to be cloned or transferred
// across worker threads. This is largely because the underlying FdEntry
Expand Down
Loading