diff --git a/mailnews/base/src/nsMsgFolderCompactor.cpp b/mailnews/base/src/nsMsgFolderCompactor.cpp index 211ce6752d..6b399b7954 100644 --- a/mailnews/base/src/nsMsgFolderCompactor.cpp +++ b/mailnews/base/src/nsMsgFolderCompactor.cpp @@ -195,8 +195,8 @@ nsFolderCompactState::Compact(nsIMsgFolder *folder, bool aOfflineStore, } else { - bool valid; - rv = db->GetSummaryValid(&valid); + bool valid; + rv = db->GetSummaryValid(&valid); if (!valid) //we are probably parsing the folder because we selected it. { folder->NotifyCompactCompleted(); @@ -213,81 +213,95 @@ nsFolderCompactState::Compact(nsIMsgFolder *folder, bool aOfflineStore, NS_ENSURE_SUCCESS(rv, rv); } - rv = folder->GetFilePath(getter_AddRefs(path)); - NS_ENSURE_SUCCESS(rv, rv); + rv = folder->GetFilePath(getter_AddRefs(path)); + NS_ENSURE_SUCCESS(rv, rv); - int64_t expunged; - folder->GetExpungedBytes(&expunged); + do { + bool exists = false; + rv = path->Exists(&exists); + if (!exists) { + // No need to compact if the local file does not exist. + // Can happen e.g. on IMAP when the folder is not marked for offline use. + break; + } - bool abortCompactFolder = false; - int64_t diskSize; - rv = folder->GetSizeOnDisk(&diskSize); - NS_ENSURE_SUCCESS(rv, rv); + int64_t expunged = 0; + folder->GetExpungedBytes(&expunged); + if (expunged == 0) { + // No need to compact if nothing would be expunged. + break; + } - int64_t diskFree; - rv = path->GetDiskSpaceAvailable(&diskFree); - NS_ENSURE_SUCCESS(rv, rv); + int64_t diskSize; + rv = folder->GetSizeOnDisk(&diskSize); + NS_ENSURE_SUCCESS(rv, rv); - // Let's try to not even start compact if there is really low free space. - // It may still fail later as we do not know how big exactly the folder DB will - // end up being. - // The DB already doesn't contain references to messages that are already deleted. - // So theoretically it shouldn't shrink with compact. But in practice, - // the automatic shrinking of the DB may still have not yet happened. - // So we cap the final size at 1KB per message. - db->Commit(nsMsgDBCommitType::kCompressCommit); + int64_t diskFree; + rv = path->GetDiskSpaceAvailable(&diskFree); + if (NS_FAILED(rv)) { + // If GetDiskSpaceAvailable() failed, better bail out fast. + if (rv != NS_ERROR_NOT_IMPLEMENTED) + return rv; + // Some platforms do not have GetDiskSpaceAvailable implemented. + // In that case skip the preventive free space analysis and let it + // fail in compact later if space actually wasn't available. + } else { + // Let's try to not even start compact if there is really low free space. + // It may still fail later as we do not know how big exactly the folder DB will + // end up being. + // The DB already doesn't contain references to messages that are already deleted. + // So theoretically it shouldn't shrink with compact. But in practice, + // the automatic shrinking of the DB may still have not yet happened. + // So we cap the final size at 1KB per message. + db->Commit(nsMsgDBCommitType::kCompressCommit); - int64_t dbSize; - rv = db->GetDatabaseSize(&dbSize); - NS_ENSURE_SUCCESS(rv, rv); + int64_t dbSize; + rv = db->GetDatabaseSize(&dbSize); + NS_ENSURE_SUCCESS(rv, rv); - int32_t totalMsgs; - rv = folder->GetTotalMessages(false, &totalMsgs); - NS_ENSURE_SUCCESS(rv, rv); - int64_t expectedDBSize = std::min(dbSize, totalMsgs * 1024); - if (diskFree < diskSize - expunged + expectedDBSize) - { - if (!m_alreadyWarnedDiskSpace) - { - folder->ThrowAlertMsg("compactFolderInsufficientSpace", m_window); - m_alreadyWarnedDiskSpace = true; - } - abortCompactFolder = true; - } + int32_t totalMsgs; + rv = folder->GetTotalMessages(false, &totalMsgs); + NS_ENSURE_SUCCESS(rv, rv); + int64_t expectedDBSize = std::min(dbSize, ((int64_t)totalMsgs) * 1024); + if (diskFree < diskSize - expunged + expectedDBSize) + { + if (!m_alreadyWarnedDiskSpace) + { + folder->ThrowAlertMsg("compactFolderInsufficientSpace", m_window); + m_alreadyWarnedDiskSpace = true; + } + break; + } + } - if (!abortCompactFolder) - { - rv = folder->GetBaseMessageURI(baseMessageURI); - NS_ENSURE_SUCCESS(rv, rv); + rv = folder->GetBaseMessageURI(baseMessageURI); + NS_ENSURE_SUCCESS(rv, rv); - rv = Init(folder, baseMessageURI.get(), db, path, m_window); - NS_ENSURE_SUCCESS(rv, rv); + rv = Init(folder, baseMessageURI.get(), db, path, m_window); + NS_ENSURE_SUCCESS(rv, rv); - bool isLocked; - m_folder->GetLocked(&isLocked); - if (isLocked) - { - m_folder->NotifyCompactCompleted(); - CleanupTempFilesAfterError(); - m_folder->ThrowAlertMsg("compactFolderDeniedLock", m_window); - abortCompactFolder = true; - } - } + bool isLocked = true; + m_folder->GetLocked(&isLocked); + if (isLocked) + { + CleanupTempFilesAfterError(); + m_folder->ThrowAlertMsg("compactFolderDeniedLock", m_window); + break; + } - if (!abortCompactFolder) - { - nsCOMPtr supports = do_QueryInterface(static_cast(this)); - m_folder->AcquireSemaphore(supports); - m_totalExpungedBytes += expunged; - return StartCompacting(); - } - else - { - if (m_compactAll) - return CompactNextFolder(); - else - return NS_OK; - } + // If we got here start the real compacting. + nsCOMPtr supports = do_QueryInterface(static_cast(this)); + m_folder->AcquireSemaphore(supports); + m_totalExpungedBytes += expunged; + return StartCompacting(); + + } while(false); // block for easy skipping the compaction using 'break' + + folder->NotifyCompactCompleted(); + if (m_compactAll) + return CompactNextFolder(); + else + return NS_OK; } nsresult nsFolderCompactState::ShowStatusMsg(const nsString& aMsg) diff --git a/mailnews/local/src/nsMsgLocalStoreUtils.cpp b/mailnews/local/src/nsMsgLocalStoreUtils.cpp index 58cede6709..ef790dd82f 100644 --- a/mailnews/local/src/nsMsgLocalStoreUtils.cpp +++ b/mailnews/local/src/nsMsgLocalStoreUtils.cpp @@ -310,17 +310,20 @@ nsMsgLocalStoreUtils::DiskSpaceAvailableInStore(nsIFile *aFile, uint64_t aSpaceR // sector sizes, allocation blocks, etc. The space "available" may be greater // than the actual space usable. return ((aSpaceRequested + EXTRA_SAFETY_SPACE) < (uint64_t) diskFree); - } else { - // The call to GetDiskSpaceAvailable FAILED! + } else if (rv == NS_ERROR_NOT_IMPLEMENTED) { + // The call to GetDiskSpaceAvailable is not implemented! // This will happen on certain platforms where GetDiskSpaceAvailable // is not implemented. Since people on those platforms still need // to download mail, we will simply bypass the disk-space check. // // We'll leave a debug message to warn people. #ifdef DEBUG - printf("Call to GetDiskSpaceAvailable FAILED! \n"); + printf("Call to GetDiskSpaceAvailable FAILED because it is not implemented!\n"); #endif return true; + } else { + printf("Call to GetDiskSpaceAvailable FAILED!\n"); + return false; } }