[Box Backup-dev] COMMIT r338 - in box/chris/bb-save-state: bin/bbackupd lib/backupclient lib/common

boxbackup-dev@fluffy.co.uk boxbackup-dev@fluffy.co.uk
Fri, 27 Jan 2006 22:29:13 +0000 (GMT)


Author: chris
Date: 2006-01-27 22:29:09 +0000 (Fri, 27 Jan 2006)
New Revision: 338

Modified:
   box/chris/bb-save-state/bin/bbackupd/BackupClientDirectoryRecord.cpp
   box/chris/bb-save-state/bin/bbackupd/BackupClientDirectoryRecord.h
   box/chris/bb-save-state/bin/bbackupd/BackupDaemon.cpp
   box/chris/bb-save-state/bin/bbackupd/BackupDaemon.h
   box/chris/bb-save-state/lib/backupclient/BackupDaemonConfigVerify.cpp
   box/chris/bb-save-state/lib/common/Configuration.cpp
   box/chris/bb-save-state/lib/common/Configuration.h
   box/chris/bb-save-state/lib/common/ExcludeList.cpp
   box/chris/bb-save-state/lib/common/ExcludeList.h
Log:
* lib/backupclient/BackupDaemonConfigVerify.cpp
* lib/common/Configuration.h
* lib/common/ExcludeList.h
* lib/common/Configuration.cpp
* lib/common/ExcludeList.cpp
* bin/bbackupd/BackupDaemon.h
* bin/bbackupd/BackupClientDirectoryRecord.cpp
* bin/bbackupd/BackupDaemon.cpp
* bin/bbackupd/BackupClientDirectoryRecord.h
- Committed Gary's save state (serialisation) patch, with minor modifications


Modified: box/chris/bb-save-state/bin/bbackupd/BackupClientDirectoryRecord.cpp
===================================================================
--- box/chris/bb-save-state/bin/bbackupd/BackupClientDirectoryRecord.cpp	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/bin/bbackupd/BackupClientDirectoryRecord.cpp	2006-01-27 22:29:09 UTC (rev 338)
@@ -1211,5 +1211,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/chris/bb-save-state/bin/bbackupd/BackupClientDirectoryRecord.h
===================================================================
--- box/chris/bb-save-state/bin/bbackupd/BackupClientDirectoryRecord.h	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/bin/bbackupd/BackupClientDirectoryRecord.h	2006-01-27 22:29:09 UTC (rev 338)
@@ -18,6 +18,8 @@
 #include "BackupStoreDirectory.h"
 #include "MD5Digest.h"
 
+#include "Archive.h"
+
 class BackupClientContext;
 class BackupDaemon;
 
@@ -34,6 +36,9 @@
 public:
 	BackupClientDirectoryRecord(int64_t ObjectID, const std::string &rSubDirName);
 	~BackupClientDirectoryRecord();
+
+	void Deserialize(Archive & rArchive);
+	void Serialize(Archive & rArchive) const;
 private:
 	BackupClientDirectoryRecord(const BackupClientDirectoryRecord &);
 public:

Modified: box/chris/bb-save-state/bin/bbackupd/BackupDaemon.cpp
===================================================================
--- box/chris/bb-save-state/bin/bbackupd/BackupDaemon.cpp	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/bin/bbackupd/BackupDaemon.cpp	2006-01-27 22:29:09 UTC (rev 338)
@@ -463,10 +463,18 @@
 	// 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);
@@ -670,6 +678,13 @@
 
 				// Log
 				::syslog(LOG_INFO, "Finished scan of local files");
+
+				// --------------------------------------------------------------------------------------------
+
+				// We had a successful backup, save the store info
+				SerializeStoreObjectInfo(clientStoreMarker, lastSyncTime, nextSyncTime);
+
+				// --------------------------------------------------------------------------------------------
 			}
 			catch(BoxException &e)
 			{
@@ -1827,7 +1842,19 @@
 	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;
+
 // --------------------------------------------------------------------------
 //
 // Function
@@ -1866,10 +1893,177 @@
 	}
 }
 
+// --------------------------------------------------------------------------
+//
+// 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
 //		Name:    BackupDaemon::CommandSocketInfo::CommandSocketInfo()
 //		Purpose: Constructor
 //		Created: 18/2/04
@@ -1897,3 +2091,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/chris/bb-save-state/bin/bbackupd/BackupDaemon.h
===================================================================
--- box/chris/bb-save-state/bin/bbackupd/BackupDaemon.h	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/bin/bbackupd/BackupDaemon.h	2006-01-27 22:29:09 UTC (rev 338)
@@ -21,6 +21,8 @@
 #include "SocketStream.h"
 #include "WinNamedPipeStream.h"
 
+#include "Archive.h"
+
 class BackupClientDirectoryRecord;
 class BackupClientContext;
 class Configuration;
@@ -41,6 +43,10 @@
 public:
 	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:
@@ -117,6 +123,9 @@
 	public:
 		Location();
 		~Location();
+
+		void Deserialize(Archive & rArchive);
+		void Serialize(Archive & rArchive) const;
 	private:
 		Location(const Location &);	// copy not allowed
 		Location &operator=(const Location &);

