1173 lines
24 KiB
C++
1173 lines
24 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
TrackFS.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Track the directories the app looks at and record them into a file.
|
||
|
|
||
|
History:
|
||
|
|
||
|
04/04/2001 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include "utils.h"
|
||
|
#include "secutils.h"
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#define APPPATCH_DIR L"AppPatch\\"
|
||
|
#define APPPATCH_DIR_LEN (sizeof(APPPATCH_DIR) / sizeof(WCHAR) - 1)
|
||
|
|
||
|
#define TRACK_LOG_SUFFIX L".LUA.log"
|
||
|
#define TRACK_LOG_SUFFIX_LEN (sizeof(TRACK_LOG_SUFFIX) / sizeof(WCHAR) - 1)
|
||
|
|
||
|
struct DISTINCT_OBJ
|
||
|
{
|
||
|
DISTINCT_OBJ* next;
|
||
|
|
||
|
LPWSTR pwszName;
|
||
|
};
|
||
|
|
||
|
static WCHAR g_wszProgramFiles[MAX_PATH] = L"";
|
||
|
static DWORD g_cProgramFiles = 0;
|
||
|
|
||
|
DWORD
|
||
|
LuatpGetProgramFilesDirW()
|
||
|
{
|
||
|
if (g_cProgramFiles == 0)
|
||
|
{
|
||
|
WCHAR wszProgramFiles[MAX_PATH];
|
||
|
|
||
|
if (GetEnvironmentVariableW(L"ProgramFiles", wszProgramFiles, MAX_PATH))
|
||
|
{
|
||
|
DWORD dwSize = GetLongPathNameW(wszProgramFiles, g_wszProgramFiles, MAX_PATH);
|
||
|
|
||
|
if (dwSize <= MAX_PATH)
|
||
|
{
|
||
|
//
|
||
|
// Only if we successfully got the path and it's not more
|
||
|
// than MAX_PATH will we set the global values.
|
||
|
//
|
||
|
g_cProgramFiles = dwSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_wszProgramFiles[0] = L'\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return g_cProgramFiles;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatpIsProgramFilesDirectory(
|
||
|
LPCWSTR pwszPath
|
||
|
)
|
||
|
{
|
||
|
LuatpGetProgramFilesDirW();
|
||
|
|
||
|
if (g_cProgramFiles)
|
||
|
{
|
||
|
return !_wcsnicmp(pwszPath, g_wszProgramFiles, g_cProgramFiles);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// We only record things when the file
|
||
|
// 1) is not in the user profile dir - in which we know we don't need to redirect;
|
||
|
// 2) is not in the program files dir - in which we know we will need to redirect;
|
||
|
// because in those cases we know what to do so the user doesn't need to make the
|
||
|
// choice.
|
||
|
BOOL
|
||
|
LuatpShouldRecord(
|
||
|
LPCWSTR pwszPath
|
||
|
)
|
||
|
{
|
||
|
//if (LuatpIsUserDirectory(pwszPath) ||
|
||
|
// LuatpIsProgramFilesDirectory(pwszPath))
|
||
|
if (IsUserDirectory(pwszPath))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
LPWSTR
|
||
|
LuatpGetLongObjectName(
|
||
|
LPCWSTR pwszName,
|
||
|
BOOL fIsDirectory
|
||
|
)
|
||
|
{
|
||
|
BOOL fIsSuccess = FALSE;
|
||
|
LPWSTR pwszLongNameObject = NULL;
|
||
|
LPWSTR pwszObject = NULL;
|
||
|
|
||
|
if (!pwszName)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// First get the full path.
|
||
|
//
|
||
|
DWORD cFullPath = GetFullPathNameW(pwszName, 0, NULL, NULL);
|
||
|
|
||
|
if (!cFullPath)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[LuatpGetLongObjectName] Failed to get the length of full path: %d",
|
||
|
GetLastError());
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We allocate one more char to make space for the trailing slash for dir names.
|
||
|
//
|
||
|
pwszObject = new WCHAR [cFullPath + 1];
|
||
|
|
||
|
if (!pwszObject)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[LuatpGetLongObjectName] Failed to allocate %d WCHARs",
|
||
|
cFullPath + 1);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!GetFullPathNameW(pwszName, cFullPath, pwszObject, NULL))
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[LuatpGetLongObjectName] Failed to get the full path: %d",
|
||
|
GetLastError());
|
||
|
|
||
|
goto EXIT;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If it's not a valid file name, we don't add it.
|
||
|
//
|
||
|
if (wcslen(pwszObject) < 2 || !iswalpha(pwszObject[0]) || (pwszObject[1] != L':'))
|
||
|
{
|
||
|
goto EXIT;
|
||
|
}
|
||
|
|
||
|
if (fIsDirectory)
|
||
|
{
|
||
|
//
|
||
|
// If it's a directory we make sure there's a trailing slash.
|
||
|
//
|
||
|
if (pwszObject[cFullPath - 2] != L'\\')
|
||
|
{
|
||
|
pwszObject[cFullPath - 1] = L'\\';
|
||
|
pwszObject[cFullPath] = L'\0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Convert it to all lower case.
|
||
|
//
|
||
|
_wcslwr(pwszObject);
|
||
|
|
||
|
//
|
||
|
// Convert it to the long names.
|
||
|
//
|
||
|
DWORD cLongPath = GetLongPathName(pwszObject, NULL, 0);
|
||
|
|
||
|
if (!cLongPath)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[LuatpGetLongObjectName] Failed to get the length of long path: %d",
|
||
|
GetLastError());
|
||
|
|
||
|
goto EXIT;
|
||
|
}
|
||
|
|
||
|
pwszLongNameObject = new WCHAR [cLongPath];
|
||
|
|
||
|
if (!pwszLongNameObject)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[LuatpGetLongObjectName] Failed to allocate %d WCHARs",
|
||
|
cLongPath);
|
||
|
|
||
|
goto EXIT;
|
||
|
}
|
||
|
|
||
|
if (!GetLongPathName(pwszObject, pwszLongNameObject, cLongPath))
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[LuatpGetLongObjectName] Failed to get the long path: %d",
|
||
|
GetLastError());
|
||
|
|
||
|
goto EXIT;
|
||
|
}
|
||
|
|
||
|
if (LuatpShouldRecord(pwszLongNameObject))
|
||
|
{
|
||
|
//
|
||
|
// We only record the objects that are not in the user profile directory.
|
||
|
//
|
||
|
fIsSuccess = TRUE;
|
||
|
}
|
||
|
|
||
|
EXIT:
|
||
|
|
||
|
delete [] pwszObject;
|
||
|
|
||
|
if (!fIsSuccess)
|
||
|
{
|
||
|
delete [] pwszLongNameObject;
|
||
|
pwszLongNameObject = NULL;
|
||
|
}
|
||
|
|
||
|
return pwszLongNameObject;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
The tracking class for the file system.
|
||
|
|
||
|
History:
|
||
|
|
||
|
04/04/2001 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
class CTrackObject
|
||
|
{
|
||
|
public:
|
||
|
BOOL Init();
|
||
|
VOID Free();
|
||
|
|
||
|
// If the object name needs to be processed, eg, it's not the full path
|
||
|
// or not the long name, call this method to process it first before
|
||
|
// adding to the list.
|
||
|
VOID AddObject(LPCWSTR pwszName, BOOL fIsDirectory);
|
||
|
|
||
|
// If the caller already processed the file name, call this method
|
||
|
// to add it directly.
|
||
|
VOID AddObjectDirect(LPWSTR pwszName, BOOL fIsDirectory);
|
||
|
|
||
|
// This is specially for GetTempFileName - we add
|
||
|
// *.tmp after the path.
|
||
|
VOID AddObjectGetTempFileName(LPCWSTR pwszPath);
|
||
|
|
||
|
VOID Record();
|
||
|
|
||
|
private:
|
||
|
|
||
|
BOOL AddObjectToList(LPWSTR pwszName, BOOL fIsDirectory);
|
||
|
|
||
|
VOID WriteToLog(LPCWSTR pwszDir);
|
||
|
|
||
|
HANDLE m_hLog;
|
||
|
WCHAR m_wszLog[MAX_PATH];
|
||
|
|
||
|
DISTINCT_OBJ* m_pDistinctDirs;
|
||
|
DISTINCT_OBJ* m_pDistinctFiles;
|
||
|
|
||
|
DWORD m_cDistinctDirs;
|
||
|
DWORD m_cDistinctFiles;
|
||
|
};
|
||
|
|
||
|
BOOL
|
||
|
CTrackObject::AddObjectToList(
|
||
|
LPWSTR pwszName,
|
||
|
BOOL fIsDirectory
|
||
|
)
|
||
|
{
|
||
|
BOOL fIsSuccess = FALSE;
|
||
|
|
||
|
DISTINCT_OBJ* pDistinctObjs = fIsDirectory ? m_pDistinctDirs : m_pDistinctFiles;
|
||
|
DISTINCT_OBJ* pObj = pDistinctObjs;
|
||
|
|
||
|
// Check to see if this file already exists in the list.
|
||
|
while (pObj)
|
||
|
{
|
||
|
if (!wcscmp(pObj->pwszName, pwszName))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pObj = pObj->next;
|
||
|
}
|
||
|
|
||
|
if (!pObj)
|
||
|
{
|
||
|
pObj = new DISTINCT_OBJ;
|
||
|
if (pObj)
|
||
|
{
|
||
|
DWORD cLen = wcslen(pwszName);
|
||
|
|
||
|
pObj->pwszName = new WCHAR [cLen + 1];
|
||
|
|
||
|
if (pObj->pwszName)
|
||
|
{
|
||
|
wcscpy(pObj->pwszName, pwszName);
|
||
|
pObj->next = pDistinctObjs;
|
||
|
|
||
|
if (fIsDirectory)
|
||
|
{
|
||
|
++m_cDistinctDirs;
|
||
|
m_pDistinctDirs = pObj;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
++m_cDistinctFiles;
|
||
|
m_pDistinctFiles = pObj;
|
||
|
}
|
||
|
|
||
|
fIsSuccess = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::AddObjectToList] Error allocating %d WCHARs",
|
||
|
cLen + 1);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::AddObjectToList] Error allocating memory for new node");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fIsSuccess;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function Description:
|
||
|
|
||
|
For files it's simple - we just store the file name in a list and search
|
||
|
through the list to see if it's already in the list. If it is we are done;
|
||
|
else we add it to the beginning of the list.
|
||
|
We don't expect there are too many calls to modify files so a linked list
|
||
|
is fine.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
IN pwszFileName - file name.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
none.
|
||
|
|
||
|
History:
|
||
|
|
||
|
05/08/2001 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
CTrackObject::AddObject(
|
||
|
LPCWSTR pwszName,
|
||
|
BOOL fIsDirectory
|
||
|
)
|
||
|
{
|
||
|
BOOL fIsSuccess = FALSE;
|
||
|
|
||
|
LPWSTR pwszLongNameObject = LuatpGetLongObjectName(pwszName, fIsDirectory);
|
||
|
|
||
|
if (pwszLongNameObject)
|
||
|
{
|
||
|
AddObjectToList(pwszLongNameObject, fIsDirectory);
|
||
|
|
||
|
delete [] pwszLongNameObject;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CTrackObject::AddObjectDirect(
|
||
|
LPWSTR pwszName,
|
||
|
BOOL fIsDirectory
|
||
|
)
|
||
|
{
|
||
|
if (pwszName)
|
||
|
{
|
||
|
AddObjectToList(pwszName, fIsDirectory);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function Description:
|
||
|
|
||
|
Write the directory to the log as ANSI characters.
|
||
|
Note this method uses 2 str* routines and it IS DBCS aware.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
IN pwszDir - the directory to write to the log.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
History:
|
||
|
|
||
|
04/04/2001 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
CTrackObject::WriteToLog(
|
||
|
LPCWSTR pwsz)
|
||
|
{
|
||
|
if (!pwsz || !*pwsz)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the number of bytes required to convert the string to ansi.
|
||
|
//
|
||
|
DWORD dwSize = WideCharToMultiByte(CP_ACP, 0, pwsz, -1, NULL, 0, NULL, NULL);
|
||
|
|
||
|
LPSTR psz = new CHAR [dwSize + 2];
|
||
|
if (psz)
|
||
|
{
|
||
|
WideCharToMultiByte(CP_ACP, 0, pwsz, -1, psz, dwSize, 0, 0);
|
||
|
psz[dwSize - 1] = '\r';
|
||
|
psz[dwSize] = '\n';
|
||
|
psz[dwSize + 1] = '\0';
|
||
|
|
||
|
DWORD dwBytesWritten = 0;
|
||
|
|
||
|
WriteFile(
|
||
|
m_hLog,
|
||
|
psz,
|
||
|
dwSize + 1,
|
||
|
&dwBytesWritten,
|
||
|
NULL);
|
||
|
|
||
|
delete [] psz;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::WriteToLog] Failed to allocate %d CHARs",
|
||
|
dwSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function Description:
|
||
|
|
||
|
Create the log file in %windir%\apppatch directory. We want to make sure
|
||
|
we can create this file so we don't run the app to the end only to find
|
||
|
that we can't record the results into a file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - if log created successfully.
|
||
|
FALSE otherwise.
|
||
|
|
||
|
History:
|
||
|
|
||
|
04/04/2001 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
BOOL
|
||
|
CTrackObject::Init()
|
||
|
{
|
||
|
m_pDistinctDirs = NULL;
|
||
|
m_pDistinctFiles = NULL;
|
||
|
m_cDistinctDirs = 0;
|
||
|
m_cDistinctFiles = 0;
|
||
|
|
||
|
WCHAR szModuleName[MAX_PATH + 1] = L"";
|
||
|
LPWSTR pwszModuleNameStart = NULL;
|
||
|
LPWSTR pwszModuleNameExtStart = NULL;
|
||
|
DWORD cAppPatchLen = 0;
|
||
|
DWORD cModuleNameLen = 0;
|
||
|
DWORD cTotalLen = 0;
|
||
|
DWORD dwRes = 0;
|
||
|
|
||
|
GetSystemRootDirW();
|
||
|
|
||
|
//
|
||
|
// GetModuleFileNameW is an awful API. If you don't pass in a buffer
|
||
|
// that's big enough to hold the module (including the terminating NULL), it
|
||
|
// returns the passed in buffer size (NOT the required length) which means
|
||
|
// it doesn't return an error - it just fills upto the passed in buffer size
|
||
|
// so does NOT NULL terminate the string. So we set the last char to NULL and
|
||
|
// make sure it doesn't get overwritten.
|
||
|
//
|
||
|
szModuleName[MAX_PATH] = L'\0';
|
||
|
|
||
|
dwRes = GetModuleFileNameW(NULL, szModuleName, MAX_PATH + 1);
|
||
|
|
||
|
if (!dwRes || szModuleName[MAX_PATH] != L'\0')
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::Init] Error getting the module name: %d",
|
||
|
GetLastError());
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pwszModuleNameStart = wcsrchr(szModuleName, L'\\');
|
||
|
|
||
|
if (!pwszModuleNameStart)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::Init] We can't find where the file name starts??? %S",
|
||
|
szModuleName);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
++pwszModuleNameStart;
|
||
|
cModuleNameLen = wcslen(pwszModuleNameStart);
|
||
|
|
||
|
//
|
||
|
// We don't need the path anymore.
|
||
|
//
|
||
|
memmove(szModuleName, pwszModuleNameStart, cModuleNameLen * sizeof(WCHAR));
|
||
|
szModuleName[cModuleNameLen] = L'\0';
|
||
|
|
||
|
//
|
||
|
// Get rid of the extension.
|
||
|
//
|
||
|
pwszModuleNameExtStart = wcsrchr(szModuleName, L'.');
|
||
|
|
||
|
//
|
||
|
// If there's no extension we just use the whole file name.
|
||
|
//
|
||
|
if (pwszModuleNameExtStart)
|
||
|
{
|
||
|
*pwszModuleNameExtStart = L'\0';
|
||
|
}
|
||
|
|
||
|
cModuleNameLen = wcslen(szModuleName);
|
||
|
|
||
|
//
|
||
|
// Make sure we don't have a buffer overflow.
|
||
|
//
|
||
|
cTotalLen =
|
||
|
g_cSystemRoot + APPPATCH_DIR_LEN + // %windir%\AppPatch\ dir
|
||
|
cModuleNameLen + // module name without extension
|
||
|
TRACK_LOG_SUFFIX_LEN + // .LUA.log suffix
|
||
|
1; // terminating NULL
|
||
|
|
||
|
if (cTotalLen > MAX_PATH)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::Init] The file name is %d chars - "
|
||
|
"we don't handle names longer than MAX_PATH",
|
||
|
cTotalLen);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Construct the file name.
|
||
|
//
|
||
|
wcsncpy(m_wszLog, g_wszSystemRoot, g_cSystemRoot);
|
||
|
wcsncpy(m_wszLog + g_cSystemRoot, APPPATCH_DIR, APPPATCH_DIR_LEN);
|
||
|
wcsncpy(m_wszLog + (g_cSystemRoot + APPPATCH_DIR_LEN), szModuleName, cModuleNameLen);
|
||
|
wcsncpy(m_wszLog + (g_cSystemRoot + APPPATCH_DIR_LEN + cModuleNameLen), TRACK_LOG_SUFFIX, TRACK_LOG_SUFFIX_LEN);
|
||
|
m_wszLog[cTotalLen - 1] = L'\0';
|
||
|
|
||
|
//
|
||
|
// Delete the file first if it exists.
|
||
|
//
|
||
|
DeleteFileW(m_wszLog);
|
||
|
|
||
|
if ((m_hLog = CreateFileW(
|
||
|
m_wszLog,
|
||
|
GENERIC_READ | GENERIC_WRITE,
|
||
|
FILE_SHARE_READ,
|
||
|
NULL,
|
||
|
CREATE_ALWAYS,
|
||
|
0,
|
||
|
NULL)) == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::Init] Error creating log %S: %d", m_wszLog, GetLastError());
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo, "[CTrackObject::Init] Created the log %S", m_wszLog);
|
||
|
CloseHandle(m_hLog);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function Description:
|
||
|
|
||
|
Free the linked list.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
History:
|
||
|
|
||
|
04/04/2001 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
CTrackObject::Free()
|
||
|
{
|
||
|
DISTINCT_OBJ* pDir = m_pDistinctDirs;
|
||
|
DISTINCT_OBJ* pTempDir;
|
||
|
|
||
|
while (pDir)
|
||
|
{
|
||
|
pTempDir = pDir;
|
||
|
pDir = pDir->next;
|
||
|
|
||
|
delete [] pTempDir->pwszName;
|
||
|
delete pTempDir;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function Description:
|
||
|
|
||
|
Write the list of directories to the log.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
History:
|
||
|
|
||
|
04/04/2001 maonis Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
CTrackObject::Record()
|
||
|
{
|
||
|
if ((m_hLog = CreateFileW(
|
||
|
m_wszLog,
|
||
|
GENERIC_READ | GENERIC_WRITE,
|
||
|
FILE_SHARE_READ,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
0,
|
||
|
NULL)) != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
// Empty the old log.
|
||
|
SetFilePointer(m_hLog, 0, 0, FILE_BEGIN);
|
||
|
SetEndOfFile(m_hLog);
|
||
|
|
||
|
WCHAR wszHeader[32];
|
||
|
if (_snwprintf(wszHeader, 31, L"D%d", m_cDistinctDirs) < 0)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::Record] Too many dirs??? %d",
|
||
|
m_cDistinctDirs);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
wszHeader[31] = L'\0';
|
||
|
WriteToLog(wszHeader);
|
||
|
|
||
|
//
|
||
|
// Dump the directories to the log - each dir is on its own line.
|
||
|
//
|
||
|
DISTINCT_OBJ* pDir = m_pDistinctDirs;
|
||
|
|
||
|
while (pDir)
|
||
|
{
|
||
|
WriteToLog(pDir->pwszName);
|
||
|
pDir = pDir->next;
|
||
|
}
|
||
|
|
||
|
if (_snwprintf(wszHeader, 31, L"F%d", m_cDistinctFiles) < 0)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelError,
|
||
|
"[CTrackObject::Record] Too many files??? %d",
|
||
|
m_cDistinctFiles);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
wszHeader[31] = L'\0';
|
||
|
WriteToLog(wszHeader);
|
||
|
|
||
|
//
|
||
|
// Dump the files to the log - each file is on its own line.
|
||
|
//
|
||
|
DISTINCT_OBJ* pFile = m_pDistinctFiles;
|
||
|
|
||
|
while (pFile)
|
||
|
{
|
||
|
WriteToLog(pFile->pwszName);
|
||
|
pFile = pFile->next;
|
||
|
}
|
||
|
|
||
|
CloseHandle(m_hLog);
|
||
|
}
|
||
|
|
||
|
// Make the file hidden so people don't accidently mess it up.
|
||
|
DWORD dwAttrib = GetFileAttributes(m_wszLog);
|
||
|
SetFileAttributes(m_wszLog, dwAttrib | FILE_ATTRIBUTE_HIDDEN);
|
||
|
}
|
||
|
|
||
|
CTrackObject g_td;
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Custom exception handler.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
LONG
|
||
|
ExceptionFilter(
|
||
|
struct _EXCEPTION_POINTERS *ExceptionInfo
|
||
|
)
|
||
|
{
|
||
|
// Whenever we get an unhandled exception, we dump the stuff to the log.
|
||
|
g_td.Record();
|
||
|
|
||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Exported APIs.
|
||
|
//
|
||
|
|
||
|
HANDLE
|
||
|
LuatCreateFileW(
|
||
|
LPCWSTR lpFileName,
|
||
|
DWORD dwDesiredAccess,
|
||
|
DWORD dwShareMode,
|
||
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||
|
DWORD dwCreationDisposition,
|
||
|
DWORD dwFlagsAndAttributes,
|
||
|
HANDLE hTemplateFile
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[CreateFileW] lpFileName=%S; dwDesiredAccess=0x%08x; dwCreationDisposition=%d",
|
||
|
lpFileName, dwDesiredAccess, dwCreationDisposition);
|
||
|
|
||
|
HANDLE hFile = CreateFileW(
|
||
|
lpFileName,
|
||
|
dwDesiredAccess,
|
||
|
dwShareMode,
|
||
|
lpSecurityAttributes,
|
||
|
dwCreationDisposition,
|
||
|
dwFlagsAndAttributes,
|
||
|
hTemplateFile);
|
||
|
|
||
|
if (hFile != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
|
||
|
if (RequestWriteAccess(dwCreationDisposition, dwDesiredAccess))
|
||
|
{
|
||
|
g_td.AddObject(lpFileName, FALSE);
|
||
|
}
|
||
|
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return hFile;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatCopyFileW(
|
||
|
LPCWSTR lpExistingFileName,
|
||
|
LPCWSTR lpNewFileName,
|
||
|
BOOL bFailIfExists
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[CopyFileW] lpExistingFileName=%S; lpNewFileName=%S; bFailIfExists=%d",
|
||
|
lpExistingFileName, lpNewFileName, bFailIfExists);
|
||
|
|
||
|
BOOL bRet = CopyFileW(lpExistingFileName, lpNewFileName, bFailIfExists);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
g_td.AddObject(lpNewFileName, FALSE);
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatCreateDirectoryW(
|
||
|
LPCWSTR lpPathName,
|
||
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[CreateDirectoryW] lpPathName=%S", lpPathName);
|
||
|
|
||
|
BOOL bRet = CreateDirectoryW(lpPathName, lpSecurityAttributes);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
g_td.AddObject(lpPathName, TRUE);
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatSetFileAttributesW(
|
||
|
LPCWSTR lpFileName,
|
||
|
DWORD dwFileAttributes
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[SetFileAttributesW] lpFileName=%S", lpFileName);
|
||
|
|
||
|
BOOL bRet = SetFileAttributesW(lpFileName, dwFileAttributes);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
|
||
|
DWORD dwAttrib = GetFileAttributesW(lpFileName);
|
||
|
if (dwAttrib != -1)
|
||
|
{
|
||
|
g_td.AddObject(lpFileName, dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
|
||
|
}
|
||
|
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatDeleteFileW(
|
||
|
LPCWSTR lpFileName
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[DeleteFileW] lpFileName=%S", lpFileName);
|
||
|
|
||
|
LPWSTR pwszTempFile = LuatpGetLongObjectName(lpFileName, FALSE);
|
||
|
|
||
|
BOOL bRet = DeleteFileW(lpFileName);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
g_td.AddObjectDirect(pwszTempFile, FALSE);
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
delete [] pwszTempFile;
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatMoveFileW(
|
||
|
LPCWSTR lpExistingFileName,
|
||
|
LPCWSTR lpNewFileName
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[MoveFileW] lpExistingFileName=%S; lpNewFileName=%S", lpExistingFileName, lpNewFileName);
|
||
|
|
||
|
LPWSTR pwszTempFile = LuatpGetLongObjectName(lpExistingFileName, FALSE);
|
||
|
|
||
|
BOOL bRet = MoveFileW(lpExistingFileName, lpNewFileName);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
g_td.AddObjectDirect(pwszTempFile, FALSE);
|
||
|
g_td.AddObject(lpNewFileName, FALSE);
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
delete [] pwszTempFile;
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatRemoveDirectoryW(
|
||
|
LPCWSTR lpPathName
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[RemoveDirectoryW] lpPathName=%S", lpPathName);
|
||
|
|
||
|
LPWSTR pwszTempDir = LuatpGetLongObjectName(lpPathName, TRUE);
|
||
|
|
||
|
BOOL bRet = RemoveDirectoryW(lpPathName);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
g_td.AddObjectDirect(pwszTempDir, TRUE);
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
delete [] pwszTempDir;
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
UINT
|
||
|
LuatGetTempFileNameW(
|
||
|
LPCWSTR lpPathName,
|
||
|
LPCWSTR lpPrefixString,
|
||
|
UINT uUnique,
|
||
|
LPWSTR lpTempFileName
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[GetTempFileNameW] lpPathName=%S", lpPathName);
|
||
|
|
||
|
UINT uiRet = GetTempFileNameW(lpPathName, lpPrefixString, uUnique, lpTempFileName);
|
||
|
|
||
|
if (uiRet && !uUnique)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
g_td.AddObject(lpTempFileName, FALSE);
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return uiRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatWritePrivateProfileStringW(
|
||
|
LPCWSTR lpAppName,
|
||
|
LPCWSTR lpKeyName,
|
||
|
LPCWSTR lpString,
|
||
|
LPCWSTR lpFileName
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[WritePrivateProfileStringW] lpAppName=%S; lpKeyName=%S; lpString=%S; lpFileName=%S",
|
||
|
lpAppName, lpKeyName, lpString, lpFileName);
|
||
|
|
||
|
BOOL bRet = WritePrivateProfileStringW(
|
||
|
lpAppName,
|
||
|
lpKeyName,
|
||
|
lpString,
|
||
|
lpFileName);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
|
||
|
WCHAR wszFileName[MAX_PATH] = L"";
|
||
|
MakeFileNameForProfileAPIsW(lpFileName, wszFileName);
|
||
|
g_td.AddObject(wszFileName, FALSE);
|
||
|
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatWritePrivateProfileSectionW(
|
||
|
LPCWSTR lpAppName,
|
||
|
LPCWSTR lpString,
|
||
|
LPCWSTR lpFileName
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[WritePrivateProfileSectionW] lpAppName=%S; lpString=%S; lpFileName=%S",
|
||
|
lpAppName, lpString, lpFileName);
|
||
|
|
||
|
BOOL bRet = WritePrivateProfileSectionW(
|
||
|
lpAppName,
|
||
|
lpString,
|
||
|
lpFileName);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
|
||
|
WCHAR wszFileName[MAX_PATH] = L"";
|
||
|
MakeFileNameForProfileAPIsW(lpFileName, wszFileName);
|
||
|
|
||
|
g_td.AddObject(wszFileName, FALSE);
|
||
|
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatWritePrivateProfileStructW(
|
||
|
LPCWSTR lpszSection,
|
||
|
LPCWSTR lpszKey,
|
||
|
LPVOID lpStruct,
|
||
|
UINT uSizeStruct,
|
||
|
LPCWSTR szFile
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[WritePrivateProfileStructW] lpszKey=%S; szFile=%S",
|
||
|
lpszKey, szFile);
|
||
|
|
||
|
BOOL bRet = WritePrivateProfileStructW(
|
||
|
lpszSection,
|
||
|
lpszKey,
|
||
|
lpStruct,
|
||
|
uSizeStruct,
|
||
|
szFile);
|
||
|
|
||
|
if (bRet)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
|
||
|
WCHAR wszFileName[MAX_PATH] = L"";
|
||
|
MakeFileNameForProfileAPIsW(szFile, wszFileName);
|
||
|
|
||
|
g_td.AddObject(wszFileName, FALSE);
|
||
|
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
HFILE
|
||
|
LuatOpenFile(
|
||
|
LPCSTR lpFileName,
|
||
|
LPOFSTRUCT lpReOpenBuff,
|
||
|
UINT uStyle
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[OpenFile] lpFileName=%s", lpFileName);
|
||
|
|
||
|
STRINGA2W wstrFileName(lpFileName);
|
||
|
LPWSTR pwszTempFile = LuatpGetLongObjectName(wstrFileName, FALSE);
|
||
|
|
||
|
HFILE hFile = OpenFile(lpFileName, lpReOpenBuff, uStyle);
|
||
|
|
||
|
if (hFile != HFILE_ERROR)
|
||
|
{
|
||
|
if (uStyle & OF_CREATE ||
|
||
|
uStyle & OF_DELETE ||
|
||
|
uStyle & OF_READWRITE ||
|
||
|
uStyle & OF_WRITE)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
|
||
|
g_td.AddObjectDirect(pwszTempFile, FALSE);
|
||
|
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete [] pwszTempFile;
|
||
|
|
||
|
return hFile;
|
||
|
}
|
||
|
|
||
|
HFILE
|
||
|
Luat_lopen(
|
||
|
LPCSTR lpPathName,
|
||
|
int iReadWrite
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[_lopen] lpPathName=%s", lpPathName);
|
||
|
|
||
|
HFILE hFile = _lopen(lpPathName, iReadWrite);
|
||
|
|
||
|
if (hFile != HFILE_ERROR)
|
||
|
{
|
||
|
if (iReadWrite & OF_READWRITE || iReadWrite & OF_WRITE)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
|
||
|
STRINGA2W wstrPathName(lpPathName);
|
||
|
g_td.AddObject(wstrPathName, FALSE);
|
||
|
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return hFile;
|
||
|
}
|
||
|
|
||
|
HFILE
|
||
|
Luat_lcreat(
|
||
|
LPCSTR lpPathName,
|
||
|
int iAttribute
|
||
|
)
|
||
|
{
|
||
|
DPF("TrackFS", eDbgLevelInfo,
|
||
|
"[_lcreat] lpPathName=%s", lpPathName);
|
||
|
|
||
|
HFILE hFile = _lcreat(lpPathName, iAttribute);
|
||
|
|
||
|
if (hFile != HFILE_ERROR)
|
||
|
{
|
||
|
LUA_GET_API_ERROR;
|
||
|
|
||
|
STRINGA2W wstrPathName(lpPathName);
|
||
|
g_td.AddObject(wstrPathName, FALSE);
|
||
|
|
||
|
LUA_SET_API_ERROR;
|
||
|
}
|
||
|
|
||
|
return hFile;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
LuatFSInit()
|
||
|
{
|
||
|
SetUnhandledExceptionFilter(ExceptionFilter);
|
||
|
|
||
|
return g_td.Init();
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
LuatFSCleanup()
|
||
|
{
|
||
|
g_td.Record();
|
||
|
g_td.Free();
|
||
|
}
|