You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1545 lines
47 KiB
1545 lines
47 KiB
/*++
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name: filemgr.cxx
|
|
|
|
Abstract:
|
|
|
|
Manages cache file & directory creation/deletion.
|
|
|
|
Author:
|
|
Adriaan Canter (adriaanc) 04-02-97
|
|
|
|
Modifications:
|
|
Ahsan Kabir (akabir) 25-Sept-97 made minor alterations.
|
|
|
|
--*/
|
|
|
|
#include <wininetp.h>
|
|
#include <cache.hxx>
|
|
#define WWW_DOT "www."
|
|
|
|
#define MAP_KEY_TO_PATH 0
|
|
#define MAP_PATH_TO_KEY 1
|
|
|
|
|
|
//
|
|
//==================== CFileMgr Public Functions =============================
|
|
//
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CFileMgr::CFileMgr
|
|
----------------------------------------------------------------------------*/
|
|
CFileMgr::CFileMgr(MEMMAP_FILE* mmFile, DWORD dwOptions) : _mmFile(mmFile), _dwOptions(dwOptions)
|
|
{
|
|
INET_ASSERT(_mmFile);
|
|
|
|
// GetFullPathNameLen includes trailing backslash.
|
|
_cbBasePathLen = _mmFile->GetFullPathNameLen();
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CFileMgr::~CFileMgr
|
|
----------------------------------------------------------------------------*/
|
|
CFileMgr::~CFileMgr()
|
|
{}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
virtual CFileMgr::Init
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::Init()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
virtual GetDirLen
|
|
Returns length of cache dir path.
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CFileMgr::GetDirLen(DWORD nKey)
|
|
{
|
|
return _cbBasePathLen;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
virtual CFileMgr::CreateUniqueFile
|
|
Generates cache files.
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CFileMgr::CreateUniqueFile(LPCSTR szUrl, DWORD dwExpectedLength, LPTSTR szFileName,
|
|
LPTSTR szFileExtension, HANDLE *phfHandle, BOOL fCreatePerUser)
|
|
{
|
|
return CreateUniqueFile((LPCSTR) szUrl, (DWORD) dwExpectedLength, (LPTSTR) _mmFile->GetFullPathName(),
|
|
(LPTSTR) szFileName, (LPTSTR) szFileExtension, (HANDLE*) phfHandle, fCreatePerUser);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
virtual CFileMgr::NotifyCommit
|
|
No-op.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::NotifyCommit(DWORD nDirIndex)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CFileMgr::DeleteCache
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::DeleteCache(LPSTR szRoot)
|
|
{
|
|
BOOL fHasCacheVu = IsValidCacheSubDir(szRoot);
|
|
|
|
if ( fHasCacheVu)
|
|
DisableCacheVu(szRoot);
|
|
|
|
if (DeleteCachedFilesInDir(szRoot) == ERROR_SUCCESS)
|
|
{
|
|
SetFileAttributes(szRoot, FILE_ATTRIBUTE_DIRECTORY);
|
|
RemoveDirectory(szRoot);
|
|
}
|
|
|
|
if( fHasCacheVu)
|
|
EnableCacheVu( szRoot);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CFileMgr::Cleanup
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::Cleanup()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
virtual CFileMgr::GetDirIndex
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::GetDirIndex(LPSTR szFilePath, LPDWORD pnIndex)
|
|
{
|
|
*pnIndex = NOT_A_CACHE_SUBDIRECTORY;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
virtual CFileMgr::GetFilePathFromEntry
|
|
|
|
Retrieves the full path to the cache subdirectory for a cache entry.
|
|
Maps the directory index from the URL_FILEMAP_ENTRY pointer passed in
|
|
to a string containing the full path.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::GetFilePathFromEntry(URL_FILEMAP_ENTRY *pEntry,
|
|
LPSTR szSubDirPath, LPDWORD pcb)
|
|
{
|
|
INET_ASSERT(pEntry && szSubDirPath && pcb && *pcb);
|
|
|
|
// "[email protected]"
|
|
LPTSTR szFile = (LPTSTR) OFFSET_TO_POINTER(pEntry, pEntry->InternalFileNameOffset);
|
|
|
|
// Lengths of path and file.
|
|
DWORD cbFile = strlen(szFile);
|
|
DWORD cbPath = _mmFile->GetFullPathNameLen();
|
|
|
|
// Don't overflow output buffer.
|
|
DWORD cbSubDirPath = cbPath + cbFile;
|
|
if (cbSubDirPath + 1 > *pcb)
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
// "C:\Windows\Profiles\anyuser\Cookies\"
|
|
memcpy(szSubDirPath, _mmFile->GetFullPathName(), cbPath);
|
|
|
|
// "C:\Windows\Profiles\anyuser\Cookies\[email protected]"
|
|
memcpy(szSubDirPath + cbPath, szFile, cbFile + 1);
|
|
|
|
*pcb = cbSubDirPath;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
virtual CFileMgr::DeleteOneCachedFile
|
|
Deletes a single cache file given the absolute path.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::DeleteOneCachedFile(LPSTR lpszFileName,
|
|
DWORD dostEntry, DWORD nIndex)
|
|
{
|
|
return ::DeleteOneCachedFile(lpszFileName, dostEntry);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
virtual BOOL CreateDirWithSecureName( LPSTR);
|
|
|
|
Creates a cache directory with a given name to allow existing directories
|
|
to be copied into another cache file. Just the eight letters of the new
|
|
directory are given.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::CreateDirWithSecureName( LPSTR szDirName)
|
|
{
|
|
return _mmFile->CreateDirWithSecureName( szDirName);
|
|
}
|
|
|
|
|
|
//
|
|
//================== CFileMgr Protected Functions =============================
|
|
//
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CFileMgr::GetStoreDirectory
|
|
Returns "%windir%\web\" - ie "C:\Windows\Web\" and length. There
|
|
is currently only ONE store directory and this is it.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::GetStoreDirectory(LPSTR szPath, LPDWORD pcbPath)
|
|
{
|
|
DWORD cb;
|
|
|
|
// Hardwired to "%windir%\Web\"
|
|
if ((cb = GetWindowsDirectory(szPath, MAX_PATH)) && cb<=MAX_PATH)
|
|
{
|
|
AppendSlashIfNecessary(szPath, &cb);
|
|
memcpy(szPath + cb, WEBDIR_STRING, sizeof(WEBDIR_STRING));
|
|
cb += sizeof(WEBDIR_STRING) - 1;
|
|
*pcbPath = cb;
|
|
return TRUE;
|
|
}
|
|
INET_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CFileMgr::MapStoreKey
|
|
Maps path to storage directory key (stored in the FILEMAP_ENTRY::DirIndex)
|
|
or storage directory key to path (ie C:\Windows\Web\). There is currently
|
|
only one key and it is INSTALLED_DIRECTORY_KEY. Mapping depends on dwFlag.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CFileMgr::MapStoreKey(LPSTR szPath, LPDWORD pcbPath,
|
|
LPDWORD dwKey, DWORD dwFlag)
|
|
{
|
|
DWORD cb;
|
|
BOOL fReturn = FALSE;
|
|
CHAR szStoreDir[MAX_PATH];
|
|
|
|
// Must be able to get store dir in any case.
|
|
if (GetStoreDirectory(szStoreDir, &cb))
|
|
{
|
|
// Mapping a path to a key requested.
|
|
if (dwFlag == MAP_PATH_TO_KEY)
|
|
{
|
|
// Path matches?
|
|
if ((*pcbPath == cb)
|
|
&& !strnicmp(szStoreDir, szPath, cb))
|
|
{
|
|
// We only map one directory for now.
|
|
*dwKey = INSTALLED_DIRECTORY_KEY;
|
|
fReturn = TRUE;
|
|
}
|
|
}
|
|
|
|
// Mapping a key to a path requested.
|
|
else if (dwFlag == MAP_KEY_TO_PATH)
|
|
{
|
|
if (*dwKey == INSTALLED_DIRECTORY_KEY)
|
|
{
|
|
memcpy(szPath, szStoreDir, cb+1);
|
|
*pcbPath = cb;
|
|
fReturn = TRUE;
|
|
}
|
|
}
|
|
}
|
|
//INET_ASSERT(fReturn);
|
|
return fReturn;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
SetFileSize
|
|
|
|
Routine Description: Set the expected file size of a newly created file
|
|
|
|
Arguments:
|
|
|
|
hfHandle: pointer to the file handle
|
|
|
|
dwExpectedLength: size of the file
|
|
|
|
Return Value:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
VOID CFileMgr::SetFileSize(HANDLE hfHandle, DWORD dwExpectedLength)
|
|
{
|
|
DWORD dwFilePointer = 0;
|
|
|
|
// Set the expected size of the file if necessary
|
|
if (dwExpectedLength != 0)
|
|
{
|
|
dwFilePointer = SetFilePointer(hfHandle, dwExpectedLength, NULL, FILE_BEGIN );
|
|
if( dwFilePointer != INVALID_SET_FILE_POINTER )
|
|
{
|
|
SetEndOfFile( hfHandle );
|
|
|
|
// reset the file pointer to the beginning of the file
|
|
dwFilePointer = SetFilePointer(hfHandle, 0, NULL, FILE_BEGIN );
|
|
INET_ASSERT (INVALID_SET_FILE_POINTER != dwFilePointer);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CreateUniqueFile
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
UrlName : pointer to url name.
|
|
|
|
Path : pointer to cache path.
|
|
|
|
FileName : pointer to a buffer that receives the full path name of the
|
|
newly created file.
|
|
|
|
Extension : if specified the extension is used to make random file.
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CFileMgr::CreateUniqueFile(LPCSTR UrlName, DWORD ExpectedLength,
|
|
LPTSTR Path, LPTSTR FileName, LPTSTR Extension,
|
|
HANDLE *phfHandle, BOOL fCreatePerUser)
|
|
{
|
|
DWORD cbPath, cbName, cbFull;
|
|
cbPath = strlen(Path);
|
|
|
|
DWORD Error, len, lenExt=0;
|
|
|
|
TCHAR RandomFileName[MAX_PATH];
|
|
|
|
TCHAR FullFileName[MAX_PATH];
|
|
|
|
HANDLE FileHandle;
|
|
|
|
DWORD dwCollision = 0, dwTotalCollissionCount;
|
|
char szHost[MAX_PATH], szUrl[INTERNET_MAX_PATH_LENGTH], szExtraInfo[MAX_PATH];
|
|
URL_COMPONENTS sUrl;
|
|
|
|
LPTSTR FileNamePtr = FileName, lpT;
|
|
|
|
BOOL fUseFileName = FALSE, fPrettyName = FALSE;
|
|
|
|
DWORD cbFileName;
|
|
CHAR szExt[MAX_PATH];
|
|
*szExt = '\0';
|
|
|
|
if (phfHandle)
|
|
*phfHandle = INVALID_HANDLE_VALUE;
|
|
|
|
// If a filename has been passed in attempt to use it.
|
|
if (FileName[0] != '\0')
|
|
{
|
|
// Various checks to determine validity of name.
|
|
|
|
// First strip any trailing whitespace.
|
|
cbFileName = strlen(FileName);
|
|
StripTrailingWhiteSpace(FileName, &cbFileName);
|
|
|
|
// Check length.
|
|
if (cbFileName < MAX_PATH)
|
|
{
|
|
|
|
// '.' and '..' are illegal.
|
|
if (memcmp(FileName, ".", sizeof("."))
|
|
&& memcmp(FileName, "..", sizeof("..")))
|
|
{
|
|
// slashes and backslashes are illegal.
|
|
LPTSTR ptr = FileName;
|
|
while (*ptr != '\0')
|
|
{
|
|
if (IsDBCSLeadByte(*ptr))
|
|
++ptr;
|
|
else
|
|
if (*ptr == '\\' || *ptr == '/')
|
|
break;
|
|
ptr++;
|
|
}
|
|
|
|
|
|
// Filename has no slashes in it.
|
|
if (!*ptr)
|
|
{
|
|
// Preliminary judgment. Creating
|
|
// this file could possibly fail,
|
|
// depending on further tests.
|
|
fUseFileName = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Preliminary checks indicate valid filename.
|
|
if (fUseFileName)
|
|
{
|
|
// Attempt to parse a file extension.
|
|
|
|
CHAR* pExt = StrChr(FileName, '.');
|
|
|
|
// Found a file extension delimiter.
|
|
if (pExt)
|
|
{
|
|
// '.' but no extension (eg "foo.")
|
|
if (*(pExt + 1) == '\0')
|
|
{
|
|
*pExt = '\0';
|
|
len = cbFileName - 1;
|
|
}
|
|
|
|
// '.' at beginning (eg ".foo") Valid file, no extension.
|
|
else if (pExt == FileName)
|
|
{
|
|
len = cbFileName;
|
|
}
|
|
|
|
// Common case (eg foo.bar)
|
|
else
|
|
{
|
|
// Separate out the file extension w/o '.'
|
|
lenExt = (DWORD) (cbFileName - (pExt - FileName) - 1); // 64BIT
|
|
memcpy(szExt, pExt+1, lenExt + 1);
|
|
|
|
// Filename without extension.
|
|
*pExt = '\0';
|
|
len = (DWORD) (pExt - FileName); // 64BIT
|
|
}
|
|
}
|
|
|
|
// No file extension found
|
|
else
|
|
{
|
|
len = cbFileName;
|
|
}
|
|
fPrettyName = TRUE;
|
|
goto have_file_name;
|
|
}
|
|
|
|
// No or bad filename passed in.
|
|
else
|
|
{
|
|
// Copy over any extension passed in,
|
|
// limiting the length as necessary.
|
|
if (Extension)
|
|
{
|
|
lenExt = strlen(Extension);
|
|
if (lenExt >= MAX_PATH)
|
|
{
|
|
lenExt = MAX_PATH - 1;
|
|
}
|
|
memcpy(szExt, Extension, lenExt);
|
|
szExt[lenExt] = '\0';
|
|
}
|
|
else
|
|
{
|
|
*szExt = '\0';
|
|
lenExt = 3;
|
|
}
|
|
}
|
|
|
|
memset(&sUrl, 0, sizeof(sUrl));
|
|
|
|
sUrl.dwStructSize = sizeof(sUrl);
|
|
|
|
sUrl.lpszHostName = szHost;
|
|
sUrl.dwHostNameLength = sizeof(szHost);
|
|
|
|
sUrl.lpszUrlPath = szUrl;
|
|
sUrl.dwUrlPathLength = sizeof(szUrl);
|
|
|
|
|
|
sUrl.lpszExtraInfo = szExtraInfo;
|
|
sUrl.dwExtraInfoLength = sizeof(szExtraInfo);
|
|
|
|
// changed from InternetCrackUrl to WinHttpCrackUrlA
|
|
if (WinHttpCrackUrlA(UrlName, lstrlen(UrlName), 0, &sUrl)) {
|
|
fPrettyName = TRUE;
|
|
|
|
if ((sUrl.dwUrlPathLength == 1) && (szUrl[0] == '/')) {
|
|
|
|
FileNamePtr = szHost;
|
|
len = sUrl.dwHostNameLength;
|
|
|
|
// strip out www., this info is redundant
|
|
|
|
if (!strnicmp(FileNamePtr, WWW_DOT, sizeof(WWW_DOT)-1)) {
|
|
|
|
len -= (sizeof(WWW_DOT)-1);
|
|
|
|
// copy the NULL terminator too
|
|
|
|
memmove(FileNamePtr, FileNamePtr+sizeof(WWW_DOT)-1,len+1);
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
FileNamePtr = szUrl;
|
|
len = sUrl.dwUrlPathLength;
|
|
|
|
// if there is a terminating slash let us fix it.
|
|
// len-1 wont' break because we know the url is more than 1 char
|
|
// Above assumption not valid.
|
|
if (len && (FileNamePtr[len-1] == '/'))
|
|
{
|
|
FileNamePtr[len-1] = 0;
|
|
--len;
|
|
}
|
|
|
|
// get the tail
|
|
if (lpT=StrRChrA(FileNamePtr, FileNamePtr+len-1, '/'))
|
|
{
|
|
++lpT;
|
|
|
|
len = len - (DWORD)PtrDifference(lpT, FileNamePtr);
|
|
|
|
//
|
|
// truncate the FileNamePtr if it is too long -
|
|
// the "fudge-factor" number is to allow room for stuff like "[%d]"
|
|
// in the URL -- this number doesn't have to be accurate since
|
|
// the worst-case scenario is us using a random (ugly) filename.
|
|
//
|
|
unsigned int newlen = MAX_PATH - (cbPath + lenExt + 2 + /*fudge-factor*/5);
|
|
|
|
if ((newlen > 2) && (newlen < len))
|
|
{
|
|
// For UTF-8, we don't want to chop in the middle of a %XX
|
|
if (lpT[newlen - 2] == '%')
|
|
newlen -= 2;
|
|
else if (lpT[newlen - 1] == '%')
|
|
newlen -= 1;
|
|
|
|
len = newlen;
|
|
lpT[len] = '\0';
|
|
}
|
|
|
|
// copy the NULL terminator as well
|
|
memmove(FileNamePtr, lpT, len+1);
|
|
}
|
|
|
|
// Special hack for cookies: Ensure that the username is
|
|
// prepended on to the filename. The preceding filename
|
|
// generation code does not generate this for cookies
|
|
// which specify paths in addition to domains.
|
|
if (!memcmp(UrlName, COOKIE_PREFIX, sizeof(COOKIE_PREFIX) - 1))
|
|
{
|
|
// This is a cookie url of the form Cookie:username@domain/path
|
|
if (GetWininetUserName())
|
|
{
|
|
DWORD cb = vdwCurrentUserLen;
|
|
if (len + cb + 1 < MAX_PATH)
|
|
{
|
|
if (memcmp(FileNamePtr, vszCurrentUser, cb)
|
|
|| FileNamePtr[cb] != '@'
|
|
|| FileNamePtr[cb+1] == '\0')
|
|
{
|
|
memmove(FileNamePtr + cb + 1, FileNamePtr, len+1);
|
|
FileNamePtr[cb] = '@';
|
|
memcpy(FileNamePtr, vszCurrentUser, cb);
|
|
len += cb + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (lpT=StrRChrA(FileNamePtr, FileNamePtr+len-1, '.'))
|
|
{
|
|
*lpT = 0;
|
|
len = (DWORD) PtrDifference(lpT, FileNamePtr);
|
|
}
|
|
|
|
// convert all invalid char (including '%') to '_'
|
|
for(lpT = FileNamePtr; *lpT; ++lpT)
|
|
{
|
|
if (IsDBCSLeadByte(*lpT))
|
|
++lpT;
|
|
else if ((strchr(vszInvalidFilenameChars, *lpT)))
|
|
*lpT = '_';
|
|
}
|
|
|
|
if ((cbPath+len+lenExt+2) > MAX_PATH) {
|
|
|
|
fPrettyName = FALSE;
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
fPrettyName = FALSE;
|
|
}
|
|
|
|
|
|
have_file_name:
|
|
|
|
|
|
for(dwTotalCollissionCount = 0;
|
|
dwTotalCollissionCount < MAX_COLLISSION_ATTEMPTS;
|
|
dwTotalCollissionCount++) {
|
|
|
|
|
|
//
|
|
// make a random file name.
|
|
//
|
|
if (!fPrettyName)
|
|
{
|
|
// If fUseFileName is TRUE, it means we've attempted to create
|
|
// a file using the filename passed in and failed. We still want
|
|
// to create a cache file, but since the extension parsed from the
|
|
// filename is also suspect, we want to create a cache filename
|
|
// without any passed in extension, or NULL.
|
|
if (fUseFileName)
|
|
{
|
|
if (Extension)
|
|
{
|
|
lenExt = strlen(Extension);
|
|
memcpy(szExt, Extension, lenExt+1);
|
|
}
|
|
else
|
|
{
|
|
lenExt = 0;
|
|
*szExt = '\0';
|
|
}
|
|
}
|
|
|
|
Error = MakeRandomFileName(UrlName, RandomFileName, szExt);
|
|
|
|
}
|
|
else {
|
|
|
|
DWORD digit;
|
|
DWORD cb = strlen(FileNamePtr);
|
|
memcpy(RandomFileName, FileNamePtr, cb+1);
|
|
|
|
lpT = RandomFileName+len;
|
|
|
|
// Always decorate the cache file name with [1-99]
|
|
// We use square brackets instead of parens because
|
|
// NT cmd shell barfs on parens.
|
|
|
|
if (++dwCollision > 99)
|
|
{
|
|
fPrettyName = FALSE;
|
|
continue;
|
|
}
|
|
|
|
#ifndef UNIX
|
|
if (fCreatePerUser && GlobalIdentity)
|
|
{
|
|
lpT += wsprintf (lpT, "[%d][%d]", GlobalIdentity, dwCollision);
|
|
}
|
|
else
|
|
{
|
|
lpT += wsprintf (lpT, "[%d]", dwCollision);
|
|
}
|
|
#else
|
|
/* Square brackets cause problems on UNIX */
|
|
lpT += wsprintf (lpT, "(%d)", dwCollision);
|
|
#endif /* UNIX */
|
|
|
|
if (*szExt)
|
|
{
|
|
*lpT++ = '.';
|
|
memcpy(lpT, szExt, lenExt + 1);
|
|
}
|
|
|
|
Error = ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
INET_ASSERT(FALSE);
|
|
return (Error);
|
|
|
|
}
|
|
|
|
cbName = strlen(RandomFileName);
|
|
cbFull = cbPath + cbName + 1;
|
|
|
|
if (cbFull > MAX_PATH)
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
return(ERROR_FILENAME_EXCED_RANGE);
|
|
}
|
|
#ifndef UNIX
|
|
// Hack for special DOS filenames:
|
|
// aux.*, com[0-9].*, con.*, lpt[0-9].*,
|
|
// nul.* and prn.* on non-NT platforms.
|
|
if (!IsPlatformWinNT())
|
|
{
|
|
DWORD cbMajor = cbName - lenExt;
|
|
if (cbMajor == 4 || cbMajor == 5)
|
|
{
|
|
switch(tolower(*RandomFileName))
|
|
{
|
|
// Test for aux.*
|
|
case 'a':
|
|
if (!strnicmp(RandomFileName + 1, "ux.", 3))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
// Test for com[0-9].* and con.*
|
|
case 'c':
|
|
if (tolower(RandomFileName[1]) == 'o')
|
|
{
|
|
CHAR c = tolower(RandomFileName[2]);
|
|
if (c == 'm')
|
|
{
|
|
if (isdigit(RandomFileName[3])
|
|
&& RandomFileName[4] == '.')
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (c == 'n')
|
|
{
|
|
if (RandomFileName[3] == '.')
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Test for lpt[0-9].*
|
|
case 'l':
|
|
{
|
|
if (!strnicmp(RandomFileName + 1, "pt", 2)
|
|
&& isdigit(RandomFileName[3])
|
|
&& RandomFileName[4] == '.')
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Test for nul.*
|
|
case 'n':
|
|
{
|
|
if (!strnicmp(RandomFileName + 1, "ul.", 3))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Test for prn.*
|
|
case 'p':
|
|
{
|
|
if (!strnicmp(RandomFileName + 1, "rn.", 3))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* !UNIX */
|
|
|
|
// Make full path name.
|
|
memcpy(FullFileName, Path, cbPath);
|
|
memcpy(FullFileName + cbPath, RandomFileName, cbName + 1);
|
|
|
|
// Check if this file exists.
|
|
if (GetFileAttributes(FullFileName)!=0xffffffff)
|
|
{
|
|
// A file or dir by this name exists.
|
|
// This will also take care of special DOS filenames
|
|
// on NT, which return !0xffffffff.
|
|
continue;
|
|
}
|
|
|
|
|
|
|
|
FileHandle = CreateFile(
|
|
FullFileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if( FileHandle != INVALID_HANDLE_VALUE )
|
|
{
|
|
SetFileSize(FileHandle, ExpectedLength);
|
|
|
|
// successfully create a new file either return handle or close it and return.
|
|
if ( phfHandle )
|
|
*phfHandle = FileHandle;
|
|
else
|
|
CloseHandle( FileHandle );
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Couldn't create the file. This is possibly due to the file
|
|
// already existing or to the fact that the directory was deleted.
|
|
|
|
// Check for the existance of the directory:
|
|
if (GetFileAttributes(Path) == 0xffffffff)
|
|
{
|
|
// Directory was deleted. Create one and then
|
|
// create the file.
|
|
if (CreateDirectory(Path, NULL))
|
|
{
|
|
// Set system attribute.
|
|
SetFileAttributes(Path, FILE_ATTRIBUTE_SYSTEM);
|
|
|
|
// Enable cachevu in this directory
|
|
if (!(GetOptions() & INTERNET_CACHE_CONTAINER_NODESKTOPINIT))
|
|
EnableCacheVu(Path);
|
|
|
|
FileHandle = CreateFile(
|
|
FullFileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
// We just created the directory and the
|
|
// child file, so the file handle should
|
|
// be valid.
|
|
if( FileHandle != INVALID_HANDLE_VALUE )
|
|
{
|
|
SetFileSize(FileHandle, ExpectedLength);
|
|
|
|
// successfully create a new file either return handle or close it and return.
|
|
if ( phfHandle )
|
|
*phfHandle = FileHandle;
|
|
else
|
|
CloseHandle( FileHandle );
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Error = GetLastError();
|
|
|
|
if( Error != ERROR_FILE_EXISTS )
|
|
{
|
|
if (!fPrettyName)
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
return( Error );
|
|
}
|
|
else
|
|
{
|
|
fPrettyName = FALSE;
|
|
Error = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else {
|
|
|
|
// We found that the file exists
|
|
// if it is zero size, let us just use it.
|
|
// this in itself is an unlikely occurrence
|
|
// but we any way try to work around the IBM virus software
|
|
|
|
// ACHTUNG!!! this is a special hack for IBM antivirus software
|
|
|
|
FileHandle = CreateFile(
|
|
FullFileName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL );
|
|
|
|
if (FileHandle != INVALID_HANDLE_VALUE) {
|
|
|
|
// this looks usable
|
|
if (GetFileSize(FileHandle, NULL) == 0)
|
|
{
|
|
if (phfHandle)
|
|
*phfHandle = FileHandle;
|
|
else
|
|
CloseHandle( FileHandle );
|
|
break;
|
|
}
|
|
|
|
CloseHandle( FileHandle );
|
|
INET_ASSERT(FALSE);
|
|
}
|
|
return (ERROR_DISK_FULL);
|
|
}
|
|
|
|
//
|
|
// try another random file.
|
|
//
|
|
} // end of the for loop
|
|
|
|
if (dwTotalCollissionCount < MAX_COLLISSION_ATTEMPTS) {
|
|
|
|
memcpy(FileName, FullFileName, cbFull);
|
|
return( ERROR_SUCCESS );
|
|
|
|
}
|
|
else {
|
|
INET_ASSERT(FALSE);
|
|
return (ERROR_DISK_OPERATION_FAILED);
|
|
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
MakeRandomFileName
|
|
|
|
Routine Description:
|
|
|
|
Creates a random 8.3 file name. The format of the name will be as
|
|
below:
|
|
|
|
ca(0-99999).(0-999)
|
|
|
|
Ex ca19200.340
|
|
Ex ca19354.tmp - if an extension (tmp) is specified.
|
|
|
|
Arguments:
|
|
|
|
UrlName : pointer to an URL string
|
|
|
|
FileName : pointer to a string buffer where the random file name is
|
|
returned. The buffer length must be atleast 8+3+1+1= 13 wchars.
|
|
|
|
Extension : pointer to an extension string. if this is non-NULL, then
|
|
the specified extension is used otherwise random extension as
|
|
explained above is used.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CFileMgr::MakeRandomFileName(LPCSTR UrlName,
|
|
LPTSTR FileName, LPTSTR Extension)
|
|
{
|
|
DWORD RandNum;
|
|
LPTSTR FileNamePtr = FileName;
|
|
static Counter;
|
|
DWORD i;
|
|
DWORD cbExtension = 0;
|
|
|
|
if (Extension)
|
|
cbExtension = lstrlen(Extension) + 1;
|
|
|
|
if (cbExtension > (MAX_PATH-(8+1)))
|
|
{
|
|
return(ERROR_FILENAME_EXCED_RANGE);
|
|
}
|
|
|
|
// Additional special hack for cookie urls.
|
|
|
|
if (!memcmp(UrlName, COOKIE_PREFIX, sizeof(COOKIE_PREFIX) - 1))
|
|
{
|
|
// This is a cookie url of the form Cookie:username@domain/path
|
|
if (GetWininetUserName())
|
|
{
|
|
DWORD cb = vdwCurrentUserLen;
|
|
|
|
if (cb + 8 + cbExtension + 1 < MAX_PATH)
|
|
{
|
|
memcpy(FileName, vszCurrentUser, cb);
|
|
FileName[cb] = '@';
|
|
FileNamePtr += (cb + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Check that the total name doesn't exceed MAX_PATH
|
|
// Our total name is 8 chars basename + a dot + the extension + 0
|
|
|
|
|
|
*FileNamePtr++ = L'C';
|
|
*FileNamePtr++ = L'A';
|
|
|
|
//
|
|
// generate a six digits random string;
|
|
//
|
|
|
|
//
|
|
// We can't use rand() alone to generate a random number because it will
|
|
// repeat the same sequence for each new thread that comes in. We can't
|
|
// use the TickCount alone because it is a little too predicable. But
|
|
// the two combined should be nice. Adding in Counter will take care of
|
|
// the case of two brand-new threads coming in at the same time.
|
|
//
|
|
|
|
|
|
for ( i = 0; i < 6; i++) {
|
|
UINT digit;
|
|
|
|
RandNum = (GetTickCount() * rand()) + Counter++;
|
|
|
|
digit = RandNum % 36; // 10 digits + 26 letters
|
|
|
|
*FileNamePtr++ = ( digit < 10 ) ? (CHAR)('0' + digit) : (CHAR)('A' + (digit - 10));
|
|
}
|
|
|
|
*FileNamePtr++ = L'.';
|
|
|
|
|
|
//
|
|
// if an extension is specified, use it.
|
|
//
|
|
if( Extension != NULL )
|
|
{
|
|
// if a 0 extension if provided, we will create a
|
|
// file with no extension
|
|
memcpy(FileNamePtr, Extension, cbExtension);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
// Append default file extension.
|
|
memcpy(FileNamePtr, DEFAULT_FILE_EXTENSION, sizeof(DEFAULT_FILE_EXTENSION));
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
//===================== CSecFileMgr Public Functions ==========================
|
|
//
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::CSecFileMgr
|
|
----------------------------------------------------------------------------*/
|
|
CSecFileMgr::CSecFileMgr(MEMMAP_FILE* mmFile, DWORD dwOptions) : CFileMgr(mmFile, dwOptions)
|
|
{
|
|
INET_ASSERT(_mmFile);
|
|
|
|
// BUGBUG - have to guard against getting out of sync with dirs.
|
|
if (_mmFile->GetDirCount() == 0)
|
|
Init();
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::~CSecFileMgr
|
|
----------------------------------------------------------------------------*/
|
|
CSecFileMgr::~CSecFileMgr()
|
|
{}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::Init
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::Init()
|
|
{
|
|
if (!(GetOptions() & INTERNET_CACHE_CONTAINER_NODESKTOPINIT))
|
|
EnableCacheVu(_mmFile->GetFullPathName());
|
|
|
|
return CreateAdditionalSubDirectories(DEFAULT_DIR_TABLE_GROW_SIZE);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
GetDirLen()
|
|
Returns cache dir path length.
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CSecFileMgr::GetDirLen(DWORD nKey)
|
|
{
|
|
DWORD cb = 0;
|
|
|
|
if (nKey < DEFAULT_MAX_DIRS)
|
|
{
|
|
// + 1 to account for trailing backslash.
|
|
cb = _cbBasePathLen + DIR_NAME_SIZE + 1;
|
|
}
|
|
else
|
|
{
|
|
CHAR szStoreDir[MAX_PATH];
|
|
GetStoreDirectory(szStoreDir, &cb);
|
|
}
|
|
INET_ASSERT(cb);
|
|
return cb;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::CreateUniqueFile
|
|
Creates a cache file.
|
|
----------------------------------------------------------------------------*/
|
|
DWORD CSecFileMgr::CreateUniqueFile(LPCSTR szUrl, DWORD dwExpectedLength, LPTSTR szFileName,
|
|
LPTSTR szFileExtension, HANDLE *phfHandle, BOOL fCreatePerUser)
|
|
{
|
|
DWORD nDir, nFiles;
|
|
DWORD nDirCount = _mmFile->GetDirCount();
|
|
|
|
INET_ASSERT(nDirCount <= DEFAULT_MAX_DIRS);
|
|
|
|
FindMinFilesSubDir(nDir, nFiles);
|
|
|
|
if (nFiles >= MAX_FILES_PER_CACHE_DIRECTORY
|
|
&& nDirCount < DEFAULT_MAX_DIRS)
|
|
{
|
|
if (CreateAdditionalSubDirectories(DEFAULT_DIR_TABLE_GROW_SIZE))
|
|
nDir++;
|
|
}
|
|
|
|
// Get the cache path and subdirectory
|
|
// from the memory mapped file
|
|
CHAR szSubDirPath[MAX_PATH];
|
|
|
|
DWORD cb = _mmFile->GetFullPathNameLen();
|
|
memcpy(szSubDirPath, _mmFile->GetFullPathName(), cb);
|
|
|
|
_mmFile->GetDirName(nDir, szSubDirPath + cb);
|
|
memcpy(szSubDirPath + cb + DIR_NAME_SIZE, DIR_SEPARATOR_STRING, sizeof(DIR_SEPARATOR_STRING));
|
|
return CFileMgr::CreateUniqueFile((LPCSTR) szUrl, dwExpectedLength, (LPTSTR) szSubDirPath,
|
|
(LPTSTR) szFileName, (LPTSTR) szFileExtension,
|
|
(HANDLE*) phfHandle, fCreatePerUser);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::NotifyCommit
|
|
Tracks committed cache file counts.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::NotifyCommit(DWORD nDirIndex)
|
|
{
|
|
INET_ASSERT(_mmFile->GetDirCount() <= DEFAULT_MAX_DIRS);
|
|
|
|
// Regular random subdir
|
|
if (nDirIndex < _mmFile->GetDirCount())
|
|
{
|
|
_mmFile->IncrementFileCount(nDirIndex);
|
|
return TRUE;
|
|
}
|
|
// Not a directory.
|
|
else if (nDirIndex == NOT_A_CACHE_SUBDIRECTORY)
|
|
{
|
|
//INET_ASSERT(FALSE);
|
|
//return FALSE;
|
|
// May be an absolute path EDITED_CACHE_ENTRY so pass
|
|
return TRUE;
|
|
}
|
|
|
|
// Otherwise this had better be an installed directory.
|
|
INET_ASSERT(nDirIndex == INSTALLED_DIRECTORY_KEY);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::Cleanup
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::Cleanup()
|
|
{
|
|
|
|
CHAR szPath[MAX_PATH];
|
|
|
|
DWORD cb = _mmFile->GetFullPathNameLen();
|
|
memcpy(szPath, _mmFile->GetFullPathName(), cb+1);
|
|
|
|
if (!AppendSlashIfNecessary(szPath, &cb))
|
|
return FALSE;
|
|
|
|
memcpy(szPath + cb, "*.*", sizeof("*.*"));
|
|
|
|
WIN32_FIND_DATA fd;
|
|
|
|
HANDLE handle = FindFirstFile(szPath, &fd);
|
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
do
|
|
{
|
|
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
&& (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..")))
|
|
{
|
|
memcpy(szPath + cb, fd.cFileName, strlen(fd.cFileName) + 1);
|
|
|
|
// Only delete directory if it is a valid subdirectory.
|
|
if (IsValidCacheSubDir(szPath))
|
|
{
|
|
if (_mmFile->GetDirIndex(szPath) == NOT_A_CACHE_SUBDIRECTORY)
|
|
{
|
|
DisableCacheVu(szPath);
|
|
if (DeleteCachedFilesInDir(szPath) == ERROR_SUCCESS)
|
|
{
|
|
SetFileAttributes(szPath, FILE_ATTRIBUTE_DIRECTORY);
|
|
RemoveDirectory(szPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (FindNextFile(handle, &fd));
|
|
|
|
|
|
FindClose(handle);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::GetDirIndex
|
|
Returns index of random cache subdirectory from an absolute file path.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::GetDirIndex(LPSTR szAbsPath, LPDWORD pnIndex)
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
DWORD idx;
|
|
|
|
INET_ASSERT(pnIndex);
|
|
|
|
if (szAbsPath && *szAbsPath)
|
|
{
|
|
// First look in mem map file for regular dir.
|
|
idx = _mmFile->GetDirIndex(szAbsPath);
|
|
|
|
// If didn't find it in the mem map file,
|
|
// check if it is the storage directory.
|
|
if (idx == NOT_A_CACHE_SUBDIRECTORY)
|
|
{
|
|
// First we need to find the path to the file sans \filename.ext
|
|
DWORD cbAbsPath = strlen(szAbsPath);
|
|
LPSTR ptr = StrRChr(szAbsPath, szAbsPath + cbAbsPath, DIR_SEPARATOR_CHAR);
|
|
if (ptr)
|
|
{
|
|
// Separate path from filename and attempt to map.
|
|
// Note - trailing slash is included in path mapped.
|
|
DWORD cbPath = (DWORD) (ptr - szAbsPath + 1); // 64BIT
|
|
if (MapStoreKey(szAbsPath, &cbPath, &idx, MAP_PATH_TO_KEY))
|
|
{
|
|
*pnIndex = idx;
|
|
fReturn = TRUE;
|
|
}
|
|
// Must be an EDITED_CACHE_ENTRY set at an absolute path so just update the idx and fail
|
|
else
|
|
{
|
|
*pnIndex = NOT_A_CACHE_SUBDIRECTORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otherwise, this should be a valid cache subdirectory.
|
|
else
|
|
{
|
|
*pnIndex = idx;
|
|
fReturn = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pnIndex = NOT_A_CACHE_SUBDIRECTORY;
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::GetFilePathFromEntry
|
|
|
|
Retrieves the full path to the cache subdirectory for a cache entry.
|
|
Maps the directory index from the URL_FILEMAP_ENTRY pointer passed in
|
|
to a string containing the full path.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::GetFilePathFromEntry(URL_FILEMAP_ENTRY *pEntry,
|
|
LPSTR szAbsPath, LPDWORD pcb)
|
|
{
|
|
DWORD cbSubDirPath, cbFile;
|
|
|
|
INET_ASSERT(pEntry && szAbsPath && pcb && *pcb);
|
|
|
|
// Get file name and length - eg "default.html"
|
|
LPTSTR szFile = (LPTSTR) OFFSET_TO_POINTER(pEntry, pEntry->InternalFileNameOffset);
|
|
cbFile = strlen(szFile);
|
|
|
|
// Make real time check?
|
|
if (cbFile && (cbFile < MAX_PATH))
|
|
{
|
|
// Does entry reside in on of the random subdirs?
|
|
if (pEntry->DirIndex != NOT_A_CACHE_SUBDIRECTORY
|
|
&& pEntry->DirIndex < DEFAULT_MAX_DIRS)
|
|
{
|
|
// Path length.
|
|
DWORD cbFull = _mmFile->GetFullPathNameLen();
|
|
|
|
// Don't overflow output buffer.
|
|
cbSubDirPath =
|
|
cbFull
|
|
+ DIR_NAME_SIZE
|
|
+ sizeof(DIR_SEPARATOR_STRING) - 1
|
|
+ cbFile;
|
|
|
|
if (cbSubDirPath + 1 > *pcb)
|
|
{
|
|
// INET_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
// "C:\Windows\Profiles\anyuser\Temporary Internet Files\"
|
|
memcpy(szAbsPath, _mmFile->GetFullPathName(), cbFull);
|
|
|
|
// "C:\Windows\Profiles\anyuser\Temporary Internet Files\XAQRTLY7"
|
|
_mmFile->GetDirName(pEntry->DirIndex, szAbsPath + cbFull);
|
|
|
|
// "C:\Windows\Profiles\anyuser\Temporary Internet Files\XAQRTLY7\"
|
|
memcpy(szAbsPath + cbFull + DIR_NAME_SIZE, DIR_SEPARATOR_STRING, sizeof (DIR_SEPARATOR_STRING));
|
|
|
|
// "C:\Windows\Profiles\anyuser\Temporary Internet Files\XAQRTLY7\default.htm"
|
|
memcpy(szAbsPath + cbFull + DIR_NAME_SIZE + sizeof(DIR_SEPARATOR_STRING) - 1, szFile, cbFile + 1);
|
|
}
|
|
|
|
// There is no cache subdirectory which has been can be mapped
|
|
// from the index. See if there is an existing store mapping.
|
|
else
|
|
{
|
|
|
|
if (pEntry->DirIndex == NOT_A_CACHE_SUBDIRECTORY)
|
|
// Assume an ECE absolute path item as AddURL only writes NACS entries with ECE set
|
|
{
|
|
cbSubDirPath = cbFile + 1; // Add terminator to size
|
|
if (cbSubDirPath > *pcb)
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
memcpy(szAbsPath, szFile, cbSubDirPath);
|
|
}
|
|
else
|
|
{
|
|
|
|
INET_ASSERT(pEntry->DirIndex == INSTALLED_DIRECTORY_KEY);
|
|
|
|
DWORD cbPath = 0;
|
|
DWORD dwIndex = INSTALLED_DIRECTORY_KEY;
|
|
if (MapStoreKey(szAbsPath, &cbPath, &dwIndex, MAP_KEY_TO_PATH))
|
|
{
|
|
// "C:\Winnt\Web\"
|
|
cbSubDirPath = cbPath + cbFile;
|
|
if (cbSubDirPath + 1 > *pcb)
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
// "C:\Winnt\Web\default.html"
|
|
memcpy(szAbsPath + cbPath, szFile, cbFile + 1);
|
|
}
|
|
else
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Hand out the absolute path to the file.
|
|
*pcb = cbSubDirPath;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
INET_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::DeleteOneCachedFile
|
|
Deletes one cache file and decrements the file count.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::DeleteOneCachedFile(LPSTR lpszFileName,
|
|
DWORD dostEntry, DWORD nDirIndex)
|
|
{
|
|
if (!::DeleteOneCachedFile(lpszFileName, dostEntry))
|
|
return FALSE;
|
|
|
|
INET_ASSERT(nDirIndex != NOT_A_CACHE_SUBDIRECTORY);
|
|
_mmFile->DecrementFileCount(nDirIndex);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//==================== CSecFileMgr Protected Functions =======================
|
|
//
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::CreateRandomDirName
|
|
Creates a random subdirectory name under the root container path.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::CreateRandomDirName(LPSTR szDirName)
|
|
{
|
|
DWORD RandNum;
|
|
LPSTR ptr = szDirName;
|
|
static Counter;
|
|
|
|
INET_ASSERT(szDirName);
|
|
|
|
// Stolen from MakeRandomFileName.
|
|
for (DWORD i = 0; i < DIR_NAME_SIZE; i++)
|
|
{
|
|
UINT digit;
|
|
RandNum = (GetTickCount() * rand()) + Counter++;
|
|
|
|
// 10 digits + 26 letters
|
|
digit = RandNum % 36;
|
|
*ptr++ = ( digit < 10 ) ? (CHAR)('0' + digit) : (CHAR)('A' + (digit - 10));
|
|
}
|
|
|
|
*ptr = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::CreateAdditionalSubDirectories
|
|
Creates nAdditionalDirs random subdirectories, up to DEFAULT_MAX_DIRS.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::CreateAdditionalSubDirectories(DWORD nAdditionalDirs)
|
|
{
|
|
DWORD nTotalDirs;
|
|
DWORD nDirCount = _mmFile->GetDirCount();
|
|
BOOL bSuccess = TRUE;
|
|
|
|
INET_ASSERT(nDirCount <= DEFAULT_MAX_DIRS);
|
|
|
|
// Don't create more than the max allowed dirs.
|
|
nTotalDirs = nAdditionalDirs + nDirCount;
|
|
INET_ASSERT(nTotalDirs <= DEFAULT_MAX_DIRS);
|
|
|
|
// Create the dir and set the file count to 0.
|
|
DWORD i = nDirCount;
|
|
DWORD nTotalTries = 0;
|
|
do
|
|
{
|
|
if (CreateSubDirectory(i))
|
|
{
|
|
_mmFile->SetFileCount(i, 0);
|
|
_mmFile->IncrementDirCount();
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
bSuccess = FALSE;
|
|
}
|
|
|
|
if (nTotalTries++ > 100)
|
|
{
|
|
bSuccess = FALSE;
|
|
break;
|
|
}
|
|
|
|
} while (i < nTotalDirs);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::CreateSubDirectory(DWORD nIdx)
|
|
Actual creation of subdirectory.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::CreateSubDirectory(DWORD nIdx)
|
|
{
|
|
CHAR szCacheDir[MAX_PATH];
|
|
CHAR szSubDir[DIR_NAME_SIZE + 1];
|
|
|
|
// Generate full path to random dir.
|
|
CreateRandomDirName(szSubDir);
|
|
DWORD cb = _mmFile->GetFullPathNameLen();
|
|
|
|
memcpy(szCacheDir, _mmFile->GetFullPathName(), cb);
|
|
memcpy(szCacheDir + cb, szSubDir, DIR_NAME_SIZE + 1);
|
|
|
|
// Create the directory and add it to
|
|
// the list of directories in the index.
|
|
if (CreateDirectory(szCacheDir, NULL))
|
|
{
|
|
_mmFile->SetDirName(nIdx, szSubDir);
|
|
|
|
// For cachevu must be hidden and system.
|
|
// BUGBUG - sure it must be hidden?
|
|
SetFileAttributes(szCacheDir, FILE_ATTRIBUTE_SYSTEM);
|
|
|
|
if (!(GetOptions() & INTERNET_CACHE_CONTAINER_NODESKTOPINIT))
|
|
EnableCacheVu(szCacheDir);
|
|
|
|
}
|
|
else
|
|
{
|
|
// Couldn't create the directory.
|
|
INET_ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
CSecFileMgr::FindMinFilesSubDir
|
|
Determines the cache subdirectory with the minimum file count for load balancing.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL CSecFileMgr::FindMinFilesSubDir(DWORD& nMinFileDir, DWORD& nFiles)
|
|
{
|
|
DWORD nDirCount = _mmFile->GetDirCount();
|
|
|
|
if (nDirCount == 0 || nDirCount > DEFAULT_MAX_DIRS)
|
|
{
|
|
INET_ASSERT(FALSE);
|
|
_mmFile->SetDirCount(0);
|
|
CreateAdditionalSubDirectories(DEFAULT_DIR_TABLE_GROW_SIZE);
|
|
nDirCount = _mmFile->GetDirCount();
|
|
}
|
|
|
|
nMinFileDir = 0;
|
|
DWORD nMinFiles = _mmFile->GetFileCount(0);
|
|
|
|
for (DWORD i = 1; i < nDirCount; i++)
|
|
{
|
|
if (_mmFile->GetFileCount(i) < nMinFiles)
|
|
{
|
|
nMinFiles = _mmFile->GetFileCount(i);
|
|
nMinFileDir = i;
|
|
}
|
|
|
|
}
|
|
nFiles = _mmFile->GetFileCount(nMinFileDir);
|
|
return TRUE;
|
|
}
|
|
|