24 #ifdef HAVE_SYS_INOTIFY_H
25 #include <sys/inotify.h>
29 fd = inotify_init1(IN_CLOEXEC);
30 if (fd == -1) fd = inotify_init();
31 if (fd == -1)
LogF(
"inotify_init %s", strerror(errno));
42 while (close(fd) == -1 && errno == EINTR) { }
57 int wd = inotify_add_watch(fd, file, IN_CREATE | IN_MODIFY | IN_MOVED_TO | IN_MOVE_SELF | IN_ONLYDIR);
59 LogF(
"inotify_add_watch %s", strerror(errno));
60 watch_descriptors[wd] = file;
65 if ((pfd->revents & pfd->events) != POLLIN || pfd->fd != fd)
66 LogF(
"C4FileMonitor::Execute unexpectedly called %d %d %hd %hd", fd, pfd->fd, pfd->events, pfd->revents);
68 inotify_event*
event =
new (buf) inotify_event;
69 if (read(fd, buf,
sizeof(buf)) > 0)
71 const char * file = watch_descriptors[
event->wd];
72 uint32_t mask =
event->mask;
78 if (mask & IN_MOVED_TO)
80 if (mask & IN_MOVE_SELF)
86 Log(
"inotify buffer too small");
94 pCallback((
const char *)pEventData,
nullptr);
99 pollfd pfd = { fd, POLLIN, 0 };
103 #elif defined(_WIN32)
107 : fStarted(false), pCallback(pCallback), pWatches(nullptr)
109 hEvent = CreateEvent(
nullptr,
true,
false,
nullptr);
122 CloseHandle(pWatches->hDir);
123 TreeWatch *pDelete = pWatches;
124 pWatches = pWatches->Next;
138 const DWORD C4FileMonitorNotifies = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE;
143 HANDLE hDir = CreateFileW(
GetWideChar(szDir), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
nullptr);
144 if (hDir == INVALID_HANDLE_VALUE)
return;
146 TreeWatch *pWatch =
new TreeWatch();
148 pWatch->DirName = szDir;
150 ZeroMem(&pWatch->ov,
sizeof(pWatch->ov));
151 pWatch->ov.hEvent = hEvent;
153 pWatch->Next = pWatches;
156 if (!ReadDirectoryChangesW(hDir, pWatch->Buffer,
sizeof(pWatch->Buffer),
false, C4FileMonitorNotifies,
nullptr, &pWatch->ov,
nullptr))
157 if (GetLastError() != ERROR_IO_PENDING)
167 if (WaitForSingleObject(hEvent, iTimeout) != WAIT_OBJECT_0)
170 for (TreeWatch *pWatch = pWatches; pWatch; pWatch = pWatch->Next)
174 if (GetOverlappedResult(pWatch->hDir, &pWatch->ov, &dwBytes,
false))
177 const char *pPos = pWatch->Buffer;
180 const _FILE_NOTIFY_INFORMATION *pNotify =
reinterpret_cast<const _FILE_NOTIFY_INFORMATION *
>(pPos);
182 HandleNotify(pWatch->DirName.getData(), pNotify);
184 if (!pNotify->NextEntryOffset)
break;
185 pPos += pNotify->NextEntryOffset;
186 if (pPos >= pWatch->Buffer + std::min<size_t>(
sizeof(pWatch->Buffer), dwBytes))
191 ReadDirectoryChangesW(pWatch->hDir, pWatch->Buffer,
sizeof(pWatch->Buffer),
false, C4FileMonitorNotifies,
nullptr, &pWatch->ov,
nullptr);
193 while (GetOverlappedResult(pWatch->hDir, &pWatch->ov, &dwBytes,
false))
195 ReadDirectoryChangesW(pWatch->hDir, pWatch->Buffer,
sizeof(pWatch->Buffer),
false, C4FileMonitorNotifies,
nullptr, &pWatch->ov,
nullptr);
207 pCallback((
const char *)pEventData,
nullptr);
211 HANDLE C4FileMonitor::GetEvent()
216 void C4FileMonitor::HandleNotify(
const char *szDir,
const _FILE_NOTIFY_INFORMATION *pNotify)
219 UINT iCodePage = CP_UTF8;
220 int iFileNameBytes = WideCharToMultiByte(iCodePage, 0,
221 pNotify->FileName, pNotify->FileNameLength / 2,
nullptr, 0,
nullptr,
nullptr);
225 Path.Grow(iFileNameBytes);
226 char *pFilename = Path.getMPtr(
SLen(Path.getData()));
228 int iWritten = WideCharToMultiByte(iCodePage, 0,
229 pNotify->FileName, pNotify->FileNameLength / 2,
230 pFilename, iFileNameBytes,
232 if (iWritten != iFileNameBytes)
233 Path.Shrink(iFileNameBytes+1);
238 #elif not defined(__APPLE__)
243 #ifdef HAVE_SYS_INOTIFY_H
244 C4FileMonitor::pCallback = pCallback;
255 #ifdef STDSCHEDULER_USE_EVENTS
256 HANDLE C4FileMonitor::GetEvent() {
return 0; }
C4Application Application
bool Log(const char *szMessage)
bool LogF(const char *strMessage,...)
StdStrBuf::wchar_t_holder GetWideChar(const char *utf8, bool double_null_terminate=false)
std::enable_if< std::is_pod< T >::value >::type ZeroMem(T *lpMem, size_t dwSize)
size_t SLen(const char *sptr)
C4InteractiveThread InteractiveThread
void GetFDs(std::vector< struct pollfd > &FDs) override
void OnThreadEvent(C4InteractiveEventType eEvent, void *pEventData) override
bool Execute(int iTimeout=-1, pollfd *=nullptr) override
~C4FileMonitor() override
void AddDirectory(const char *szDir)
C4FileMonitor(ChangeNotify pCallback)
void RemoveProc(StdSchedulerProc *pProc)
void ClearCallback(C4InteractiveEventType eEvent, Callback *pnNetworkCallback)
bool AddProc(StdSchedulerProc *pProc)
bool PushEvent(C4InteractiveEventType eEventType, void *pData=nullptr)
void SetCallback(C4InteractiveEventType eEvent, Callback *pnNetworkCallback)
static void DeletePointer(void *data)