From cbd8d715b2286e5726e6988921f5c870cbf74127 Mon Sep 17 00:00:00 2001 From: Jeremiah Senkpiel Date: Tue, 27 Aug 2019 17:14:27 -0700 Subject: fs: introduce `opendir()` and `fs.Dir` This adds long-requested methods for asynchronously interacting and iterating through directory entries by using `uv_fs_opendir`, `uv_fs_readdir`, and `uv_fs_closedir`. `fs.opendir()` and friends return an `fs.Dir`, which contains methods for doing reads and cleanup. `fs.Dir` also has the async iterator symbol exposed. The `read()` method and friends only return `fs.Dirent`s for this API. Having a entry type or doing a `stat` call is deemed to be necessary in the majority of cases, so just returning dirents seems like the logical choice for a new api. Reading when there are no more entries returns `null` instead of a dirent. However the async iterator hides that (and does automatic cleanup). The code lives in separate files from the rest of fs, this is done partially to prevent over-pollution of those (already very large) files, but also in the case of js allows loading into `fsPromises`. Due to async_hooks, this introduces a new handle type of `DIRHANDLE`. This PR does not attempt to make complete optimization of this feature. Notable future improvements include: - Moving promise work into C++ land like FileHandle. - Possibly adding `readv()` to do multi-entry directory reads. - Aliasing `fs.readdir` to `fs.scandir` and doing a deprecation. Refs: https://github.com/nodejs/node-v0.x-archive/issues/388 Refs: https://github.com/nodejs/node/issues/583 Refs: https://github.com/libuv/libuv/pull/2057 PR-URL: https://github.com/nodejs/node/pull/29349 Reviewed-By: Anna Henningsen Reviewed-By: David Carlier --- src/node_dir.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/node_dir.h (limited to 'src/node_dir.h') diff --git a/src/node_dir.h b/src/node_dir.h new file mode 100644 index 0000000000..e099fe5510 --- /dev/null +++ b/src/node_dir.h @@ -0,0 +1,60 @@ +#ifndef SRC_NODE_DIR_H_ +#define SRC_NODE_DIR_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "node_file.h" +#include "node.h" +#include "req_wrap-inl.h" + +namespace node { + +namespace fs_dir { + +// Needed to propagate `uv_dir_t`. +class DirHandle : public AsyncWrap { + public: + static constexpr int kDirHandleFieldCount = 1; + + static DirHandle* New(Environment* env, uv_dir_t* dir); + ~DirHandle() override; + + static void New(const v8::FunctionCallbackInfo& args); + static void Open(const v8::FunctionCallbackInfo& args); + static void Read(const v8::FunctionCallbackInfo& args); + static void Close(const v8::FunctionCallbackInfo& args); + + inline uv_dir_t* dir() { return dir_; } + AsyncWrap* GetAsyncWrap() { return this; } + + void MemoryInfo(MemoryTracker* tracker) const override { + tracker->TrackFieldWithSize("dir", sizeof(*dir_)); + } + + SET_MEMORY_INFO_NAME(DirHandle) + SET_SELF_SIZE(DirHandle) + + DirHandle(const DirHandle&) = delete; + DirHandle& operator=(const DirHandle&) = delete; + DirHandle(const DirHandle&&) = delete; + DirHandle& operator=(const DirHandle&&) = delete; + + private: + DirHandle(Environment* env, v8::Local obj, uv_dir_t* dir); + + // Synchronous close that emits a warning + void GCClose(); + + uv_dir_t* dir_; + uv_dirent_t dirent_; + bool closing_ = false; + bool closed_ = false; +}; + +} // namespace fs_dir + +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_NODE_DIR_H_ -- cgit v1.2.3