annotate src/core/filesystem.cc @ 404:e561b7542b7b

*: fix build on mac os x
author Paper <paper@tflc.us>
date Mon, 19 Jan 2026 20:50:40 -0500
parents d859306e2db4
children 31ce85df55a8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
36
2743011a6042 *: mass update
Paper <mrpapersonic@gmail.com>
parents: 18
diff changeset
1 #include "core/filesystem.h"
15
cde8f67a7c7d *: update, megacommit :)
Paper <mrpapersonic@gmail.com>
parents: 11
diff changeset
2 #include "core/config.h"
62
4c6dd5999b39 *: update
Paper <mrpapersonic@gmail.com>
parents: 61
diff changeset
3 #include "core/strings.h"
250
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
4
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
5 #include <QStandardPaths>
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
6
135
0a458cb26ff4 filesystem: move to using std::filesystem after C++17 switch
Paper <mrpapersonic@gmail.com>
parents: 134
diff changeset
7 #include <filesystem>
404
e561b7542b7b *: fix build on mac os x
Paper <paper@tflc.us>
parents: 402
diff changeset
8 #include <unordered_map>
2
Paper <mrpapersonic@gmail.com>
parents: 1
diff changeset
9
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
10 #ifdef WIN32
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
11 # include <windows.h>
402
d859306e2db4 filesystem: actually check for inotify instead of blindly assuming it exists
Paper <paper@tflc.us>
parents: 401
diff changeset
12 #elif defined(HAVE_INOTIFY)
401
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
13 /* ehhhh */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
14 # include <fcntl.h>
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
15 # include <unistd.h>
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
16 # include <sys/inotify.h>
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
17 #endif
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
18
401
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
19 #include <iostream>
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
20
11
fc1bf97c528b *: use C++11 standard
Paper <mrpapersonic@gmail.com>
parents: 9
diff changeset
21 namespace Filesystem {
fc1bf97c528b *: use C++11 standard
Paper <mrpapersonic@gmail.com>
parents: 9
diff changeset
22
135
0a458cb26ff4 filesystem: move to using std::filesystem after C++17 switch
Paper <mrpapersonic@gmail.com>
parents: 134
diff changeset
23 /* this runs fs::create_directories() on the
0a458cb26ff4 filesystem: move to using std::filesystem after C++17 switch
Paper <mrpapersonic@gmail.com>
parents: 134
diff changeset
24 PARENT directory. */
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
25 void CreateDirectories(const std::filesystem::path &path)
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
26 {
158
80d6b28eb29f dep/animia: fix most X11 stuff
Paper <mrpapersonic@gmail.com>
parents: 138
diff changeset
27 if (path.empty())
80d6b28eb29f dep/animia: fix most X11 stuff
Paper <mrpapersonic@gmail.com>
parents: 138
diff changeset
28 return;
80d6b28eb29f dep/animia: fix most X11 stuff
Paper <mrpapersonic@gmail.com>
parents: 138
diff changeset
29
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
30 const auto &parent = path.parent_path();
158
80d6b28eb29f dep/animia: fix most X11 stuff
Paper <mrpapersonic@gmail.com>
parents: 138
diff changeset
31 if (!std::filesystem::exists(parent))
80d6b28eb29f dep/animia: fix most X11 stuff
Paper <mrpapersonic@gmail.com>
parents: 138
diff changeset
32 std::filesystem::create_directories(parent);
11
fc1bf97c528b *: use C++11 standard
Paper <mrpapersonic@gmail.com>
parents: 9
diff changeset
33 }
fc1bf97c528b *: use C++11 standard
Paper <mrpapersonic@gmail.com>
parents: 9
diff changeset
34
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
35 std::filesystem::path GetDotPath()
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
36 {
250
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
37 /*
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
38 * Windows: ~/AppData/Roaming/Minori
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
39 * macOS: ~/Library/Application Support/Minori
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
40 * ...: ~/.config/minori
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
41 *
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
42 * FIXME: are windows and mac properly cased?
258
862d0d8619f6 *: HUUUGE changes
Paper <paper@paper.us.eu.org>
parents: 250
diff changeset
43 */
9
5c0397762b53 INCOMPLETE: megacommit :)
Paper <mrpapersonic@gmail.com>
parents: 7
diff changeset
44 #ifdef WIN32
250
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
45 return Strings::ToUtf8String(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
46 #else
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
47 return Strings::ToUtf8String(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
c130f47f6f48 *: many many changes
Paper <paper@paper.us.eu.org>
parents: 230
diff changeset
48 #endif
45
4b05bc7668eb filesystem: split config path into dotpath and config, add anime db path
Paper <mrpapersonic@gmail.com>
parents: 44
diff changeset
49 }
4b05bc7668eb filesystem: split config path into dotpath and config, add anime db path
Paper <mrpapersonic@gmail.com>
parents: 44
diff changeset
50
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
51 std::filesystem::path GetConfigPath()
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
52 {
135
0a458cb26ff4 filesystem: move to using std::filesystem after C++17 switch
Paper <mrpapersonic@gmail.com>
parents: 134
diff changeset
53 return GetDotPath() / CONFIG_NAME;
118
39521c47c7a3 *: another huge megacommit, SORRY
Paper <mrpapersonic@gmail.com>
parents: 106
diff changeset
54 }
39521c47c7a3 *: another huge megacommit, SORRY
Paper <mrpapersonic@gmail.com>
parents: 106
diff changeset
55
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
56 std::filesystem::path GetAnimeDBPath()
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
57 {
135
0a458cb26ff4 filesystem: move to using std::filesystem after C++17 switch
Paper <mrpapersonic@gmail.com>
parents: 134
diff changeset
58 return GetDotPath() / "anime" / "db.json";
45
4b05bc7668eb filesystem: split config path into dotpath and config, add anime db path
Paper <mrpapersonic@gmail.com>
parents: 44
diff changeset
59 }
4b05bc7668eb filesystem: split config path into dotpath and config, add anime db path
Paper <mrpapersonic@gmail.com>
parents: 44
diff changeset
60
369
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
61 std::filesystem::path GetTorrentsPath()
47c9f8502269 *: clang-format all the things
Paper <paper@tflc.us>
parents: 258
diff changeset
62 {
230
2f5a9247e501 torrents: implement download button
Paper <paper@paper.us.eu.org>
parents: 221
diff changeset
63 return GetDotPath() / "torrents";
2f5a9247e501 torrents: implement download button
Paper <paper@paper.us.eu.org>
parents: 221
diff changeset
64 }
2f5a9247e501 torrents: implement download button
Paper <paper@paper.us.eu.org>
parents: 221
diff changeset
65
378
5912dafc6e28 anime: add poster cache
Paper <paper@tflc.us>
parents: 369
diff changeset
66 std::filesystem::path GetAnimePostersPath()
5912dafc6e28 anime: add poster cache
Paper <paper@tflc.us>
parents: 369
diff changeset
67 {
5912dafc6e28 anime: add poster cache
Paper <paper@tflc.us>
parents: 369
diff changeset
68 return GetDotPath() / "anime" / "posters";
5912dafc6e28 anime: add poster cache
Paper <paper@tflc.us>
parents: 369
diff changeset
69 }
5912dafc6e28 anime: add poster cache
Paper <paper@tflc.us>
parents: 369
diff changeset
70
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
71 /* ------------------------------------------------------------------------ */
399
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
72 /* This is the "base class" for basically every watcher. */
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
73
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
74 class Watcher : public IWatcher {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
75 public:
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
76 Watcher(void *opaque, const std::filesystem::path &path, EventHandler handler)
393
963047512d34 *: clang-format
Paper <paper@tflc.us>
parents: 391
diff changeset
77 : path_(path), handler_(handler), opaque_(opaque)
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
78 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
79 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
80
393
963047512d34 *: clang-format
Paper <paper@tflc.us>
parents: 391
diff changeset
81 virtual ~Watcher() override {}
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
82
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
83 protected:
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
84 std::filesystem::path path_;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
85 EventHandler handler_;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
86 void *opaque_;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
87 };
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
88
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
89 /* ------------------------------------------------------------------------ */
391
c3f717b7321b filesystem: only iterate over the list once when erasing deleted files
Paper <paper@tflc.us>
parents: 382
diff changeset
90 /* Filesystem watcher.
399
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
91 * This is the portable version for non-Windows; however, pretty much
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
92 * every implementation should be based on this in some shape or form. */
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
93
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
94 /*
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
95 We can't use std::recursive_directory_iterator!
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
96 Why? Well, to put it blunt, it sucks. The main reason
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
97 being is that if it finds a single directory it cannot
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
98 recurse into, instead of safely recovering, it just
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
99 completely stops. I am dumbfounded at this behavior, but
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
100 nevertheless it means we simply can't use it, and must
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
101 resort to old-fashioned recursion. --paper
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
102 */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
103 static void IterateDirectory(const std::filesystem::path &path, bool recursive,
404
e561b7542b7b *: fix build on mac os x
Paper <paper@tflc.us>
parents: 402
diff changeset
104 const std::function<void(const std::filesystem::path &path)> &func)
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
105 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
106 std::error_code ec;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
107 static const std::filesystem::directory_iterator end;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
108
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
109 for (std::filesystem::directory_iterator item(path, ec); item != end; item.increment(ec)) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
110 if (ec)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
111 continue;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
112
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
113 std::filesystem::path p = item->path();
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
114
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
115 /* Hand the path off to the listener */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
116 func(p);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
117
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
118 /* If we're dealing with another directory, recurse into it. */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
119 if (recursive && item->is_directory())
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
120 IterateDirectory(p, true, func);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
121 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
122 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
123
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
124 class StdFilesystemWatcher : public Watcher {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
125 public:
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
126 StdFilesystemWatcher(void *opaque, const std::filesystem::path &path, EventHandler handler, bool recursive)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
127 : Watcher(opaque, path, handler), recursive_(recursive)
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
128 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
129 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
130
393
963047512d34 *: clang-format
Paper <paper@tflc.us>
parents: 391
diff changeset
131 virtual ~StdFilesystemWatcher() override {}
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
132
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
133 virtual void Process() override
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
134 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
135 /* Untoggle all paths. This allows us to only ever
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
136 * iterate over the directory ONCE. */
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
137 UntoggleAllPaths();
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
138
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
139 /* Start iterating directories. If we're recursive, this
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
140 * will go through the whole tree. */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
141 IterateDirectory(path_, recursive_, [this](const std::filesystem::path &p) {
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
142 if (FindAndTogglePath(p))
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
143 return;
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
144
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
145 handler_(opaque_, p, Event::Created);
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
146 paths_.insert({p, true});
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
147 });
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
148
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
149 DeleteUntoggledPaths();
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
150 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
151
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
152 protected:
391
c3f717b7321b filesystem: only iterate over the list once when erasing deleted files
Paper <paper@tflc.us>
parents: 382
diff changeset
153 bool FindAndTogglePath(const std::filesystem::path &p)
c3f717b7321b filesystem: only iterate over the list once when erasing deleted files
Paper <paper@tflc.us>
parents: 382
diff changeset
154 {
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
155 auto it = paths_.find(p);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
156 if (it == paths_.end())
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
157 return false;
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
158
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
159 it->second = true;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
160 return true;
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
161 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
162
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
163 void UntoggleAllPaths()
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
164 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
165 for (auto &pp : paths_)
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
166 pp.second = false;
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
167 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
168
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
169 void DeleteUntoggledPaths()
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
170 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
171 auto it = paths_.begin();
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
172
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
173 while (it != paths_.end()) {
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
174 if (!it->second) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
175 handler_(opaque_, it->first, Event::Deleted);
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
176 it = paths_.erase(it);
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
177 } else {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
178 it++;
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
179 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
180 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
181 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
182
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
183 /* unordered hashmap, path[found] */
404
e561b7542b7b *: fix build on mac os x
Paper <paper@tflc.us>
parents: 402
diff changeset
184 PathMap<bool> paths_;
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
185 bool recursive_;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
186 };
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
187
399
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
188 /* There does actually exist an API in Qt to do file system watching.
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
189 * However, it is of little use for us, since it
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
190 * a) isn't recursive
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
191 * b) requires constant conversion to and from QString, which takes
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
192 * up valuable system resources
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
193 * c) uses signals etc. that are a pain in the ass to use in an
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
194 * event-processing logic like we do here. */
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
195
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
196 #ifdef WIN32
399
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
197 /* On Windows, we can ask the OS whether the directory tree has changed or not.
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
198 * This is great for us! */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
199 class Win32Watcher : public StdFilesystemWatcher {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
200 public:
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
201 Win32Watcher(void *opaque, const std::filesystem::path &path, IWatcher::EventHandler handler, bool recursive)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
202 : StdFilesystemWatcher(opaque, path, handler, recursive), dirwatcher_(INVALID_HANDLE_VALUE), first_(true)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
203 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
204 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
205
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
206 virtual ~Win32Watcher() override
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
207 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
208 // delete handle
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
209 if (dirwatcher_ != INVALID_HANDLE_VALUE)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
210 FindCloseChangeNotification(dirwatcher_);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
211 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
212
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
213 virtual void Process() override
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
214 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
215 if (first_ || dirwatcher_ == INVALID_HANDLE_VALUE) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
216 /* We want to create this right before iteration so
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
217 * we minimize possible race conditions while also
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
218 * reducing unnecessary processing */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
219 TryCreateDirWatcher();
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
220 StdFilesystemWatcher::Process();
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
221 first_ = false;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
222 return;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
223 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
224
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
225 /* We have a valid handle */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
226 if (WaitForSingleObject(dirwatcher_, 0) != WAIT_OBJECT_0)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
227 return;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
228
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
229 StdFilesystemWatcher::Process();
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
230 FindNextChangeNotification(dirwatcher_);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
231 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
232
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
233 protected:
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
234 bool TryCreateDirWatcher()
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
235 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
236 dirwatcher_ = FindFirstChangeNotificationW(Watcher::path_.wstring().c_str(), recursive_,
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
237 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
238
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
239 return (dirwatcher_ != INVALID_HANDLE_VALUE);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
240 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
241
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
242 /* variables */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
243 HANDLE dirwatcher_;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
244 bool first_;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
245 };
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
246
399
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
247 /* I think "Vista" is actually a misnomer, MSDN says that ReadDirectoryChangesW
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
248 * has existed since Windows XP.
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
249 *
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
250 * Anyway, this is a version that doesn't need to keep the whole directory
a0bc3ae5164a anime_list: actually obey "highlight anime if they are available"
Paper <paper@tflc.us>
parents: 398
diff changeset
251 * tree in-memory if it is available. */
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
252 class Win32WatcherVista : public Win32Watcher {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
253 public:
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
254 Win32WatcherVista(void *opaque, const std::filesystem::path &path, IWatcher::EventHandler handler, bool recursive)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
255 : Win32Watcher(opaque, path, handler, recursive), dirhandle_(INVALID_HANDLE_VALUE)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
256 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
257 overlapped_.hEvent = nullptr;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
258 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
259
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
260 virtual ~Win32WatcherVista() override
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
261 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
262 if (dirhandle_ != INVALID_HANDLE_VALUE)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
263 CloseHandle(dirhandle_);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
264
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
265 if (overlapped_.hEvent != nullptr)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
266 CloseHandle(overlapped_.hEvent);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
267 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
268
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
269 virtual void Process() override
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
270 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
271 if (first_) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
272 if (TryCreateHandles()) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
273 /* Queue a directory read asynchronously. On the next run, this will
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
274 * be waited on. */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
275 QueueDirectoryRead();
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
276
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
277 /* Avoid running Win32Watcher::Process, as it will read the whole
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
278 * directory tree into memory. Instead, iterate through the directory
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
279 * ourselves. */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
280 IterateDirectory(path_, recursive_,
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
281 [this](const std::filesystem::path &p) { handler_(opaque_, p, Event::Created); });
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
282 } else {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
283 /* Uh oh; we might have to fall back to Win32Watcher. Call into it to
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
284 * load the tree into memory. */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
285 Win32Watcher::Process();
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
286 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
287
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
288 first_ = false;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
289 return;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
290 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
291
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
292 if (!HandlesAreValid()) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
293 /* If we're here, we already fell back into Win32Watcher, so just
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
294 * call back into again. On the slim chance TryCreateHandles() might
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
295 * succeed, call it as well... */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
296 if (TryCreateHandles())
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
297 QueueDirectoryRead();
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
298 Win32Watcher::Process();
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
299 return;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
300 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
301
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
302 if (WaitForSingleObject(overlapped_.hEvent, 0) != WAIT_OBJECT_0)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
303 return;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
304
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
305 FILE_NOTIFY_INFORMATION *ev = reinterpret_cast<FILE_NOTIFY_INFORMATION *>(change_buf_);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
306
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
307 for (;;) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
308 /* Tack on the file name to the end of our path */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
309 std::filesystem::path p = Watcher::path_ / std::wstring(ev->FileName, ev->FileNameLength / sizeof(WCHAR));
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
310
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
311 switch (ev->Action) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
312 case FILE_ACTION_ADDED:
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
313 case FILE_ACTION_RENAMED_NEW_NAME:
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
314 /* File was added */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
315 handler_(opaque_, p, Event::Created);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
316 break;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
317 case FILE_ACTION_REMOVED:
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
318 case FILE_ACTION_RENAMED_OLD_NAME:
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
319 /* File was removed */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
320 handler_(opaque_, p, Event::Deleted);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
321 break;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
322 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
323
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
324 if (ev->NextEntryOffset) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
325 /* ugh ugh ugh ugh */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
326 ev = reinterpret_cast<FILE_NOTIFY_INFORMATION *>(reinterpret_cast<char *>(ev) + ev->NextEntryOffset);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
327 } else {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
328 break;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
329 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
330 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
331
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
332 /* Queue a directory read for the next call */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
333 QueueDirectoryRead();
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
334 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
335
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
336 protected:
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
337 bool HandlesAreValid() { return (overlapped_.hEvent && dirhandle_ != INVALID_HANDLE_VALUE); }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
338
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
339 bool TryCreateHandles()
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
340 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
341 if (!overlapped_.hEvent) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
342 overlapped_.hEvent = CreateEventW(nullptr, FALSE, 0, nullptr);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
343 if (!overlapped_.hEvent)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
344 return false;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
345 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
346
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
347 if (dirhandle_ == INVALID_HANDLE_VALUE) {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
348 dirhandle_ =
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
349 CreateFileW(Watcher::path_.wstring().c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE,
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
350 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
351 if (dirhandle_ == INVALID_HANDLE_VALUE)
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
352 return false;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
353 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
354
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
355 /* We're done here */
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
356 return true;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
357 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
358
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
359 bool QueueDirectoryRead()
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
360 {
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
361 return ReadDirectoryChangesW(dirhandle_, change_buf_, sizeof(change_buf_), TRUE,
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
362 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME, nullptr, &overlapped_,
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
363 nullptr);
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
364 }
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
365
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
366 HANDLE dirhandle_;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
367 OVERLAPPED overlapped_;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
368 alignas(FILE_NOTIFY_INFORMATION) char change_buf_[4096];
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
369 };
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
370
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
371 using DefaultWatcher = Win32WatcherVista;
402
d859306e2db4 filesystem: actually check for inotify instead of blindly assuming it exists
Paper <paper@tflc.us>
parents: 401
diff changeset
372 #elif defined(HAVE_INOTIFY)
401
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
373 /* Inotify watcher */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
374 class InotifyWatcher : public StdFilesystemWatcher {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
375 public:
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
376 InotifyWatcher(void *opaque, const std::filesystem::path &path, IWatcher::EventHandler handler, bool recursive)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
377 : StdFilesystemWatcher(opaque, path, handler, recursive)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
378 , first_(true)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
379 , giveup_(false)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
380 , ev_(nullptr)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
381 , ev_size_(0)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
382 {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
383 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
384
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
385 virtual ~InotifyWatcher() override
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
386 {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
387 /* We don't need to free our watch descriptors;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
388 * they are automatically free'd up by the kernel */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
389 std::free(ev_);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
390 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
391
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
392 virtual void Process() override
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
393 {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
394 if (giveup_) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
395 StdFilesystemWatcher::Process();
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
396 return;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
397 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
398
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
399 if (first_) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
400 /* Try creating the file descriptor */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
401 if (TryCreateFd()) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
402 /* Add toplevel directory */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
403 AddWatchDescriptor(Watcher::path_);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
404
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
405 /* Yay, we don't need to keep the dir structure in memory */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
406 IterateDirectory(Watcher::path_, recursive_, [this](const std::filesystem::path &p) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
407 /* hmm, we're stat'ing the file twice now... */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
408 if (std::filesystem::is_directory(p))
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
409 AddWatchDescriptor(p);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
410 handler_(opaque_, p, Event::Created);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
411 });
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
412 } else {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
413 /* Uh oh */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
414 giveup_ = true;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
415 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
416
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
417 if (giveup_) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
418 /* ;p */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
419 StdFilesystemWatcher::Process();
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
420 return;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
421 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
422
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
423 first_ = false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
424 return;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
425 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
426
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
427 if (!fd_) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
428 /* oh what the hell */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
429 giveup_ = true;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
430 StdFilesystemWatcher::Process();
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
431 return;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
432 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
433
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
434 /* Read in everything */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
435 for (;;) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
436 int r;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
437 do {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
438 ev_size_ = (ev_size_) ? (ev_size_ * 2) : (sizeof(struct inotify_event) + 4096);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
439 ev_ = reinterpret_cast<struct inotify_event *>(std::realloc(ev_, ev_size_));
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
440 if (!ev_) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
441 /* uh oh */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
442 ev_size_ = 0;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
443 return;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
444 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
445
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
446 r = read(fd_.get(), ev_, ev_size_);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
447 } while (r == 0 || (r < 0 && errno == EINVAL));
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
448
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
449 if (r < 0 && errno == EAGAIN) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
450 /* No more events to process */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
451 break;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
452 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
453
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
454 for (int i = 0; i < r; /* ok */) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
455 struct inotify_event *ev = reinterpret_cast<struct inotify_event *>(reinterpret_cast<char *>(ev_) + i);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
456
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
457 if (ev->mask & (IN_DELETE_SELF)) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
458 /* Watched directory has been deleted */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
459 RemoveWatchDescriptor(ev->wd);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
460 continue;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
461 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
462
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
463 if (ev->mask & (IN_MOVE|IN_CREATE|IN_DELETE)) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
464 std::filesystem::path p = wds_[ev->wd] / ev->name;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
465
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
466 if (ev->mask & (IN_MOVED_TO|IN_CREATE)) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
467 if (std::filesystem::is_directory(p))
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
468 AddWatchDescriptor(p);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
469 handler_(opaque_, p, Event::Created);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
470 } else if (ev->mask & (IN_MOVED_FROM|IN_DELETE)) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
471
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
472 handler_(opaque_, wds_[ev->wd] / ev->name, Event::Deleted);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
473 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
474 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
475
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
476 i += sizeof(inotify_event) + ev->len;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
477 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
478 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
479 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
480
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
481 protected:
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
482 /* File descriptor helper. Mostly follows std::unique_ptr,
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
483 * but has a function for toggling non-blocking */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
484 struct FileDescriptor {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
485 public:
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
486 FileDescriptor() : fd_(-1) { }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
487 ~FileDescriptor() { reset(); }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
488
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
489 int get() { return fd_; }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
490 operator bool() { return (fd_ != -1); }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
491 void reset(int fd = -1)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
492 {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
493 /* Close anything we already have */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
494 if (fd_ != -1)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
495 ::close(fd_);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
496 /* Put the new one in */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
497 fd_ = fd;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
498 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
499
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
500 bool SetNonBlocking(bool on)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
501 {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
502 if (fd_ < 0)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
503 return false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
504
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
505 int x = fcntl(fd_, F_GETFL);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
506 if (x < 0)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
507 return false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
508
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
509 if (on) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
510 x |= O_NONBLOCK;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
511 } else {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
512 x &= ~O_NONBLOCK;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
513 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
514
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
515 int r = fcntl(fd_, F_SETFL, x);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
516 if (r < 0)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
517 return false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
518
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
519 return true;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
520 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
521
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
522 private:
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
523 int fd_;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
524 };
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
525
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
526 bool TryCreateFd()
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
527 {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
528 if (giveup_)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
529 return false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
530
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
531 if (!fd_) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
532 #ifdef HAVE_INOTIFY_INIT1
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
533 fd_.reset(inotify_init1(IN_NONBLOCK));
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
534 #else
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
535 fd_.reset(inotify_init());
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
536 #endif
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
537 if (!fd_)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
538 return false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
539
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
540 #ifndef HAVE_INOTIFY_INIT1
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
541 /* Very old linux */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
542 if (!fd_.SetNonBlocking(true))
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
543 return false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
544 #endif
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
545 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
546
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
547 return !!fd_;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
548 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
549
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
550 bool AddWatchDescriptor(const std::filesystem::path &p)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
551 {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
552 if (!fd_ || giveup_)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
553 return false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
554
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
555 int wd = inotify_add_watch(fd_.get(), p.string().c_str(), IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE_SELF);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
556 if (wd < 0) {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
557 /* Don't even try to watch any more */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
558 giveup_ = true;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
559 return false;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
560 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
561
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
562 /* Add to our list; these IDs (should be) unique */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
563 wds_[wd] = p;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
564 return true;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
565 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
566
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
567 void RemoveWatchDescriptor(int wd)
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
568 {
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
569 inotify_rm_watch(fd_.get(), wd);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
570 wds_.erase(wd);
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
571 }
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
572
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
573 /* variables */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
574 FileDescriptor fd_;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
575 std::unordered_map<int, std::filesystem::path> wds_; /* watch descriptors */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
576 bool first_;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
577
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
578 /* set this variable if we've completely run out of
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
579 * resources (watch descriptors) and need to fall
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
580 * back to std::filesystem or fear ultimate damage */
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
581 bool giveup_;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
582
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
583 struct inotify_event *ev_;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
584 std::size_t ev_size_;
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
585 };
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
586
2f89797b6a44 filesystem: add linux inotify watcher
Paper <paper@tflc.us>
parents: 399
diff changeset
587 using DefaultWatcher = InotifyWatcher;
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
588 #else
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
589 using DefaultWatcher = StdFilesystemWatcher;
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
590 #endif
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
591
393
963047512d34 *: clang-format
Paper <paper@tflc.us>
parents: 391
diff changeset
592 IWatcher *GetRecursiveFilesystemWatcher(void *opaque, const std::filesystem::path &path, IWatcher::EventHandler handler)
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
593 {
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
594 /* .... :) */
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
595 return new DefaultWatcher(opaque, path, handler, true);
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
596 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
597
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
598 IWatcher *GetFilesystemWatcher(void *opaque, const std::filesystem::path &path, IWatcher::EventHandler handler)
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
599 {
398
650a9159a0e7 filesystem: implement win32 watchers
Paper <paper@tflc.us>
parents: 393
diff changeset
600 return new DefaultWatcher(opaque, path, handler, false);
382
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
601 }
0265e125f680 filesystem: implement filesystem watcher
Paper <paper@tflc.us>
parents: 378
diff changeset
602
15
cde8f67a7c7d *: update, megacommit :)
Paper <mrpapersonic@gmail.com>
parents: 11
diff changeset
603 } // namespace Filesystem