nsresult nsFolderCompactState::CompactNextFolder() { m_folderIndex++; PRUint32 cnt = 0; nsresult rv = m_folderArray->GetLength(&cnt); NS_ENSURE_SUCCESS(rv, rv); // m_folderIndex might be > cnt if we compact offline stores, // and get back here from OnStopRunningUrl. if (m_folderIndex >= cnt) { if (!m_compactOfflineAlso || m_compactingOfflineFolders) { CompactCompleted(NS_OK); return rv; } m_compactingOfflineFolders = true; nsCOMPtr<nsIMsgFolder> folder = do_QueryElementAt(m_folderArray, m_folderIndex-1, &rv); if (NS_SUCCEEDED(rv) && folder) return folder->CompactAllOfflineStores(this, m_window, m_offlineFolderArray); else NS_WARNING("couldn't get folder to compact offline stores"); } nsCOMPtr<nsIMsgFolder> folder = do_QueryElementAt(m_folderArray, m_folderIndex, &rv); if (NS_SUCCEEDED(rv) && folder) rv = Compact(folder, m_compactingOfflineFolders, m_listener, m_window); else CompactCompleted(rv); return rv; }
NS_IMETHODIMP nsFolderCompactState::OnStopRunningUrl(nsIURI *url, nsresult status) { if (m_parsingFolder) { m_parsingFolder = false; if (NS_SUCCEEDED(status)) status = Compact(m_folder, m_compactingOfflineFolders, m_listener, m_window); else if (m_compactAll) CompactNextFolder(); } else if (m_compactAll) // this should be the imap case only { nsCOMPtr <nsIMsgFolder> prevFolder = do_QueryElementAt(m_folderArray, m_folderIndex); if (prevFolder) prevFolder->SetMsgDatabase(nsnull); CompactNextFolder(); } else if (m_listener) { CompactCompleted(status); } return NS_OK; }
nsresult nsFolderCompactState::FinishCompact() { if (!m_folder) return NS_ERROR_NOT_INITIALIZED; // All okay time to finish up the compact process nsCOMPtr<nsILocalFile> path; nsCOMPtr<nsIDBFolderInfo> folderInfo; // get leaf name and database name of the folder nsresult rv = m_folder->GetFilePath(getter_AddRefs(path)); nsCOMPtr <nsILocalFile> folderPath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr <nsILocalFile> summaryFile; folderPath->InitWithFile(path); // need to make sure we put the .msf file in the same directory // as the original mailbox, so resolve symlinks. folderPath->SetFollowLinks(true); GetSummaryFileLocation(folderPath, getter_AddRefs(summaryFile)); nsCString leafName; summaryFile->GetNativeLeafName(leafName); nsCAutoString dbName(leafName); path->GetNativeLeafName(leafName); // close down the temp file stream; preparing for deleting the old folder // and its database; then rename the temp folder and database m_fileStream->Flush(); m_fileStream->Close(); m_fileStream = nsnull; // make sure the new database is valid. // Close it so we can rename the .msf file. if (m_db) { m_db->ForceClosed(); m_db = nsnull; } nsCOMPtr <nsILocalFile> newSummaryFile; GetSummaryFileLocation(m_file, getter_AddRefs(newSummaryFile)); nsCOMPtr <nsIDBFolderInfo> transferInfo; m_folder->GetDBTransferInfo(getter_AddRefs(transferInfo)); // close down database of the original folder m_folder->ForceDBClosed(); nsCOMPtr<nsIFile> cloneFile; PRInt64 fileSize; m_file->Clone(getter_AddRefs(cloneFile)); cloneFile->GetFileSize(&fileSize); bool tempFileRightSize = (fileSize == m_totalMsgSize); NS_ASSERTION(tempFileRightSize, "temp file not of expected size in compact"); bool folderRenameSucceeded = false; bool msfRenameSucceeded = false; if (tempFileRightSize) { bool summaryFileExists; // remove the old folder and database rv = summaryFile->Remove(false); summaryFile->Exists(&summaryFileExists); if (NS_SUCCEEDED(rv) && !summaryFileExists) { bool folderPathExists; rv = folderPath->Remove(false); folderPath->Exists(&folderPathExists); if (NS_SUCCEEDED(rv) && !folderPathExists) { // rename the copied folder and database to be the original folder and // database rv = m_file->MoveToNative((nsIFile *) nsnull, leafName); NS_ASSERTION(NS_SUCCEEDED(rv), "error renaming compacted folder"); if (NS_SUCCEEDED(rv)) { folderRenameSucceeded = true; rv = newSummaryFile->MoveToNative((nsIFile *) nsnull, dbName); NS_ASSERTION(NS_SUCCEEDED(rv), "error renaming compacted folder's db"); msfRenameSucceeded = NS_SUCCEEDED(rv); } } } NS_ASSERTION(msfRenameSucceeded && folderRenameSucceeded, "rename failed in compact"); } if (!folderRenameSucceeded) m_file->Remove(false); if (!msfRenameSucceeded) newSummaryFile->Remove(false); rv = ReleaseFolderLock(); NS_ASSERTION(NS_SUCCEEDED(rv),"folder lock not released successfully"); if (msfRenameSucceeded && folderRenameSucceeded) { nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = msgDBService->OpenFolderDB(m_folder, true, getter_AddRefs(m_db)); m_db->SetSummaryValid(true); m_folder->SetDBTransferInfo(transferInfo); nsCOMPtr<nsIDBFolderInfo> dbFolderInfo; m_db->GetDBFolderInfo(getter_AddRefs(dbFolderInfo)); // since we're transferring info from the old db, we need to reset the expunged bytes, // and set the summary valid again. if(dbFolderInfo) dbFolderInfo->SetExpungedBytes(0); } if (m_db) m_db->Close(true); m_db = nsnull; // Notify that compaction of the folder is completed. nsCOMPtr<nsIMsgFolderNotificationService> notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID)); if (notifier) notifier->NotifyItemEvent(m_folder, NS_LITERAL_CSTRING("FolderCompactFinish"), nsnull); m_folder->NotifyCompactCompleted(); if (m_compactAll) rv = CompactNextFolder(); else CompactCompleted(NS_OK); return rv; }
nsresult nsFolderCompactState::FinishCompact() { NS_ENSURE_TRUE(m_folder, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(m_file, NS_ERROR_NOT_INITIALIZED); // All okay time to finish up the compact process nsCOMPtr<nsIFile> path; nsCOMPtr<nsIDBFolderInfo> folderInfo; // get leaf name and database name of the folder nsresult rv = m_folder->GetFilePath(getter_AddRefs(path)); nsCOMPtr <nsIFile> folderPath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = folderPath->InitWithFile(path); NS_ENSURE_SUCCESS(rv, rv); // need to make sure we put the .msf file in the same directory // as the original mailbox, so resolve symlinks. folderPath->SetFollowLinks(true); nsCOMPtr <nsIFile> oldSummaryFile; rv = GetSummaryFileLocation(folderPath, getter_AddRefs(oldSummaryFile)); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString dbName; oldSummaryFile->GetNativeLeafName(dbName); nsAutoCString folderName; path->GetNativeLeafName(folderName); // close down the temp file stream; preparing for deleting the old folder // and its database; then rename the temp folder and database if (m_fileStream) { m_fileStream->Flush(); m_fileStream->Close(); m_fileStream = nullptr; } // make sure the new database is valid. // Close it so we can rename the .msf file. if (m_db) { m_db->ForceClosed(); m_db = nullptr; } nsCOMPtr <nsIFile> newSummaryFile; rv = GetSummaryFileLocation(m_file, getter_AddRefs(newSummaryFile)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr <nsIDBFolderInfo> transferInfo; m_folder->GetDBTransferInfo(getter_AddRefs(transferInfo)); // close down database of the original folder m_folder->ForceDBClosed(); nsCOMPtr<nsIFile> cloneFile; int64_t fileSize; rv = m_file->Clone(getter_AddRefs(cloneFile)); if (NS_SUCCEEDED(rv)) rv = cloneFile->GetFileSize(&fileSize); bool tempFileRightSize = (fileSize == m_totalMsgSize); NS_WARN_IF_FALSE(tempFileRightSize, "temp file not of expected size in compact"); bool folderRenameSucceeded = false; bool msfRenameSucceeded = false; if (NS_SUCCEEDED(rv) && tempFileRightSize) { // First we're going to try and move the old summary file out the way. // We don't delete it yet, as we want to keep the files in sync. nsCOMPtr<nsIFile> tempSummaryFile; rv = oldSummaryFile->Clone(getter_AddRefs(tempSummaryFile)); if (NS_SUCCEEDED(rv)) rv = tempSummaryFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); nsAutoCString tempSummaryFileName; if (NS_SUCCEEDED(rv)) rv = tempSummaryFile->GetNativeLeafName(tempSummaryFileName); if (NS_SUCCEEDED(rv)) rv = oldSummaryFile->MoveToNative((nsIFile*) nullptr, tempSummaryFileName); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "error moving compacted folder's db out of the way"); if (NS_SUCCEEDED(rv)) { // Now we've successfully moved the summary file out the way, try moving // the newly compacted message file over the old one. rv = m_file->MoveToNative((nsIFile *) nullptr, folderName); folderRenameSucceeded = NS_SUCCEEDED(rv); NS_WARN_IF_FALSE(folderRenameSucceeded, "error renaming compacted folder"); if (folderRenameSucceeded) { // That worked, so land the new summary file in the right place. nsCOMPtr<nsIFile> renamedCompactedSummaryFile; newSummaryFile->Clone(getter_AddRefs(renamedCompactedSummaryFile)); if (renamedCompactedSummaryFile) { rv = renamedCompactedSummaryFile->MoveToNative((nsIFile *) nullptr, dbName); msfRenameSucceeded = NS_SUCCEEDED(rv); } NS_WARN_IF_FALSE(msfRenameSucceeded, "error renaming compacted folder's db"); } if (!msfRenameSucceeded) { // Do our best to put the summary file back to where it was rv = tempSummaryFile->MoveToNative((nsIFile*) nullptr, dbName); if (NS_SUCCEEDED(rv)) tempSummaryFile = nullptr; // flagging that a renamed db no longer exists else NS_WARNING("error restoring uncompacted folder's db"); } } // We don't want any temporarily renamed summary file to lie around if (tempSummaryFile) tempSummaryFile->Remove(false); } NS_WARN_IF_FALSE(msfRenameSucceeded, "compact failed"); rv = ReleaseFolderLock(); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),"folder lock not released successfully"); // Cleanup of nstmp-named compacted files if failure if (!folderRenameSucceeded) { // remove the abandoned compacted version with the wrong name m_file->Remove(false); } if (!msfRenameSucceeded) { // remove the abandoned compacted summary file newSummaryFile->Remove(false); } if (msfRenameSucceeded) { // Transfer local db information from transferInfo nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = msgDBService->OpenFolderDB(m_folder, true, getter_AddRefs(m_db)); NS_ENSURE_TRUE(m_db, NS_FAILED(rv) ? rv : NS_ERROR_FAILURE); m_db->SetSummaryValid(true); m_folder->SetDBTransferInfo(transferInfo); // since we're transferring info from the old db, we need to reset the expunged bytes nsCOMPtr<nsIDBFolderInfo> dbFolderInfo; m_db->GetDBFolderInfo(getter_AddRefs(dbFolderInfo)); if(dbFolderInfo) dbFolderInfo->SetExpungedBytes(0); } if (m_db) m_db->Close(true); m_db = nullptr; // Notify that compaction of the folder is completed. nsCOMPtr<nsIMsgFolderNotificationService> notifier(do_GetService(NS_MSGNOTIFICATIONSERVICE_CONTRACTID)); if (notifier) notifier->NotifyItemEvent(m_folder, NS_LITERAL_CSTRING("FolderCompactFinish"), nullptr); m_folder->NotifyCompactCompleted(); if (m_compactAll) rv = CompactNextFolder(); else CompactCompleted(NS_OK); return rv; }