moving native binaries to community
[fedora-idea.git] / native / fileWatcher / fileWatcher3.cpp
blob8c61739b839849164257642735f1b786c09e9b27
1 // fileWatcher3.cpp : Defines the entry point for the console application.
2 //
4 #include "stdafx.h"
6 struct WatchRootInfo {
7 char driveLetter;
8 HANDLE hThread;
9 HANDLE hStopEvent;
10 bool bInitialized;
11 bool bUsed;
12 bool bFailed;
15 const int ROOT_COUNT = 26;
17 WatchRootInfo watchRootInfos[ROOT_COUNT];
19 CRITICAL_SECTION csOutput;
21 bool IsNetworkDrive(const char *name)
23 const int BUF_SIZE = 1024;
24 char buffer[BUF_SIZE];
25 UNIVERSAL_NAME_INFO* uni = (UNIVERSAL_NAME_INFO*) buffer;
26 DWORD size = BUF_SIZE;
28 DWORD result = WNetGetUniversalNameA(
29 name, // path for network resource
30 UNIVERSAL_NAME_INFO_LEVEL, // level of information
31 buffer, // name buffer
32 &size // size of buffer
35 return result == NO_ERROR;
38 bool IsSubstedDrive(const char* name)
40 char deviceName[3] = {name[0], name[1], 0};
41 const int BUF_SIZE = 1024;
42 char targetPath[BUF_SIZE];
44 DWORD result = QueryDosDeviceA(deviceName, targetPath, BUF_SIZE);
45 if (result == 0) {
46 return false;
48 else {
49 bool result = (targetPath[0] == '\\' && targetPath[1] == '?' && targetPath[2] == '?');
50 return result;
54 bool IsUnwatchableFS(const char *path)
56 char volumeName[MAX_PATH];
57 char fsName[MAX_PATH];
58 DWORD fsFlags;
59 DWORD maxComponentLength;
60 SetErrorMode(SEM_FAILCRITICALERRORS);
61 if (!GetVolumeInformationA(path, volumeName, MAX_PATH-1, NULL, &maxComponentLength, &fsFlags, fsName, MAX_PATH-1))
62 return false;
63 if (strcmp(fsName, "NTFS") && strcmp(fsName, "FAT") && strcmp(fsName, "FAT32"))
64 return true;
66 if (!strcmp(fsName, "NTFS") && maxComponentLength != 255 && !(fsFlags & FILE_SUPPORTS_REPARSE_POINTS))
68 // SAMBA reports itself as NTFS
69 return true;
72 return false;
75 bool IsWatchable(const char *path)
77 if (IsNetworkDrive(path))
78 return false;
79 if (IsSubstedDrive(path))
80 return false;
81 if (IsUnwatchableFS(path))
82 return false;
83 return true;
86 const int BUFSIZE = 1024;
88 void PrintMountPointsForVolume(HANDLE hVol, const char* volumePath, char *Buf)
90 HANDLE hPt; // handle for mount point scan
91 char Path[BUFSIZE]; // string buffer for mount points
92 DWORD dwSysFlags; // flags that describe the file system
93 char FileSysNameBuf[BUFSIZE];
95 // Is this volume NTFS?
96 GetVolumeInformationA(Buf, NULL, 0, NULL, NULL, &dwSysFlags, FileSysNameBuf, BUFSIZE);
98 // Detect support for reparse points, and therefore for volume
99 // mount points, which are implemented using reparse points.
101 if (! (dwSysFlags & FILE_SUPPORTS_REPARSE_POINTS)) {
102 return;
105 // Start processing mount points on this volume.
106 hPt = FindFirstVolumeMountPointA(
107 Buf, // root path of volume to be scanned
108 Path, // pointer to output string
109 BUFSIZE // size of output buffer
112 // Shall we error out?
113 if (hPt == INVALID_HANDLE_VALUE) {
114 return;
117 // Process the volume mount point.
118 do {
119 printf("%s%s\n", volumePath, Path);
120 } while (FindNextVolumeMountPointA(hPt, Path, BUFSIZE));
122 FindVolumeMountPointClose(hPt);
125 void PrintMountPoints(const char *path)
127 char volumeUniqueName[128];
128 BOOL res = GetVolumeNameForVolumeMountPointA(path, volumeUniqueName, 128);
129 if (!res) {
130 return;
133 char buf[BUFSIZE]; // buffer for unique volume identifiers
134 HANDLE hVol; // handle for the volume scan
136 // Open a scan for volumes.
137 hVol = FindFirstVolumeA(buf, BUFSIZE );
139 // Shall we error out?
140 if (hVol == INVALID_HANDLE_VALUE) {
141 return;
144 do {
145 if (!strcmp(buf, volumeUniqueName)) {
146 PrintMountPointsForVolume(hVol, path, buf);
148 } while (FindNextVolumeA(hVol, buf, BUFSIZE));
150 FindVolumeClose(hVol);
153 void PrintChangeInfo(char *rootPath, FILE_NOTIFY_INFORMATION *info)
155 char FileNameBuffer[_MAX_PATH];
156 int converted = WideCharToMultiByte(CP_ACP, 0, info->FileName, info->FileNameLength/sizeof(WCHAR), FileNameBuffer, _MAX_PATH-1, NULL, NULL);
157 FileNameBuffer[converted] = '\0';
158 char *command;
159 if (info->Action == FILE_ACTION_ADDED || info->Action == FILE_ACTION_RENAMED_OLD_NAME)
161 command = "CREATE";
163 else if (info->Action == FILE_ACTION_REMOVED || info->Action == FILE_ACTION_RENAMED_OLD_NAME)
165 command = "DELETE";
167 else if (info->Action == FILE_ACTION_MODIFIED)
169 command = "CHANGE";
171 else
173 return; // unknown command
176 EnterCriticalSection(&csOutput);
177 puts(command);
178 printf("%s", rootPath);
179 puts(FileNameBuffer);
180 fflush(stdout);
181 LeaveCriticalSection(&csOutput);
184 DWORD WINAPI WatcherThread(void *param)
186 WatchRootInfo *info = (WatchRootInfo *) param;
188 OVERLAPPED overlapped;
189 memset(&overlapped, 0, sizeof(overlapped));
190 overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
192 char rootPath[8];
193 sprintf_s(rootPath, 8, "%c:\\", info->driveLetter);
194 HANDLE hRootDir = CreateFileA(rootPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
195 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
197 int buffer_size = 10240;
198 char *buffer = new char[buffer_size];
200 HANDLE handles [2];
201 handles [0] = info->hStopEvent;
202 handles [1] = overlapped.hEvent;
203 while(true)
205 int rcDir = ReadDirectoryChangesW(hRootDir, buffer, buffer_size, TRUE,
206 FILE_NOTIFY_CHANGE_FILE_NAME |
207 FILE_NOTIFY_CHANGE_DIR_NAME |
208 FILE_NOTIFY_CHANGE_ATTRIBUTES |
209 FILE_NOTIFY_CHANGE_SIZE |
210 FILE_NOTIFY_CHANGE_LAST_WRITE,
211 NULL,
212 &overlapped,
213 NULL);
214 if (rcDir == 0)
216 info->bFailed = true;
217 break;
220 int rc = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
221 if (rc == WAIT_OBJECT_0)
223 break;
225 if (rc == WAIT_OBJECT_0+1)
227 FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION *) buffer;
228 while(true)
230 PrintChangeInfo(rootPath, info);
231 if (!info->NextEntryOffset)
232 break;
233 info = (FILE_NOTIFY_INFORMATION *) ((char *) info + info->NextEntryOffset);
237 CloseHandle(overlapped.hEvent);
238 CloseHandle(hRootDir);
239 delete[] buffer;
240 return 0;
243 void MarkAllRootsUnused()
245 for(int i=0; i<ROOT_COUNT; i++)
247 watchRootInfos [i].bUsed = false;
251 void StartRoot(WatchRootInfo *info)
253 info->hStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
254 info->hThread = CreateThread(NULL, 0, &WatcherThread, info, 0, NULL);
255 info->bInitialized = true;
258 void StopRoot(WatchRootInfo *info)
260 SetEvent(info->hStopEvent);
261 WaitForSingleObject(info->hThread, INFINITE);
262 CloseHandle(info->hThread);
263 CloseHandle(info->hStopEvent);
264 info->bInitialized = false;
267 void UpdateRoots()
269 char infoBuffer [256];
270 strcpy_s(infoBuffer, "UNWATCHEABLE\n");
271 for(int i=0; i<ROOT_COUNT; i++)
273 if (watchRootInfos [i].bInitialized && (!watchRootInfos [i].bUsed || watchRootInfos [i].bFailed))
275 StopRoot(&watchRootInfos [i]);
276 watchRootInfos [i].bFailed = false;
278 if (watchRootInfos [i].bUsed)
280 char rootPath[8];
281 sprintf_s(rootPath, 8, "%c:\\", watchRootInfos [i].driveLetter);
282 if (!IsWatchable(rootPath))
284 strcat_s(infoBuffer, rootPath);
285 strcat_s(infoBuffer, "\n");
286 continue;
288 if (!watchRootInfos [i].bInitialized)
290 StartRoot(&watchRootInfos [i]);
294 EnterCriticalSection(&csOutput);
295 fprintf(stdout, "%s", infoBuffer);
296 for(int i=0; i<ROOT_COUNT; i++)
298 if (watchRootInfos [i].bUsed)
300 char rootPath[8];
301 sprintf_s(rootPath, 8, "%c:\\", watchRootInfos [i].driveLetter);
302 PrintMountPoints(rootPath);
305 puts("#");
306 fflush(stdout);
307 LeaveCriticalSection(&csOutput);
310 int _tmain(int argc, _TCHAR* argv[])
312 InitializeCriticalSection(&csOutput);
314 for(int i=0; i<26; i++)
316 watchRootInfos [i].driveLetter = 'A' + i;
317 watchRootInfos [i].bInitialized = false;
318 watchRootInfos [i].bUsed = false;
321 char buffer[8192];
322 while(true)
324 if (!gets_s(buffer, sizeof(buffer)-1))
325 break;
327 if (!strcmp(buffer, "ROOTS"))
329 MarkAllRootsUnused();
330 bool failed = false;
331 while(true)
333 if (!gets_s(buffer, sizeof(buffer)-1))
335 failed = true;
336 break;
338 if (buffer [0] == '#')
339 break;
340 int driveLetterPos = 0;
341 _strupr_s(buffer, sizeof(buffer)-1);
342 char driveLetter = buffer[0];
343 if (driveLetter == '|')
344 driveLetter = buffer[1];
345 if (driveLetter >= 'A' && driveLetter <= 'Z')
347 watchRootInfos [driveLetter-'A'].bUsed = true;
350 if (failed)
351 break;
353 UpdateRoots();
355 if (!strcmp(buffer, "EXIT"))
356 break;
359 MarkAllRootsUnused();
360 UpdateRoots();
362 DeleteCriticalSection(&csOutput);