[0c6b92a] | 1 | #include "DirTree.hh"
|
---|
| 2 | #include <inttypes.h>
|
---|
| 3 |
|
---|
| 4 | static std::mutex mDirCacheMutex;
|
---|
| 5 | static std::unordered_map<std::string, std::weak_ptr<DirTree>> dirTreeCache;
|
---|
| 6 |
|
---|
| 7 | struct DirTreeDeleter {
|
---|
| 8 | void operator()(DirTree *tree) {
|
---|
| 9 | std::lock_guard<std::mutex> lock(mDirCacheMutex);
|
---|
| 10 | dirTreeCache.erase(tree->root);
|
---|
| 11 | delete tree;
|
---|
| 12 |
|
---|
| 13 | // Free up memory.
|
---|
| 14 | if (dirTreeCache.size() == 0) {
|
---|
| 15 | dirTreeCache.rehash(0);
|
---|
| 16 | }
|
---|
| 17 | }
|
---|
| 18 | };
|
---|
| 19 |
|
---|
| 20 | std::shared_ptr<DirTree> DirTree::getCached(std::string root) {
|
---|
| 21 | std::lock_guard<std::mutex> lock(mDirCacheMutex);
|
---|
| 22 |
|
---|
| 23 | auto found = dirTreeCache.find(root);
|
---|
| 24 | std::shared_ptr<DirTree> tree;
|
---|
| 25 |
|
---|
| 26 | // Use cached tree, or create an empty one.
|
---|
| 27 | if (found != dirTreeCache.end()) {
|
---|
| 28 | tree = found->second.lock();
|
---|
| 29 | } else {
|
---|
| 30 | tree = std::shared_ptr<DirTree>(new DirTree(root), DirTreeDeleter());
|
---|
| 31 | dirTreeCache.emplace(root, tree);
|
---|
| 32 | }
|
---|
| 33 |
|
---|
| 34 | return tree;
|
---|
| 35 | }
|
---|
| 36 |
|
---|
| 37 | DirTree::DirTree(std::string root, FILE *f) : root(root), isComplete(true) {
|
---|
| 38 | size_t size;
|
---|
| 39 | if (fscanf(f, "%zu", &size)) {
|
---|
| 40 | for (size_t i = 0; i < size; i++) {
|
---|
| 41 | DirEntry entry(f);
|
---|
| 42 | entries.emplace(entry.path, entry);
|
---|
| 43 | }
|
---|
| 44 | }
|
---|
| 45 | }
|
---|
| 46 |
|
---|
| 47 | // Internal find method that has no lock
|
---|
| 48 | DirEntry *DirTree::_find(std::string path) {
|
---|
| 49 | auto found = entries.find(path);
|
---|
| 50 | if (found == entries.end()) {
|
---|
| 51 | return NULL;
|
---|
| 52 | }
|
---|
| 53 |
|
---|
| 54 | return &found->second;
|
---|
| 55 | }
|
---|
| 56 |
|
---|
| 57 | DirEntry *DirTree::add(std::string path, uint64_t mtime, bool isDir) {
|
---|
| 58 | std::lock_guard<std::mutex> lock(mMutex);
|
---|
| 59 |
|
---|
| 60 | DirEntry entry(path, mtime, isDir);
|
---|
| 61 | auto it = entries.emplace(entry.path, entry);
|
---|
| 62 | return &it.first->second;
|
---|
| 63 | }
|
---|
| 64 |
|
---|
| 65 | DirEntry *DirTree::find(std::string path) {
|
---|
| 66 | std::lock_guard<std::mutex> lock(mMutex);
|
---|
| 67 | return _find(path);
|
---|
| 68 | }
|
---|
| 69 |
|
---|
| 70 | DirEntry *DirTree::update(std::string path, uint64_t mtime) {
|
---|
| 71 | std::lock_guard<std::mutex> lock(mMutex);
|
---|
| 72 |
|
---|
| 73 | DirEntry *found = _find(path);
|
---|
| 74 | if (found) {
|
---|
| 75 | found->mtime = mtime;
|
---|
| 76 | }
|
---|
| 77 |
|
---|
| 78 | return found;
|
---|
| 79 | }
|
---|
| 80 |
|
---|
| 81 | void DirTree::remove(std::string path) {
|
---|
| 82 | std::lock_guard<std::mutex> lock(mMutex);
|
---|
| 83 |
|
---|
| 84 | DirEntry *found = _find(path);
|
---|
| 85 |
|
---|
| 86 | // Remove all sub-entries if this is a directory
|
---|
| 87 | if (found && found->isDir) {
|
---|
| 88 | std::string pathStart = path + DIR_SEP;
|
---|
| 89 | for (auto it = entries.begin(); it != entries.end();) {
|
---|
| 90 | if (it->first.rfind(pathStart, 0) == 0) {
|
---|
| 91 | it = entries.erase(it);
|
---|
| 92 | } else {
|
---|
| 93 | it++;
|
---|
| 94 | }
|
---|
| 95 | }
|
---|
| 96 | }
|
---|
| 97 |
|
---|
| 98 | entries.erase(path);
|
---|
| 99 | }
|
---|
| 100 |
|
---|
| 101 | void DirTree::write(FILE *f) {
|
---|
| 102 | std::lock_guard<std::mutex> lock(mMutex);
|
---|
| 103 |
|
---|
| 104 | fprintf(f, "%zu\n", entries.size());
|
---|
| 105 | for (auto it = entries.begin(); it != entries.end(); it++) {
|
---|
| 106 | it->second.write(f);
|
---|
| 107 | }
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | void DirTree::getChanges(DirTree *snapshot, EventList &events) {
|
---|
| 111 | std::lock_guard<std::mutex> lock(mMutex);
|
---|
| 112 | std::lock_guard<std::mutex> snapshotLock(snapshot->mMutex);
|
---|
| 113 |
|
---|
| 114 | for (auto it = entries.begin(); it != entries.end(); it++) {
|
---|
| 115 | auto found = snapshot->entries.find(it->first);
|
---|
| 116 | if (found == snapshot->entries.end()) {
|
---|
| 117 | events.create(it->second.path);
|
---|
| 118 | } else if (found->second.mtime != it->second.mtime && !found->second.isDir && !it->second.isDir) {
|
---|
| 119 | events.update(it->second.path);
|
---|
| 120 | }
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | for (auto it = snapshot->entries.begin(); it != snapshot->entries.end(); it++) {
|
---|
| 124 | size_t count = entries.count(it->first);
|
---|
| 125 | if (count == 0) {
|
---|
| 126 | events.remove(it->second.path);
|
---|
| 127 | }
|
---|
| 128 | }
|
---|
| 129 | }
|
---|
| 130 |
|
---|
| 131 | DirEntry::DirEntry(std::string p, uint64_t t, bool d) {
|
---|
| 132 | path = p;
|
---|
| 133 | mtime = t;
|
---|
| 134 | isDir = d;
|
---|
| 135 | state = NULL;
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 | DirEntry::DirEntry(FILE *f) {
|
---|
| 139 | size_t size;
|
---|
| 140 | if (fscanf(f, "%zu", &size)) {
|
---|
| 141 | path.resize(size);
|
---|
| 142 | if (fread(&path[0], sizeof(char), size, f)) {
|
---|
| 143 | int d = 0;
|
---|
| 144 | fscanf(f, "%" PRIu64 " %d\n", &mtime, &d);
|
---|
| 145 | isDir = d == 1;
|
---|
| 146 | }
|
---|
| 147 | }
|
---|
| 148 | }
|
---|
| 149 |
|
---|
| 150 | void DirEntry::write(FILE *f) const {
|
---|
| 151 | fprintf(f, "%zu%s%" PRIu64 " %d\n", path.size(), path.c_str(), mtime, isDir);
|
---|
| 152 | }
|
---|