diff options
Diffstat (limited to 'lib/backupstore/BackupStoreCheck2.cpp')
-rw-r--r-- | lib/backupstore/BackupStoreCheck2.cpp | 879 |
1 files changed, 879 insertions, 0 deletions
diff --git a/lib/backupstore/BackupStoreCheck2.cpp b/lib/backupstore/BackupStoreCheck2.cpp new file mode 100644 index 00000000..38e8bf92 --- /dev/null +++ b/lib/backupstore/BackupStoreCheck2.cpp @@ -0,0 +1,879 @@ +// distribution boxbackup-0.10 (svn version: 494) +// +// Copyright (c) 2003 - 2006 +// Ben Summers and contributors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. All use of this software and associated advertising materials must +// display the following acknowledgment: +// This product includes software developed by Ben Summers. +// 4. The names of the Authors may not be used to endorse or promote +// products derived from this software without specific prior written +// permission. +// +// [Where legally impermissible the Authors do not disclaim liability for +// direct physical injury or death caused solely by defects in the software +// unless it is modified by a third party.] +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// +// +// -------------------------------------------------------------------------- +// +// File +// Name: BackupStoreCheck2.cpp +// Purpose: More backup store checking +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- + +#include "Box.h" + +#include <stdio.h> +#include <string.h> + +#include "BackupStoreCheck.h" +#include "StoreStructure.h" +#include "RaidFileRead.h" +#include "RaidFileWrite.h" +#include "autogen_BackupStoreException.h" +#include "BackupStoreObjectMagic.h" +#include "BackupStoreFile.h" +#include "BackupStoreFileWire.h" +#include "BackupStoreDirectory.h" +#include "BackupStoreConstants.h" +#include "BackupStoreInfo.h" + +#include "MemLeakFindOn.h" + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::CheckRoot() +// Purpose: Check the root directory exists. +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +void BackupStoreCheck::CheckRoot() +{ + int32_t index = 0; + IDBlock *pblock = LookupID(BACKUPSTORE_ROOT_DIRECTORY_ID, index); + + if(pblock != 0) + { + // Found it. Which is lucky. Mark it as contained. + SetFlags(pblock, index, Flags_IsContained); + } + else + { + ::printf("Root directory doesn't exist\n"); + + ++mNumberErrorsFound; + + if(mFixErrors) + { + // Create a new root directory + CreateBlankDirectory(BACKUPSTORE_ROOT_DIRECTORY_ID, BACKUPSTORE_ROOT_DIRECTORY_ID); + } + } +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::CreateBlankDirectory(int64_t, int64_t) +// Purpose: Creates a blank directory +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +void BackupStoreCheck::CreateBlankDirectory(int64_t DirectoryID, int64_t ContainingDirID) +{ + if(!mFixErrors) + { + // Don't do anything if we're not supposed to fix errors + return; + } + + BackupStoreDirectory dir(DirectoryID, ContainingDirID); + + // Serialise to disc + std::string filename; + StoreStructure::MakeObjectFilename(DirectoryID, mStoreRoot, mDiscSetNumber, filename, true /* make sure the dir exists */); + RaidFileWrite obj(mDiscSetNumber, filename); + obj.Open(false /* don't allow overwriting */); + dir.WriteToStream(obj); + int64_t size = obj.GetDiscUsageInBlocks(); + obj.Commit(true /* convert to raid now */); + + // Record the fact we've done this + mDirsAdded.insert(DirectoryID); + + // Add to sizes + mBlocksUsed += size; + mBlocksInDirectories += size; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::CheckUnattachedObjects() +// Purpose: Check for objects which aren't attached to anything +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +void BackupStoreCheck::CheckUnattachedObjects() +{ + // Scan all objects, finding ones which have no container + for(Info_t::const_iterator i(mInfo.begin()); i != mInfo.end(); ++i) + { + IDBlock *pblock = i->second; + int32_t bentries = (pblock == mpInfoLastBlock)?mInfoLastBlockEntries:BACKUPSTORECHECK_BLOCK_SIZE; + + for(int e = 0; e < bentries; ++e) + { + uint8_t flags = GetFlags(pblock, e); + if((flags & Flags_IsContained) == 0) + { + // Unattached object... + ::printf("Object %llx is unattached.\n", pblock->mID[e]); + ++mNumberErrorsFound; + + // What's to be done? + int64_t putIntoDirectoryID = 0; + + if((flags & Flags_IsDir) == Flags_IsDir) + { + // Directory. Just put into lost and found. + putIntoDirectoryID = GetLostAndFoundDirID(); + } + else + { + // File. Only attempt to attach it somewhere if it isn't a patch + { + int64_t diffFromObjectID = 0; + std::string filename; + StoreStructure::MakeObjectFilename(pblock->mID[e], mStoreRoot, mDiscSetNumber, filename, false /* don't attempt to make sure the dir exists */); + // The easiest way to do this is to verify it again. Not such a bad penalty, because + // this really shouldn't be done very often. + { + std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(mDiscSetNumber, filename)); + BackupStoreFile::VerifyEncodedFileFormat(*file, &diffFromObjectID); + } + + // If not zero, then it depends on another file, which may or may not be available. + // Just delete it to be safe. + if(diffFromObjectID != 0) + { + ::printf("Object %llx is unattached, and is a patch. Deleting, cannot reliably recover.\n", pblock->mID[e]); + + // Delete this object instead + if(mFixErrors) + { + RaidFileWrite del(mDiscSetNumber, filename); + del.Delete(); + } + + // Move on to next item + continue; + } + } + + // Files contain their original filename, so perhaps the orginal directory still exists, + // or we can infer the existance of a directory? + // Look for a matching entry in the mDirsWhichContainLostDirs map. + // Can't do this with a directory, because the name just wouldn't be known, which is + // pretty useless as bbackupd would just delete it. So better to put it in lost+found + // where the admin can do something about it. + int32_t dirindex; + IDBlock *pdirblock = LookupID(pblock->mContainer[e], dirindex); + if(pdirblock != 0) + { + // Something with that ID has been found. Is it a directory? + if(GetFlags(pdirblock, dirindex) & Flags_IsDir) + { + // Directory exists, add to that one + putIntoDirectoryID = pblock->mContainer[e]; + } + else + { + // Not a directory. Use lost and found dir + putIntoDirectoryID = GetLostAndFoundDirID(); + } + } + else if(mDirsAdded.find(pblock->mContainer[e]) != mDirsAdded.end() + || TryToRecreateDirectory(pblock->mContainer[e])) + { + // The directory reappeared, or was created somehow elsewhere + putIntoDirectoryID = pblock->mContainer[e]; + } + else + { + putIntoDirectoryID = GetLostAndFoundDirID(); + } + } + ASSERT(putIntoDirectoryID != 0); + + // Add it to the directory + InsertObjectIntoDirectory(pblock->mID[e], putIntoDirectoryID, + ((flags & Flags_IsDir) == Flags_IsDir)); + } + } + } +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::TryToRecreateDirectory(int64_t) +// Purpose: Recreate a missing directory +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +bool BackupStoreCheck::TryToRecreateDirectory(int64_t MissingDirectoryID) +{ + // During the directory checking phase, a map of "missing directory" to + // containing directory was built. If we can find it here, then it's + // something which can be recreated! + std::map<BackupStoreCheck_ID_t, BackupStoreCheck_ID_t>::iterator missing( + mDirsWhichContainLostDirs.find(MissingDirectoryID)); + if(missing == mDirsWhichContainLostDirs.end()) + { + // Not a missing directory, can't recreate. + return false; + } + + // Can recreate this! Wooo! + if(!mFixErrors) + { + ::printf("Missing directory %llx could be recreated\n", MissingDirectoryID); + mDirsAdded.insert(MissingDirectoryID); + return true; + } + ::printf("Recreating missing directory %llx\n", MissingDirectoryID); + + // Create a blank directory + BackupStoreDirectory dir(MissingDirectoryID, missing->second /* containing dir ID */); + // Note that this directory already contains a directory entry pointing to + // this dir, so it doesn't have to be added. + + // Serialise to disc + std::string filename; + StoreStructure::MakeObjectFilename(MissingDirectoryID, mStoreRoot, mDiscSetNumber, filename, true /* make sure the dir exists */); + RaidFileWrite root(mDiscSetNumber, filename); + root.Open(false /* don't allow overwriting */); + dir.WriteToStream(root); + root.Commit(true /* convert to raid now */); + + // Record the fact we've done this + mDirsAdded.insert(MissingDirectoryID); + + // Remove the entry from the map, so this doesn't happen again + mDirsWhichContainLostDirs.erase(missing); + + return true; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::GetLostAndFoundDirID() +// Purpose: Returns the ID of the lost and found directory, creating it if necessary +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +int64_t BackupStoreCheck::GetLostAndFoundDirID() +{ + // Already allocated it? + if(mLostAndFoundDirectoryID != 0) + { + return mLostAndFoundDirectoryID; + } + + if(!mFixErrors) + { + // The result will never be used anyway if errors aren't being fixed + return 1; + } + + // Load up the root directory + BackupStoreDirectory dir; + std::string filename; + StoreStructure::MakeObjectFilename(BACKUPSTORE_ROOT_DIRECTORY_ID, mStoreRoot, mDiscSetNumber, filename, false /* don't make sure the dir exists */); + { + std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(mDiscSetNumber, filename)); + dir.ReadFromStream(*file, IOStream::TimeOutInfinite); + } + + // Find a suitable name + BackupStoreFilename lostAndFound; + int n = 0; + while(true) + { + char name[32]; + ::sprintf(name, "lost+found%d", n++); + lostAndFound.SetAsClearFilename(name); + if(!dir.NameInUse(lostAndFound)) + { + // Found a name which can be used + ::printf("Lost and found dir has name %s\n", name); + break; + } + } + + // Allocate an ID + int64_t id = mLastIDInInfo + 1; + + // Create a blank directory + CreateBlankDirectory(id, BACKUPSTORE_ROOT_DIRECTORY_ID); + + // Add an entry for it + dir.AddEntry(lostAndFound, 0, id, 0, BackupStoreDirectory::Entry::Flags_Dir, 0); + + // Write out root dir + RaidFileWrite root(mDiscSetNumber, filename); + root.Open(true /* allow overwriting */); + dir.WriteToStream(root); + root.Commit(true /* convert to raid now */); + + // Store + mLostAndFoundDirectoryID = id; + + // Tell caller + return mLostAndFoundDirectoryID; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::InsertObjectIntoDirectory(int64_t, int64_t, bool) +// Purpose: +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +void BackupStoreCheck::InsertObjectIntoDirectory(int64_t ObjectID, int64_t DirectoryID, bool IsDirectory) +{ + if(!mFixErrors) + { + // Don't do anything if we're not supposed to fix errors + return; + } + + // Data for the object + BackupStoreFilename objectStoreFilename; + int64_t modTime = 100; // something which isn't zero or a special time + int32_t sizeInBlocks = 0; // suitable for directories + + if(IsDirectory) + { + // Directory -- simply generate a name for it. + char name[32]; + ::sprintf(name, "dir%08x", mLostDirNameSerial++); + objectStoreFilename.SetAsClearFilename(name); + } + else + { + // Files require a little more work... + // Open file + std::string fileFilename; + StoreStructure::MakeObjectFilename(ObjectID, mStoreRoot, mDiscSetNumber, fileFilename, false /* don't make sure the dir exists */); + std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(mDiscSetNumber, fileFilename)); + // Fill in size information + sizeInBlocks = file->GetDiscUsageInBlocks(); + // Read in header + file_StreamFormat hdr; + if(file->Read(&hdr, sizeof(hdr)) != sizeof(hdr) || (ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1 +#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE + && ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V0 +#endif + )) + { + // This should never happen, everything has been checked before. + THROW_EXCEPTION(BackupStoreException, Internal) + } + // This tells us nice things + modTime = box_ntoh64(hdr.mModificationTime); + // And the filename comes next + objectStoreFilename.ReadFromStream(*file, IOStream::TimeOutInfinite); + } + + // Directory object + BackupStoreDirectory dir; + + // Generate filename + std::string filename; + StoreStructure::MakeObjectFilename(DirectoryID, mStoreRoot, mDiscSetNumber, filename, false /* don't make sure the dir exists */); + + // Read it in + { + std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(mDiscSetNumber, filename)); + dir.ReadFromStream(*file, IOStream::TimeOutInfinite); + } + + // Add a new entry in an appropraite place + dir.AddUnattactedObject(objectStoreFilename, modTime, ObjectID, sizeInBlocks, + IsDirectory?(BackupStoreDirectory::Entry::Flags_Dir):(BackupStoreDirectory::Entry::Flags_File)); + + // Fix any flags which have been broken, which there's a good change of going + dir.CheckAndFix(); + + // Write it out + if(mFixErrors) + { + RaidFileWrite root(mDiscSetNumber, filename); + root.Open(true /* allow overwriting */); + dir.WriteToStream(root); + root.Commit(true /* convert to raid now */); + } +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::FixDirsWithWrongContainerID() +// Purpose: Rewrites container IDs where required +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +void BackupStoreCheck::FixDirsWithWrongContainerID() +{ + if(!mFixErrors) + { + // Don't do anything if we're not supposed to fix errors + return; + } + + // Run through things which need fixing + for(std::vector<BackupStoreCheck_ID_t>::iterator i(mDirsWithWrongContainerID.begin()); + i != mDirsWithWrongContainerID.end(); ++i) + { + int32_t index = 0; + IDBlock *pblock = LookupID(*i, index); + if(pblock == 0) continue; + + // Load in + BackupStoreDirectory dir; + std::string filename; + StoreStructure::MakeObjectFilename(*i, mStoreRoot, mDiscSetNumber, filename, false /* don't make sure the dir exists */); + { + std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(mDiscSetNumber, filename)); + dir.ReadFromStream(*file, IOStream::TimeOutInfinite); + } + + // Adjust container ID + dir.SetContainerID(pblock->mContainer[index]); + + // Write it out + RaidFileWrite root(mDiscSetNumber, filename); + root.Open(true /* allow overwriting */); + dir.WriteToStream(root); + root.Commit(true /* convert to raid now */); + } +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::FixDirsWithLostDirs() +// Purpose: Fix directories +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +void BackupStoreCheck::FixDirsWithLostDirs() +{ + if(!mFixErrors) + { + // Don't do anything if we're not supposed to fix errors + return; + } + + // Run through things which need fixing + for(std::map<BackupStoreCheck_ID_t, BackupStoreCheck_ID_t>::iterator i(mDirsWhichContainLostDirs.begin()); + i != mDirsWhichContainLostDirs.end(); ++i) + { + int32_t index = 0; + IDBlock *pblock = LookupID(i->second, index); + if(pblock == 0) continue; + + // Load in + BackupStoreDirectory dir; + std::string filename; + StoreStructure::MakeObjectFilename(i->second, mStoreRoot, mDiscSetNumber, filename, false /* don't make sure the dir exists */); + { + std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(mDiscSetNumber, filename)); + dir.ReadFromStream(*file, IOStream::TimeOutInfinite); + } + + // Delete the dodgy entry + dir.DeleteEntry(i->first); + + // Fix it up + dir.CheckAndFix(); + + // Write it out + RaidFileWrite root(mDiscSetNumber, filename); + root.Open(true /* allow overwriting */); + dir.WriteToStream(root); + root.Commit(true /* convert to raid now */); + } +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreCheck::WriteNewStoreInfo() +// Purpose: Regenerate store info +// Created: 23/4/04 +// +// -------------------------------------------------------------------------- +void BackupStoreCheck::WriteNewStoreInfo() +{ + // Attempt to load the existing store info file + std::auto_ptr<BackupStoreInfo> poldInfo; + try + { + poldInfo.reset(BackupStoreInfo::Load(mAccountID, mStoreRoot, mDiscSetNumber, true /* read only */).release()); + } + catch(...) + { + ::printf("Load of existing store info failed, regenerating.\n"); + ++mNumberErrorsFound; + } + + // Minimum soft and hard limits + int64_t minSoft = ((mBlocksUsed * 11) / 10) + 1024; + int64_t minHard = ((minSoft * 11) / 10) + 1024; + + // Need to do anything? + if(poldInfo.get() != 0 && mNumberErrorsFound == 0 && poldInfo->GetAccountID() == mAccountID) + { + // Leave the store info as it is, no need to alter it because nothing really changed, + // and the only essential thing was that the account ID was correct, which is was. + return; + } + + // NOTE: We will always build a new store info, so the client store marker gets changed. + + // Work out the new limits + int64_t softLimit = minSoft; + int64_t hardLimit = minHard; + if(poldInfo.get() != 0 && poldInfo->GetBlocksSoftLimit() > minSoft) + { + softLimit = poldInfo->GetBlocksSoftLimit(); + } + else + { + ::printf("NOTE: Soft limit for account changed to ensure housekeeping doesn't delete files on next run\n"); + } + if(poldInfo.get() != 0 && poldInfo->GetBlocksHardLimit() > minHard) + { + hardLimit = poldInfo->GetBlocksHardLimit(); + } + else + { + ::printf("NOTE: Hard limit for account changed to ensure housekeeping doesn't delete files on next run\n"); + } + + // Object ID + int64_t lastObjID = mLastIDInInfo; + if(mLostAndFoundDirectoryID != 0) + { + mLastIDInInfo++; + } + + // Build a new store info + std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::CreateForRegeneration( + mAccountID, + mStoreRoot, + mDiscSetNumber, + lastObjID, + mBlocksUsed, + mBlocksInOldFiles, + mBlocksInDeletedFiles, + mBlocksInDirectories, + softLimit, + hardLimit)); + + // Save to disc? + if(mFixErrors) + { + info->Save(); + ::printf("New store info file written successfully.\n"); + } +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreDirectory::CheckAndFix() +// Purpose: Check the directory for obvious logical problems, and fix them. +// Return true if the directory was changed. +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +bool BackupStoreDirectory::CheckAndFix() +{ + bool changed = false; + + // Check that if a file depends on a new version, that version is in this directory + { + std::vector<Entry*>::iterator i(mEntries.begin()); + for(; i != mEntries.end(); ++i) + { + int64_t dependsNewer = (*i)->GetDependsNewer(); + if(dependsNewer != 0) + { + BackupStoreDirectory::Entry *newerEn = FindEntryByID(dependsNewer); + if(newerEn == 0) + { + // Depends on something, but it isn't there. + TRACE2("Entry id %llx removed because depends on newer version %llx which doesn't exist\n", (*i)->GetObjectID(), dependsNewer); + + // Remove + delete *i; + mEntries.erase(i); + + // Start again at the beginning of the vector, the iterator is now invalid + i = mEntries.begin(); + + // Mark as changed + changed = true; + } + else + { + // Check that newerEn has it marked + if(newerEn->GetDependsOlder() != (*i)->GetObjectID()) + { + // Wrong entry + TRACE3("Entry id %llx, correcting DependsOlder to %llx, was %llx\n", dependsNewer, (*i)->GetObjectID(), newerEn->GetDependsOlder()); + newerEn->SetDependsOlder((*i)->GetObjectID()); + // Mark as changed + changed = true; + } + } + } + } + } + + // Check that if a file has a dependency marked, it exists, and remove it if it doesn't + { + std::vector<Entry*>::iterator i(mEntries.begin()); + for(; i != mEntries.end(); ++i) + { + int64_t dependsOlder = (*i)->GetDependsOlder(); + if(dependsOlder != 0 && FindEntryByID(dependsOlder) == 0) + { + // Has an older version marked, but this doesn't exist. Remove this mark + TRACE2("Entry id %llx was marked that %llx depended on it, which doesn't exist, dependency info cleaered\n", (*i)->GetObjectID(), dependsOlder); + + (*i)->SetDependsOlder(0); + + // Mark as changed + changed = true; + } + } + } + + bool ch = false; + do + { + // Reset change marker + ch = false; + + // Search backwards -- so see newer versions first + std::vector<Entry*>::iterator i(mEntries.end()); + if(i == mEntries.begin()) + { + // Directory is empty, stop now + return changed; // changed flag + } + + // Records of things seen + std::set<int64_t> idsEncountered; + std::set<BackupStoreFilename> filenamesEncountered; + + do + { + // Look at previous + --i; + + bool removeEntry = false; + if((*i) == 0) + { + TRACE0("Remove because null pointer found\n"); + removeEntry = true; + } + else + { + bool isDir = (((*i)->GetFlags() & Entry::Flags_Dir) == Entry::Flags_Dir); + + // Check mutually exclusive flags + if(isDir && (((*i)->GetFlags() & Entry::Flags_File) == Entry::Flags_File)) + { + // Bad! Unset the file flag + TRACE1("Entry %llx: File flag set when dir flag set\n", (*i)->GetObjectID()); + (*i)->RemoveFlags(Entry::Flags_File); + changed = true; + } + + // Check... + if(idsEncountered.find((*i)->GetObjectID()) != idsEncountered.end()) + { + // ID already seen, or type doesn't match + TRACE1("Entry %llx: Remove because ID already seen\n", (*i)->GetObjectID()); + removeEntry = true; + } + else + { + // Haven't already seen this ID, remember it + idsEncountered.insert((*i)->GetObjectID()); + + // Check to see if the name has already been encountered -- if not, then it + // needs to have the old version flag set + if(filenamesEncountered.find((*i)->GetName()) != filenamesEncountered.end()) + { + // Seen before -- check old version flag set + if(((*i)->GetFlags() & Entry::Flags_OldVersion) != Entry::Flags_OldVersion + && ((*i)->GetFlags() & Entry::Flags_Deleted) == 0) + { + // Not set, set it + TRACE1("Entry %llx: Set old flag\n", (*i)->GetObjectID()); + (*i)->AddFlags(Entry::Flags_OldVersion); + changed = true; + } + } + else + { + // Check old version flag NOT set + if(((*i)->GetFlags() & Entry::Flags_OldVersion) == Entry::Flags_OldVersion) + { + // Set, unset it + TRACE1("Entry %llx: Old flag unset\n", (*i)->GetObjectID()); + (*i)->RemoveFlags(Entry::Flags_OldVersion); + changed = true; + } + + // Remember filename + filenamesEncountered.insert((*i)->GetName()); + } + } + } + + if(removeEntry) + { + // Mark something as changed, in loop + ch = true; + + // Mark something as globally changed + changed = true; + + // erase the thing from the list + Entry *pentry = (*i); + mEntries.erase(i); + + // And delete the entry object + delete pentry; + + // Stop going around this loop, as the iterator is now invalid + break; + } + } while(i != mEntries.begin()); + + } while(ch != false); + + return changed; +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreDirectory::AddUnattactedObject(...) +// Purpose: Adds an object which is currently unattached. Assume that CheckAndFix() will be called afterwards. +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +void BackupStoreDirectory::AddUnattactedObject(const BackupStoreFilename &rName, + box_time_t ModificationTime, int64_t ObjectID, int64_t SizeInBlocks, int16_t Flags) +{ + Entry *pnew = new Entry(rName, ModificationTime, ObjectID, SizeInBlocks, Flags, + ModificationTime /* use as attr mod time too */); + try + { + // Want to order this just before the first object which has a higher ID, + // which is the place it's most likely to be correct. + std::vector<Entry*>::iterator i(mEntries.begin()); + for(; i != mEntries.end(); ++i) + { + if((*i)->GetObjectID() > ObjectID) + { + // Found a good place to insert it + break; + } + } + if(i == mEntries.end()) + { + mEntries.push_back(pnew); + } + else + { + mEntries.insert(i, 1 /* just the one copy */, pnew); + } + } + catch(...) + { + delete pnew; + throw; + } +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreDirectory::NameInUse(const BackupStoreFilename &) +// Purpose: Returns true if the name is currently in use in the directory +// Created: 22/4/04 +// +// -------------------------------------------------------------------------- +bool BackupStoreDirectory::NameInUse(const BackupStoreFilename &rName) +{ + for(std::vector<Entry*>::iterator i(mEntries.begin()); i != mEntries.end(); ++i) + { + if((*i)->GetName() == rName) + { + return true; + } + } + + return false; +} + + |