filewatcher supports substed drives and junction points (IDEADEV-41841, IDEADEV-41842)

This commit is contained in:
Dmitry Jemerov
2009-12-04 16:45:35 +03:00
parent 39c4aebab0
commit f94b590e53
4 changed files with 189 additions and 33 deletions

Binary file not shown.

View File

@@ -25,12 +25,28 @@ struct WatchRootInfo {
bool bFailed;
};
struct WatchRoot {
char *path;
WatchRoot *next;
};
const int ROOT_COUNT = 26;
WatchRootInfo watchRootInfos[ROOT_COUNT];
WatchRoot *firstWatchRoot = NULL;
CRITICAL_SECTION csOutput;
void NormalizeSlashes(char *path, char slash)
{
for(char *p=path; *p; p++)
if (*p == '\\' || *p == '/')
*p = slash;
}
// -- Watchable root checks ---------------------------------------------------
bool IsNetworkDrive(const char *name)
{
const int BUF_SIZE = 1024;
@@ -48,22 +64,6 @@ bool IsNetworkDrive(const char *name)
return result == NO_ERROR;
}
bool IsSubstedDrive(const char* name)
{
char deviceName[3] = {name[0], name[1], 0};
const int BUF_SIZE = 1024;
char targetPath[BUF_SIZE];
DWORD result = QueryDosDeviceA(deviceName, targetPath, BUF_SIZE);
if (result == 0) {
return false;
}
else {
bool result = (targetPath[0] == '\\' && targetPath[1] == '?' && targetPath[2] == '?');
return result;
}
}
bool IsUnwatchableFS(const char *path)
{
char volumeName[MAX_PATH];
@@ -89,16 +89,87 @@ bool IsWatchable(const char *path)
{
if (IsNetworkDrive(path))
return false;
if (IsSubstedDrive(path))
return false;
if (IsUnwatchableFS(path))
return false;
return true;
}
// -- Substed drive checks ----------------------------------------------------
void PrintRemapForSubstDrive(char driveLetter)
{
const int BUF_SIZE = 1024;
char targetPath[BUF_SIZE];
char rootPath[8];
sprintf_s(rootPath, 8, "%c:", driveLetter);
DWORD result = QueryDosDeviceA(rootPath, targetPath, BUF_SIZE);
if (result == 0) {
return;
}
else
{
if (targetPath[0] == '\\' && targetPath[1] == '?' && targetPath[2] == '?' && targetPath[3] == '\\')
{
// example path: \??\C:\jetbrains\idea
NormalizeSlashes(targetPath, '/');
printf("%c:\n%s\n", driveLetter, targetPath+4);
}
}
}
void PrintRemapForSubstDrives()
{
for(int i=0; i<ROOT_COUNT; i++)
{
if (watchRootInfos [i].bUsed)
{
PrintRemapForSubstDrive(watchRootInfos [i].driveLetter);
}
}
}
// -- Mount point enumeration -------------------------------------------------
const int BUFSIZE = 1024;
void PrintMountPointsForVolume(HANDLE hVol, const char* volumePath, char *Buf)
void PrintDirectoryReparsePoint(const char *path)
{
int size = strlen(path)+2;
char *directory = (char *) malloc(size);
strcpy_s(directory, size, path);
NormalizeSlashes(directory, '\\');
if (directory [strlen(directory)-1] != '\\')
strcat_s(directory, size, "\\");
char volumeName[_MAX_PATH];
int rc = GetVolumeNameForVolumeMountPointA(directory, volumeName, sizeof(volumeName));
if (rc)
{
char volumePathNames[_MAX_PATH];
DWORD returnLength;
rc = GetVolumePathNamesForVolumeNameA(volumeName, volumePathNames, sizeof(volumePathNames), &returnLength);
if (rc)
{
char *p = volumePathNames;
while(*p)
{
if (_stricmp(p, directory)) // if it's not the path we've already found
{
NormalizeSlashes(directory, '/');
NormalizeSlashes(p, '/');
puts(directory);
puts(p);
}
p += strlen(p)+1;
}
}
}
free(directory);
}
bool PrintMountPointsForVolume(HANDLE hVol, const char* volumePath, char *Buf)
{
HANDLE hPt; // handle for mount point scan
char Path[BUFSIZE]; // string buffer for mount points
@@ -112,7 +183,7 @@ void PrintMountPointsForVolume(HANDLE hVol, const char* volumePath, char *Buf)
// mount points, which are implemented using reparse points.
if (! (dwSysFlags & FILE_SUPPORTS_REPARSE_POINTS)) {
return;
return true;
}
// Start processing mount points on this volume.
@@ -124,23 +195,27 @@ void PrintMountPointsForVolume(HANDLE hVol, const char* volumePath, char *Buf)
// Shall we error out?
if (hPt == INVALID_HANDLE_VALUE) {
return;
return GetLastError() != ERROR_ACCESS_DENIED;
}
// Process the volume mount point.
char *buf = new char[MAX_PATH];
do {
printf("%s%s\n", volumePath, Path);
strcpy_s(buf, MAX_PATH, volumePath);
strcat_s(buf, MAX_PATH, Path);
PrintDirectoryReparsePoint(buf);
} while (FindNextVolumeMountPointA(hPt, Path, BUFSIZE));
FindVolumeMountPointClose(hPt);
return true;
}
void PrintMountPoints(const char *path)
bool PrintMountPoints(const char *path)
{
char volumeUniqueName[128];
BOOL res = GetVolumeNameForVolumeMountPointA(path, volumeUniqueName, 128);
if (!res) {
return;
return false;
}
char buf[BUFSIZE]; // buffer for unique volume identifiers
@@ -151,18 +226,59 @@ void PrintMountPoints(const char *path)
// Shall we error out?
if (hVol == INVALID_HANDLE_VALUE) {
return;
return false;
}
do {
bool success = true;
do {
if (!strcmp(buf, volumeUniqueName)) {
PrintMountPointsForVolume(hVol, path, buf);
success = PrintMountPointsForVolume(hVol, path, buf);
if (!success) break;
}
} while (FindNextVolumeA(hVol, buf, BUFSIZE));
FindVolumeClose(hVol);
return success;
}
// -- Searching for mount points in watch roots (fallback) --------------------
void PrintDirectoryReparsePoints(const char *path)
{
char *const buf = _strdup(path);
while(strchr(buf, '/'))
{
DWORD attributes = GetFileAttributesA(buf);
if (attributes == INVALID_FILE_ATTRIBUTES)
break;
if (attributes & FILE_ATTRIBUTE_REPARSE_POINT)
{
PrintDirectoryReparsePoint(buf);
}
char *pSlash = strrchr(buf, '/');
if (pSlash)
{
*pSlash = '\0';
}
}
free(buf);
}
// This is called if we got an ERROR_ACCESS_DENIED when trying to enumerate all mount points for volume.
// In this case, we walk the directory tree up from each watch root, and look at each parent directory
// to check whether it's a reparse point.
void PrintWatchRootReparsePoints()
{
WatchRoot *pWatchRoot = firstWatchRoot;
while(pWatchRoot)
{
PrintDirectoryReparsePoints(pWatchRoot->path);
pWatchRoot = pWatchRoot->next;
}
}
// -- Watcher thread ----------------------------------------------------------
void PrintChangeInfo(char *rootPath, FILE_NOTIFY_INFORMATION *info)
{
char FileNameBuffer[_MAX_PATH];
@@ -253,6 +369,8 @@ DWORD WINAPI WatcherThread(void *param)
return 0;
}
// -- Roots update ------------------------------------------------------------
void MarkAllRootsUnused()
{
for(int i=0; i<ROOT_COUNT; i++)
@@ -306,20 +424,53 @@ void UpdateRoots()
}
EnterCriticalSection(&csOutput);
fprintf(stdout, "%s", infoBuffer);
puts("#\nREMAP");
PrintRemapForSubstDrives();
bool printedMountPoints = true;
for(int i=0; i<ROOT_COUNT; i++)
{
if (watchRootInfos [i].bUsed)
{
char rootPath[8];
sprintf_s(rootPath, 8, "%c:\\", watchRootInfos [i].driveLetter);
PrintMountPoints(rootPath);
if (!PrintMountPoints(rootPath))
printedMountPoints = false;
}
}
if (!printedMountPoints)
{
PrintWatchRootReparsePoints();
}
puts("#");
fflush(stdout);
LeaveCriticalSection(&csOutput);
}
void AddWatchRoot(const char *path)
{
WatchRoot *watchRoot = (WatchRoot *) malloc(sizeof(WatchRoot));
watchRoot->next = NULL;
watchRoot->path = _strdup(path);
watchRoot->next = firstWatchRoot;
firstWatchRoot = watchRoot;
}
void FreeWatchRootsList()
{
WatchRoot *pWatchRoot = firstWatchRoot;
WatchRoot *pNext;
while(pWatchRoot)
{
pNext = pWatchRoot->next;
free(pWatchRoot->path);
free(pWatchRoot);
pWatchRoot=pNext;
}
firstWatchRoot = NULL;
}
// -- Main - filewatcher protocol ---------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
InitializeCriticalSection(&csOutput);
@@ -340,6 +491,7 @@ int _tmain(int argc, _TCHAR* argv[])
if (!strcmp(buffer, "ROOTS"))
{
MarkAllRootsUnused();
FreeWatchRootsList();
bool failed = false;
while(true)
{
@@ -351,10 +503,14 @@ int _tmain(int argc, _TCHAR* argv[])
if (buffer [0] == '#')
break;
int driveLetterPos = 0;
char *pDriveLetter = buffer;
if (*pDriveLetter == '|')
pDriveLetter++;
AddWatchRoot(pDriveLetter);
_strupr_s(buffer, sizeof(buffer)-1);
char driveLetter = buffer[0];
if (driveLetter == '|')
driveLetter = buffer[1];
char driveLetter = *pDriveLetter;
if (driveLetter >= 'A' && driveLetter <= 'Z')
{
watchRootInfos [driveLetter-'A'].bUsed = true;

View File

@@ -73,7 +73,7 @@ BEGIN
VALUE "FileDescription", "File System Notification Processor"
VALUE "FileVersion", "1, 0, 0, 1"
VALUE "InternalName", "fsnotifier"
VALUE "LegalCopyright", "Copyright (C) 2008 JetBrains, Inc."
VALUE "LegalCopyright", "Copyright (C) 2008-09 JetBrains, Inc."
VALUE "OriginalFilename", "fsnotifier.exe"
VALUE "ProductName", "IntelliJ IDEA"
VALUE "ProductVersion", "1, 0, 0, 1"

View File

@@ -62,7 +62,7 @@
Name="VCLinkerTool"
AdditionalDependencies="mpr.lib"
OutputFile="$(OutDir)\fsnotifier.exe"
LinkIncremental="2"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"