github.com/nycdavid/zeus@v0.0.0-20201208104106-9ba439429e03/vagrant/ext/inotify-wrapper/inotify-wrapper.cpp (about) 1 #include <map> 2 #include <string> 3 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <errno.h> 8 #include <unistd.h> 9 #include <sys/types.h> 10 #include <sys/inotify.h> 11 12 #include <errno.h> 13 14 #define EVENT_SIZE (sizeof (struct inotify_event)) 15 #define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16)) 16 17 using namespace std; 18 19 static int _inotify_fd; 20 static map<int, string> _WatchedFiles; 21 static map<string, bool> _FileIsWatched; 22 23 // static int inotifyFlags = IN_ATTRIB | IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF; 24 static int inotifyFlags = IN_ATTRIB | IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF; 25 26 void maybeAddFileToWatchList(string file) 27 { 28 if (_FileIsWatched[file]) return; 29 30 int wd = inotify_add_watch(_inotify_fd, file.c_str(), inotifyFlags); 31 int attempts = 0; 32 // Files are momentarily inaccessible when they are rewritten. I couldn't 33 // find a good way to deal with this, so we poll 'deleted' files for 0.25s or so 34 // to see if they reappear. 35 while (wd == -1 && errno == ENOENT) { 36 usleep(10000); 37 wd = inotify_add_watch(_inotify_fd, file.c_str(), inotifyFlags); 38 if (attempts++ == 25) break; // try for at most about a quarter of a second 39 } 40 if (wd != -1) { 41 _WatchedFiles[wd] = file; 42 _FileIsWatched[file] = true; 43 } 44 } 45 46 // This essentially removes a file from the watchlist then 47 // immediately re-adds it. This is because when a file is rewritten, 48 // as so many editors love to do, the watchdescriptor no longer refers to 49 // the file, so re must re-watch the path. 50 void replaceFileInWatchList(int wd, string file) 51 { 52 _FileIsWatched.erase(file); 53 _WatchedFiles.erase(wd); 54 inotify_rm_watch(_inotify_fd, wd); 55 maybeAddFileToWatchList(file); 56 } 57 58 void handleStdin() 59 { 60 char line[2048]; 61 if (fgets(line, sizeof(line), stdin) == NULL) return; 62 line[strlen(line)-1] = 0; 63 64 maybeAddFileToWatchList(string(line)); 65 } 66 67 void handleInotify() 68 { 69 int length; 70 int i = 0; 71 char buffer[EVENT_BUF_LEN]; 72 string filename; 73 74 length = read(_inotify_fd, buffer, EVENT_BUF_LEN); 75 if (length < 0) return; 76 77 while (i < length) { 78 struct inotify_event *event = (struct inotify_event *) &buffer[i]; 79 string file = _WatchedFiles[event->wd]; 80 if (file != "") { 81 printf("%s\n", file.c_str()); 82 fflush(stdout); 83 replaceFileInWatchList(event->wd, file); 84 } 85 86 i += EVENT_SIZE + event->len; 87 } 88 } 89 90 void go() 91 { 92 fd_set rfds; 93 int retval; 94 95 for (;;) { 96 FD_ZERO(&rfds); 97 FD_SET(0, &rfds); 98 FD_SET(_inotify_fd, &rfds); 99 100 retval = select(_inotify_fd+1, &rfds, NULL, NULL, NULL); 101 102 if (retval == -1) { 103 // perror("select"); 104 } else if (retval) { 105 if(feof(stdin)) break; 106 if (FD_ISSET(0, &rfds)) handleStdin(); 107 if (FD_ISSET(_inotify_fd, &rfds)) handleInotify(); 108 } 109 } 110 } 111 112 113 int main(int argc, const char *argv[]) 114 { 115 _inotify_fd = inotify_init(); 116 go(); 117 }