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 );
}
Exemple #3
0
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);
	}
} 
Exemple #4
0
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;
}