// 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;
}
syntax highlighted by Code2HTML, v. 0.9.1