Modified: box/chris/bb-save-state/lib/backupclient/BackupDaemonConfigVerify.cpp
===================================================================
--- box/chris/bb-save-state/lib/backupclient/BackupDaemonConfigVerify.cpp	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/lib/backupclient/BackupDaemonConfigVerify.cpp	2006-01-27 22:29:09 UTC (rev 338)
@@ -84,6 +84,7 @@
 	{"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
 
 	{"NotifyScript", 0, 0, 0},				// optional script to run when backup needs attention, eg store full
 	
@@ -102,4 +103,3 @@
 	ConfigTest_Exists | ConfigTest_LastEntry,
 	0
 };
-

Modified: box/chris/bb-save-state/lib/common/Configuration.cpp
===================================================================
--- box/chris/bb-save-state/lib/common/Configuration.cpp	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/lib/common/Configuration.cpp	2006-01-27 22:29:09 UTC (rev 338)
@@ -11,6 +11,7 @@
 
 #include <stdlib.h>
 #include <limits.h>
+#include <errno.h>
 
 #include "Configuration.h"
 #include "CommonException.h"
@@ -19,6 +20,8 @@
 
 #include "MemLeakFindOn.h"
 
+#include "FileModificationTime.h"
+
 // utility whitespace function
 inline bool iw(int c)
 {
@@ -29,22 +32,19 @@
 static const char *sValueBooleanStrings[] = {"yes", "true", "no", "false", 0};
 static const bool sValueBooleanValue[] = {true, true, false, false};
 
-
-
 // --------------------------------------------------------------------------
 //
 // Function
-//		Name:    Configuration::Configuration(const std::string &)
+//		Name:    Configuration::Configuration(const std::string &, box_time_t)
 //		Purpose: Constructor
 //		Created: 2003/07/23
 //
 // --------------------------------------------------------------------------
-Configuration::Configuration(const std::string &rName)
-	: mName(rName)
+Configuration::Configuration(const std::string &rName, box_time_t configModTime)
+	: mName(rName), mConfigModTime(configModTime)
 {
 }
 
-
 // --------------------------------------------------------------------------
 //
 // Function
@@ -56,7 +56,8 @@
 Configuration::Configuration(const Configuration &rToCopy)
 	: mName(rToCopy.mName),
 	  mSubConfigurations(rToCopy.mSubConfigurations),
-	  mKeys(rToCopy.mKeys)
+	  mKeys(rToCopy.mKeys),
+	  mConfigModTime(rToCopy.mConfigModTime)
 {
 }
 
@@ -94,6 +95,19 @@
 	// 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)
+	{
+		// Used to THROW_EXCEPTION(CommonException, OSFileError) here
+		// but this is not the normal behaviour if the file doesn't
+		// exist
+		if (errno != ENOENT)
+		{
+			THROW_EXCEPTION(CommonException, OSFileError)
+		}
+	}
+
 	// Open the file
 	FileHandleGuard<O_RDONLY> file(Filename);
 	
@@ -101,7 +115,7 @@
 	FdGetLine getline(file);
 	
 	// Object to create
-	Configuration *pconfig = new Configuration(std::string("<root>"));
+	Configuration *pconfig = new Configuration(std::string("<root>"), FileModificationTime(st));
 	
 	try
 	{
@@ -176,7 +190,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/chris/bb-save-state/lib/common/Configuration.h
===================================================================
--- box/chris/bb-save-state/lib/common/Configuration.h	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/lib/common/Configuration.h	2006-01-27 22:29:09 UTC (rev 338)
@@ -16,6 +16,8 @@
 #include <string>
 #include <memory>
 
+#include "BoxTime.h"
+
 // For defining tests
 enum
 {
@@ -58,11 +60,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
@@ -88,7 +92,8 @@
 	SubConfigListType mSubConfigurations;
 	// Order of keys, not preserved
 	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/chris/bb-save-state/lib/common/ExcludeList.cpp
===================================================================
--- box/chris/bb-save-state/lib/common/ExcludeList.cpp	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/lib/common/ExcludeList.cpp	2006-01-27 22:29:09 UTC (rev 338)
@@ -130,6 +130,8 @@
 				
 				// Store in list of regular expressions
 				mRegex.push_back(pregex);
+				// Store in list of regular expression string for Serialize
+				mRegexStr.push_back(i->c_str());
 			}
 			catch(...)
 			{
@@ -213,7 +215,169 @@
 	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/chris/bb-save-state/lib/common/ExcludeList.h
===================================================================
--- box/chris/bb-save-state/lib/common/ExcludeList.h	2006-01-27 22:23:29 UTC (rev 337)
+++ box/chris/bb-save-state/lib/common/ExcludeList.h	2006-01-27 22:29:09 UTC (rev 338)
@@ -19,6 +19,8 @@
 	typedef int regex_t;
 #endif
 
+#include "Archive.h"
+
 // --------------------------------------------------------------------------
 //
 // Class
@@ -33,6 +35,9 @@
 	ExcludeList();
 	~ExcludeList();
 
+	void Deserialize(Archive & rArchive);
+	void Serialize(Archive & rArchive) const;
+
 	void AddDefiniteEntries(const std::string &rEntries);
 	void AddRegexEntries(const std::string &rEntries);
 
@@ -55,6 +60,7 @@
 	std::set<std::string> mDefinite;
 #ifdef HAVE_REGEX_H
 	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