Further improvements to r1183.

This commit is contained in:
Birunthan Mohanathas 2012-02-14 19:34:00 +00:00
parent d20299b87a
commit 9bdf3ef167

View File

@ -18,6 +18,7 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
#include <Sddl.h>
#include <ShellAPI.h> #include <ShellAPI.h>
#include <ShlObj.h> #include <ShlObj.h>
#include <process.h> #include <process.h>
@ -34,21 +35,24 @@ struct MeasureData
struct BinData struct BinData
{ {
FILETIME lastWrite; ULONGLONG lastWrite;
HANDLE directory; HANDLE directory;
WCHAR drive; WCHAR drive;
bool isFAT;
}; };
unsigned int __stdcall QueryRecycleBinThreadProc(void* pParam); unsigned int __stdcall QueryRecycleBinThreadProc(void* pParam);
HRESULT GetFolderCLSID(LPCWSTR pszPath, CLSID* pathCLSID); HRESULT GetFolderCLSID(LPCWSTR pszPath, CLSID* pathCLSID);
HANDLE GetRecycleBinHandle(WCHAR drive); HANDLE GetRecycleBinHandle(WCHAR drive, bool& isFAT);
std::vector<BinData> g_BinData; std::vector<BinData> g_BinData;
double g_BinCount = 0; double g_BinCount = 0;
double g_BinSize = 0; double g_BinSize = 0;
UINT g_UpdateCount = 0; bool g_IsXP = false;
UINT g_InstanceCount = 0;
int g_UpdateCount = 0;
int g_InstanceCount = 0;
HANDLE g_Thread = NULL; HANDLE g_Thread = NULL;
PLUGIN_EXPORT void Initialize(void** data, void* rm) PLUGIN_EXPORT void Initialize(void** data, void* rm)
@ -56,6 +60,19 @@ PLUGIN_EXPORT void Initialize(void** data, void* rm)
MeasureData* measure = new MeasureData; MeasureData* measure = new MeasureData;
*data = measure; *data = measure;
if (g_InstanceCount == 0)
{
OSVERSIONINFOEX osvi = {sizeof(OSVERSIONINFOEX)};
if (GetVersionEx((OSVERSIONINFO*)&osvi))
{
if (osvi.dwMajorVersion == 5)
{
// Not checking for osvi.dwMinorVersion >= 1 because we won't run on pre-XP
g_IsXP = true;
}
}
}
++g_InstanceCount; ++g_InstanceCount;
} }
@ -111,22 +128,27 @@ PLUGIN_EXPORT double Update(void* data)
WCHAR* pos = wcschr(buffer, data.drive); WCHAR* pos = wcschr(buffer, data.drive);
if (pos != NULL) if (pos != NULL)
{ {
*pos = DRIVE_HANDLED; if (data.lastWrite != -1)
++iter;
if (data.lastWrite.dwHighDateTime != 0xFFFFFFFF &&
data.lastWrite.dwLowDateTime != 0xFFFFFFFF)
{ {
FILETIME lastWrite; if (data.isFAT)
GetFileTime(data.directory, NULL, NULL, &lastWrite);
if (data.lastWrite.dwHighDateTime != lastWrite.dwHighDateTime ||
data.lastWrite.dwLowDateTime != lastWrite.dwLowDateTime)
{ {
data.lastWrite.dwHighDateTime = lastWrite.dwHighDateTime; // FAT/FAT32 doesn't update directory last write time.
data.lastWrite.dwLowDateTime = lastWrite.dwLowDateTime; // TODO: Fix me?
changed = true; }
else
{
ULONGLONG lastWrite;
GetFileTime(data.directory, NULL, NULL, (FILETIME*)&lastWrite);
if (data.lastWrite != lastWrite)
{
data.lastWrite = lastWrite;
changed = true;
}
} }
} }
*pos = DRIVE_HANDLED;
++iter;
} }
else else
{ {
@ -152,11 +174,10 @@ PLUGIN_EXPORT double Update(void* data)
drive[0] = buffer[i]; drive[0] = buffer[i];
if (GetDriveType(drive) == DRIVE_FIXED) if (GetDriveType(drive) == DRIVE_FIXED)
{ {
data.directory = GetRecycleBinHandle(buffer[i]); data.directory = GetRecycleBinHandle(buffer[i], data.isFAT);
} }
data.lastWrite.dwHighDateTime = data.lastWrite = (data.directory || data.isFAT) ? 0 : -1;
data.lastWrite.dwLowDateTime = data.directory ? 0 : 0xFFFFFFFF;
g_BinData.push_back(data); g_BinData.push_back(data);
} }
@ -164,6 +185,8 @@ PLUGIN_EXPORT double Update(void* data)
if (changed) if (changed)
{ {
RmLog(LOG_WARNING, L"g_UpdateCount");
g_UpdateCount = -8;
g_Thread = (HANDLE)_beginthreadex(NULL, 0, QueryRecycleBinThreadProc, NULL, 0, NULL); g_Thread = (HANDLE)_beginthreadex(NULL, 0, QueryRecycleBinThreadProc, NULL, 0, NULL);
} }
} }
@ -246,82 +269,113 @@ HRESULT GetFolderCLSID(LPCWSTR path, CLSID* clsid)
return hr; return hr;
} }
HANDLE GetRecycleBinHandle(WCHAR drive) // Return value must be freed with LocalFree
LPWSTR GetCurrentUserSid()
{ {
WCHAR search[] = L"\0:\\*"; LPWSTR sidStr = NULL;
search[0] = drive; HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
WIN32_FIND_DATA fd;
HANDLE hSearch = FindFirstFile(search, &fd);
if (hSearch != INVALID_HANDLE_VALUE)
{ {
bool found = false; DWORD dwBufSize = 0;
std::wstring path; GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufSize);
BYTE* buf = new BYTE[dwBufSize];
do if (GetTokenInformation(hToken, TokenUser, buf, dwBufSize, &dwBufSize))
{ {
if ((fd.dwFileAttributes & TOKEN_USER* tu = (TOKEN_USER*)buf;
(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY)) == 0) if (ConvertSidToStringSid(tu->User.Sid, &sidStr))
{ {
continue;
}
WCHAR buffer[MAX_PATH];
int len = _snwprintf_s(buffer, _TRUNCATE, L"%c:\\%s\\*", drive, fd.cFileName);
// Find the SID-specific child directory
HANDLE hChildSearch = FindFirstFile(buffer, &fd);
if (hChildSearch != INVALID_HANDLE_VALUE)
{
do
{
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
(fd.cFileName[0] == L'.') ||
(wcsnlen(fd.cFileName, 10) < 10))
{
continue;
}
path.assign(buffer, len - 1);
path += fd.cFileName;
CLSID id;
HRESULT hr = GetFolderCLSID(path.c_str(), &id);
if (SUCCEEDED(hr) && IsEqualGUID(CLSID_RecycleBin, id))
{
found = true;
break;
}
}
while (FindNextFile(hChildSearch, &fd));
FindClose(hChildSearch);
if (found)
{
// Break out of main loop
break;
}
} }
} }
while (FindNextFile(hSearch, &fd));
FindClose(hSearch); delete [] buf;
if (found) CloseHandle(hToken);
}
return sidStr;
}
HANDLE GetRecycleBinHandle(WCHAR drive, bool& isFAT)
{
WCHAR search[] = L"\0:\\";
search[0] = drive;
WCHAR filesystem[16];
if (!GetVolumeInformation(search, NULL, 0, NULL, NULL, NULL, filesystem, _countof(filesystem)))
{
return NULL;
}
isFAT = true;
if (wcscmp(filesystem, L"NTFS") == 0)
{
isFAT = false;
}
else if (wcscmp(filesystem, L"FAT") != 0 && wcscmp(filesystem, L"FAT32"))
{
RmLog(LOG_ERROR, L"RecycleManager.dll: Unsupported filesystem");
return NULL;
}
const WCHAR* binFolder;
if (g_IsXP)
{
binFolder = isFAT ? L"RECYCLED" : L"RECYCLER";
}
else
{
binFolder = L"$RECYCLE.BIN";
}
HANDLE hDir = NULL;
WCHAR binPath[MAX_PATH];
_snwprintf_s(binPath, _TRUNCATE, L"%s%s\\", search, binFolder);
DWORD binAttributes = GetFileAttributes(binPath);
if (binAttributes != INVALID_FILE_ATTRIBUTES &&
binAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY))
{
if (isFAT)
{ {
HANDLE hDir = CreateFile( if (_waccess(binPath, 0) != -1)
path.c_str(), {
GENERIC_READ, isFAT = true;
FILE_SHARE_READ | FILE_SHARE_WRITE, return hDir;
NULL, }
OPEN_EXISTING, }
FILE_FLAG_BACKUP_SEMANTICS, else
NULL); {
// Get the correct, SID-specific bin for NTFS
LPWSTR currentSid = GetCurrentUserSid();
if (currentSid)
{
wcscat(binPath, currentSid);
binAttributes = GetFileAttributes(binPath);
return hDir; if (binAttributes != INVALID_FILE_ATTRIBUTES &&
binAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
CLSID id;
HRESULT hr = GetFolderCLSID(binPath, &id);
if (SUCCEEDED(hr) && IsEqualGUID(CLSID_RecycleBin, id))
{
hDir = CreateFile(
binPath,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
}
}
LocalFree(currentSid);
}
} }
} }
return NULL; if (!hDir) RmLog(LOG_ERROR, L"RecycleManager.dll: Unable to find bin");
return hDir;
} }