mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
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:
1 parent
e5a1ce2125
commit
05447419fb
4 files changed
+33
-7
No files matched your search
+11
-4
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
+5
-2
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user