/*++ Copyright (c) 1997 Microsoft Corporation Module Name: instcon.cxx Abstract: Installed container class derived from URL_CONTAINER Author: Adriaan Canter (adriaanc) 04-10-97 --*/ #include #define HTTP_OK "HTTP/1.0 200 OK\r\n\r\n" /*--------------------- CInstCon Public Functions-----------------------------*/ /*----------------------------------------------------------------------------- CInstCon::CInstCon -----------------------------------------------------------------------------*/ CInstCon::CInstCon(LPSTR CacheName, LPSTR VolumeLabel, LPSTR VolumeTitle, LPSTR CachePath, LPSTR CachePrefix, LPSTR PrefixMap, LONGLONG CacheLimit, DWORD dwOptions) : URL_CONTAINER(CacheName, CachePath, CachePrefix, CacheLimit, dwOptions) { if (_Status != ERROR_SUCCESS) { INET_ASSERT(FALSE); return; } _szVolumeLabel = NewString(VolumeLabel); _szVolumeTitle = NewString(VolumeTitle); _szPrefixMap = NewString(PrefixMap); if (!(_szVolumeLabel && _szVolumeTitle && _szPrefixMap)) { INET_ASSERT(FALSE); _Status = ERROR_NOT_ENOUGH_MEMORY; return; } _cbPrefixMap = strlen(PrefixMap); _cbMaxFileSize = MAX_FILE_SIZE_TO_MIGRATE; _Status = ERROR_SUCCESS; } /*----------------------------------------------------------------------------- CInstCon::~CInstCon -----------------------------------------------------------------------------*/ CInstCon::~CInstCon() { delete _szPrefixMap; delete _szVolumeLabel; delete _szVolumeTitle; } /*------------------ URL_CONTAINER virtual overrides-------------------------*/ /*----------------------------------------------------------------------------- CInstCon::GetPrefixMap -----------------------------------------------------------------------------*/ LPSTR CInstCon::GetPrefixMap() { return _szPrefixMap; } /*----------------------------------------------------------------------------- CInstCon::GetVolumeLabel -----------------------------------------------------------------------------*/ LPSTR CInstCon::GetVolumeLabel() { return _szVolumeLabel; } /*----------------------------------------------------------------------------- CInstCon::GetVolumeTitle -----------------------------------------------------------------------------*/ LPSTR CInstCon::GetVolumeTitle() { return _szVolumeTitle; } /*----------------------------------------------------------------------------- CInstCon::AddUrl -----------------------------------------------------------------------------*/ DWORD CInstCon::AddUrl (AddUrlArg* pArgs) { pArgs->dwEntryType |= INSTALLED_CACHE_ENTRY; return URL_CONTAINER::AddUrl(pArgs); } /*----------------------------------------------------------------------------- CInstCon::RetrieveUrl -----------------------------------------------------------------------------*/ DWORD CInstCon::RetrieveUrl(LPCSTR UrlName, LPCACHE_ENTRY_INFO EntryInfo, LPDWORD EntryInfoSize, DWORD dwLookupFlags, DWORD dwRetrievalFlags) { DWORD dwError; BOOL fMustUnlock; INET_ASSERT(EntryInfo && EntryInfoSize); if (!LockContainer(&fMustUnlock)) { dwError = GetLastError(); goto exit; } dwError = GetEntry(UrlName, EntryInfo, EntryInfoSize, dwLookupFlags); exit: if (fMustUnlock) UnlockContainer(); return dwError; } /*----------------------------------------------------------------------------- CInstCon::GetUrlInfo -----------------------------------------------------------------------------*/ DWORD CInstCon::GetUrlInfo(LPCSTR szUrlName, LPCACHE_ENTRY_INFO pei, LPDWORD pcbei, DWORD dwLookupFlags, DWORD dwEntryFlags) { DWORD dwError; DWORD cbeiTemp = 0x256; BYTE bTemp[0x256]; BOOL fMustUnlock; if (!LockContainer(&fMustUnlock)) { dwError = GetLastError(); goto exit; } // Zero buffer case. if (pei && pcbei) { dwError = GetEntry(szUrlName, pei, pcbei, dwLookupFlags); goto exit; } // Zero buffer case. if (dwEntryFlags & INTERNET_CACHE_FLAG_ENTRY_OR_MAPPING) { // Return success to indicate that a mapping exists. // We wouldn't have gotten here otherwise. dwError = ERROR_SUCCESS; } else { // Otherwise, no flag passed in. Only return // success if the entry has been successfully found. dwError = GetEntry(szUrlName, (LPCACHE_ENTRY_INFO) bTemp, &cbeiTemp, dwLookupFlags); } exit: if (fMustUnlock) UnlockContainer(); return dwError; } /*--------------------- CInstCon Private Functions-----------------------------*/ /*----------------------------------------------------------------------------- CInstCon::GetEntry -----------------------------------------------------------------------------*/ DWORD CInstCon::GetEntry(LPCSTR UrlName, LPCACHE_ENTRY_INFO EntryInfo, LPDWORD EntryInfoSize, DWORD dwLookupFlags) { INT cbOld, cbNew, cbDiff; DWORD cbOriginalInfoSize = *EntryInfoSize; DWORD dwError = ERROR_SUCCESS, dwCDStatus; DWORD cb; LPSTR ptr; // Try to get it from the CD. dwCDStatus = GetEntryFromCD(UrlName, EntryInfo, EntryInfoSize); switch(dwCDStatus) { // Couldn't find it on the CD. case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: // Not on CD. Look in memory mapped file. dwError = URL_CONTAINER::RetrieveUrl(UrlName, (EntryInfo ? &EntryInfo : NULL), EntryInfoSize, dwLookupFlags, RETRIEVE_WITH_CHECKS); break; // CD not in drive. case ERROR_INVALID_DRIVE: case ERROR_NOT_READY: case ERROR_WRONG_DISK: dwError = ERROR_INTERNET_INSERT_CDROM; break; // Found it on the CD. case ERROR_SUCCESS: dwError = ERROR_SUCCESS; break; default: // Some other error. dwError = ERROR_INTERNET_INTERNAL_ERROR; } return dwError; } /*----------------------------------------------------------------------------- CInstCon::MapUrlToAbsPath -----------------------------------------------------------------------------*/ VOID CInstCon::MapUrlToAbsPath(LPSTR UrlName, LPSTR szAbsPath, LPDWORD pcbAbsPath) { // Construct the absolute path to the file. memcpy(szAbsPath, _szPrefixMap, _cbPrefixMap + 1); LPSTR ptr = UrlName + _CachePrefixLen; DWORD cbSuffix = strlen(ptr); *pcbAbsPath = _cbPrefixMap + cbSuffix; memcpy(szAbsPath + _cbPrefixMap, ptr, cbSuffix + 1); // Convert all forward slashes to back slashes, // including any that were inadvertently placed // in the prefix map. This path might be returned // to the caller. ptr = szAbsPath; while (*ptr++) { #ifndef unix if (*ptr == '/') *ptr = '\\'; #else if (*ptr == '\\') *ptr = '/'; #endif /* unix */ } // Unescape - final length may be less than // pcbAbsPath, but is always null terminated. UrlUnescapeInPlace(szAbsPath, NULL); } /*----------------------------------------------------------------------------- CInstCon::GetEntryFromCD -----------------------------------------------------------------------------*/ DWORD CInstCon::GetEntryFromCD(LPCSTR UrlName, LPCACHE_ENTRY_INFO EntryInfo, LPDWORD EntryInfoSize) { LPBYTE pb; CHAR szAbsPath[MAX_PATH], *ptr; DWORD cbUrl, cbSuffix, cbAbsPath, cbSizeRequired, cbExt, i, dwError = ERROR_SUCCESS; LONGLONG llZero = (LONGLONG) 0; WIN32_FILE_ATTRIBUTE_DATA FileAttributes; CHAR szVolumeLabel[MAX_PATH]; CHAR szVolRoot[4]; memcpy(szVolRoot, _szPrefixMap, 2); memcpy(szVolRoot + 2, DIR_SEPARATOR_STRING, sizeof(DIR_SEPARATOR_STRING)); // First check that the correct CD is inserted. if (GetVolumeInformation(szVolRoot, szVolumeLabel, MAX_PATH, NULL, NULL, NULL, NULL, 0)) { if (strcmp(_szVolumeLabel, szVolumeLabel)) { dwError = ERROR_WRONG_DISK; goto exit; } } else { dwError = ERROR_INVALID_DRIVE; goto exit; } // ---- Find the file and file info from the url ----- cbUrl = strlen(UrlName); // Formulate path to file. MapUrlToAbsPath((LPSTR) UrlName, szAbsPath, &cbAbsPath); // Determine required CACHE_ENTRY_INFO buffer size. cbSizeRequired = sizeof(CACHE_ENTRY_INFO) + cbUrl + 1 + cbAbsPath + 1 + MAX_EXTENSION_LEN + 1 + sizeof(HTTP_OK); if (cbSizeRequired > *EntryInfoSize) { dwError = ERROR_INSUFFICIENT_BUFFER; goto exit; } // Get the file information. Shouldn't be a directory. dwError = GetFileSizeAndTimeByName(szAbsPath, &FileAttributes); if (dwError != ERROR_SUCCESS) { if (FileAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { dwError = ERROR_FILE_NOT_FOUND; } goto exit; } // ---- Assemble the CACHE_ENTRY_INFO structure to return ---- // Urlname. pb = (LPBYTE) EntryInfo + sizeof(CACHE_ENTRY_INFO); memcpy(pb, UrlName, cbUrl + 1); EntryInfo->lpszSourceUrlName = (LPSTR) pb; // Filename. pb += cbUrl + 1; strcpy((LPSTR) pb, szAbsPath); EntryInfo->lpszLocalFileName = (LPSTR) pb; // Header. pb += cbAbsPath + 1; memcpy(pb, HTTP_OK, sizeof(HTTP_OK)); EntryInfo->lpHeaderInfo = (LPSTR)pb; // File extension cbExt = 0; ptr = (LPSTR) UrlName + cbUrl; for (i = 0; i < MAX_EXTENSION_LEN+1; i++) { if (*(--ptr) == '.') { cbExt = i+1; break; } } if (cbExt) { pb += sizeof(HTTP_OK); memcpy(pb, ptr+1, cbExt + 1); EntryInfo->lpszFileExtension = (LPSTR) pb; } else EntryInfo->lpszFileExtension = NULL; pb += cbExt +1; INET_ASSERT((DWORD) ((LPCACHE_ENTRY_INFO) pb - EntryInfo) < cbSizeRequired); // Version , type, count, hit rate, file size. EntryInfo->dwStructSize = URL_CACHE_VERSION_NUM; EntryInfo->CacheEntryType = INSTALLED_CACHE_ENTRY; EntryInfo->dwUseCount = 0; EntryInfo->dwHitRate = 0; EntryInfo->dwSizeHigh = FileAttributes.nFileSizeHigh; EntryInfo->dwSizeLow = FileAttributes.nFileSizeLow; // Times: modified, expired, accessed, synced. EntryInfo->LastModifiedTime = FileAttributes.ftCreationTime; EntryInfo->ExpireTime = *(FILETIME*) &llZero; // BUGBUG - getcurrent time for both. EntryInfo->LastAccessTime = FileAttributes.ftLastAccessTime; EntryInfo->LastSyncTime = *(FILETIME*) &llZero; // Header size, file extension, exempt delta. EntryInfo->dwHeaderInfoSize = sizeof(HTTP_OK); EntryInfo->dwExemptDelta = 0; // Buffer consumed. *EntryInfoSize = cbSizeRequired - sizeof(CACHE_ENTRY_INFO); exit: return dwError; } /*----------------------------------------------------------------------------- CInstCon::AddEntryToIndex -----------------------------------------------------------------------------*/ DWORD CInstCon::AddEntryToIndex(LPCACHE_ENTRY_INFO EntryInfo, LPDWORD EntryInfoSize) { DWORD dwError; AddUrlArg args; CHAR szFileName[MAX_PATH]; // Create a local file name for the hard disk. *szFileName = '\0'; dwError = URL_CONTAINER::CreateUniqueFile(EntryInfo->lpszSourceUrlName, NULL, EntryInfo->lpszFileExtension, szFileName, NULL); if (dwError != ERROR_SUCCESS) goto exit; // Copy the file from the CD. // CreateUniqueFile has already created a file of 0 bytes. if (!CopyFile(EntryInfo->lpszLocalFileName, szFileName, FALSE)) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto exit; } // Add the entry to the index. // Url, filename, file size and extension. memset(&args, 0, sizeof(args)); args.pszUrl = EntryInfo->lpszSourceUrlName; args.pszFilePath = szFileName; args.dwFileSize = EntryInfo->dwSizeLow; args.pszFileExt = EntryInfo->lpszFileExtension; args.dwEntryType = EntryInfo->CacheEntryType; // Headers. args.pbHeaders = EntryInfo->lpHeaderInfo; args.cbHeaders = EntryInfo->dwHeaderInfoSize; // Times: last modified and expired. args.qwLastMod = FT2LL(EntryInfo->LastModifiedTime); args.qwExpires = FT2LL(EntryInfo->ExpireTime); // Redirect. args.pszRedirect = NULL; args.fImage = FALSE; // Add the url to the index. dwError = AddUrl(&args); if (dwError != ERROR_SUCCESS) goto exit; // Retrieve the entry from the index. We do this because the EntryInfo // structure returned from the CD references the CD filename. // PERFPERF - we could optimize this by fixing up the EntryInfo // structure to reference the CD filename. dwError = URL_CONTAINER::RetrieveUrl(EntryInfo->lpszSourceUrlName, (EntryInfo ? &EntryInfo : NULL), EntryInfoSize, NULL, RETRIEVE_WITH_CHECKS); exit: return dwError; }