static void DeleteEmptyDirectories( const CString &sDir ) { vector<CString> asNewDirs; GetDirListing( sDir + "/*", asNewDirs, false, true ); for( unsigned i = 0; i < asNewDirs.size(); ++i ) { ASSERT_M( IsADirectory(asNewDirs[i]), asNewDirs[i] ); DeleteEmptyDirectories( asNewDirs[i] ); } FILEMAN->Remove( sDir ); }
BackgroundLoader::~BackgroundLoader() { if( !g_bEnableBackgroundLoading ) return; Abort(); m_bShutdownThread = true; m_StartSem.Post(); m_LoadThread.Wait(); /* Delete all leftover cached files. */ map<CString,int>::iterator it; for( it = m_FinishedRequests.begin(); it != m_FinishedRequests.end(); ++it ) FILEMAN->Remove( GetCachePath( it->first ) ); /* m_sCachePathPrefix should be filled with several empty directories. Delete * them and m_sCachePathPrefix, so we don't leak them. */ DeleteEmptyDirectories( m_sCachePathPrefix ); }
void CFileOpt::DeleteEmptyDirectories(LPCTSTR dir) { WIN32_FIND_DATA finder; HANDLE hFileFind; CString strSearch; strSearch = dir; int iLen = strSearch.GetLength(); if (iLen<=0) return ; if (strSearch.GetAt(iLen) != '\\' ) { strSearch.Append(_T("\\")); } strSearch.Append(_T("*.*")); hFileFind = FindFirstFile(strSearch, &finder); if (hFileFind != INVALID_HANDLE_VALUE) { do { CString strPath; strPath = dir; int iLen = strPath.GetLength(); if (iLen<=0) { FindClose(hFileFind); return ; } if (strPath.GetAt(iLen) != '\\' ) { strPath.Append(_T("\\")); } strPath.Append(finder.cFileName); if ((finder.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && wcscmp(finder.cFileName, _T(".")) && wcscmp(finder.cFileName, _T(".."))) { CString strSubDir; strSubDir.Append(strPath); strSubDir.Append(_T("\\")); DeleteEmptyDirectories(strSubDir); // AfxMessageBox(strSubDir); RemoveDirectory(strPath); } } while (FindNextFile(hFileFind, &finder) != 0); FindClose(hFileFind); } }
static HRESULT ProductDbToMachine( __in CFGDB_STRUCT *pcdb, __in LEGACY_SYNC_PRODUCT_SESSION *pSyncProductSession ) { HRESULT hr = S_OK; SCE_QUERY_HANDLE sqhHandle = NULL; SCE_QUERY_RESULTS_HANDLE sqrhResults = NULL; SCE_ROW_HANDLE sceRow = NULL; BOOL fIgnore = FALSE; LPWSTR sczName = NULL; BOOL fHandled = FALSE; CONFIG_VALUE cvValue = { }; // First handle all special values hr = RegSpecialsProductWrite(pcdb, pSyncProductSession); ExitOnFailure(hr, "Failed to write specially handled values back to registry"); // Now handle all the regular values, minus exceptions from when we processed special values hr = SceBeginQuery(pcdb->psceDb, VALUE_INDEX_TABLE, 0, &sqhHandle); ExitOnFailure(hr, "Failed to begin query into VALUE_INDEX_TABLE table"); hr = SceSetQueryColumnDword(sqhHandle, pcdb->dwAppID); ExitOnFailure(hr, "Failed to set AppID for query"); hr = SceRunQueryRange(&sqhHandle, &sqrhResults); if (E_NOTFOUND == hr) { ExitFunction1(hr = S_OK); } ExitOnFailure(hr, "Failed to run query into VALUE_INDEX_TABLE table for AppID: %u", pcdb->dwAppID); hr = SceGetNextResultRow(sqrhResults, &sceRow); while (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get next results row from VALUE_INDEX_TABLE table"); hr = SceGetColumnString(sceRow, VALUE_COMMON_NAME, &sczName); ExitOnFailure(hr, "Failed to get name from row while querying VALUE_INDEX_TABLE table"); hr = FilterCheckValue(&pSyncProductSession->product, sczName, &fIgnore, NULL); ExitOnFailure(hr, "Failed to check if cfg setting should be ignored: %ls", sczName); if (!fIgnore) { fHandled = FALSE; hr = DictKeyExists(pSyncProductSession->product.shRegistrySpeciallyHandled, sczName); if (S_OK == hr) { // On a registry value exception, simply skip handling this value fHandled = TRUE; } else if (E_NOTFOUND == hr) { hr = S_OK; } ExitOnFailure(hr, "Failed to check if registry value exists in reg value exceptions dictionary"); ReleaseNullCfgValue(cvValue); hr = ValueRead(pcdb, sceRow, &cvValue); ExitOnFailure(hr, "Failed to read value %ls", sczName); if (!fHandled) { hr = RegDefaultWriteValue(&pSyncProductSession->product, sczName, &cvValue, &fHandled); ExitOnFailure(hr, "Failed to write value through registry default handler: %ls", sczName); } if (!fHandled) { hr = IniFileSetValue(pSyncProductSession, sczName, &cvValue, &fHandled); ExitOnFailure(hr, "Failed to write registry value through ini handler: %ls", sczName); } if (!fHandled) { hr = DirDefaultWriteFile(&pSyncProductSession->product, sczName, &cvValue, &fHandled); ExitOnFailure(hr, "Failed to write file through default handler: %ls", sczName); } } ReleaseNullSceRow(sceRow); hr = SceGetNextResultRow(sqrhResults, &sceRow); } hr = S_OK; ReleaseNullSceQueryResults(sqrhResults); for (DWORD i = 0; i < pSyncProductSession->cIniFiles; ++i) { hr = IniFileWrite(pSyncProductSession->rgIniFiles + i); ExitOnFailure(hr, "Failed to write INI file"); } if (!pSyncProductSession->fRegistered) { hr = DeleteEmptyRegistryKeys(pSyncProductSession); ExitOnFailure(hr, "Failed to delete empty registry keys"); hr = DeleteEmptyDirectories(pSyncProductSession); ExitOnFailure(hr, "Failed to delete empty directories"); } LExit: ReleaseStr(sczName); ReleaseSceQuery(sqhHandle); ReleaseSceQueryResults(sqrhResults); ReleaseSceRow(sceRow); ReleaseCfgValue(cvValue); return hr; }
// -------------------------------------------------------------------------- // // Function // Name: HousekeepStoreAccount::DoHousekeeping() // Purpose: Perform the housekeeping // Created: 11/12/03 // // -------------------------------------------------------------------------- bool HousekeepStoreAccount::DoHousekeeping(bool KeepTryingForever) { BOX_TRACE("Starting housekeeping on account " << BOX_FORMAT_ACCOUNT(mAccountID)); // Attempt to lock the account std::string writeLockFilename; StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, writeLockFilename); NamedLock writeLock; if(!writeLock.TryAndGetLock(writeLockFilename.c_str(), 0600 /* restrictive file permissions */)) { if(KeepTryingForever) { BOX_INFO("Failed to lock account for housekeeping, " "still trying..."); while(!writeLock.TryAndGetLock(writeLockFilename, 0600 /* restrictive file permissions */)) { sleep(1); } } else { // Couldn't lock the account -- just stop now return false; } } // Load the store info to find necessary info for the housekeeping std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(mAccountID, mStoreRoot, mStoreDiscSet, false /* Read/Write */)); std::auto_ptr<BackupStoreInfo> pOldInfo( BackupStoreInfo::Load(mAccountID, mStoreRoot, mStoreDiscSet, true /* Read Only */)); // If the account has a name, change the logging tag to include it if(!(info->GetAccountName().empty())) { std::ostringstream tag; tag << "hk=" << BOX_FORMAT_ACCOUNT(mAccountID) << "/" << info->GetAccountName(); mTagWithClientID.Change(tag.str()); } // Calculate how much should be deleted mDeletionSizeTarget = info->GetBlocksUsed() - info->GetBlocksSoftLimit(); if(mDeletionSizeTarget < 0) { mDeletionSizeTarget = 0; } BackupStoreAccountDatabase::Entry account(mAccountID, mStoreDiscSet); mapNewRefs = BackupStoreRefCountDatabase::Create(account); // Scan the directory for potential things to delete // This will also remove eligible items marked with RemoveASAP bool continueHousekeeping = ScanDirectory(BACKUPSTORE_ROOT_DIRECTORY_ID, *info); if(!continueHousekeeping) { // The scan was incomplete, so the new block counts are // incorrect, we can't rely on them. It's better to discard // the new info and adjust the old one instead. info = pOldInfo; // We're about to reset counters and exit, so report what // happened now. BOX_INFO("Housekeeping on account " << BOX_FORMAT_ACCOUNT(mAccountID) << " removed " << (0 - mBlocksUsedDelta) << " blocks (" << mFilesDeleted << " files, " << mEmptyDirectoriesDeleted << " dirs) and the directory " "scan was interrupted"); } // If housekeeping made any changes, such as deleting RemoveASAP files, // the differences in block counts will be recorded in the deltas. info->ChangeBlocksUsed(mBlocksUsedDelta); info->ChangeBlocksInOldFiles(mBlocksInOldFilesDelta); info->ChangeBlocksInDeletedFiles(mBlocksInDeletedFilesDelta); // Reset the delta counts for files, as they will include // RemoveASAP flagged files deleted during the initial scan. // keep removeASAPBlocksUsedDelta for reporting int64_t removeASAPBlocksUsedDelta = mBlocksUsedDelta; mBlocksUsedDelta = 0; mBlocksInOldFilesDelta = 0; mBlocksInDeletedFilesDelta = 0; // If scan directory stopped for some reason, probably parent // instructed to terminate, stop now. // // We can only update the refcount database if we successfully // finished our scan of all directories, otherwise we don't actually // know which of the new counts are valid and which aren't // (we might not have seen second references to some objects, etc.). if(!continueHousekeeping) { mapNewRefs->Discard(); info->Save(); return false; } // Report any UNexpected changes, and consider them to be errors. // Do this before applying the expected changes below. mErrorCount += info->ReportChangesTo(*pOldInfo); info->Save(); // Try to load the old reference count database and check whether // any counts have changed. We want to compare the mapNewRefs to // apOldRefs before we delete any files, because that will also change // the reference count in a way that's not an error. try { std::auto_ptr<BackupStoreRefCountDatabase> apOldRefs = BackupStoreRefCountDatabase::Load(account, false); mErrorCount += mapNewRefs->ReportChangesTo(*apOldRefs); } catch(BoxException &e) { BOX_WARNING("Reference count database was missing or " "corrupted during housekeeping, cannot check it for " "errors."); mErrorCount++; } // Go and delete items from the accounts bool deleteInterrupted = DeleteFiles(*info); // If that wasn't interrupted, remove any empty directories which // are also marked as deleted in their containing directory if(!deleteInterrupted) { deleteInterrupted = DeleteEmptyDirectories(*info); } // Log deletion if anything was deleted if(mFilesDeleted > 0 || mEmptyDirectoriesDeleted > 0) { BOX_INFO("Housekeeping on account " << BOX_FORMAT_ACCOUNT(mAccountID) << " " "removed " << (0 - (mBlocksUsedDelta + removeASAPBlocksUsedDelta)) << " blocks (" << mFilesDeleted << " files, " << mEmptyDirectoriesDeleted << " dirs)" << (deleteInterrupted?" and was interrupted":"")); } // Make sure the delta's won't cause problems if the counts are // really wrong, and it wasn't fixed because the store was // updated during the scan. if(mBlocksUsedDelta < (0 - info->GetBlocksUsed())) { mBlocksUsedDelta = (0 - info->GetBlocksUsed()); } if(mBlocksInOldFilesDelta < (0 - info->GetBlocksInOldFiles())) { mBlocksInOldFilesDelta = (0 - info->GetBlocksInOldFiles()); } if(mBlocksInDeletedFilesDelta < (0 - info->GetBlocksInDeletedFiles())) { mBlocksInDeletedFilesDelta = (0 - info->GetBlocksInDeletedFiles()); } if(mBlocksInDirectoriesDelta < (0 - info->GetBlocksInDirectories())) { mBlocksInDirectoriesDelta = (0 - info->GetBlocksInDirectories()); } // Update the usage counts in the store info->ChangeBlocksUsed(mBlocksUsedDelta); info->ChangeBlocksInOldFiles(mBlocksInOldFilesDelta); info->ChangeBlocksInDeletedFiles(mBlocksInDeletedFilesDelta); info->ChangeBlocksInDirectories(mBlocksInDirectoriesDelta); // Save the store info back info->Save(); // force file to be saved and closed before releasing the lock below mapNewRefs->Commit(); mapNewRefs.reset(); // Explicity release the lock (would happen automatically on // going out of scope, included for code clarity) writeLock.ReleaseLock(); BOX_TRACE("Finished housekeeping on account " << BOX_FORMAT_ACCOUNT(mAccountID)); return true; }