From 59abd82fe5c4b394677c98e168305d3cd42dc02c Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Wed, 13 Mar 2019 23:39:52 -0700 Subject: [PATCH] Brute force tree walking implementation for linux --- binding.gyp | 14 +++++++- src/DirTree.hh | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Event.hh | 2 +- src/unix/nftw.cc | 36 +++++++++++++++++++ 4 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/DirTree.hh create mode 100644 src/unix/nftw.cc diff --git a/binding.gyp b/binding.gyp index 6d615134..1212e454 100644 --- a/binding.gyp +++ b/binding.gyp @@ -8,10 +8,22 @@ ], "conditions": [ ['OS=="mac"', { - "sources": ["src/macos/FSEvents.cc"], + "variables": { + "use_nftw%": "false" + }, + "conditions": [ + ['use_nftw=="true"', { + "sources": ["src/unix/nftw.cc"] + }, { + "sources": ["src/macos/FSEvents.cc"], + }] + ], "link_settings": { "libraries": ["CoreServices.framework"] } + }], + ['OS=="linux"', { + "sources": ["src/unix/nftw.cc"] }] ] } diff --git a/src/DirTree.hh b/src/DirTree.hh new file mode 100644 index 00000000..d101f44a --- /dev/null +++ b/src/DirTree.hh @@ -0,0 +1,90 @@ +#ifndef DIR_TREE_H +#define DIR_TREE_H + +#include +#include +#include +#include +#include "Event.hh" + +struct DirEntry { + std::string path; + time_t mtime; + + DirEntry(const char *p, const struct stat *info) { + path.assign(p); + mtime = info->st_mtime; + } + + DirEntry(std::istream &stream) { + size_t size; + + if (stream >> size) { + path.resize(size); + if (stream.read(&path[0], size)) { + stream >> mtime; + } + } + } + + bool operator==(const DirEntry &other) const { + return path == other.path; + } + + void write(std::ostream &stream) const { + stream << path.size() << path << mtime << "\n"; + } +}; + +namespace std { + template <> + struct hash { + std::size_t operator()(const DirEntry& k) const { + return hash()(k.path); + } + }; +} + +struct DirTree { + std::unordered_set entries; + DirTree() {} + + DirTree(std::istream &stream) { + size_t size; + if (stream >> size) { + for (size_t i = 0; i < size; i++) { + entries.insert(DirEntry(stream)); + } + } + } + + void write(std::ostream &stream) { + stream << entries.size() << "\n"; + for (auto it = entries.begin(); it != entries.end(); it++) { + it->write(stream); + } + } + + EventList *getChanges(DirTree *snapshot) { + EventList *events = new EventList(); + for (auto it = entries.begin(); it != entries.end(); it++) { + auto found = snapshot->entries.find(*it); + if (found == snapshot->entries.end()) { + events->push(it->path, "create"); + } else if (found->mtime != it->mtime) { + events->push(it->path, "update"); + } + } + + for (auto it = snapshot->entries.begin(); it != snapshot->entries.end(); it++) { + size_t count = entries.count(*it); + if (count == 0) { + events->push(it->path, "delete"); + } + } + + return events; + } +}; + +#endif diff --git a/src/Event.hh b/src/Event.hh index d1a80ae7..a03da724 100644 --- a/src/Event.hh +++ b/src/Event.hh @@ -42,7 +42,7 @@ public: arr->Set(i, mEvents[i]->toJS()); } - return scope.Escape(arr); + return scope.Escape(arr); } }; diff --git a/src/unix/nftw.cc b/src/unix/nftw.cc new file mode 100644 index 00000000..1cf6aa9e --- /dev/null +++ b/src/unix/nftw.cc @@ -0,0 +1,36 @@ +#include +#include +#include +#include "../DirTree.hh" +#include "../Event.hh" + +static DirTree *tree; +int addEntry(const char *path, const struct stat *info, const int flags, struct FTW *ftw) { + tree->entries.insert(DirEntry(path, info)); + return 0; +} + +DirTree *getDirTree(std::string *dir) { + tree = new DirTree(); + int result = nftw(dir->c_str(), &addEntry, 15, FTW_PHYS); + if (result < 0) { + printf("error\n"); + } + + return tree; +} + +std::string getCurrentTokenImpl(std::string *dir) { + auto tree = getDirTree(dir); + std::ostringstream os; + tree->write(os); + return os.str(); +} + +EventList *getEventsSinceImpl(std::string *dir, std::string *token) { + std::istringstream is(*token); + auto snapshot = new DirTree(is); + auto now = getDirTree(dir); + + return now->getChanges(snapshot); +}