[Box Backup-dev] COMMIT r320 - in box/gary/boxbackup-0.09-mod: bin/bbackupd bin/bbstored lib/backupclient lib/common
boxbackup-dev@fluffy.co.uk
boxbackup-dev@fluffy.co.uk
Tue, 17 Jan 2006 22:27:29 +0000 (GMT)
Author: chris
Date: 2006-01-17 22:27:22 +0000 (Tue, 17 Jan 2006)
New Revision: 320
Added:
box/gary/boxbackup-0.09-mod/lib/common/Archive.h
Modified:
box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientContext.cpp
box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientContext.h
box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientDirectoryRecord.cpp
box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientDirectoryRecord.h
box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupDaemon.cpp
box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupDaemon.h
box/gary/boxbackup-0.09-mod/bin/bbstored/BackupCommands.cpp
box/gary/boxbackup-0.09-mod/bin/bbstored/backupprotocol.txt
box/gary/boxbackup-0.09-mod/lib/backupclient/BackupDaemonConfigVerify.cpp
box/gary/boxbackup-0.09-mod/lib/backupclient/BackupStoreFile.h
box/gary/boxbackup-0.09-mod/lib/backupclient/BackupStoreFileDiff.cpp
box/gary/boxbackup-0.09-mod/lib/common/Configuration.cpp
box/gary/boxbackup-0.09-mod/lib/common/Configuration.h
box/gary/boxbackup-0.09-mod/lib/common/ExcludeList.cpp
box/gary/boxbackup-0.09-mod/lib/common/ExcludeList.h
Log:
* boxbackup-0.09-mod
- Uploaded Gary's patches
Modified: box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientContext.cpp
===================================================================
--- box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientContext.cpp 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientContext.cpp 2006-01-17 22:27:22 UTC (rev 320)
@@ -49,6 +49,8 @@
#include "Box.h"
#include <syslog.h>
+#include <signal.h>
+#include <sys/time.h>
#include "BoxPortsAndFiles.h"
#include "BoxTime.h"
@@ -59,6 +61,7 @@
#include "BackupStoreException.h"
#include "BackupDaemon.h"
#include "autogen_BackupProtocolClient.h"
+#include "BackupStoreFile.h"
#include "MemLeakFindOn.h"
@@ -85,7 +88,8 @@
mpNewIDMap(0),
mStorageLimitExceeded(false),
mpExcludeFiles(0),
- mpExcludeDirs(0)
+ mpExcludeDirs(0),
+ mbIsManaged(false)
{
}
@@ -488,5 +492,171 @@
// Found
return true;
}
-
-
+
+//
+//
+//
+
+// maximum time to spend diffing
+static int sMaximumDiffTime = 10;
+// maximum time of SSL inactivity (keep-alive interval)
+static int sKeepAliveTime = 0;
+// total time elapsed to keep track of what is going on
+static time_t sTimeMgmtEpoch = 0;
+
+void BackupClientContext::SetMaximumDiffingTime(int iSeconds)
+{
+ sMaximumDiffTime = iSeconds < 0 ? 0 : iSeconds;
+ TRACE1("Set maximum diffing time to %d seconds\n", sMaximumDiffTime);
+}
+
+void BackupClientContext::SetKeepAliveTime(int iSeconds)
+{
+ sKeepAliveTime = iSeconds < 0 ? 0 : iSeconds;
+ TRACE1("Set keep-alive time to %d seconds\n", sKeepAliveTime);
+}
+
+static BackupClientContext* pThisCtxInst = NULL;
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static TimerSigHandler(int)
+// Purpose: Signal handler
+// Created: 19/3/04
+//
+// --------------------------------------------------------------------------
+void TimerSigHandler(int iUnused)
+{
+ ASSERT(pThisCtxInst);
+ ASSERT(sTimeMgmtEpoch > 0);
+
+ time_t tTotalRunIntvl = time(NULL) - sTimeMgmtEpoch;
+ if (sMaximumDiffTime > 0 && tTotalRunIntvl >= sMaximumDiffTime)
+ {
+ TRACE0("MaximumDiffingTime reached - suspending file diff\n");
+ BackupStoreFile::SuspendFileDiff();
+ }
+ else if (sKeepAliveTime > 0)
+ {
+ // well, we have only two sources of timer events...
+ TRACE0("KeepAliveTime reached - initiating keep-alive\n");
+ pThisCtxInst->DoKeepAlive();
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientContext::ManageDiffProcess()
+// Purpose: Initiates a file diff control timer
+// Created: 04/19/2005
+//
+// --------------------------------------------------------------------------
+void BackupClientContext::ManageDiffProcess()
+{
+ if (mbIsManaged || !mpConnection)
+ return;
+
+ ASSERT(pThisCtxInst == NULL);
+ ASSERT(sTimeMgmtEpoch == 0);
+
+#ifdef PLATFORM_CYGWIN
+ ::signal(SIGALRM, TimerSigHandler);
+#else
+ ::signal(SIGVTALRM, TimerSigHandler);
+#endif // PLATFORM_CYGWIN
+
+ struct itimerval timeout;
+ memset(&timeout, 0, sizeof(timeout));
+
+ //
+ //
+ //
+ if (sMaximumDiffTime <= 0 && sKeepAliveTime <= 0)
+ {
+ TRACE0("Diff control not requested - letting things run wild\n");
+ return;
+ }
+ else if (sMaximumDiffTime > 0 && sKeepAliveTime > 0)
+ {
+ timeout.it_value.tv_sec = sKeepAliveTime < sMaximumDiffTime ? sKeepAliveTime : sMaximumDiffTime;
+ timeout.it_interval.tv_sec = sKeepAliveTime < sMaximumDiffTime ? sKeepAliveTime : sMaximumDiffTime;
+ }
+ else
+ {
+ timeout.it_value.tv_sec = sKeepAliveTime > 0 ? sKeepAliveTime : sMaximumDiffTime;
+ timeout.it_interval.tv_sec = sKeepAliveTime > 0 ? sKeepAliveTime : sMaximumDiffTime;
+ }
+
+ // avoid race
+ pThisCtxInst = this;
+ sTimeMgmtEpoch = time(NULL);
+
+#ifdef PLATFORM_CYGWIN
+ if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0)
+#else
+ if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0)
+#endif // PLATFORM_CYGWIN
+ {
+ sTimeMgmtEpoch = 0;
+ pThisCtxInst = NULL;
+
+ TRACE0("WARNING: couldn't set file diff control timeout\n");
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ mbIsManaged = true;
+ TRACE0("Initiated timer for file diff control\n");
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientContext::UnManageDiffProcess()
+// Purpose: suspends file diff control timer
+// Created: 04/19/2005
+//
+// --------------------------------------------------------------------------
+void BackupClientContext::UnManageDiffProcess()
+{
+ if (!mbIsManaged /* don't test for active connection, just do it */)
+ return;
+
+ ASSERT(pThisCtxInst != NULL);
+
+ struct itimerval timeout;
+ memset(&timeout, 0, sizeof(timeout));
+
+#ifdef PLATFORM_CYGWIN
+ if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0)
+#else
+ if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0)
+#endif // PLATFORM_CYGWIN
+ {
+ TRACE0("WARNING: couldn't clear file diff control timeout\n");
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ mbIsManaged = false;
+ pThisCtxInst = NULL;
+ sTimeMgmtEpoch = 0;
+
+ TRACE0("Suspended timer for file diff control\n");
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientContext::DoKeepAlive()
+// Purpose: Does something inconsequential over the SSL link to keep it up
+// Created: 04/19/2005
+//
+// --------------------------------------------------------------------------
+void BackupClientContext::DoKeepAlive()
+{
+ if (!mpConnection)
+ return;
+
+ mpConnection->QueryGetIsAlive();
+}
Modified: box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientContext.h
===================================================================
--- box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientContext.h 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientContext.h 2006-01-17 22:27:22 UTC (rev 320)
@@ -172,7 +172,56 @@
bool FindFilename(int64_t ObjectID, int64_t ContainingDirectory, std::string &rPathOut, bool &rIsDirectoryOut,
bool &rIsCurrentVersionOut, box_time_t *pModTimeOnServer = 0, box_time_t *pAttributesHashOnServer = 0,
BackupStoreFilenameClear *pLeafname = 0); // not const as may connect to server
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::SetMaximumDiffingTime()
+ // Purpose: Sets the maximum time that will be spent diffing a file
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ static void SetMaximumDiffingTime(int iSeconds);
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::SetKeepAliveTime()
+ // Purpose: Sets the time interval for repetitive keep-alive operation
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ static void SetKeepAliveTime(int iSeconds);
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::ManageDiffProcess()
+ // Purpose: Initiates an SSL connection/session keep-alive process
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ void ManageDiffProcess();
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::UnManageDiffProcess()
+ // Purpose: Suspends an SSL connection/session keep-alive process
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ void UnManageDiffProcess();
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::DoKeepAlive()
+ // Purpose: Does something inconsequential over the SSL link to keep it up
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ void DoKeepAlive();
private:
BackupDaemon &mrDaemon;
TLSContext &mrTLSContext;
@@ -187,7 +236,9 @@
BackupClientInodeToIDMap *mpNewIDMap;
bool mStorageLimitExceeded;
ExcludeList *mpExcludeFiles;
- ExcludeList *mpExcludeDirs;
+ ExcludeList *mpExcludeDirs;
+
+ bool mbIsManaged;
};
Modified: box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientDirectoryRecord.cpp
===================================================================
--- box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientDirectoryRecord.cpp 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientDirectoryRecord.cpp 2006-01-17 22:27:22 UTC (rev 320)
@@ -1083,8 +1083,6 @@
}
}
-
-
// --------------------------------------------------------------------------
//
// Function
@@ -1118,15 +1116,24 @@
{
// Found an old version -- get the index
std::auto_ptr<IOStream> blockIndexStream(connection.ReceiveStream());
-
- // Diff the file
+
+ //
+ // Diff the file
+ //
+
+ rParams.mrContext.ManageDiffProcess();
+
bool isCompletelyDifferent = false;
std::auto_ptr<IOStream> patchStream(BackupStoreFile::EncodeFileDiff(rFilename.c_str(),
mObjectID, /* containing directory */
rStoreFilename, diffFromID, *blockIndexStream,
connection.GetTimeout(), 0 /* not interested in the modification time */, &isCompletelyDifferent));
-
- // Upload the patch to the store
+
+ rParams.mrContext.UnManageDiffProcess();
+
+ //
+ // Upload the patch to the store
+ //
std::auto_ptr<BackupProtocolClientSuccess> stored(connection.QueryStoreFile(mObjectID, ModificationTime,
AttributesHash, isCompletelyDifferent?(0):(diffFromID), rStoreFilename, *patchStream));
@@ -1151,7 +1158,9 @@
}
}
catch(BoxException &e)
- {
+ {
+ rParams.mrContext.UnManageDiffProcess();
+
if(e.GetType() == ConnectionException::ExceptionType && e.GetSubType() == ConnectionException::Protocol_UnexpectedReply)
{
// Check and see what error the protocol has -- as it might be an error...
@@ -1163,8 +1172,8 @@
// The hard limit was exceeded on the server, notify!
rParams.mrDaemon.NotifySysadmin(BackupDaemon::NotifyEvent_StoreFull);
}
- }
-
+ }
+
// Send the error on it's way
throw;
}
@@ -1233,5 +1242,147 @@
{
}
-
-
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientDirectoryRecord::Deserialize(Archive & rArchive)
+// Purpose: Deserializes this object instance from a stream of bytes, using an Archive abstraction.
+//
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+void BackupClientDirectoryRecord::Deserialize(Archive & rArchive)
+{
+ // Make deletion recursive
+ DeleteSubDirectories();
+
+ // Delete maps
+ if(mpPendingEntries != 0)
+ {
+ delete mpPendingEntries;
+ mpPendingEntries = 0;
+ }
+
+ //
+ //
+ //
+ rArchive >> mObjectID >> mSubDirName >> mInitialSyncDone >> mSyncDone;
+
+ //
+ //
+ //
+ int64_t iCount = 0;
+ rArchive.Get(iCount);
+
+ if (iCount != sizeof(mStateChecksum)/sizeof(mStateChecksum[0]))
+ {
+ // we have some kind of internal system representation change: throw for now
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+
+ for (int v = 0; v < iCount; v++)
+ /**** LOAD ****/ rArchive.Get(mStateChecksum[v]);
+
+ //
+ //
+ //
+ iCount = 0;
+ rArchive.Get(iCount);
+
+ if (iCount > 0)
+ {
+ /**** LOAD ****/ mpPendingEntries = new std::map<std::string, box_time_t>;
+ if (!mpPendingEntries)
+ throw std::bad_alloc();
+
+ for (int v = 0; v < iCount; v++)
+ {
+ std::string strItem;
+ box_time_t btItem;
+
+ rArchive >> strItem >> btItem;
+ (*mpPendingEntries)[strItem] = btItem;
+ }
+ }
+
+ //
+ //
+ //
+ iCount = 0;
+ rArchive.Get(iCount);
+
+ if (iCount > 0)
+ {
+ for (int v = 0; v < iCount; v++)
+ {
+ std::string strItem;
+ rArchive.Get(strItem);
+
+ BackupClientDirectoryRecord* pSubDirRecord = new BackupClientDirectoryRecord(0, ""); // will be deserialized anyway, give it id 0 for now
+ if (!pSubDirRecord)
+ throw std::bad_alloc();
+
+ /***** RECURSE *****/
+ pSubDirRecord->Deserialize(rArchive);
+ mSubDirectories[strItem] = pSubDirRecord;
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientDirectoryRecord::Serialize(Archive & rArchive)
+// Purpose: Serializes this object instance into a stream of bytes, using an Archive abstraction.
+//
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+void BackupClientDirectoryRecord::Serialize(Archive & rArchive) const
+{
+ //
+ //
+ //
+ rArchive << mObjectID << mSubDirName << mInitialSyncDone << mSyncDone;
+
+ //
+ //
+ //
+ int64_t iCount = 0;
+
+ iCount = sizeof(mStateChecksum)/sizeof(mStateChecksum[0]);
+ rArchive.Add(iCount); // add count to see if we have crossed build-level mods
+ for (int v = 0; v < iCount; v++)
+ rArchive.Add(mStateChecksum[v]);
+
+ //
+ //
+ //
+ if (!mpPendingEntries)
+ {
+ iCount = 0;
+ rArchive.Add(iCount);
+ }
+ else
+ {
+ iCount = mpPendingEntries->size();
+ rArchive.Add(iCount);
+
+ for (std::map<std::string, box_time_t>::const_iterator i = mpPendingEntries->begin(); i != mpPendingEntries->end(); i++)
+ rArchive << (*i).first << (*i).second;
+ }
+ //
+ //
+ //
+ iCount = mSubDirectories.size();
+ rArchive.Add(iCount);
+
+ for (std::map<std::string, BackupClientDirectoryRecord*>::const_iterator i = mSubDirectories.begin(); i != mSubDirectories.end(); i++)
+ {
+ const BackupClientDirectoryRecord* pSubItem = (*i).second;
+ ASSERT(pSubItem);
+
+ rArchive.Add((*i).first);
+ pSubItem->Serialize(rArchive);
+ }
+}
Modified: box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientDirectoryRecord.h
===================================================================
--- box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientDirectoryRecord.h 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupClientDirectoryRecord.h 2006-01-17 22:27:22 UTC (rev 320)
@@ -56,6 +56,8 @@
#include "BackupClientFileAttributes.h"
#include "BackupStoreDirectory.h"
#include "MD5Digest.h"
+
+#include "Archive.h"
class BackupClientContext;
class BackupDaemon;
@@ -72,7 +74,10 @@
{
public:
BackupClientDirectoryRecord(int64_t ObjectID, const std::string &rSubDirName);
- ~BackupClientDirectoryRecord();
+ ~BackupClientDirectoryRecord();
+
+ void Deserialize(Archive & rArchive);
+ void Serialize(Archive & rArchive) const;
private:
BackupClientDirectoryRecord(const BackupClientDirectoryRecord &);
public:
Modified: box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupDaemon.cpp
===================================================================
--- box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupDaemon.cpp 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupDaemon.cpp 2006-01-17 22:27:22 UTC (rev 320)
@@ -97,7 +97,7 @@
// Make the actual sync period have a little bit of extra time, up to a 64th of the main sync period.
// This prevents repetative cycles of load on the server
#define SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY 6
-
+
// --------------------------------------------------------------------------
//
// Function
@@ -309,11 +309,15 @@
// Set up the keys for various things
BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile").c_str());
- // Set maximum diffing time?
+ // max diffing time, keep-alive time
if(conf.KeyExists("MaximumDiffingTime"))
{
- BackupStoreFile::SetMaximumDiffingTime(conf.GetKeyValueInt("MaximumDiffingTime"));
+ BackupClientContext::SetMaximumDiffingTime(conf.GetKeyValueInt("MaximumDiffingTime"));
}
+ if(conf.KeyExists("KeepAliveTime"))
+ {
+ BackupClientContext::SetKeepAliveTime(conf.GetKeyValueInt("KeepAliveTime"));
+ }
// Setup various timings
@@ -336,12 +340,16 @@
// When the last sync started (only updated if the store was not full when the sync ended)
box_time_t lastSyncTime = 0;
-
+
+ // And what's the current client store marker?
+ int64_t clientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown; // haven't contacted the store yet
+
+ // --------------------------------------------------------------------------------------------
+
+ DeserializeStoreObjectInfo(clientStoreMarker, lastSyncTime, nextSyncTime);
+
// --------------------------------------------------------------------------------------------
- // And what's the current client store marker?
- int64_t clientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown; // haven't contacted the store yet
-
// Set state
SetState(State_Idle);
@@ -540,7 +548,14 @@
CommitIDMapsAfterSync();
// Log
- ::syslog(LOG_INFO, "Finished scan of local files");
+ ::syslog(LOG_INFO, "Finished scan of local files");
+
+ // --------------------------------------------------------------------------------------------
+
+ // We had a successful backup, save the store info
+ SerializeStoreObjectInfo(clientStoreMarker, lastSyncTime, nextSyncTime);
+
+ // --------------------------------------------------------------------------------------------
}
catch(BoxException &e)
{
@@ -727,7 +742,7 @@
{
#ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
bool uidOK = true;
- ::syslog(LOG_ERR, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)");
+ ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)");
#else
// Security check -- does the process connecting to this socket have
// the same UID as this process?
@@ -1590,6 +1605,18 @@
mUnusedRootDirEntries.clear();
}
+// --------------------------------------------------------------------------
+
+typedef struct
+{
+ int32_t mMagicValue; // also the version number
+ int32_t mNumEntries;
+ int64_t mObjectID; // this object ID
+ int64_t mContainerID; // ID of container
+ uint64_t mAttributesModTime;
+ int32_t mOptionsPresent; // bit mask of optional sections / features present
+
+} loc_StreamFormat;
// --------------------------------------------------------------------------
//
@@ -1598,7 +1625,8 @@
// Purpose: Constructor
// Created: 11/11/03
//
-// --------------------------------------------------------------------------
+// --------------------------------------------------------------------------
+
BackupDaemon::Location::Location()
: mIDMapIndex(0),
mpExcludeFiles(0),
@@ -1628,8 +1656,175 @@
mpExcludeFiles = 0;
}
}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupDaemon::Location::Deserialize(Archive & rArchive)
+// Purpose: Deserializes this object instance from a stream of bytes, using an Archive abstraction.
+//
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+void BackupDaemon::Location::Deserialize(Archive & rArchive)
+{
+ //
+ //
+ //
+ mpDirectoryRecord.reset(NULL);
+ if (mpExcludeFiles)
+ {
+ delete mpExcludeFiles;
+ mpExcludeFiles = NULL;
+ }
+ if (mpExcludeDirs)
+ {
+ delete mpExcludeDirs;
+ mpExcludeDirs = NULL;
+ }
+
+ //
+ //
+ //
+ rArchive >> mName >> mPath >> mIDMapIndex;
+
+ //
+ //
+ //
+ int64_t aMagicMarker = 0;
+ rArchive.Get(aMagicMarker);
+
+ if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
+ {
+ // NOOP
+ }
+ else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
+ {
+ BackupClientDirectoryRecord *pSubRecord = new BackupClientDirectoryRecord(0, "");
+ if (!pSubRecord)
+ throw std::bad_alloc();
+
+ mpDirectoryRecord.reset(pSubRecord);
+ mpDirectoryRecord->Deserialize(rArchive);
+ }
+ else
+ {
+ // there is something going on here
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+
+ //
+ //
+ //
+ rArchive.Get(aMagicMarker);
+
+ if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
+ {
+ // NOOP
+ }
+ else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
+ {
+ mpExcludeFiles = new ExcludeList;
+ if (!mpExcludeFiles)
+ throw std::bad_alloc();
+
+ mpExcludeFiles->Deserialize(rArchive);
+ }
+ else
+ {
+ // there is something going on here
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+
+ //
+ //
+ //
+ rArchive.Get(aMagicMarker);
+
+ if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
+ {
+ // NOOP
+ }
+ else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
+ {
+ mpExcludeDirs = new ExcludeList;
+ if (!mpExcludeDirs)
+ throw std::bad_alloc();
+
+ mpExcludeDirs->Deserialize(rArchive);
+ }
+ else
+ {
+ // there is something going on here
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupDaemon::Location::Serialize(Archive & rArchive)
+// Purpose: Serializes this object instance into a stream of bytes, using an Archive abstraction.
+//
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+void BackupDaemon::Location::Serialize(Archive & rArchive) const
+{
+ //
+ //
+ //
+ rArchive << mName << mPath << mIDMapIndex;
+
+ //
+ //
+ //
+ if (mpDirectoryRecord.get() == NULL)
+ {
+ int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
+ rArchive.Add(aMagicMarker);
+ }
+ else
+ {
+ int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_RECURSE; // be explicit about whether recursion follows
+ rArchive.Add(aMagicMarker);
+
+ mpDirectoryRecord->Serialize(rArchive);
+ }
+
+ //
+ //
+ //
+ if (!mpExcludeFiles)
+ {
+ int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
+ rArchive.Add(aMagicMarker);
+ }
+ else
+ {
+ int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_RECURSE; // be explicit about whether recursion follows
+ rArchive.Add(aMagicMarker);
+
+ mpExcludeFiles->Serialize(rArchive);
+ }
+
+ //
+ //
+ //
+ if (!mpExcludeDirs)
+ {
+ int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
+ rArchive.Add(aMagicMarker);
+ }
+ else
+ {
+ int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_RECURSE; // be explicit about whether recursion follows
+ rArchive.Add(aMagicMarker);
+
+ mpExcludeDirs->Serialize(rArchive);
+ }
+}
-
// --------------------------------------------------------------------------
//
// Function
@@ -1660,4 +1855,192 @@
mpGetLine = 0;
}
}
-
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime)
+// Purpose: Serializes remote directory and file information into a stream of bytes, using an Archive abstraction.
+//
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+
+static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F;
+static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE";
+static const int STOREOBJECTINFO_VERSION = 1;
+
+void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const
+{
+ if(!GetConfiguration().KeyExists("StoreObjectInfoFile") || GetConfiguration().GetKeyValue("StoreObjectInfoFile").size() <= 0)
+ return;
+
+ try
+ {
+ FileStream aFile(GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str(), O_WRONLY | O_CREAT | O_TRUNC);
+ IOStreamArchive anArchive(aFile, 0);
+
+ anArchive << STOREOBJECTINFO_MAGIC_ID_VALUE << STOREOBJECTINFO_MAGIC_ID_STRING << STOREOBJECTINFO_VERSION
+ << GetConfiguration().GetModTime()
+ << aClientStoreMarker << theLastSyncTime << theNextSyncTime;
+
+ //
+ //
+ //
+ int64_t iCount = mLocations.size();
+ anArchive.Add(iCount);
+
+ for (int v = 0; v < iCount; v++)
+ {
+ ASSERT(mLocations[v]);
+ mLocations[v]->Serialize(anArchive);
+ }
+
+ //
+ //
+ //
+ iCount = mIDMapMounts.size();
+ anArchive.Add(iCount);
+
+ for (int v = 0; v < iCount; v++)
+ anArchive.Add(mIDMapMounts[v]);
+
+ //
+ //
+ //
+ aFile.Close();
+ ::syslog(LOG_INFO, "Saved store object info file '%s'", GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str());
+ }
+ catch (...)
+ {
+ ::syslog(LOG_WARNING, "Requested store object info file '%s' not accessible or could not be created", GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str());
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime)
+// Purpose: Deserializes remote directory and file information from a stream of bytes, using an Archive abstraction.
+//
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime)
+{
+ //
+ //
+ //
+ DeleteAllLocations();
+
+ //
+ //
+ //
+ if(!GetConfiguration().KeyExists("StoreObjectInfoFile") || GetConfiguration().GetKeyValue("StoreObjectInfoFile").size() <=0)
+ return;
+
+ try
+ {
+ FileStream aFile(GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str(), O_RDONLY);
+ IOStreamArchive anArchive(aFile, 0);
+
+ //
+ // see if the content has a chance to be what we think it is
+ //
+ int iMagicValue = 0;
+ anArchive.Get(iMagicValue);
+
+ if (iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE)
+ {
+ ::syslog(LOG_WARNING, "Store object info file '%s' is not what you think it is: no harm done, will re-cache from store", GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str());
+ return;
+ }
+
+ //
+ // get a bit optimistic and read in a string identifier
+ //
+ std::string strMagicValue;
+ anArchive.Get(strMagicValue);
+
+ if (strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING)
+ {
+ ::syslog(LOG_WARNING, "Store object info file '%s' is not what you think it is: no harm done, will re-cache from store", GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str());
+ return;
+ }
+
+ //
+ // ok, check if we are not loading some future development version by mistake
+ //
+ int iVersion = 0;
+ anArchive.Get(iVersion);
+
+ if (iVersion != STOREOBJECTINFO_VERSION)
+ {
+ ::syslog(LOG_WARNING, "Store object info file '%s' version [%d] unsupported: no harm done, will re-cache from store", GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str(), iVersion);
+ return;
+ }
+
+ //
+ // check if this state file is even valid for the loaded bbackupd.conf file
+ //
+ box_time_t lastKnownConfigModTime;
+ anArchive.Get(lastKnownConfigModTime);
+
+ if (lastKnownConfigModTime != GetConfiguration().GetModTime())
+ {
+ ::syslog(LOG_WARNING, "Store object info file '%s' out of date: no harm done, will re-cache from store", GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str());
+ return;
+ }
+
+ //
+ // this is it, go at it
+ //
+ anArchive >> aClientStoreMarker >> theLastSyncTime >> theNextSyncTime;
+
+ //
+ //
+ //
+ int64_t iCount = 0;
+ anArchive.Get(iCount);
+
+ for (int v = 0; v < iCount; v++)
+ {
+ Location* pLocation = new Location;
+ if (!pLocation)
+ throw std::bad_alloc();
+
+ pLocation->Deserialize(anArchive);
+ mLocations.push_back(pLocation);
+ }
+
+ //
+ //
+ //
+ iCount = 0;
+ anArchive.Get(iCount);
+
+ for (int v = 0; v < iCount; v++)
+ {
+ std::string strItem;
+ anArchive.Get(strItem);
+
+ mIDMapMounts.push_back(strItem);
+ }
+
+ //
+ //
+ //
+ aFile.Close();
+ ::syslog(LOG_INFO, "Loaded store object info file '%s', version [%04d]", GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str(), iVersion);
+ }
+ catch (...)
+ {
+ DeleteAllLocations();
+
+ aClientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown;
+ theLastSyncTime = 0;
+ theNextSyncTime = 0;
+
+ ::syslog(LOG_WARNING, "Requested store object info file '%s' does not exist, not accessible, or inconsistent: no harm done, will re-cache from store", GetConfiguration().GetKeyValue("StoreObjectInfoFile").c_str());
+ }
+}
Modified: box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupDaemon.h
===================================================================
--- box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupDaemon.h 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/bin/bbackupd/BackupDaemon.h 2006-01-17 22:27:22 UTC (rev 320)
@@ -58,6 +58,8 @@
#include "Socket.h"
#include "SocketListen.h"
#include "SocketStream.h"
+
+#include "Archive.h"
class BackupClientDirectoryRecord;
class BackupClientContext;
@@ -78,7 +80,11 @@
{
public:
BackupDaemon();
- ~BackupDaemon();
+ ~BackupDaemon();
+
+ // methods below do partial (specialized) serialization of client state only
+ void SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const;
+ void DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime);
private:
BackupDaemon(const BackupDaemon &);
public:
@@ -154,7 +160,10 @@
{
public:
Location();
- ~Location();
+ ~Location();
+
+ void Deserialize(Archive & rArchive);
+ void Serialize(Archive & rArchive) const;
private:
Location(const Location &); // copy not allowed
Location &operator=(const Location &);
Modified: box/gary/boxbackup-0.09-mod/bin/bbstored/BackupCommands.cpp
===================================================================
--- box/gary/boxbackup-0.09-mod/bin/bbstored/BackupCommands.cpp 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/bin/bbstored/BackupCommands.cpp 2006-01-17 22:27:22 UTC (rev 320)
@@ -898,3 +898,20 @@
));
}
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &, BackupContext &)
+// Purpose: Return the amount of disc space used
+// Created: 19/4/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ //
+ // NOOP
+ //
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerIsAlive());
+}
Modified: box/gary/boxbackup-0.09-mod/bin/bbstored/backupprotocol.txt
===================================================================
--- box/gary/boxbackup-0.09-mod/bin/bbstored/backupprotocol.txt 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/bin/bbstored/backupprotocol.txt 2006-01-17 22:27:22 UTC (rev 320)
@@ -219,3 +219,10 @@
int64 BlocksSoftLimit
int64 BlocksHardLimit
int32 BlockSize
+
+GetIsAlive 42 Command(IsAlive)
+ # no data members
+
+IsAlive 43 Reply
+ # no data members
+
Modified: box/gary/boxbackup-0.09-mod/lib/backupclient/BackupDaemonConfigVerify.cpp
===================================================================
--- box/gary/boxbackup-0.09-mod/lib/backupclient/BackupDaemonConfigVerify.cpp 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/lib/backupclient/BackupDaemonConfigVerify.cpp 2006-01-17 22:27:22 UTC (rev 320)
@@ -123,6 +123,8 @@
{"ExtendedLogging", "no", ConfigTest_IsBool, 0}, // make value "yes" to enable in config file
{"CommandSocket", 0, 0, 0}, // not compulsory to have this
+ {"StoreObjectInfoFile", 0, 0, 0}, // optional
+ {"KeepAliveTime", 0, ConfigTest_IsInt, 0}, // optional
{"NotifyScript", 0, 0, 0}, // optional script to run when backup needs attention, eg store full
Modified: box/gary/boxbackup-0.09-mod/lib/backupclient/BackupStoreFile.h
===================================================================
--- box/gary/boxbackup-0.09-mod/lib/backupclient/BackupStoreFile.h 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/lib/backupclient/BackupStoreFile.h 2006-01-17 22:27:22 UTC (rev 320)
@@ -180,8 +180,17 @@
free(a);
}
- // Limits
- static void SetMaximumDiffingTime(int Seconds);
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupStoreFile::SuspendFileDiff()
+ // Purpose: Notifies BackupStoreFile object that a diff operation should be
+ // terminated ASAP. Usually called from an external timer.
+ //
+ // Created: 12/1/04
+ //
+ // --------------------------------------------------------------------------
+ static void SuspendFileDiff();
// Building blocks
class EncodingBuffer
Modified: box/gary/boxbackup-0.09-mod/lib/backupclient/BackupStoreFileDiff.cpp
===================================================================
--- box/gary/boxbackup-0.09-mod/lib/backupclient/BackupStoreFileDiff.cpp 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/lib/backupclient/BackupStoreFileDiff.cpp 2006-01-17 22:27:22 UTC (rev 320)
@@ -50,8 +50,6 @@
#include <new>
#include <map>
-#include <signal.h>
-#include <sys/time.h>
#include "BackupStoreFile.h"
#include "BackupStoreFileWire.h"
@@ -60,7 +58,7 @@
#include "BackupStoreException.h"
#include "BackupStoreFileEncodeStream.h"
#include "BackupStoreConstants.h"
-#include "FileStream.h"
+#include "FileStream.h"
#include "RollingChecksum.h"
#include "MD5Digest.h"
#include "CommonException.h"
@@ -82,34 +80,28 @@
static void SetupHashTable(BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t BlockSize, BlocksAvailableEntry **pHashTable);
static bool SecondStageMatch(BlocksAvailableEntry *pFirstInHashList, uint16_t Hash, uint8_t *pBeginnings, uint8_t *pEndings, int Offset, int32_t BlockSize, int64_t FileBlockNumber, BlocksAvailableEntry *pIndex, std::map<int64_t, int64_t> &rFoundBlocks);
static void GenerateRecipe(BackupStoreFileEncodeStream::Recipe &rRecipe, BlocksAvailableEntry *pIndex, int64_t NumBlocks, std::map<int64_t, int64_t> &rFoundBlocks, int64_t SizeOfInputFile);
-
-// Avoid running on too long with diffs
-static int sMaximumDiffTime = 10; // maximum time to spend diffing
+
+// control whether a currently active diff should be terminated ASAP
static bool sDiffTimedOut = false;
-static bool sSetTimerSignelHandler = false;
-static void TimerSignalHandler(int signal);
-static void StartDiffTimer();
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::SuspendFileDiff()
+// Purpose: Notifies BackupStoreFile object that a diff operation should be
+// terminated ASAP. Usually called from an external timer.
+//
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::SuspendFileDiff()
+{
+ sDiffTimedOut = true;
+}
-
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupStoreFile::SetMaximumDiffingTime(int)
-// Purpose: Sets the maximum time to spend diffing, in seconds. Time is
-// process virutal time.
-// Created: 19/3/04
-//
-// --------------------------------------------------------------------------
-void BackupStoreFile::SetMaximumDiffingTime(int Seconds)
-{
- sMaximumDiffTime = Seconds;
- TRACE1("Set maximum diffing time to %d seconds\n", Seconds);
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
// Name: BackupStoreFile::MoveStreamPositionToBlockIndex(IOStream &)
// Purpose: Move the file pointer in this stream to just before the block index.
// Assumes that the stream is at the beginning, seekable, and
@@ -214,9 +206,6 @@
// Pointer to recipe we're going to create
BackupStoreFileEncodeStream::Recipe *precipe = 0;
-
- // Start the timeout timer, so that the operation doesn't continue for ever
- StartDiffTimer();
try
{
@@ -508,7 +497,10 @@
// --------------------------------------------------------------------------
static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t> &rFoundBlocks,
BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES])
-{
+{
+ // reset state in case we got timing/call-order mess-up somewhere else
+ sDiffTimedOut = false;
+
// Allocate the hash lookup table
BlocksAvailableEntry **phashTable = (BlocksAvailableEntry **)::malloc(sizeof(BlocksAvailableEntry *) * (64*1024));
@@ -630,7 +622,7 @@
if(static_cast<int64_t>(rFoundBlocks.size()) > (NumBlocks * BACKUP_FILE_DIFF_MAX_BLOCK_FIND_MULTIPLE)
|| sDiffTimedOut)
{
- abortSearch = true;
+ abortSearch = true;
break;
}
}
@@ -957,56 +949,4 @@
TRACE0("======== ========= ========\n");
}
#endif
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: static TimerSignalHandler(int)
-// Purpose: Signal handler
-// Created: 19/3/04
-//
-// --------------------------------------------------------------------------
-void TimerSignalHandler(int signal)
-{
- sDiffTimedOut = true;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: static StartDiffTimer()
-// Purpose: Starts the diff timeout timer
-// Created: 19/3/04
-//
-// --------------------------------------------------------------------------
-void StartDiffTimer()
-{
- // Set timer signal handler
- if(!sSetTimerSignelHandler)
- {
- ::signal(SIGVTALRM, TimerSignalHandler);
- sSetTimerSignelHandler = true;
- }
-
- struct itimerval timeout;
- // Don't want this to repeat
- timeout.it_interval.tv_sec = 0;
- timeout.it_interval.tv_usec = 0;
- // Single timeout after the specified number of seconds
- timeout.it_value.tv_sec = sMaximumDiffTime;
- timeout.it_value.tv_usec = 0;
- // Set timer
- if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0)
- {
- TRACE0("WARNING: couldn't set diff timeout\n");
- }
-
- // Unset flag (last thing)
- sDiffTimedOut = false;
-}
-
-
-
+}
Added: box/gary/boxbackup-0.09-mod/lib/common/Archive.h
===================================================================
--- box/gary/boxbackup-0.09-mod/lib/common/Archive.h 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/lib/common/Archive.h 2006-01-17 22:27:22 UTC (rev 320)
@@ -0,0 +1,243 @@
+// distribution boxbackup-0.09
+//
+//
+// Copyright (c) 2003, 2004
+// Ben Summers. 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 acknowledgement:
+// 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: Archive.h
+// Purpose: Backup daemon state archive
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+
+#ifndef ARCHIVE__H
+#define ARCHIVE__H
+
+#include <vector>
+#include <string>
+#include <memory>
+
+#include "IOStream.h"
+#include "Guards.h"
+
+#define ARCHIVE_GET_SIZE(hdr) (( ((uint8_t)((hdr)[0])) | ( ((uint8_t)((hdr)[1])) << 8)) >> 2)
+
+#define ARCHIVE_MAGIC_VALUE_RECURSE 0x4449525F
+#define ARCHIVE_MAGIC_VALUE_NOOP 0x5449525F
+
+class Archive
+{
+public:
+ Archive()
+ {
+ }
+ virtual ~Archive()
+ {
+ }
+ //
+ // primitive insertion operations
+ //
+ virtual void Add(bool bItem) = 0;
+ virtual void Add(int iItem) = 0;
+ virtual void Add(int64_t iItem) = 0;
+ virtual void Add(uint64_t iItem) = 0;
+ virtual void Add(uint8_t iItem) = 0;
+ virtual void Add(const std::string & strItem) = 0;
+ //
+ // chaining support
+ //
+ Archive & operator<<(bool bItem) { Add(bItem); return *this; }
+ Archive & operator<<(int iItem) { Add(iItem); return *this; }
+ Archive & operator<<(int64_t iItem) { Add(iItem); return *this; }
+ Archive & operator<<(uint64_t iItem) { Add(iItem); return *this; }
+ Archive & operator<<(uint8_t iItem) { Add(iItem); return *this; }
+ Archive & operator<<(const std::string & strItem) { Add(strItem); return *this; }
+ //
+ // primitive extraction oprations
+ //
+ virtual void Get(bool & bItem) = 0;
+ virtual void Get(int & iItem) = 0;
+ virtual void Get(int64_t & iItem) = 0;
+ virtual void Get(uint64_t & iItem) = 0;
+ virtual void Get(uint8_t & iItem) = 0;
+ virtual void Get(std::string & strItem) = 0;
+ //
+ // chaining support
+ //
+ Archive & operator>>(bool & bItem) { Get(bItem); return *this; }
+ Archive & operator>>(int & iItem) { Get(iItem); return *this; }
+ Archive & operator>>(int64_t & iItem) { Get(iItem); return *this; }
+ Archive & operator>>(uint64_t & iItem) { Get(iItem); return *this; }
+ Archive & operator>>(uint8_t & iItem) { Get(iItem); return *this; }
+ Archive & operator>>(std::string & strItem) { Get(strItem); return *this; }
+private:
+ Archive(const Archive &);
+ Archive & operator=(const Archive &);
+};
+
+class IOStreamArchive : public Archive
+{
+public:
+ IOStreamArchive(IOStream & mStream, int Timeout) : mStream(mStream)
+ {
+ mTimeout = Timeout;
+ }
+ virtual ~IOStreamArchive()
+ {
+ }
+ //
+ //
+ //
+ virtual void Add(bool bItem)
+ {
+ Add((int) bItem);
+ }
+ virtual void Add(int iItem)
+ {
+ int32_t privItem = htonl(iItem);
+ mStream.Write(&privItem, sizeof(privItem));
+ }
+ virtual void Add(int64_t iItem)
+ {
+ int64_t privItem = hton64(iItem);
+ mStream.Write(&privItem, sizeof(privItem));
+ }
+ virtual void Add(uint64_t iItem)
+ {
+ uint64_t privItem = hton64(iItem);
+ mStream.Write(&privItem, sizeof(privItem));
+ }
+ virtual void Add(uint8_t iItem)
+ {
+ int privItem = iItem;
+ Add(privItem);
+ }
+ virtual void Add(const std::string & strItem)
+ {
+ int iSize = strItem.size();
+ Add(iSize);
+ mStream.Write(strItem.c_str(), iSize);
+ }
+ //
+ //
+ //
+ virtual void Get(bool & bItem)
+ {
+ int privItem;
+ Get(privItem);
+
+ if (privItem)
+ bItem = true;
+ else
+ bItem = false;
+ }
+ virtual void Get(int & iItem)
+ {
+ int32_t privItem;
+ if(!mStream.ReadFullBuffer(&privItem, sizeof(privItem), 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+ iItem = ntohl(privItem);
+ }
+ virtual void Get(int64_t & iItem)
+ {
+ int64_t privItem;
+ if(!mStream.ReadFullBuffer(&privItem, sizeof(privItem), 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+ iItem = ntoh64(privItem);
+ }
+ virtual void Get(uint64_t & iItem)
+ {
+ uint64_t privItem;
+ if(!mStream.ReadFullBuffer(&privItem, sizeof(privItem), 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+ iItem = ntoh64(privItem);
+ }
+ virtual void Get(uint8_t & iItem)
+ {
+ int privItem;
+ Get(privItem);
+ iItem = privItem;
+ }
+ virtual void Get(std::string & strItem)
+ {
+ int iSize;
+ Get(iSize);
+
+ // Assume most strings are relatively small
+ char buf[256];
+ if(iSize < (int) sizeof(buf))
+ {
+ // Fetch rest of pPayload, relying on the Protocol to error on stupidly large sizes for us
+ if(!mStream.ReadFullBuffer(buf, iSize, 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+ // assign to this string, storing the header and the extra pPayload
+ strItem.assign(buf, iSize);
+ }
+ else
+ {
+ // Block of memory to hold it
+ MemoryBlockGuard<char*> dataB(iSize);
+ char *pPayload = dataB;
+
+ // Fetch rest of pPayload, relying on the Protocol to error on stupidly large sizes for us
+ if(!mStream.ReadFullBuffer(pPayload, iSize, 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+ // assign to this string, storing the header and the extra pPayload
+ strItem.assign(pPayload, iSize);
+ }
+ }
+protected:
+ IOStream & mStream;
+ int mTimeout;
+private:
+ IOStreamArchive(const IOStreamArchive &);
+ IOStreamArchive & operator=(const IOStreamArchive &);
+};
+
+#endif // ARCHIVE__H
Modified: box/gary/boxbackup-0.09-mod/lib/common/Configuration.cpp
===================================================================
--- box/gary/boxbackup-0.09-mod/lib/common/Configuration.cpp 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/lib/common/Configuration.cpp 2006-01-17 22:27:22 UTC (rev 320)
@@ -57,6 +57,8 @@
#include "FdGetLine.h"
#include "MemLeakFindOn.h"
+
+#include "FileModificationTime.h"
// utility whitespace function
inline bool iw(int c)
@@ -68,25 +70,22 @@
static const char *sValueBooleanStrings[] = {"yes", "true", "no", "false", 0};
static const bool sValueBooleanValue[] = {true, true, false, false};
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::Configuration(const std::string &, box_time_t)
+// Purpose: Constructor
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+Configuration::Configuration(const std::string &rName, box_time_t configModTime)
+ : mName(rName), mConfigModTime(configModTime)
+{
+}
-
// --------------------------------------------------------------------------
//
// Function
-// Name: Configuration::Configuration(const std::string &)
-// Purpose: Constructor
-// Created: 2003/07/23
-//
-// --------------------------------------------------------------------------
-Configuration::Configuration(const std::string &rName)
- : mName(rName)
-{
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
// Name: Configuration::Configuration(const Configuration &)
// Purpose: Copy constructor
// Created: 2003/07/23
@@ -95,7 +94,8 @@
Configuration::Configuration(const Configuration &rToCopy)
: mName(rToCopy.mName),
mSubConfigurations(rToCopy.mSubConfigurations),
- mKeys(rToCopy.mKeys)
+ mKeys(rToCopy.mKeys),
+ mConfigModTime(rToCopy.mConfigModTime)
{
}
@@ -132,7 +132,14 @@
// Just to make sure
rErrorMsg.erase();
-
+
+ // Save modification time to be able to distinguish across configuration sets
+ struct stat st;
+ if(::stat(Filename, &st) != 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
// Open the file
FileHandleGuard<O_RDONLY> file(Filename);
@@ -140,7 +147,7 @@
FdGetLine getline(file);
// Object to create
- Configuration *pconfig = new Configuration(std::string("<root>"));
+ Configuration *pconfig = new Configuration(std::string("<root>"), FileModificationTime(st));
try
{
@@ -215,7 +222,7 @@
if(startBlockExpected)
{
// New config object
- Configuration config(blockName);
+ Configuration config(blockName, rConfig.mConfigModTime);
// Continue processing into this block
if(!LoadInto(config, rGetLine, rErrorMsg, false))
Modified: box/gary/boxbackup-0.09-mod/lib/common/Configuration.h
===================================================================
--- box/gary/boxbackup-0.09-mod/lib/common/Configuration.h 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/lib/common/Configuration.h 2006-01-17 22:27:22 UTC (rev 320)
@@ -54,6 +54,8 @@
#include <vector>
#include <string>
#include <memory>
+
+#include "BoxTime.h"
// For defining tests
enum
@@ -97,11 +99,13 @@
class Configuration
{
private:
- Configuration(const std::string &rName);
+ Configuration(const std::string &rName, box_time_t configModTime);
public:
Configuration(const Configuration &rToCopy);
~Configuration();
-
+
+ box_time_t GetModTime() const { return mConfigModTime; }
+
enum
{
// The character to separate multi-values
@@ -126,8 +130,9 @@
typedef std::list<std::pair<std::string, Configuration> > SubConfigListType;
SubConfigListType mSubConfigurations;
// Order of keys, not preserved
- std::map<std::string, std::string> mKeys;
-
+ std::map<std::string, std::string> mKeys;
+protected:
+ box_time_t mConfigModTime;
private:
static bool LoadInto(Configuration &rConfig, FdGetLine &rGetLine, std::string &rErrorMsg, bool RootLevel);
static bool Verify(Configuration &rConfig, const ConfigurationVerify &rVerify, const std::string &rLevel, std::string &rErrorMsg);
Modified: box/gary/boxbackup-0.09-mod/lib/common/ExcludeList.cpp
===================================================================
--- box/gary/boxbackup-0.09-mod/lib/common/ExcludeList.cpp 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/lib/common/ExcludeList.cpp 2006-01-17 22:27:22 UTC (rev 320)
@@ -168,7 +168,9 @@
}
// Store in list of regular expressions
- mRegex.push_back(pregex);
+ mRegex.push_back(pregex);
+ // Store in list of regular expression string for Serialize
+ mRegexStr.push_back(i->c_str());
}
catch(...)
{
@@ -251,8 +253,170 @@
// Store the pointer
mpAlwaysInclude = pAlwaysInclude;
}
-
-
-
-
-
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ExcludeList::Deserialize(Archive & rArchive)
+// Purpose: Deserializes this object instance from a stream of bytes, using an Archive abstraction.
+//
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+void ExcludeList::Deserialize(Archive & rArchive)
+{
+ //
+ //
+ //
+ mDefinite.clear();
+
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+ // free regex memory
+ while(mRegex.size() > 0)
+ {
+ regex_t *pregex = mRegex.back();
+ mRegex.pop_back();
+ // Free regex storage, and the structure itself
+ ::regfree(pregex);
+ delete pregex;
+ }
+
+ mRegexStr.clear();
+#endif
+
+ // Clean up exceptions list
+ if(mpAlwaysInclude != 0)
+ {
+ delete mpAlwaysInclude;
+ mpAlwaysInclude = 0;
+ }
+
+ //
+ //
+ //
+ int64_t iCount = 0;
+ rArchive.Get(iCount);
+
+ if (iCount > 0)
+ {
+ for (int v = 0; v < iCount; v++)
+ {
+ std::string strItem;
+ rArchive.Get(strItem);
+
+ /**** LOAD ****/ mDefinite.insert(strItem);
+ }
+ }
+
+ //
+ //
+ //
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+ rArchive.Get(iCount);
+
+ if (iCount > 0)
+ {
+ for (int v = 0; v < iCount; v++)
+ {
+ std::string strItem;
+ rArchive.Get(strItem);
+
+ // Allocate memory
+ regex_t* pregex = new regex_t;
+
+ try
+ {
+ // Compile
+ if(::regcomp(pregex, strItem.c_str(), REG_EXTENDED | REG_NOSUB) != 0)
+ {
+ THROW_EXCEPTION(CommonException, BadRegularExpression)
+ }
+
+ // Store in list of regular expressions
+ /**** LOAD ****/ mRegex.push_back(pregex);
+ // Store in list of regular expression string for Serialize
+ /**** LOAD ****/ mRegexStr.push_back(strItem);
+ }
+ catch(...)
+ {
+ delete pregex;
+ throw;
+ }
+ }
+ }
+#endif // PLATFORM_REGEX_NOT_SUPPORTED
+
+ //
+ //
+ //
+ int64_t aMagicMarker = 0;
+ rArchive.Get(aMagicMarker);
+
+ if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
+ {
+ // NOOP
+ }
+ else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
+ {
+ /**** LOAD ****/ mpAlwaysInclude = new ExcludeList;
+ if (!mpAlwaysInclude)
+ throw std::bad_alloc();
+
+ mpAlwaysInclude->Deserialize(rArchive);
+ }
+ else
+ {
+ // there is something going on here
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ExcludeList::Serialize(Archive & rArchive)
+// Purpose: Serializes this object instance into a stream of bytes, using an Archive abstraction.
+//
+// Created: 2005/04/11
+//
+// --------------------------------------------------------------------------
+void ExcludeList::Serialize(Archive & rArchive) const
+{
+ //
+ //
+ //
+ int64_t iCount = mDefinite.size();
+ rArchive.Add(iCount);
+
+ for (std::set<std::string>::const_iterator i = mDefinite.begin(); i != mDefinite.end(); i++)
+ rArchive.Add(*i);
+
+ //
+ //
+ //
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+ ASSERT(mRegex.size() == mRegexStr.size()); // don't even try to save compiled regular expressions - use string copies
+
+ iCount = mRegexStr.size();
+ rArchive.Add(iCount);
+
+ for (std::vector<std::string>::const_iterator i = mRegexStr.begin(); i != mRegexStr.end(); i++)
+ rArchive.Add(*i);
+#endif // PLATFORM_REGEX_NOT_SUPPORTED
+
+ //
+ //
+ //
+ if (!mpAlwaysInclude)
+ {
+ int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
+ rArchive.Add(aMagicMarker);
+ }
+ else
+ {
+ int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_RECURSE; // be explicit about whether recursion follows
+ rArchive.Add(aMagicMarker);
+
+ mpAlwaysInclude->Serialize(rArchive);
+ }
+}
Modified: box/gary/boxbackup-0.09-mod/lib/common/ExcludeList.h
===================================================================
--- box/gary/boxbackup-0.09-mod/lib/common/ExcludeList.h 2006-01-17 22:24:47 UTC (rev 319)
+++ box/gary/boxbackup-0.09-mod/lib/common/ExcludeList.h 2006-01-17 22:27:22 UTC (rev 320)
@@ -57,6 +57,8 @@
#ifndef EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED
typedef int regex_t;
#endif
+
+#include "Archive.h"
// --------------------------------------------------------------------------
//
@@ -71,6 +73,9 @@
public:
ExcludeList();
~ExcludeList();
+
+ void Deserialize(Archive & rArchive);
+ void Serialize(Archive & rArchive) const;
void AddDefiniteEntries(const std::string &rEntries);
void AddRegexEntries(const std::string &rEntries);
@@ -93,7 +98,8 @@
private:
std::set<std::string> mDefinite;
#ifndef PLATFORM_REGEX_NOT_SUPPORTED
- std::vector<regex_t *> mRegex;
+ std::vector<regex_t *> mRegex;
+ std::vector<std::string> mRegexStr; // save original regular expression string-based source for Serialize
#endif
// For exceptions to the excludes