[Box Backup-dev] COMMIT r710 - in box/chris/merge: . bin/bbackupctl bin/bbackupd bin/bbackupquery bin/bbstored docs/backup infrastructure infrastructure/msvc/2003 lib/backupclient lib/backupstore lib/common lib/raidfile lib/server test/backupdiff test/backupstore test/backupstorefix/testfiles test/backupstorepatch test/basicserver test/bbackupd test/bbackupd/testfiles test/common test/raidfile test/win32

boxbackup-dev at fluffy.co.uk boxbackup-dev at fluffy.co.uk
Fri Jul 28 00:19:12 BST 2006


Author: chris
Date: 2006-07-27 23:18:35 +0000 (Thu, 27 Jul 2006)
New Revision: 710

Added:
   box/chris/merge/test/bbackupd/testfiles/bbackupd.conf.in
Removed:
   box/chris/merge/infrastructure/msvc/2003/boxbackup.ncb
   box/chris/merge/infrastructure/msvc/2003/boxbackup.suo
   box/chris/merge/test/bbackupd/testfiles/bbackupd.conf
Modified:
   box/chris/merge/bin/bbackupctl/bbackupctl.cpp
   box/chris/merge/bin/bbackupd/BackupClientContext.cpp
   box/chris/merge/bin/bbackupd/BackupClientDirectoryRecord.cpp
   box/chris/merge/bin/bbackupd/BackupDaemon.cpp
   box/chris/merge/bin/bbackupd/BackupDaemon.h
   box/chris/merge/bin/bbackupd/Win32BackupService.cpp
   box/chris/merge/bin/bbackupd/Win32BackupService.h
   box/chris/merge/bin/bbackupd/Win32ServiceFunctions.cpp
   box/chris/merge/bin/bbackupd/Win32ServiceFunctions.h
   box/chris/merge/bin/bbackupd/bbackupd.cpp
   box/chris/merge/bin/bbackupquery/BackupQueries.cpp
   box/chris/merge/bin/bbackupquery/BackupQueries.h
   box/chris/merge/bin/bbackupquery/documentation.txt
   box/chris/merge/bin/bbstored/BBStoreDHousekeeping.cpp
   box/chris/merge/bin/bbstored/BackupCommands.cpp
   box/chris/merge/bin/bbstored/BackupContext.cpp
   box/chris/merge/bin/bbstored/BackupStoreDaemon.cpp
   box/chris/merge/bin/bbstored/BackupStoreDaemon.h
   box/chris/merge/bin/bbstored/HousekeepStoreAccount.cpp
   box/chris/merge/configure.ac
   box/chris/merge/docs/backup/win32_build_on_linux_using_mingw.txt
   box/chris/merge/infrastructure/BoxPlatform.pm.in
   box/chris/merge/infrastructure/buildenv-testmain-template.cpp
   box/chris/merge/infrastructure/makebuildenv.pl.in
   box/chris/merge/lib/backupclient/BackupClientFileAttributes.cpp
   box/chris/merge/lib/backupclient/BackupStoreFile.cpp
   box/chris/merge/lib/backupclient/BackupStoreObjectDump.cpp
   box/chris/merge/lib/backupstore/BackupStoreAccounts.cpp
   box/chris/merge/lib/backupstore/BackupStoreCheck.cpp
   box/chris/merge/lib/common/BoxPlatform.h
   box/chris/merge/lib/common/FdGetLine.h
   box/chris/merge/lib/common/Guards.h
   box/chris/merge/lib/common/UnixUser.cpp
   box/chris/merge/lib/common/makeexception.pl.in
   box/chris/merge/lib/raidfile/RaidFileRead.cpp
   box/chris/merge/lib/raidfile/RaidFileWrite.cpp
   box/chris/merge/lib/server/Daemon.cpp
   box/chris/merge/lib/server/ServerStream.h
   box/chris/merge/lib/server/SocketStream.cpp
   box/chris/merge/lib/server/SocketStream.h
   box/chris/merge/lib/server/SocketStreamTLS.cpp
   box/chris/merge/lib/server/makeprotocol.pl.in
   box/chris/merge/runtest.pl.in
   box/chris/merge/test/backupdiff/testbackupdiff.cpp
   box/chris/merge/test/backupstore/testbackupstore.cpp
   box/chris/merge/test/backupstorefix/testfiles/testbackupstorefix.pl.in
   box/chris/merge/test/backupstorepatch/testbackupstorepatch.cpp
   box/chris/merge/test/basicserver/TestCommands.cpp
   box/chris/merge/test/basicserver/testbasicserver.cpp
   box/chris/merge/test/bbackupd/testbbackupd.cpp
   box/chris/merge/test/bbackupd/testfiles/extcheck1.pl.in
   box/chris/merge/test/bbackupd/testfiles/extcheck2.pl.in
   box/chris/merge/test/common/testcommon.cpp
   box/chris/merge/test/raidfile/intercept.cpp
   box/chris/merge/test/raidfile/testraidfile.cpp
   box/chris/merge/test/win32/testlibwin32.cpp
   box/chris/merge/win32.bat
Log:
* merge
- This is my current patch queue. I think that all of these are safe 
  to apply. This is just under half of the pending changes in 
  chris/general (the easy half).


Modified: box/chris/merge/bin/bbackupctl/bbackupctl.cpp
===================================================================
--- box/chris/merge/bin/bbackupctl/bbackupctl.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupctl/bbackupctl.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -32,12 +32,14 @@
 {
 	printf("Usage: bbackupctl [-q] [-c config_file] <command>\n"
 	"Commands are:\n"
-	"  sync -- start a syncronisation run now\n"
-	"  force-sync -- force the start of a syncronisation run, "
+	"  sync -- start a synchronisation (backup) run now\n"
+	"  force-sync -- force the start of a synchronisation run, "
 	"even if SyncAllowScript says no\n"
 	"  reload -- reload daemon configuration\n"
 	"  terminate -- terminate daemon now\n"
 	"  wait-for-sync -- wait until the next sync starts, then exit\n"
+	"  wait-for-end  -- wait until the next sync finishes, then exit\n"
+	"  sync-and-wait -- start sync, wait until it finishes, then exit\n"
 	);
 	exit(1);
 }
@@ -107,7 +109,10 @@
 	// Check there's a socket defined in the config file
 	if(!conf.KeyExists("CommandSocket"))
 	{
-		printf("Daemon isn't using a control socket, could not execute command.\nAdd a CommandSocket declaration to the bbackupd.conf file.\n");
+		printf("Daemon isn't using a control socket, "
+			"could not execute command.\n"
+			"Add a CommandSocket declaration to the "
+			"bbackupd.conf file.\n");
 		return 1;
 	}
 	
@@ -188,28 +193,75 @@
 	// Print summary?
 	if(!quiet)
 	{
-		printf("Daemon configuration summary:\n"	\
-			   "  AutomaticBackup = %s\n"			\
-			   "  UpdateStoreInterval = %d seconds\n"	\
-			   "  MinimumFileAge = %d seconds\n"	\
-			   "  MaxUploadWait = %d seconds\n",
-			   autoBackup?"true":"false", updateStoreInterval, minimumFileAge, maxUploadWait);
+		printf("Daemon configuration summary:\n"
+			"  AutomaticBackup = %s\n"
+			"  UpdateStoreInterval = %d seconds\n"
+			"  MinimumFileAge = %d seconds\n"
+			"  MaxUploadWait = %d seconds\n",
+			autoBackup?"true":"false", updateStoreInterval, 
+			minimumFileAge, maxUploadWait);
 	}
 
+	std::string stateLine;
+	if(!getLine.GetLine(stateLine) || getLine.IsEOF())
+	{
+#if defined WIN32 && ! defined NDEBUG
+		syslog(LOG_ERR, "Failed to receive state line from daemon");
+#else
+		printf("Failed to receive state line from daemon\n");
+#endif
+		return 1;
+	}
+
+	// Decode it
+	int currentState;
+	if(::sscanf(stateLine.c_str(), "state %d", &currentState) != 1)
+	{
+		printf("State line didn't decode\n");
+		return 1;
+	}
+
 	// Is the command the "wait for sync to start" command?
 	bool areWaitingForSync = false;
-	if(::strcmp(argv[0], "wait-for-sync") == 0)
+	bool areWaitingForSyncEnd = false;
+
+	if(::strcmp(argv[0], "wait-for-sync") == 0 ||
+	   ::strcmp(argv[0], "wait-for-end") == 0)
 	{
-		// Check that it's not in non-automatic mode, because then it'll never start
+		// Check that it's not in non-automatic mode, 
+		// because then it'll never start
 		if(!autoBackup)
 		{
-			printf("ERROR: Daemon is not in automatic mode -- sync will never start!\n");
+			printf("ERROR: Daemon is not in automatic mode -- "
+				"sync will never start!\n");
 			return 1;
 		}
 	
-		// Yes... set the flag so we know what we're waiting for a sync to start
-		areWaitingForSync = true;
+		// Yes... set the flag so we know that 
+		// we're waiting for a sync to start/end
+		if(::strcmp(argv[0], "wait-for-sync") == 0)
+		{
+			areWaitingForSync = true;
+		}
+		else if (::strcmp(argv[0], "wait-for-end") == 0)
+		{
+			areWaitingForSyncEnd = true;
+		}
 	}
+	else if (::strcmp(argv[0], "sync-and-wait") == 0)
+	{
+		// send a sync command
+		std::string cmd("force-sync\n");
+		connection.Write(cmd.c_str(), cmd.size());
+		connection.WriteAllBuffered();
+		areWaitingForSyncEnd = true;
+
+		if (currentState != 0)
+		{
+			printf("Waiting for current sync/error state "
+				"to finish...\n");
+		}
+	}
 	else
 	{
 		// No? Just send the command given plus a quit command.
@@ -220,6 +272,8 @@
 	
 	// Read the response
 	std::string line;
+	bool syncIsRunning = false;
+
 	while(!getLine.IsEOF() && getLine.GetLine(line))
 	{
 		if(areWaitingForSync)
@@ -234,6 +288,28 @@
 				break;
 			}		
 		}
+		else if(areWaitingForSyncEnd)
+		{
+			if(line == "start-sync")
+			{
+				if (!quiet) printf("Sync started...\n");
+				syncIsRunning = true;
+			}
+			else if(line == "finish-sync" && syncIsRunning)
+			{
+				if (!quiet) printf("Sync finished.\n");
+				// Send a quit command to finish nicely
+				connection.Write("quit\n", 5);
+				
+				// And we're done
+				break;
+			}
+			else if(line == "finish-sync")
+			{
+				if (!quiet) printf("Previous sync finished.\n");
+			}
+			// daemon must still be busy
+		}
 		else
 		{
 			// Is this an OK or error line?

Modified: box/chris/merge/bin/bbackupd/BackupClientContext.cpp
===================================================================
--- box/chris/merge/bin/bbackupd/BackupClientContext.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/BackupClientContext.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -176,7 +176,7 @@
 			// no -- flag so only things like deletions happen
 			mStorageLimitExceeded = true;
 			// Log
-			::syslog(LOG_INFO, "Exceeded storage limits on server -- not uploading changes to files");
+			::syslog(LOG_WARNING, "Exceeded storage limits on server -- not uploading changes to files");
 		}
 	}
 	catch(...)

Modified: box/chris/merge/bin/bbackupd/BackupClientDirectoryRecord.cpp
===================================================================
--- box/chris/merge/bin/bbackupd/BackupClientDirectoryRecord.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/BackupClientDirectoryRecord.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -645,35 +645,76 @@
 		// Need to update?
 		//
 		// Condition for upload:
-		//    modifiction time within sync period
+		//    modification time within sync period
 		//    if it's been seen before but not uploaded, is the time from this first sight longer than the MaxUploadWait
 		//	  and if we know about it from a directory listing, that it hasn't got the same upload time as on the store
-		if(
-			(
-				// Check the file modified within the acceptable time period we're checking
-				// If the file isn't on the server, the acceptable time starts at zero.
-				// Check pDirOnStore and en, because if we didn't download a directory listing,
-				// pDirOnStore will be zero, but we know it's on the server.
-				( ((pDirOnStore != 0 && en == 0) || (modTime >= rParams.mSyncPeriodStart)) && modTime < rParams.mSyncPeriodEnd)
 
-				// However, just in case things are continually modified, we check the first seen time.
-				// The two compares of syncPeriodEnd and pendingFirstSeenTime are because the values are unsigned.
-				|| (pendingFirstSeenTime != 0 &&
-					(rParams.mSyncPeriodEnd > pendingFirstSeenTime)
-						&& ((rParams.mSyncPeriodEnd - pendingFirstSeenTime) > rParams.mMaxUploadWait))
+		bool doUpload = false;
 
-				// Then make sure that if files are added with a time less than the sync period start
-				// (which can easily happen on file server), it gets uploaded. The directory contents checksum
-				// will pick up the fact it has been added, so the store listing will be available when this happens.
-				|| ((modTime <= rParams.mSyncPeriodStart) && (en != 0) && (en->GetModificationTime() != modTime))
-				
-				// And just to catch really badly off clocks in the future for file server clients,
-				// just upload the file if it's madly in the future.
-				|| (modTime > rParams.mUploadAfterThisTimeInTheFuture)
-			)			
-			// But even then, only upload it if the mod time locally is different to that on the server.
-			&& (en == 0 || en->GetModificationTime() != modTime))
+		// Only upload a file if the mod time locally is 
+		// different to that on the server.
+
+		if (en == 0 || en->GetModificationTime() != modTime)
 		{
+			// Check the file modified within the acceptable time period we're checking
+			// If the file isn't on the server, the acceptable time starts at zero.
+			// Check pDirOnStore and en, because if we didn't download a directory listing,
+			// pDirOnStore will be zero, but we know it's on the server.
+			if (modTime < rParams.mSyncPeriodEnd)
+			{
+				if (pDirOnStore != 0 && en == 0)
+				{
+					doUpload = true;
+				}
+				else if (modTime >= rParams.mSyncPeriodStart)
+				{
+					doUpload = true;
+				}
+			}
+
+			// However, just in case things are continually 
+			// modified, we check the first seen time.
+			// The two compares of syncPeriodEnd and 
+			// pendingFirstSeenTime are because the values 
+			// are unsigned.
+
+			if (!doUpload && 
+				pendingFirstSeenTime != 0 &&
+				rParams.mSyncPeriodEnd > pendingFirstSeenTime &&
+				(rParams.mSyncPeriodEnd - pendingFirstSeenTime) 
+				> rParams.mMaxUploadWait)
+			{
+				doUpload = true;
+			}
+
+			// Then make sure that if files are added with a 
+			// time less than the sync period start
+			// (which can easily happen on file server), it 
+			// gets uploaded. The directory contents checksum
+			// will pick up the fact it has been added, so the 
+			// store listing will be available when this happens.
+
+			if (!doUpload &&
+				modTime <= rParams.mSyncPeriodStart && 
+				en != 0 && 
+				en->GetModificationTime() != modTime)
+			{
+				doUpload = true;
+			}
+
+			// And just to catch really badly off clocks in 
+			// the future for file server clients,
+			// just upload the file if it's madly in the future.
+
+			if (!doUpload && modTime > 
+				rParams.mUploadAfterThisTimeInTheFuture)
+			{
+				doUpload = true;
+			}
+		}
+
+		if (doUpload)
+		{
 			// Make sure we're connected -- must connect here so we know whether
 			// the storage limit has been exceeded, and hence whether or not
 			// to actually upload the file.
@@ -1022,7 +1063,10 @@
 					BackupClientDirectoryRecord *rec = e->second;
 					mSubDirectories.erase(e);
 					delete rec;
-					TRACE2("Deleted directory record for %s/%s\n", rLocalPath.c_str(), dirname.GetClearFilename().c_str());
+					TRACE2("Deleted directory record for "
+						"%s" DIRECTORY_SEPARATOR "%s\n",
+						rLocalPath.c_str(), 
+						dirname.GetClearFilename().c_str());
 				}				
 			}
 		}

Modified: box/chris/merge/bin/bbackupd/BackupDaemon.cpp
===================================================================
--- box/chris/merge/bin/bbackupd/BackupDaemon.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/BackupDaemon.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -125,6 +125,29 @@
 	}
 
 #ifdef WIN32
+	// Create the event object to signal from main thread to worker
+	// when new messages are queued to be sent to the command socket.
+	mhMessageToSendEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+	if (mhMessageToSendEvent == INVALID_HANDLE_VALUE)
+	{
+		syslog(LOG_ERR, "Failed to create event object: error %d",
+			GetLastError);
+		exit(1);
+	}
+
+	// Create the event object to signal from worker to main thread
+	// when a command has been received on the command socket.
+	mhCommandReceivedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+	if (mhCommandReceivedEvent == INVALID_HANDLE_VALUE)
+	{
+		syslog(LOG_ERR, "Failed to create event object: error %d",
+			GetLastError);
+		exit(1);
+	}
+
+	// Create the critical section to protect the message queue
+	InitializeCriticalSection(&mMessageQueueLock);
+
 	// Create a thread to handle the named pipe
 	HANDLE hThread;
 	unsigned int dwThreadId;
@@ -263,16 +286,35 @@
 void BackupDaemon::RunHelperThread(void)
 {
 	mpCommandSocketInfo = new CommandSocketInfo;
-	this->mReceivedCommandConn = false;
+	WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket);
 
 	// loop until the parent process exits
-	while (TRUE)
+	while (!IsTerminateWanted())
 	{
 		try
 		{
-			mpCommandSocketInfo->mListeningSocket.Accept(
-				BOX_NAMED_PIPE_NAME);
+			rSocket.Accept(BOX_NAMED_PIPE_NAME);
+		}
+		catch (BoxException &e)
+		{
+			::syslog(LOG_ERR, "Failed to open command socket: %s",
+				e.what());
+			SetTerminateWanted();
+			break; // this is fatal
+		}
+		catch (...)
+		{
+			::syslog(LOG_ERR, "Failed to open command socket: "
+				"unknown error");
+			SetTerminateWanted();
+			break; // this is fatal
+		}
 
+		try
+		{
+			// Errors here do not kill the thread,
+			// only the current connection.
+
 			// This next section comes from Ben's original function
 			// Log
 			::syslog(LOG_INFO, "Connection from command socket");
@@ -289,18 +331,73 @@
 				conf.GetKeyValueInt("MaxUploadWait"),
 				mState);
 
-			mpCommandSocketInfo->mListeningSocket.Write(summary, summarySize);
-			mpCommandSocketInfo->mListeningSocket.Write("ping\n", 5);
+			rSocket.Write(summary, summarySize);
+			rSocket.Write("ping\n", 5);
 
-			IOStreamGetLine readLine(mpCommandSocketInfo->mListeningSocket);
+			// old queued messages are not useful
+			EnterCriticalSection(&mMessageQueueLock);
+			mMessageList.clear();
+			ResetEvent(mhMessageToSendEvent);
+			LeaveCriticalSection(&mMessageQueueLock);
+
+			IOStreamGetLine readLine(rSocket);
 			std::string command;
 
-			while (mpCommandSocketInfo->mListeningSocket.IsConnected() &&
-			       readLine.GetLine(command) )
+			while (rSocket.IsConnected() && !IsTerminateWanted())
 			{
-				TRACE1("Receiving command '%s' over "
-					"command socket\n", command.c_str());
+				HANDLE handles[2];
+				handles[0] = mhMessageToSendEvent;
+				handles[1] = rSocket.GetReadableEvent();
 
+				DWORD result = WaitForMultipleObjects(
+					sizeof(handles)/sizeof(*handles),
+					handles, FALSE, 1000);
+
+				if (result == 0)
+				{
+					ResetEvent(mhMessageToSendEvent);
+
+					EnterCriticalSection(&mMessageQueueLock);
+					try
+					{
+						while (mMessageList.size() > 0)
+						{
+							std::string message = *(mMessageList.begin());
+							mMessageList.erase(mMessageList.begin());
+							printf("Sending '%s' to waiting client... ", message.c_str());
+							message += "\n";
+							rSocket.Write(message.c_str(),
+								message.length());
+
+							printf("done.\n");
+						}
+					}
+					catch (...)
+					{
+						LeaveCriticalSection(&mMessageQueueLock);
+						throw;
+					}
+					LeaveCriticalSection(&mMessageQueueLock);
+					continue;
+				}
+				else if (result == WAIT_TIMEOUT)
+				{
+					continue;
+				}
+				else if (result != 1)
+				{
+					::syslog(LOG_ERR, "WaitForMultipleObjects returned invalid result %d", result);
+					continue;
+				}
+
+				if (!readLine.GetLine(command))
+				{
+					::syslog(LOG_ERR, "Failed to read line");
+					continue;
+				}
+
+				printf("Received command '%s' from client\n", command.c_str());
+
 				bool sendOK = false;
 				bool sendResponse = true;
 				bool disconnect = false;
@@ -338,12 +435,18 @@
 					SetTerminateWanted();
 					sendOK = true;
 				}
+				else
+				{
+					::syslog(LOG_ERR, "Received unknown command '%s' from client", command.c_str());
+					sendResponse = true;
+					sendOK = false;
+				}
 
 				// Send a response back?
 				if (sendResponse)
 				{
 					const char* response = sendOK ? "ok\n" : "error\n";
-					mpCommandSocketInfo->mListeningSocket.Write(
+					rSocket.Write(
 						response, strlen(response));
 				}
 
@@ -352,10 +455,10 @@
 					break;
 				}
 
-				this->mReceivedCommandConn = true;
+				// this->mReceivedCommandConn = true;
 			}
 
-			mpCommandSocketInfo->mListeningSocket.Close();
+			rSocket.Close();
 		}
 		catch (BoxException &e)
 		{
@@ -504,8 +607,8 @@
 		BackupClientContext::ClientStoreMarker_NotKnown;
 	// haven't contacted the store yet
 
- 	bool deserialised = DeserializeStoreObjectInfo(clientStoreMarker, 
-		lastSyncTime, nextSyncTime);
+ 	bool deleteStoreObjectInfoFile = DeserializeStoreObjectInfo(
+		clientStoreMarker, lastSyncTime, nextSyncTime);
  
 	// --------------------------------------------------------------------------------------------
 	
@@ -611,7 +714,8 @@
 			// Delete the serialised store object file,
 			// so that we don't try to reload it after a
 			// partially completed backup
-			if(deserialised && !DeleteStoreObjectInfo())
+			if(deleteStoreObjectInfoFile && 
+				!DeleteStoreObjectInfo())
 			{
 				::syslog(LOG_ERR, "Failed to delete the "
 					"StoreObjectInfoFile, backup cannot "
@@ -621,6 +725,11 @@
 				::sleep(60); 
 				continue;
 			}
+
+			// In case the backup throws an exception,
+			// we should not try to delete the store info
+			// object file again.
+			deleteStoreObjectInfoFile = false;
 			
 			// Do sync
 			bool errorOccurred = false;
@@ -729,9 +838,15 @@
 
 				// --------------------------------------------------------------------------------------------
 
-				// We had a successful backup, save the store info
-				SerializeStoreObjectInfo(clientStoreMarker, lastSyncTime, nextSyncTime);
+				// We had a successful backup, save the store 
+				// info. If we save successfully, we must 
+				// delete the file next time we start a backup
 
+				deleteStoreObjectInfoFile = 
+					SerializeStoreObjectInfo(
+						clientStoreMarker, 
+						lastSyncTime, nextSyncTime);
+
 				// --------------------------------------------------------------------------------------------
 			}
 			catch(BoxException &e)
@@ -902,25 +1017,27 @@
 void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut)
 {
 #ifdef WIN32
-	// Really could use some interprocess protection, mutex etc
-	// any side effect should be too bad???? :)
-	DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay);
+	DWORD requiredDelayMs = BoxTimeToMilliSeconds(RequiredDelay);
 
-	while ( this->mReceivedCommandConn == false )
+	DWORD result = WaitForSingleObject(mhCommandReceivedEvent, 
+		(DWORD)requiredDelayMs);
+
+	if (result == WAIT_OBJECT_0)
 	{
-		Sleep(1);
-
-		if ( timeout == 0 )
-		{
-			DoSyncFlagOut = false;
-			SyncIsForcedOut = false;
-			return;
-		}
-		timeout--;
+		DoSyncFlagOut = this->mDoSyncFlagOut;
+		SyncIsForcedOut = this->mSyncIsForcedOut;
+		ResetEvent(mhCommandReceivedEvent);
 	}
-	this->mReceivedCommandConn = false;
-	DoSyncFlagOut = this->mDoSyncFlagOut;
-	SyncIsForcedOut = this->mSyncIsForcedOut;
+	else if (result == WAIT_TIMEOUT)
+	{
+		DoSyncFlagOut = false;
+		SyncIsForcedOut = false;
+	}
+	else
+	{
+		::syslog(LOG_ERR, "Unexpected result from "
+			"WaitForSingleObject: error %d", GetLastError());
+	}
 
 	return;
 #else // ! WIN32
@@ -953,7 +1070,7 @@
 			{
 #ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
 				bool uidOK = true;
-				::syslog(LOG_WARNING, "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 credentials 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?
@@ -1023,8 +1140,13 @@
 		while(mpCommandSocketInfo->mpGetLine != 0 && !mpCommandSocketInfo->mpGetLine->IsEOF()
 			&& mpCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout))
 		{
-			TRACE1("Receiving command '%s' over command socket\n", command.c_str());
-			
+			TRACE1("Receiving command '%s' over command socket\n", 
+				command.c_str());
+
+			#ifdef WIN32
+			SetEvent(mhCommandReceivedEvent);
+			#endif
+
 			bool sendOK = false;
 			bool sendResponse = true;
 		
@@ -1137,13 +1259,9 @@
 // --------------------------------------------------------------------------
 void BackupDaemon::SendSyncStartOrFinish(bool SendStart)
 {
-	// The bbackupctl program can't rely on a state change, because it may never
-	// change if the server doesn't need to be contacted.
+	// The bbackupctl program can't rely on a state change, because it 
+	// may never change if the server doesn't need to be contacted.
 
-#ifdef __MINGW32__
-#warning race condition: what happens if socket is closed?
-#endif
-
 	if (mpCommandSocketInfo != NULL &&
 #ifdef WIN32
 	    mpCommandSocketInfo->mListeningSocket.IsConnected()
@@ -1152,15 +1270,18 @@
 #endif
 	    )
 	{
-		const char* message = SendStart ? "start-sync\n" : "finish-sync\n";
+		std::string message = SendStart ? "start-sync" : "finish-sync";
 		try
 		{
 #ifdef WIN32
-			mpCommandSocketInfo->mListeningSocket.Write(message, 
-				(int)strlen(message));
+			EnterCriticalSection(&mMessageQueueLock);
+			mMessageList.push_back(message);
+			SetEvent(mhMessageToSendEvent);
+			LeaveCriticalSection(&mMessageQueueLock);
 #else
-			mpCommandSocketInfo->mpConnectedSocket->Write(message,
-				strlen(message));
+			message += "\n";
+			mpCommandSocketInfo->mpConnectedSocket->Write(
+				message.c_str(), message.size());
 #endif
 		}
 		catch(...)
@@ -1756,40 +1877,37 @@
 	// command socket if there's an error
 
 	char newState[64];
-	char newStateSize = sprintf(newState, "state %d\n", State);
+	sprintf(newState, "state %d", State);
+	std::string message = newState;
 
 #ifdef WIN32
-	#ifndef _MSC_VER
-		#warning FIX ME: race condition
-	#endif
+	EnterCriticalSection(&mMessageQueueLock);
+	mMessageList.push_back(newState);
+	SetEvent(mhMessageToSendEvent);
+	LeaveCriticalSection(&mMessageQueueLock);
+#else
+	message += "\n";
 
-	// what happens if the socket is closed by the other thread before
-	// we can write to it? Null pointer deref at best.
-	if (mpCommandSocketInfo && 
-	    mpCommandSocketInfo->mListeningSocket.IsConnected())
+	if(mpCommandSocketInfo == 0)
 	{
-		try
-		{
-			mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize);
-		}
-		catch(...)
-		{
-			CloseCommandConnection();
-		}
+		return;
 	}
-#else
-	if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0)
+
+	if (mpCommandSocketInfo->mpConnectedSocket.get() == 0)
 	{
-		// Something connected to the command socket, tell it about the new state
-		try
-		{
-			mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize);
-		}
-		catch(...)
-		{
-			CloseCommandConnection();
-		}
+		return;
 	}
+
+	// Something connected to the command socket, tell it about the new state
+	try
+	{
+		mpCommandSocketInfo->mpConnectedSocket->Write(message.c_str(),
+			message.length());
+	}
+	catch(...)
+	{
+		CloseCommandConnection();
+	}
 #endif
 }
 
@@ -2173,11 +2291,11 @@
 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
+bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const
 {
 	if(!GetConfiguration().KeyExists("StoreObjectInfoFile"))
 	{
-		return;
+		return false;
 	}
 
 	std::string StoreObjectInfoFile = 
@@ -2185,13 +2303,17 @@
 
 	if (StoreObjectInfoFile.size() <= 0)
 	{
-		return;
+		return false;
 	}
 
+	bool created = false;
+
 	try
 	{
 		FileStream aFile(StoreObjectInfoFile.c_str(), 
 			O_WRONLY | O_CREAT | O_TRUNC);
+		created = true;
+
 		Archive anArchive(aFile, 0);
 
 		anArchive.Write(STOREOBJECTINFO_MAGIC_ID_VALUE);
@@ -2236,6 +2358,8 @@
 			"not accessible or could not be created", 
 			StoreObjectInfoFile.c_str());
 	}
+
+	return created;
 }
 
 // --------------------------------------------------------------------------

Modified: box/chris/merge/bin/bbackupd/BackupDaemon.h
===================================================================
--- box/chris/merge/bin/bbackupd/BackupDaemon.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/BackupDaemon.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -46,9 +46,12 @@
 	~BackupDaemon();
 
 private:
-	// methods below do partial (specialized) serialization of client state only
-	void SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const;
-	bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime);
+	// methods below do partial (specialized) serialization of 
+	// client state only
+	bool SerializeStoreObjectInfo(int64_t aClientStoreMarker, 
+		box_time_t theLastSyncTime, box_time_t theNextSyncTime) const;
+	bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, 
+		box_time_t & theLastSyncTime, box_time_t & theNextSyncTime);
 	bool DeleteStoreObjectInfo() const;
 	BackupDaemon(const BackupDaemon &);
 public:
@@ -182,7 +185,10 @@
 	void RunHelperThread(void);
 
 	private:
-	bool mDoSyncFlagOut, mSyncIsForcedOut, mReceivedCommandConn;
+	bool mDoSyncFlagOut, mSyncIsForcedOut;
+	HANDLE mhMessageToSendEvent, mhCommandReceivedEvent;
+	CRITICAL_SECTION mMessageQueueLock;
+	std::vector<std::string> mMessageList;
 #endif
 };
 

Modified: box/chris/merge/bin/bbackupd/Win32BackupService.cpp
===================================================================
--- box/chris/merge/bin/bbackupd/Win32BackupService.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/Win32BackupService.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -12,40 +12,51 @@
 
 #include "Win32BackupService.h"
 
-Win32BackupService gDaemonService;
+Win32BackupService* gpDaemonService = NULL;
 extern HANDLE gStopServiceEvent;
 
 unsigned int WINAPI RunService(LPVOID lpParameter)
 {
-	DWORD retVal = gDaemonService.WinService();
-	SetEvent( gStopServiceEvent );
+	DWORD retVal = gpDaemonService->WinService((const char*) lpParameter);
+	SetEvent(gStopServiceEvent);
 	return retVal;
 }
 
 void TerminateService(void)
 {
-	gDaemonService.SetTerminateWanted();
+	gpDaemonService->SetTerminateWanted();
 }
 
-DWORD Win32BackupService::WinService(void)
+DWORD Win32BackupService::WinService(const char* pConfigFileName)
 {
-	int argc = 2;
-	//first off get the path name for the default 
-	char buf[MAX_PATH];
+	char exepath[MAX_PATH];
+	GetModuleFileName(NULL, exepath, sizeof(exepath));
+
+	std::string configfile;
 	
-	GetModuleFileName(NULL, buf, sizeof(buf));
-	std::string buffer(buf);
-	std::string conf( "-c");
-	std::string cfile(buffer.substr(0,(buffer.find("bbackupd.exe"))) 
-			+ "bbackupd.conf");
+	if (pConfigFileName != NULL)
+	{
+		configfile = pConfigFileName;
+	}
+	else
+	{
+		// make the default config file name,
+		// based on the program path
+		configfile = exepath;
+		configfile = configfile.substr(0,
+			configfile.rfind(DIRECTORY_SEPARATOR_ASCHAR));
+		configfile += DIRECTORY_SEPARATOR "bbackupd.conf";
+	}
 
-	const char *argv[] = {conf.c_str(), cfile.c_str()};
+	const char *argv[] = {exepath, "-c", configfile.c_str()};
+	int argc = sizeof(argv) / sizeof(*argv);
+	DWORD ret;
 
 	MAINHELPER_START
+	ret = this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv);
+	MAINHELPER_END
 
-	return this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv);
-
-	MAINHELPER_END
+	return ret;
 }
 
 #endif // WIN32

Modified: box/chris/merge/bin/bbackupd/Win32BackupService.h
===================================================================
--- box/chris/merge/bin/bbackupd/Win32BackupService.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/Win32BackupService.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -12,7 +12,7 @@
 class Win32BackupService : public BackupDaemon
 {
 public:
-	DWORD WinService(void);
+	DWORD WinService(const char* pConfigFileName);
 };
 
 #endif // WIN32

Modified: box/chris/merge/bin/bbackupd/Win32ServiceFunctions.cpp
===================================================================
--- box/chris/merge/bin/bbackupd/Win32ServiceFunctions.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/Win32ServiceFunctions.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -93,28 +93,30 @@
 // It also returns on any error because the
 // service cannot start if there is an eror.
 
+static char* spConfigFileName;
+
 VOID ServiceMain(DWORD argc, LPTSTR *argv) 
 {
-    // initialise service status
-    gServiceStatus.dwServiceType = SERVICE_WIN32;
-    gServiceStatus.dwCurrentState = SERVICE_STOPPED;
-    gServiceStatus.dwControlsAccepted = 0;
-    gServiceStatus.dwWin32ExitCode = NO_ERROR;
-    gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
-    gServiceStatus.dwCheckPoint = 0;
-    gServiceStatus.dwWaitHint = 0;
+	// initialise service status
+	gServiceStatus.dwServiceType = SERVICE_WIN32;
+	gServiceStatus.dwCurrentState = SERVICE_STOPPED;
+	gServiceStatus.dwControlsAccepted = 0;
+	gServiceStatus.dwWin32ExitCode = NO_ERROR;
+	gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
+	gServiceStatus.dwCheckPoint = 0;
+	gServiceStatus.dwWaitHint = 0;
 
-    gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName, 
-	ServiceControlHandler);
+	gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName, 
+		ServiceControlHandler);
 
-    if (gServiceStatusHandle)
-    {
-        // service is starting
-        gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
-        SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
+	if (gServiceStatusHandle)
+	{
+		// service is starting
+		gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+		SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
 
-        // do initialisation here
-        gStopServiceEvent = CreateEvent( 0, TRUE, FALSE, 0 );
+		// do initialisation here
+		gStopServiceEvent = CreateEvent(0, TRUE, FALSE, 0);
 		if (!gStopServiceEvent)
 		{
 			gServiceStatus.dwControlsAccepted &= 
@@ -129,7 +131,7 @@
 			NULL,
 			0,
 			RunService,
-			0,
+			spConfigFileName,
 			CREATE_SUSPENDED,
 			NULL);
 
@@ -138,7 +140,7 @@
 
 		// we are now running so tell the SCM
 		gServiceStatus.dwControlsAccepted |= 
-		(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
+			(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
 		gServiceStatus.dwCurrentState = SERVICE_RUNNING;
 		SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
 
@@ -156,11 +158,13 @@
 			~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
 		gServiceStatus.dwCurrentState = SERVICE_STOPPED;
 		SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
-    }
+	}
 }
 
-void OurService(void)
+void OurService(char* pConfigFileName)
 {
+	spConfigFileName = pConfigFileName;
+
 	SERVICE_TABLE_ENTRY serviceTable[] = 
 	{ 
 		{ SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain },
@@ -179,28 +183,52 @@
 	}
 }
 
-void InstallService(void)
+int InstallService(const char* pConfigFileName)
 {
-	SC_HANDLE newService, scm;
+	if (pConfigFileName != NULL)
+	{
+		struct stat st;
 
-	scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
+		if (emu_stat(pConfigFileName, &st) != 0)
+		{
+			syslog(LOG_ERR, "Failed to open configuration file: "
+				"%s: %s", pConfigFileName, strerror(errno));
+			return 1;
+		}
 
+		if (! st.st_mode & S_IFREG)
+		{
+	
+			syslog(LOG_ERR, "Failed to open configuration file: "
+				"%s: not a file", pConfigFileName);
+			return 1;
+		}
+	}
+
+	SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
+
 	if (!scm) 
 	{
 		syslog(LOG_ERR, "Failed to open service control manager: "
 			"error %d", GetLastError());
-		return;
+		return 1;
 	}
 
 	char cmd[MAX_PATH];
 	GetModuleFileName(NULL, cmd, sizeof(cmd)-1);
 	cmd[sizeof(cmd)-1] = 0;
 
-	char cmd_args[MAX_PATH];
-	_snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd);
-	cmd_args[sizeof(cmd_args)-1] = 0;
+	std::string cmdWithArgs(cmd);
+	cmdWithArgs += " --service";
 
-	newService = CreateService(
+	if (pConfigFileName != NULL)
+	{
+		cmdWithArgs += " \"";
+		cmdWithArgs += pConfigFileName;
+		cmdWithArgs += "\"";
+	}
+
+	SC_HANDLE newService = CreateService(
 		scm, 
 		SERVICE_NAME, 
 		"Box Backup", 
@@ -208,14 +236,36 @@
 		SERVICE_WIN32_OWN_PROCESS, 
 		SERVICE_AUTO_START, 
 		SERVICE_ERROR_NORMAL, 
-		cmd_args, 
+		cmdWithArgs.c_str(),
 		0,0,0,0,0);
 
+	DWORD err = GetLastError();
+	CloseServiceHandle(scm);
+
 	if (!newService) 
 	{
-		::syslog(LOG_ERR, "Failed to create Box Backup service: "
-			"error %d", GetLastError());
-		return;
+		if (err == ERROR_SERVICE_EXISTS)
+		{
+			::syslog(LOG_ERR, "Failed to create Box Backup "
+				"service: it already exists");
+		}
+		else if (err == ERROR_SERVICE_MARKED_FOR_DELETE)
+		{
+			::syslog(LOG_ERR, "Failed to create Box Backup "
+				"service: it is waiting to be deleted");
+		}
+		else if (err == ERROR_DUPLICATE_SERVICE_NAME)
+		{
+			::syslog(LOG_ERR, "Failed to create Box Backup "
+				"service: a service with this name "
+				"already exists");
+		}
+		else
+		{
+			::syslog(LOG_ERR, "Failed to create Box Backup "
+				"service: error %d", err);
+		}
+		return 1;
 	}
 
 	::syslog(LOG_INFO, "Created Box Backup service");
@@ -231,45 +281,75 @@
 	}
 
 	CloseServiceHandle(newService);
-	CloseServiceHandle(scm);
+
+	return 0;
 }
 
-void RemoveService(void)
+int RemoveService(void)
 {
-	SC_HANDLE service, scm;
-	SERVICE_STATUS status;
+	SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
 
-	scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
-
 	if (!scm) 
 	{
 		syslog(LOG_ERR, "Failed to open service control manager: "
 			"error %d", GetLastError());
-		return;
+		return 1;
 	}
 
-	service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE);
-	ControlService(service, SERVICE_CONTROL_STOP, &status);
+	SC_HANDLE service = OpenService(scm, SERVICE_NAME, 
+		SERVICE_ALL_ACCESS|DELETE);
+	DWORD err = GetLastError();
+	CloseServiceHandle(scm);
 
 	if (!service)
 	{
-		syslog(LOG_ERR, "Failed to open Box Backup service: "
-			"error %d", GetLastError());
-		return;
+		if (err == ERROR_SERVICE_DOES_NOT_EXIST ||
+			err == ERROR_IO_PENDING) 
+			// hello microsoft? anyone home?
+		{
+			syslog(LOG_ERR, "Failed to open Box Backup service: "
+				"not installed or not found");
+		}
+		else
+		{
+			syslog(LOG_ERR, "Failed to open Box Backup service: "
+				"error %d", err);
+		}
+		return 1;
 	}
 
-	if (DeleteService(service))
+	SERVICE_STATUS status;
+	if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
 	{
+		err = GetLastError();
+		if (err != ERROR_SERVICE_NOT_ACTIVE)
+		{
+			syslog(LOG_WARNING, "Failed to stop Box Backup "
+				"service: error %d", err);
+		}
+	}
+
+	BOOL deleted = DeleteService(service);
+	err = GetLastError();
+	CloseServiceHandle(service);
+
+	if (deleted)
+	{
 		syslog(LOG_INFO, "Box Backup service deleted");
+		return 0;
 	}
+	else if (err == ERROR_SERVICE_MARKED_FOR_DELETE)
+	{
+		syslog(LOG_ERR, "Failed to remove Box Backup service: "
+			"it is already being deleted");
+	}
 	else
 	{
 		syslog(LOG_ERR, "Failed to remove Box Backup service: "
-			"error %d", GetLastError());
+			"error %d", err);
 	}
 
-	CloseServiceHandle(service);
-	CloseServiceHandle(scm);
+	return 1;
 }
 
 #endif // WIN32

Modified: box/chris/merge/bin/bbackupd/Win32ServiceFunctions.h
===================================================================
--- box/chris/merge/bin/bbackupd/Win32ServiceFunctions.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/Win32ServiceFunctions.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -12,8 +12,8 @@
 #ifndef WIN32SERVICEFUNCTIONS_H
 #define WIN32SERVICEFUNCTIONS_H
 
-void RemoveService(void);
-void InstallService(void);
-void OurService(void);
+int  RemoveService(void);
+int  InstallService(const char* pConfigFilePath);
+void OurService(char* pConfigFileName);
 
 #endif

Modified: box/chris/merge/bin/bbackupd/bbackupd.cpp
===================================================================
--- box/chris/merge/bin/bbackupd/bbackupd.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupd/bbackupd.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -19,7 +19,7 @@
 	#include "Win32ServiceFunctions.h"
 	#include "Win32BackupService.h"
 
-	extern Win32BackupService gDaemonService;
+	extern Win32BackupService* gpDaemonService;
 #endif
 
 int main(int argc, const char *argv[])
@@ -28,7 +28,7 @@
 
 #ifdef WIN32
 
-	::openlog("Box Backup (bbackupd)", 0, 0);
+	::openlog("Box Backup (bbackupd)", LOG_PID, LOG_LOCAL6);
 
 	if(argc == 2 &&
 		(::strcmp(argv[1], "--help") == 0 ||
@@ -40,32 +40,25 @@
 	}
 	if(argc == 2 && ::strcmp(argv[1], "-r") == 0)
 	{
-		RemoveService();
-		return 0;
+		return RemoveService();
 	}
-	if(argc == 2 && ::strcmp(argv[1], "-i") == 0)
+	if((argc == 2 || argc == 3) && ::strcmp(argv[1], "-i") == 0)
 	{
-		InstallService();
-		return 0;
+		const char* config = NULL;
+		if (argc == 3)
+		{
+			config = argv[2];
+		}
+		return InstallService(config);
 	}
 
 	bool runAsWin32Service = false;
-	if (argc == 2 && ::strcmp(argv[1], "--service") == 0)
+	if (argc >= 2 && ::strcmp(argv[1], "--service") == 0)
 	{
 		runAsWin32Service = true;
 	}
-	
-	// Under win32 we must initialise the Winsock library
-	// before using sockets
-		
-	WSADATA info;
 
-	if (WSAStartup(0x0101, &info) == SOCKET_ERROR) 
-	{
-		// box backup will not run without sockets
-		::syslog(LOG_ERR, "Failed to initialise Windows Sockets");
-		THROW_EXCEPTION(BackupStoreException, Internal)
-	}
+	gpDaemonService = new Win32BackupService();
 
 	EnableBackupRights();
 
@@ -73,20 +66,33 @@
 
 	if (runAsWin32Service)
 	{
-		syslog(LOG_INFO,"Starting Box Backup Service");
-		OurService();
+		syslog(LOG_INFO, "Box Backup service starting");
+
+		char* config = NULL;
+		if (argc >= 3)
+		{
+			config = strdup(argv[2]);
+		}
+
+		OurService(config);
+
+		if (config)
+		{
+			free(config);
+		}
+
+		syslog(LOG_INFO, "Box Backup service shut down");
 	}
 	else
 	{
-		ExitCode = gDaemonService.Main(
+		ExitCode = gpDaemonService->Main(
 			BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv);
 	}
 
-	// Clean up our sockets
-	WSACleanup();
-
 	::closelog();
 
+	delete gpDaemonService;
+
 	return ExitCode;
 
 #else // !WIN32

Modified: box/chris/merge/bin/bbackupquery/BackupQueries.cpp
===================================================================
--- box/chris/merge/bin/bbackupquery/BackupQueries.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupquery/BackupQueries.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -70,7 +70,11 @@
 	  mWarnedAboutOwnerAttributes(false),
 	  mReturnCode(0)		// default return code
 {
+	#ifdef WIN32
+	mRunningAsRoot = TRUE;
+	#else
 	mRunningAsRoot = (::geteuid() == 0);
+	#endif
 }
 
 // --------------------------------------------------------------------------
@@ -85,6 +89,12 @@
 {
 }
 
+typedef struct cmd_info
+{
+	const char* name;
+	const char* opts;
+} cmd_info_t;
+
 // --------------------------------------------------------------------------
 //
 // Function
@@ -162,8 +172,24 @@
 	}
 	
 	// Data about commands
-	static const char *commandNames[] = {"quit", "exit", "list",	 "pwd", "cd", "lcd",	"sh", "getobject", "get", "compare", "restore", "help", "usage", "undelete", 0};
-	static const char *validOptions[] = {"",	 "",	 "rodIFtsh", "",	   "od", "",	"",	  "",		   "i",   "alcqE",   "dri",     "",     "",      "",		 0};
+	static cmd_info_t commands[] = 
+	{
+		{ "quit", "" },
+		{ "exit", "" },
+		{ "list", "rodIFtTsh", },
+		{ "pwd",  "" },
+		{ "cd",   "od" },
+		{ "lcd",  "" },
+		{ "sh",   "" },
+		{ "getobject", "" },
+		{ "get",  "i" },
+		{ "compare", "alcqAE" },
+		{ "restore", "dri" },
+		{ "help", "" },
+		{ "usage", "" },
+		{ "undelete", "" },
+		{ NULL, NULL } 
+	};
 	#define COMMAND_Quit		0
 	#define COMMAND_Exit		1
 	#define COMMAND_List		2
@@ -183,11 +209,11 @@
 	
 	// Work out which command it is...
 	int cmd = 0;
-	while(commandNames[cmd] != 0 && ::strcmp(cmdElements[0].c_str(), commandNames[cmd]) != 0)
+	while(commands[cmd].name != 0 && ::strcmp(cmdElements[0].c_str(), commands[cmd].name) != 0)
 	{
 		cmd++;
 	}
-	if(commandNames[cmd] == 0)
+	if(commands[cmd].name == 0)
 	{
 		// Check for aliases
 		int a;
@@ -222,9 +248,10 @@
 		while(*c != 0)
 		{
 			// Valid option?
-			if(::strchr(validOptions[cmd], *c) == NULL)
+			if(::strchr(commands[cmd].opts, *c) == NULL)
 			{
-				printf("Invalid option '%c' for command %s\n", *c, commandNames[cmd]);
+				printf("Invalid option '%c' for command %s\n", 
+					*c, commands[cmd].name);
 				return;
 			}
 			opts[(int)*c] = true;
@@ -319,8 +346,9 @@
 	#define LIST_OPTION_ALLOWOLD		'o'
 	#define LIST_OPTION_ALLOWDELETED	'd'
 	#define LIST_OPTION_NOOBJECTID		'I'
-	#define LIST_OPTION_NOFLAGS			'F'
-	#define LIST_OPTION_TIMES			't'
+	#define LIST_OPTION_NOFLAGS		'F'
+	#define LIST_OPTION_TIMES_LOCAL		't'
+	#define LIST_OPTION_TIMES_UTC		'T'
 	#define LIST_OPTION_SIZEINBLOCKS	's'
 	#define LIST_OPTION_DISPLAY_HASH	'h'
 
@@ -362,7 +390,7 @@
 // --------------------------------------------------------------------------
 //
 // Function
-//		Name:    BackupQueries::CommandList2(int64_t, const std::string &, const bool *)
+//		Name:    BackupQueries::List(int64_t, const std::string &, const bool *, bool)
 //		Purpose: Do the actual listing of directories and files
 //		Created: 2003/10/10
 //
@@ -437,9 +465,9 @@
 			}
 		}
 		
-		if(opts[LIST_OPTION_TIMES])
+		if(opts[LIST_OPTION_TIMES_LOCAL])
 		{
-			// Show times...
+			// Show local times...
 			std::string time = BoxTimeToISO8601String(
 				en->GetModificationTime());
 			printf("%s ", time.c_str());
@@ -844,13 +872,44 @@
 	}
 
 	// Find object ID somehow
-	int64_t id;
+	int64_t fileId;
+	int64_t dirId = GetCurrentDirectoryID();
 	std::string localName;
+
 	// BLOCK
 	{
+#ifdef WIN32
+		std::string fileName;
+		if(!ConvertConsoleToUtf8(args[0].c_str(), fileName))
+			return;
+#else
+		std::string fileName(args[0]);
+#endif
+
+		if(!opts['i'])
+		{
+			// does this remote filename include a path?
+			std::string::size_type index = fileName.rfind('/');
+			if(index != std::string::npos)
+			{
+				std::string dirName(fileName.substr(0, index));
+				fileName = fileName.substr(index + 1);
+
+				dirId = FindDirectoryObjectID(dirName);
+				if(dirId == 0)
+				{
+					printf("Directory '%s' not found\n", 
+						dirName.c_str());
+					return;
+				}
+			}
+		}
+
+		BackupStoreFilenameClear fn(fileName);
+
 		// Need to look it up in the current directory
 		mrConnection.QueryListDirectory(
-				GetCurrentDirectoryID(),
+				dirId,
 				BackupProtocolClientListDirectory::Flags_File,	// just files
 				(opts['i'])?(BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING):(BackupProtocolClientListDirectory::Flags_OldVersion | BackupProtocolClientListDirectory::Flags_Deleted), // only current versions
 				false /* don't want attributes */);
@@ -863,17 +922,23 @@
 		if(opts['i'])
 		{
 			// Specified as ID. 
-			id = ::strtoll(args[0].c_str(), 0, 16);
-			if(id == std::numeric_limits<long long>::min() || id == std::numeric_limits<long long>::max() || id == 0)
+			fileId = ::strtoll(args[0].c_str(), 0, 16);
+			if(fileId == std::numeric_limits<long long>::min() || 
+				fileId == std::numeric_limits<long long>::max() || 
+				fileId == 0)
 			{
 				printf("Not a valid object ID (specified in hex)\n");
 				return;
 			}
 			
 			// Check that the item is actually in the directory
-			if(dir.FindEntryByID(id) == 0)
+			if(dir.FindEntryByID(fileId) == 0)
 			{
-				printf("ID '%08llx' not found in current directory on store.\n(You can only download objects by ID from the current directory.)\n", id);
+				printf("ID '%08llx' not found in current "
+					"directory on store.\n"
+					"(You can only download objects by ID "
+					"from the current directory.)\n", 
+					fileId);
 				return;
 			}
 			
@@ -884,26 +949,22 @@
 		{				
 			// Specified by name, find the object in the directory to get the ID
 			BackupStoreDirectory::Iterator i(dir);
-#ifdef WIN32
-			std::string fileName;
-			if(!ConvertConsoleToUtf8(args[0].c_str(), fileName))
-				return;
-			BackupStoreFilenameClear fn(fileName);
-#else
-			BackupStoreFilenameClear fn(args[0]);
-#endif
 			BackupStoreDirectory::Entry *en = i.FindMatchingClearName(fn);
 			
 			if(en == 0)
 			{
-				printf("Filename '%s' not found in current directory on store.\n(Subdirectories in path not searched.)\n", args[0].c_str());
+				printf("Filename '%s' not found in current "
+					"directory on store.\n"
+					"(Subdirectories in path not "
+					"searched.)\n", args[0].c_str());
 				return;
 			}
 			
-			id = en->GetObjectID();
+			fileId = en->GetObjectID();
 			
-			// Local name is the last argument, which is either the looked up filename, or
-			// a filename specified by the user.
+			// Local name is the last argument, which is either 
+			// the looked up filename, or a filename specified 
+			// by the user.
 			localName = args[args.size() - 1];
 		}
 	}
@@ -920,7 +981,7 @@
 	try
 	{
 		// Request object
-		mrConnection.QueryGetFile(GetCurrentDirectoryID(), id);
+		mrConnection.QueryGetFile(dirId, fileId);
 
 		// Stream containing encoded file
 		std::auto_ptr<IOStream> objectStream(mrConnection.ReceiveStream());
@@ -929,7 +990,7 @@
 		BackupStoreFile::DecodeFile(*objectStream, localName.c_str(), mrConnection.GetTimeout());
 
 		// Done.
-		printf("Object ID %08llx fetched sucessfully.\n", id);
+		printf("Object ID %08llx fetched sucessfully.\n", fileId);
 	}
 	catch(...)
 	{
@@ -950,8 +1011,10 @@
 BackupQueries::CompareParams::CompareParams()
 	: mQuickCompare(false),
 	  mIgnoreExcludes(false),
+	  mIgnoreAttributes(false),
 	  mDifferences(0),
 	  mDifferencesExplainedByModTime(0),
+	  mUncheckedFiles(0),
 	  mExcludedDirs(0),
 	  mExcludedFiles(0),
 	  mpExcludeFiles(0),
@@ -1012,6 +1075,7 @@
 	BackupQueries::CompareParams params;
 	params.mQuickCompare = opts['q'];
 	params.mIgnoreExcludes = opts['E'];
+	params.mIgnoreAttributes = opts['A'];
 	
 	// Try and work out the time before which all files should be on the server
 	{
@@ -1074,13 +1138,29 @@
 		return;
 	}
 	
-	printf("\n[ %d (of %d) differences probably due to file modifications after the last upload ]\nDifferences: %d (%d dirs excluded, %d files excluded)\n",
-		params.mDifferencesExplainedByModTime, params.mDifferences, params.mDifferences, params.mExcludedDirs, params.mExcludedFiles);
+	printf("\n[ %d (of %d) differences probably due to file "
+		"modifications after the last upload ]\n"
+		"Differences: %d (%d dirs excluded, %d files excluded, "
+		"%d files not checked)\n",
+		params.mDifferencesExplainedByModTime, params.mDifferences, 
+		params.mDifferences, params.mExcludedDirs, 
+		params.mExcludedFiles, params.mUncheckedFiles);
 	
 	// Set return code?
 	if(opts['c'])
 	{
-		SetReturnCode((params.mDifferences == 0)?COMPARE_RETURN_SAME:COMPARE_RETURN_DIFFERENT);
+		if (params.mUncheckedFiles != 0)
+		{
+			SetReturnCode(COMPARE_RETURN_ERROR);
+		} 
+		else if (params.mDifferences != 0)
+		{
+			SetReturnCode(COMPARE_RETURN_DIFFERENT);
+		}
+		else
+		{
+			SetReturnCode(COMPARE_RETURN_SAME);
+		}
 	}
 }
 
@@ -1214,11 +1294,13 @@
 				"(compared to server directory '%s')\n",
 				localDirDisplay.c_str(), 
 				storeDirDisplay.c_str());
+			rParams.mDifferences ++;
 		}
 		else
 		{
 			printf("ERROR: stat on local dir '%s'\n", 
 				localDirDisplay.c_str());
+			rParams.mUncheckedFiles ++;
 		}
 		return;
 	}
@@ -1268,6 +1350,7 @@
 	{
 		printf("ERROR: opendir on local dir '%s'\n", 
 			localDirDisplay.c_str());
+		rParams.mUncheckedFiles ++;
 		return;
 	}
 	try
@@ -1455,11 +1538,12 @@
 						}
 						
 						// Compare attributes
+						box_time_t fileModTime = 0;
 						BackupClientFileAttributes localAttr;
-						box_time_t fileModTime = 0;
 						localAttr.ReadAttributes(localPath.c_str(), false /* don't zero mod times */, &fileModTime);					
 						modifiedAfterLastSync = (fileModTime > rParams.mLatestFileUploadTime);
-						if(!localAttr.Compare(fileOnServerStream->GetAttributes(),
+						if(!rParams.mIgnoreAttributes &&
+						   !localAttr.Compare(fileOnServerStream->GetAttributes(),
 								true /* ignore attr mod time */,
 								fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */))
 						{
@@ -1554,10 +1638,12 @@
 						e.GetType(),
 						e.GetSubType(),
 						storePathDisplay.c_str());
+					rParams.mUncheckedFiles ++;
 				}
 				catch(...)
-				{
+				{	
 					printf("ERROR: (unknown) during file fetch and comparison for '%s'\n", storePathDisplay.c_str());
+					rParams.mUncheckedFiles ++;
 				}
 
 				// Remove from set so that we know it's been compared
@@ -1793,6 +1879,14 @@
 		printf("The target directory exists. You cannot restore over an existing directory.\n");
 		break;
 		
+	#ifdef WIN32
+	case Restore_TargetPathNotFound:
+		printf("The target directory path does not exist.\n"
+			"To restore to a directory whose parent "
+			"does not exist, create the parent first.\n");
+		break;
+	#endif
+
 	default:
 		printf("ERROR: Unknown restore result.\n");
 		break;

Modified: box/chris/merge/bin/bbackupquery/BackupQueries.h
===================================================================
--- box/chris/merge/bin/bbackupquery/BackupQueries.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupquery/BackupQueries.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -68,8 +68,10 @@
 		void DeleteExcludeLists();
 		bool mQuickCompare;
 		bool mIgnoreExcludes;
+		bool mIgnoreAttributes;
 		int mDifferences;
 		int mDifferencesExplainedByModTime;
+		int mUncheckedFiles;
 		int mExcludedDirs;
 		int mExcludedFiles;
 		const ExcludeList *mpExcludeFiles;

Modified: box/chris/merge/bin/bbackupquery/documentation.txt
===================================================================
--- box/chris/merge/bin/bbackupquery/documentation.txt	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbackupquery/documentation.txt	2006-07-27 23:18:35 UTC (rev 710)
@@ -104,6 +104,7 @@
 	-c -- set return code
 	-q -- quick compare. Only checks file contents against checksums,
 			doesn't do a full download
+	-A -- ignore attribute differences
 	-E -- ignore exclusion settings
 	
 	Comparing with the root directory is an error, use -a option instead.

Modified: box/chris/merge/bin/bbstored/BBStoreDHousekeeping.cpp
===================================================================
--- box/chris/merge/bin/bbstored/BBStoreDHousekeeping.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbstored/BBStoreDHousekeeping.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -10,7 +10,10 @@
 #include "Box.h"
 
 #include <stdio.h>
+
+#ifdef HAVE_SYSLOG_H
 #include <syslog.h>
+#endif
 
 #include "BackupStoreDaemon.h"
 #include "BackupStoreAccountDatabase.h"
@@ -29,96 +32,129 @@
 //		Created: 11/12/03
 //
 // --------------------------------------------------------------------------
+void BackupStoreDaemon::HousekeepingInit()
+{
+
+	mLastHousekeepingRun = 0;
+}
+
+#ifndef WIN32
 void BackupStoreDaemon::HousekeepingProcess()
 {
+	HousekeepingInit();
+
 	// Get the time between housekeeping runs
 	const Configuration &rconfig(GetConfiguration());
 	int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping"));
-	
-	int64_t lastHousekeepingRun = 0;
 
 	while(!StopRun())
 	{
-		// Time now
+		RunHousekeepingIfNeeded();
+
+		// Calculate how long should wait before doing the next housekeeping run
 		int64_t timeNow = GetCurrentBoxTime();
-		// Do housekeeping if the time interval has elapsed since the last check
-		if((timeNow - lastHousekeepingRun) >= housekeepingInterval)
-		{
-			// Store the time
-			lastHousekeepingRun = timeNow;
-			::syslog(LOG_INFO, "Starting housekeeping");
+		time_t secondsToGo = BoxTimeToSeconds((mLastHousekeepingRun + housekeepingInterval) - timeNow);
+		if(secondsToGo < 1) secondsToGo = 1;
+		if(secondsToGo > 60) secondsToGo = 60;
+		int32_t millisecondsToGo = ((int)secondsToGo) * 1000;
+	
+		// Check to see if there's any message pending
+		CheckForInterProcessMsg(0 /* no account */, millisecondsToGo);
+	}
+}
+#endif
 
-			// Get the list of accounts
-			std::vector<int32_t> accounts;
-			if(mpAccountDatabase)
-			{
-				mpAccountDatabase->GetAllAccountIDs(accounts);
-			}
+void BackupStoreDaemon::RunHousekeepingIfNeeded()
+{
+	// Get the time between housekeeping runs
+	const Configuration &rconfig(GetConfiguration());
+	int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping"));
+
+	// Time now
+	int64_t timeNow = GetCurrentBoxTime();
+	// Do housekeeping if the time interval has elapsed since the last check
+	if((timeNow - mLastHousekeepingRun) < housekeepingInterval)
+	{
+		return;
+	}
+
+	// Store the time
+	mLastHousekeepingRun = timeNow;
+	::syslog(LOG_INFO, "Starting housekeeping");
+
+	// Get the list of accounts
+	std::vector<int32_t> accounts;
+	if(mpAccountDatabase)
+	{
+		mpAccountDatabase->GetAllAccountIDs(accounts);
+	}
 			
-			SetProcessTitle("housekeeping, active");
+	SetProcessTitle("housekeeping, active");
 			
-			// Check them all
-			for(std::vector<int32_t>::const_iterator i = accounts.begin(); i != accounts.end(); ++i)
+	// Check them all
+	for(std::vector<int32_t>::const_iterator i = accounts.begin(); i != accounts.end(); ++i)
+	{
+		try
+		{
+			if(mpAccounts)
 			{
-				try
-				{
-					if(mpAccounts)
-					{
-						// Get the account root
-						std::string rootDir;
-						int discSet = 0;
-						mpAccounts->GetAccountRoot(*i, rootDir, discSet);
-						
-						// Do housekeeping on this account
-						HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this);
-						housekeeping.DoHousekeeping();
-					}
-				}
-				catch(BoxException &e)
-				{
-					::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account",
-						*i, e.what(), e.GetType(), e.GetSubType());
-				}
-				catch(std::exception &e)
-				{
-					::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account",
-						*i, e.what());
-				}
-				catch(...)
-				{
-					::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account",
-						*i);
-				}
+				// Get the account root
+				std::string rootDir;
+				int discSet = 0;
+				mpAccounts->GetAccountRoot(*i, rootDir, discSet);
 				
-				// Check to see if there's any message pending
-				CheckForInterProcessMsg(0 /* no account */);
-		
-				// Stop early?
-				if(StopRun())
-				{
-					break;
-				}
+				// Do housekeeping on this account
+				HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this);
+				housekeeping.DoHousekeeping();
 			}
-			
-			::syslog(LOG_INFO, "Finished housekeeping");
 		}
-
-		// Placed here for accuracy, if StopRun() is true, for example.
-		SetProcessTitle("housekeeping, idle");
-		
-		// Calculate how long should wait before doing the next housekeeping run
-		timeNow = GetCurrentBoxTime();
-		time_t secondsToGo = BoxTimeToSeconds((lastHousekeepingRun + housekeepingInterval) - timeNow);
-		if(secondsToGo < 1) secondsToGo = 1;
-		if(secondsToGo > 60) secondsToGo = 60;
-		int32_t millisecondsToGo = ((int)secondsToGo) * 1000;
+		catch(BoxException &e)
+		{
+			::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account",
+				*i, e.what(), e.GetType(), e.GetSubType());
+		}
+		catch(std::exception &e)
+		{
+			::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account",
+				*i, e.what());
+		}
+		catch(...)
+		{
+			::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account",
+				*i);
+		}
 	
+#ifndef WIN32	
 		// Check to see if there's any message pending
-		CheckForInterProcessMsg(0 /* no account */, millisecondsToGo);
+		CheckForInterProcessMsg(0 /* no account */);
+#endif
+
+		// Stop early?
+		if(StopRun())
+		{
+			break;
+		}
 	}
+		
+	::syslog(LOG_INFO, "Finished housekeeping");
+
+	// Placed here for accuracy, if StopRun() is true, for example.
+	SetProcessTitle("housekeeping, idle");
 }
 
+#ifdef WIN32
+void BackupStoreDaemon::OnIdle()
+{
+	if (!mHousekeepingInited)
+	{
+		HousekeepingInit();
+		mHousekeepingInited = true;
+	}
 
+	RunHousekeepingIfNeeded();
+}
+#endif
+
 // --------------------------------------------------------------------------
 //
 // Function
@@ -128,6 +164,7 @@
 //		Created: 11/12/03
 //
 // --------------------------------------------------------------------------
+#ifndef WIN32
 bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitTime)
 {
 	// First, check to see if it's EOF -- this means something has gone wrong, and the housekeeping should terminate.
@@ -171,5 +208,6 @@
 	
 	return false;
 }
+#endif
 
 

Modified: box/chris/merge/bin/bbstored/BackupCommands.cpp
===================================================================
--- box/chris/merge/bin/bbstored/BackupCommands.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbstored/BackupCommands.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -9,8 +9,13 @@
 
 #include "Box.h"
 
+#ifdef HAVE_SYSLOG_H
 #include <syslog.h>
+#endif
 
+#include <set>
+#include <sstream>
+
 #include "autogen_BackupProtocolServer.h"
 #include "BackupConstants.h"
 #include "BackupContext.h"
@@ -327,8 +332,15 @@
 			std::auto_ptr<IOStream> diff2(rContext.OpenObject(patchID));
 			
 			// Choose a temporary filename for the result of the combination
-			std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp",
-				p + 16 /* rotate which disc it's on */));
+#ifdef WIN32
+			std::ostringstream fs(rContext.GetStoreRoot());
+			fs << ".recombinetemp.";
+			fs << p;
+			std::string tempFn(fs.str());
+			tempFn = RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), tempFn, p + 16);
+#else
+			std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", p + 16 /* rotate which disc it's on */));
+#endif
 			
 			// Open the temporary file
 			std::auto_ptr<IOStream> combined;
@@ -336,14 +348,23 @@
 			{
 				{
 					// Write nastily to allow this to work with gcc 2.x
+#ifdef WIN32
+					combined.reset(new FileStream(
+						tempFn.c_str(), 
+						O_RDWR | O_CREAT | O_EXCL | 
+						O_BINARY | O_TRUNC));
+#else
 					std::auto_ptr<IOStream> t(new FileStream(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL));
 					combined = t;
+#endif
 				}
+#ifndef WIN32
 				// Unlink immediately as it's a temporary file
 				if(::unlink(tempFn.c_str()) != 0)
 				{
 					THROW_EXCEPTION(CommonException, OSFileError);
 				}
+#endif
 			}
 			catch(...)
 			{
@@ -359,6 +380,9 @@
 			combined->Seek(0, IOStream::SeekType_Absolute);
 			
 			// Then shuffle round for the next go
+#ifdef WIN32
+			if (from.get()) from->Close();
+#endif
 			from = combined;
 		}
 		
@@ -396,8 +420,9 @@
 			stream = t;
 		}
 
-		// Object will be deleted when the stream is deleted, so can release the object auto_ptr here to
-		// avoid premature deletiong
+		// Object will be deleted when the stream is deleted, 
+		// so can release the object auto_ptr here to avoid 
+		// premature deletion
 		object.release();
 	}
 

Modified: box/chris/merge/bin/bbstored/BackupContext.cpp
===================================================================
--- box/chris/merge/bin/bbstored/BackupContext.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbstored/BackupContext.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -132,6 +132,7 @@
 	// Request the lock
 	bool gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */);
 	
+#ifndef WIN32
 	if(!gotLock)
 	{
 		// The housekeeping process might have the thing open -- ask it to stop
@@ -150,6 +151,7 @@
 			
 		} while(!gotLock && tries > 0);
 	}
+#endif
 	
 	if(gotLock)
 	{
@@ -453,13 +455,21 @@
 			try
 			{
 				// Open it twice
+#ifdef WIN32
+				FileStream diff(tempFn.c_str(), 
+					O_RDWR | O_CREAT | O_BINARY);
+				FileStream diff2(tempFn.c_str(), 
+					O_RDWR | O_BINARY);
+#else
 				FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL);
 				FileStream diff2(tempFn.c_str(), O_RDONLY);
-				// Unlink it immediately, so it definately goes away
+
+				// Unlink it immediately, so it definitely goes away
 				if(::unlink(tempFn.c_str()) != 0)
 				{
 					THROW_EXCEPTION(CommonException, OSFileError);
 				}
+#endif
 				
 				// Stream the incoming diff to this temporary file
 				if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT))
@@ -508,6 +518,14 @@
 				::unlink(tempFn.c_str());
 				throw;
 			}
+
+#ifdef WIN32
+			// we can't delete the file while it's open, above
+			if(::unlink(tempFn.c_str()) != 0)
+			{
+				THROW_EXCEPTION(CommonException, OSFileError);
+			}
+#endif
 		}
 		
 		// Get the blocks used

Modified: box/chris/merge/bin/bbstored/BackupStoreDaemon.cpp
===================================================================
--- box/chris/merge/bin/bbstored/BackupStoreDaemon.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbstored/BackupStoreDaemon.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -11,9 +11,12 @@
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <syslog.h>
 #include <signal.h>
 
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
 #include "BackupContext.h"
 #include "BackupStoreDaemon.h"
 #include "BackupStoreConfigVerify.h"
@@ -39,7 +42,11 @@
 	  mExtendedLogging(false),
 	  mHaveForkedHousekeeping(false),
 	  mIsHousekeepingProcess(false),
+#ifdef WIN32
+	  mHousekeepingInited(false)
+#else
 	  mInterProcessComms(mInterProcessCommsSocket)
+#endif
 {
 }
 
@@ -156,6 +163,7 @@
 	const Configuration &config(GetConfiguration());
 	mExtendedLogging = config.GetKeyValueBool("ExtendedLogging");
 	
+#ifndef WIN32	
 	// Fork off housekeeping daemon -- must only do this the first time Run() is called
 	if(!mHaveForkedHousekeeping)
 	{
@@ -219,9 +227,11 @@
 	}
 	else
 	{
+#endif // !WIN32
 		// In server process -- use the base class to do the magic
 		ServerTLS<BOX_PORT_BBSTORED>::Run();
 		
+#ifndef WIN32	
 		// Why did it stop? Tell the housekeeping process to do the same
 		if(IsReloadConfigWanted())
 		{
@@ -232,6 +242,7 @@
 			mInterProcessCommsSocket.Write("t\n", 2);
 		}
 	}
+#endif
 }
 
 
@@ -297,6 +308,8 @@
 	// Log the amount of data transferred
 	::syslog(LOG_INFO, "Connection statistics for %s: "
 			"IN=%lld OUT=%lld TOTAL=%lld\n", commonName,
-			s.GetBytesRead(), s.GetBytesWritten(),
-			s.GetBytesRead() + s.GetBytesWritten());
+			(long long)s.GetBytesRead(), 
+			(long long)s.GetBytesWritten(),
+			(long long)s.GetBytesRead() + 
+			(long long)s.GetBytesWritten());
 }

Modified: box/chris/merge/bin/bbstored/BackupStoreDaemon.h
===================================================================
--- box/chris/merge/bin/bbstored/BackupStoreDaemon.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbstored/BackupStoreDaemon.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -38,11 +38,13 @@
 	BackupStoreDaemon(const BackupStoreDaemon &rToCopy);
 public:
 
+#ifndef WIN32
 	// For BackupContext to comminicate with housekeeping process
 	void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen)
 	{
 		mInterProcessCommsSocket.Write(Msg, MsgLen);
 	}
+#endif
 
 protected:
 	
@@ -57,9 +59,11 @@
 
 	const ConfigurationVerify *GetConfigVerify() const;
 	
+#ifndef WIN32	
 	// Housekeeping functions
 	void HousekeepingProcess();
 	bool CheckForInterProcessMsg(int AccountNum = 0, int MaximumWaitTime = 0);
+#endif
 
 	void LogConnectionStats(const char *commonName, const SocketStreamTLS &s);
 
@@ -70,8 +74,17 @@
 	bool mHaveForkedHousekeeping;
 	bool mIsHousekeepingProcess;
 	
+#ifdef WIN32
+	virtual void OnIdle();
+	bool mHousekeepingInited;
+#else
 	SocketStream mInterProcessCommsSocket;
 	IOStreamGetLine mInterProcessComms;
+#endif
+
+	void HousekeepingInit();
+	void RunHousekeepingIfNeeded();
+	int64_t mLastHousekeepingRun;
 };
 
 

Modified: box/chris/merge/bin/bbstored/HousekeepStoreAccount.cpp
===================================================================
--- box/chris/merge/bin/bbstored/HousekeepStoreAccount.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/bin/bbstored/HousekeepStoreAccount.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -225,6 +225,7 @@
 // --------------------------------------------------------------------------
 bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID)
 {
+#ifndef WIN32
 	if((--mCountUntilNextInterprocessMsgCheck) <= 0)
 	{
 		mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY;
@@ -235,6 +236,7 @@
 			return false;
 		}
 	}
+#endif
 
 	// Get the filename
 	std::string objectFilename;
@@ -251,6 +253,7 @@
 	// Read the directory in
 	BackupStoreDirectory dir;
 	dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite);
+	dirStream->Close();
 	
 	// Is it empty?
 	if(dir.GetNumberOfEntries() == 0)
@@ -485,6 +488,7 @@
 	// (there is likely to be more in the set than should be actually deleted).
 	for(std::set<DelEn, DelEnCompare>::iterator i(mPotentialDeletions.begin()); i != mPotentialDeletions.end(); ++i)
 	{
+#ifndef WIN32
 		if((--mCountUntilNextInterprocessMsgCheck) <= 0)
 		{
 			mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY;
@@ -495,6 +499,7 @@
 				return true;
 			}
 		}
+#endif
 
 		// Load up the directory it's in
 		// Get the filename
@@ -729,6 +734,7 @@
 		// Go through list
 		for(std::vector<int64_t>::const_iterator i(mEmptyDirectories.begin()); i != mEmptyDirectories.end(); ++i)
 		{
+#ifndef WIN32
 			if((--mCountUntilNextInterprocessMsgCheck) <= 0)
 			{
 				mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY;
@@ -739,6 +745,7 @@
 					return true;
 				}
 			}
+#endif
 
 			// Do not delete the root directory
 			if(*i == BACKUPSTORE_ROOT_DIRECTORY_ID)

Modified: box/chris/merge/configure.ac
===================================================================
--- box/chris/merge/configure.ac	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/configure.ac	2006-07-27 23:18:35 UTC (rev 710)
@@ -44,7 +44,7 @@
 VL_LIB_READLINE([have_libreadline=yes], [have_libreadline=no])
 
 ## Check for Berkely DB. Restrict to certain versions
-AX_PATH_BDB(, [
+AX_PATH_BDB([1.x or 4.1], [
   LIBS="$BDB_LIBS $LIBS"
   LDFLAGS="$BDB_LDFLAGS $LDFLAGS"
   CPPFLAGS="$CPPFLAGS $BDB_CPPFLAGS"
@@ -89,7 +89,7 @@
 AC_CHECK_HEADERS([syslog.h time.h])
 AC_CHECK_HEADERS([netinet/in.h])
 AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h])
-AC_CHECK_HEADERS([sys/xattr.h])
+AC_CHECK_HEADERS([sys/uio.h sys/xattr.h])
 
 if test "$ac_cv_header_regex_h" = "yes"; then
   AC_SEARCH_LIBS([regcomp], [pcreposix])
@@ -116,6 +116,7 @@
   ]])
 AC_CHECK_DECLS([INFTIM],,, [[#include <poll.h>]])
 AC_CHECK_DECLS([SO_PEERCRED],,, [[#include <sys/socket.h>]])
+AC_CHECK_DECLS([O_BINARY],,,)
 AC_HEADER_TIME
 AC_STRUCT_TM
 AX_CHECK_DIRENT_D_TYPE
@@ -124,14 +125,14 @@
 if test "x$ac_cv_c_bigendian" != "xyes"; then
   AX_BSWAP64
 fi
+
 if test "$target_os" != "mingw32"; then
   AX_RANDOM_DEVICE
-fi
-AX_CHECK_MOUNT_POINT(,[
-  if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then
+  AX_CHECK_MOUNT_POINT(,[
     AC_MSG_ERROR([[cannot work out how to discover mount points on your platform]])
-  fi
   ])
+fi
+
 AX_CHECK_MALLOC_WORKAROUND
 
 
@@ -220,6 +221,7 @@
                    lib/server/makeprotocol.pl
                    runtest.pl
                    test/backupstorefix/testfiles/testbackupstorefix.pl
+                   test/bbackupd/testfiles/bbackupd.conf
                    test/bbackupd/testfiles/extcheck1.pl
                    test/bbackupd/testfiles/extcheck2.pl
                    test/bbackupd/testfiles/notifyscript.pl])
@@ -237,6 +239,7 @@
 without these features, but will work better where they are present. Refer
 to the documentation for more information on each feature.
 
+Regular expressions: $ac_cv_header_regex_h
 Large files:         $have_large_file_support
 Berkeley DB:         $ax_path_bdb_ok
 Readline:            $have_libreadline

Modified: box/chris/merge/docs/backup/win32_build_on_linux_using_mingw.txt
===================================================================
--- box/chris/merge/docs/backup/win32_build_on_linux_using_mingw.txt	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/docs/backup/win32_build_on_linux_using_mingw.txt	2006-07-27 23:18:35 UTC (rev 710)
@@ -7,6 +7,11 @@
 - Fedora and SuSE users can download RPM packages from 
   [http://mirzam.it.vu.nl/mingw/]
 
+You will need to know the prefix used by the cross-compiler executables.
+It will usually be something like "ix86-mingw32*-". All the binaries in the
+cross-compiler package will start with this prefix. The documentation below
+assumes that it is "i386-mingw32-". Adjust to taste.
+
 Download Zlib from [http://www.zlib.net/], unpack and enter source directory:
 
 	export CC=i386-mingw32-gcc 
@@ -16,8 +21,19 @@
 	make
 	make install prefix=/usr/local/i386-mingw32
 
-Download OpenSSL 0.9.7 from 
+Download OpenSSL 0.9.8b from 
+[http://www.openssl.org/source/openssl-0.9.8b.tar.gz]
 
+Unpack and configure:
+
+	tar xzvf openssl-0.9.8b.tar.gz
+	cd openssl-0.9.8b
+	./Configure mingw
+	make makefile.one
+	wget http://bbdev.fluffy.co.uk/svn/box/chris/win32/support/openssl-0.9.8b-mingw-cross.patch
+	patch -p1 < openssl-0.9.8b-mingw-cross.patch
+	make -f makefile.one
+
 Configure Box with:
 
 	export CXX="i386-mingw32-g++"
@@ -27,5 +43,6 @@
 	export CXXFLAGS="-mthreads"
 	export LDFLAGS="-mthreads"
 	export LIBS="-lcrypto -lws2_32 -lgdi32"
+	(if you don't have a "configure" file, run "./bootstrap")
 	./configure --target=i386-mingw32
-	make CXX="$CXX" AR="$AR" RANLIB="$RANLIB"
+	make CXX="$CXX" AR="$AR" RANLIB="$RANLIB" WINDRES="i386-mingw32-windres"

Modified: box/chris/merge/infrastructure/BoxPlatform.pm.in
===================================================================
--- box/chris/merge/infrastructure/BoxPlatform.pm.in	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/infrastructure/BoxPlatform.pm.in	2006-07-27 23:18:35 UTC (rev 710)
@@ -1,16 +1,30 @@
 package BoxPlatform;
 use Exporter;
 @ISA = qw/Exporter/;
- at EXPORT = qw/$build_os $build_cpu $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext/;
+ at EXPORT = qw/$build_os $build_cpu $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows update_if_changed/;
 
 BEGIN
 {
 
 	# which OS are we building under?
-	$build_os = `uname`;
-	chomp $build_os;
-	$build_cpu = `uname -p`;
-	chomp $build_cpu;
+	$target_os = '@target_os@';
+	$target_windows = 0;
+	$target_windows = 1 if $target_os =~ m'^mingw32' 
+		or $target_os eq "winnt";
+
+	if ($^O eq "MSWin32" and not -x "/usr/bin/uname")
+	{
+		$build_os = "winnt";
+		$build_cpu = "ix86";
+	}
+	else
+	{
+		$build_os = `uname`;
+		chomp $build_os;
+		$build_cpu = `uname -m`;
+		chomp $build_cpu;
+	}
+
 	# Cygwin Builds usually something like CYGWIN_NT-5.0, CYGWIN_NT-5.1
 	# Box Backup tried on Win2000,XP only :)
 
@@ -24,11 +38,18 @@
 	$platform_compile_line_extra =~ s/ -O2//;
 	$platform_link_line_extra = '@LDFLAGS@';
 	$platform_lib_files = '@LIBS@';
-	$target_os = '@target_os@';
 	$platform_exe_ext = '@EXEEXT@';
 
 	# get version
-	open VERSION,"VERSION.txt" or die "VERSION.txt: $!";
+	if (! -r "VERSION.txt" and -r "../../VERSION.txt")
+	{
+		open VERSION,"../../VERSION.txt" or die "../../VERSION.txt: $!";
+	}
+	else
+	{
+		open VERSION,"VERSION.txt" or die "VERSION.txt: $!";
+	}
+
 	$product_version = <VERSION>;
 	chomp $product_version;
 	$product_name = <VERSION>;
@@ -89,5 +110,34 @@
 	return $_[0].'=1';
 }
 
+sub update_if_changed ($)
+{
+	my ($file) = @_;
+	die "$file.new: not found" unless -r "$file.new";
+
+	if (-r $file)
+	{
+		die "$file.new: not found" unless -r "$file.new";
+		if (system("diff --brief $file $file.new") == 0)
+		{
+			unlink "$file.new";
+			return;
+		}
+	}
+
+	if (system("cp $file.new $file") != 0)
+	{
+		die "failed to copy $file.new to $file";
+	}
+
+	if (system("diff --brief $file $file.new") != 0)
+	{
+		die "$file and $file.new are still different";
+	}
+
+	unlink "$file.new";
+	return;
+}
+
 1;
 

Modified: box/chris/merge/infrastructure/buildenv-testmain-template.cpp
===================================================================
--- box/chris/merge/infrastructure/buildenv-testmain-template.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/infrastructure/buildenv-testmain-template.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -41,6 +41,8 @@
 #endif
 
 int failures = 0;
+int first_fail_line;
+std::string first_fail_file;
 
 int filedes_open_at_beginning = -1;
 
@@ -128,7 +130,10 @@
 			}
 			if(failures > 0)
 			{
-				printf("FAILED: %d tests failed\n", failures);
+				printf("FAILED: %d tests failed (first at "
+					"%s:%d)\n", failures, 
+					first_fail_file.c_str(),
+					first_fail_line);
 			}
 			else
 			{

Modified: box/chris/merge/infrastructure/makebuildenv.pl.in
===================================================================
--- box/chris/merge/infrastructure/makebuildenv.pl.in	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/infrastructure/makebuildenv.pl.in	2006-07-27 23:18:35 UTC (rev 710)
@@ -14,9 +14,8 @@
 
 print "Box build environment setup.\n\n";
 
+my @implicit_deps = ('lib/common');
 
-my $implicit_dep = 'lib/common';
-
 # work out platform variables
 use lib 'infrastructure';
 use BoxPlatform;
@@ -38,12 +37,16 @@
 # flags about the environment
 my %env_flags;
 
-my $windows_include_path = "-I../../lib/win32 ";
-if ($target_os ne "mingw32" && $target_os ne "winnt")
+my $windows_include_path = "";
+if ($target_windows)
 {
-	$windows_include_path = "";
-	$env_flags{'IGNORE_lib/win32'} = 1;
+	$module_dependency{"lib/common"} = ["lib/win32"];
+	push @implicit_deps, "lib/win32";
 }
+else
+{
+	# $env_flags{'IGNORE_lib/win32'} = 1;
+}
 
 # print "Flag: $_\n" for(keys %env_flags);
 
@@ -111,7 +114,7 @@
 print "done\n\n";
 
 
-# open test mail program template file
+# open test main program template file
 my $test_template_file = 'infrastructure/buildenv-testmain-template.cpp';
 open FL,$test_template_file or die "Can't open test template file\n";
 my $test_template;
@@ -271,7 +274,7 @@
 			push @md,$_ unless ignore_module($_)
 		}
 	}
-	$module_dependency{$mod} = [$implicit_dep, at md];
+	$module_dependency{$mod} = [@implicit_deps, at md];
 	$module_library_link_opts{$mod} = [@lo];
 	
 	# make directories, but not if we're using an external library and this a library module
@@ -286,17 +289,21 @@
 }
 
 # make dirs for implicit dep
-mkdir "release/$implicit_dep",0755;
-mkdir "debug/$implicit_dep",0755;
+foreach my $dep (@implicit_deps)
+{
+	mkdir "release/$dep",0755;
+	mkdir "debug/$dep",0755;
+}
 
 # write a list of all the modules we've configured to use
-open CONFIGURED_MODS,'>local/modules.h' or die "Can't write configured modules list";
+open CONFIGURED_MODS,'>local/modules.h.new' or die 
+	"Can't write configured modules list";
 print CONFIGURED_MODS <<__E;
 // automatically generated file, do not edit
 #ifndef _CONFIGURED_MODULES__H
 #define _CONFIGURED_MODULES__H
 __E
-for($implicit_dep, at modules)
+for(@implicit_deps, at modules)
 {
 	my $m = $_;
 	$m =~ s~/~_~;
@@ -306,11 +313,11 @@
 #endif // _CONFIGURED_MODULES__H
 __E
 close CONFIGURED_MODS;
+update_if_changed("local/modules.h");
 
-
 # now make a list of all the .h files we can find, recording which module they're in
 my %hfiles;
-for my $mod (@modules, $implicit_dep)
+for my $mod (@modules, @implicit_deps)
 {
 	opendir DIR,$mod;
 	my @items = readdir DIR;
@@ -347,7 +354,7 @@
 	}
 }
 
-for my $mod (@modules, $implicit_dep)
+for my $mod (@modules, @implicit_deps)
 {
 	opendir DIR,$mod;
 	for my $h (grep /\.h\Z/i, readdir DIR)
@@ -373,9 +380,10 @@
 
 print "done\n\nGenerating Makefiles...\n";
 
+my %module_resources_win32;
 
 # Then write a makefile for each module
-for my $mod (@modules, $implicit_dep)
+for my $mod (@implicit_deps, @modules)
 {
 	print $mod,"\n";
 	
@@ -386,15 +394,19 @@
 	{
 		my $testmain = $test_template;
 		$testmain =~ s/TEST_NAME/$name/g;
-		open TESTMAIN,">$mod/_main.cpp" or die "Can't open test main file for $mod for writing\n";
+		open TESTMAIN,">$mod/_main.cpp.new" or die 
+			"Can't open test main file for $mod for writing\n";
 		print TESTMAIN $testmain;
 		close TESTMAIN;
+		update_if_changed("$mod/_main.cpp");
 		
 		# test file...
 		sub writetestfile
 		{
 			my ($filename,$runcmd,$module) = @_;		
-			open TESTFILE,">$filename" or die "Can't open test script file for $module for writing\n";
+			open TESTFILE,">$filename.new" or die 
+				"Can't open test script file for $module " .
+				"for writing\n";
 			print TESTFILE "#!/bin/sh\necho TEST: $module\n";
 			if(-d "$module/testfiles")
 			{
@@ -413,12 +425,13 @@
 			}
 			print TESTFILE "$runcmd\n";
 			close TESTFILE;
+			update_if_changed($filename);
 		}
 		
 		writetestfile("$mod/_t", 
-			'./test' . $platform_exe_ext . '$1 $2 $3 $4 $5', $mod);
+			'./test' . $platform_exe_ext . ' $1 $2 $3 $4 $5', $mod);
 		writetestfile("$mod/_t-gdb", 
-			'gdb ./test ' . $platform_exe_ext, $mod);
+			'gdb ./test' . $platform_exe_ext, $mod);
 		
 	}
 	
@@ -441,14 +454,14 @@
 		add_mod_deps(\@deps_raw, $mod);
 		# and then dedup and reorder them
 		my %d_done;
-		for(my $a = $#deps_raw; $a >= 0; $a--)
+		foreach my $dep (reverse @deps_raw)
 		{
-			if(!exists $d_done{$deps_raw[$a]})
+			if(!exists $d_done{$dep})
 			{
 				# insert
-				push @all_deps_for_module, $deps_raw[$a];
+				push @all_deps_for_module, $dep;
 				# mark as done
-				$d_done{$deps_raw[$a]} = 1;
+				$d_done{$dep} = 1;
 			}
 		}
 	}	
@@ -480,11 +493,12 @@
 
 	# start the makefile
 	my $mk_name_extra = ($bsd_make)?'':'X';
-	open MAKE,">$mod/Makefile".$mk_name_extra or die "Can't open Makefile for $mod\n";
+	open MAKE,">$mod/Makefile".$mk_name_extra.".new" or die 
+		"Can't open Makefile for $mod\n";
 	my $debug_link_extra = ($target_is_library)?'':'../../debug/lib/debug/debug.a';
 
 	my $release_flags = "-O2";
-	if ($target_os eq "mingw32")
+	if ($target_windows)
 	{
 		$release_flags = "-O0 -g";
 	}
@@ -499,6 +513,7 @@
 AR = ar
 RANLIB = ranlib
 PERL = "@PERL@"
+WINDRES = windres
 .ifdef RELEASE
 CXXFLAGS = -DNDEBUG $release_flags -Wall $include_paths $extra_platform_defines -DBOX_VERSION="\\"$product_version\\""
 OUTBASE = ../../release
@@ -546,7 +561,7 @@
 		@items = (@items, @autogen_items);
 	}
 	
-	# first, obtain a list of depenencies within the .h files
+	# first, obtain a list of dependencies within the .h files
 	my %headers;
 	for my $h (grep /\.h\Z/i, @items)
 	{
@@ -566,19 +581,30 @@
 	
 	# then... do the cpp files...
 	my @obj_base;
-	for my $cpp (@items)
+	for my $file (@items)
 	{
-		next unless $cpp =~ m/\A(.+)\.cpp\Z/i;
-		next if $cpp =~ /\A\._/;	# Temp Mac OS Resource hack
+		my $is_cpp = $file =~ m/\A(.+)\.cpp\Z/i;
+		my $is_rc  = $file =~ m/\A(.+)\.rc\Z/i;
+		my $base = $1;
 
+		if ($target_windows)
+		{
+			next if not $is_cpp and not $is_rc;
+		}
+		else
+		{
+			next if not $is_cpp;
+		}
+
+		next if $file =~ /\A\._/; # Temp Mac OS Resource hack
+
 		# store for later
-		my $base = $1;
 		push @obj_base,$base;
 	
 		# get the file...
-		open FL,"$mod/$cpp";
+		open FL,"$mod/$file";
 		my $f;
-		read FL,$f,-s "$mod/$cpp";
+		read FL,$f,-s "$mod/$file";
 		close FL;
 		
 		my %dep;
@@ -592,10 +618,29 @@
 		my $out_name = '$(OUTDIR)/'.$base.'.o';
 		
 		# write the line for this cpp file
-		$make .= $out_name.': '.join(' ',$cpp,map
-			{ ($hfiles{$_} eq $mod)?$_:'../../'.$hfiles{$_}."/$_" } keys %dep)."\n";
-		$make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra -c $cpp -o $out_name\n\n";
+		my @dep_paths = map 
+		{ 
+			($hfiles{$_} eq $mod)
+			? $_ 
+			: '../../'.$hfiles{$_}."/$_"
+		}
+		keys %dep;
 
+		$make .= $out_name.': '.join(' ',$file, at dep_paths)."\n";
+
+		if ($is_cpp)
+		{
+			$make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra ".
+				"-c $file -o $out_name\n\n";
+		}
+		elsif ($is_rc)
+		{
+			$make .= "\t\$(WINDRES) $file $out_name\n\n";
+			my $res_list = $module_resources_win32{$mod};
+			$res_list ||= [];
+			push @$res_list, $base.'.o';
+			$module_resources_win32{$mod} = $res_list;
+		}
 	}
 
 	my $has_deps = ($#{$module_dependency{$mod}} >= 0);
@@ -647,11 +692,28 @@
 	additional_objects_from_make_fragment("$mod/Makefile.extra.$build_os", \@objs, \@makefile_includes);
 
 	my $o_file_list = join(' ',map {'$(OUTDIR)/'.$_.'.o'} @objs);
+
+	if ($has_deps and not $bsd_make)
+	{
+		print MAKE ".PHONY: all\n" .
+			"all: dep_modules $end_target\n\n";
+	}
+
 	print MAKE $end_target,': ',$o_file_list;
-	print MAKE ' dep_modules' if $has_deps and not $bsd_make;
 	print MAKE " ",$lib_files unless $target_is_library;
 	print MAKE "\n";
 	
+	if ($target_windows)
+	{
+		foreach my $dep (@all_deps_for_module)
+		{
+			my $res_list = $module_resources_win32{$dep};
+			next unless $res_list;
+			$o_file_list .= ' '.join(' ', 
+				map {'$(OUTBASE)/'.$dep."/$_"} @$res_list);
+		}
+	}
+
 	# stuff to make the final target...
 	if($target_is_library)
 	{
@@ -730,8 +792,8 @@
 	if(!$bsd_make)
 	{
 		# need to post process this into a GNU makefile
-		open MAKE,">$mod/Makefile";
-		open MAKEB,"$mod/MakefileX";
+		open MAKE,">$mod/Makefile.new" or die $!;
+		open MAKEB,"$mod/MakefileX.new" or die $!;
 
 		while(<MAKEB>)
 		{
@@ -743,8 +805,10 @@
 
 		close MAKEB;
 		close MAKE;
-		unlink "$mod/MakefileX";
+		unlink "$mod/MakefileX.new";
 	}
+
+	update_if_changed("$mod/Makefile");
 }
 
 print "\nType 'cd <module_dir>; $make_command' to build a module\n\n";

Deleted: box/chris/merge/infrastructure/msvc/2003/boxbackup.ncb
===================================================================
(Binary files differ)

Deleted: box/chris/merge/infrastructure/msvc/2003/boxbackup.suo
===================================================================
(Binary files differ)

Modified: box/chris/merge/lib/backupclient/BackupClientFileAttributes.cpp
===================================================================
--- box/chris/merge/lib/backupclient/BackupClientFileAttributes.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/backupclient/BackupClientFileAttributes.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -642,6 +642,7 @@
 	}
 	
 	// If working as root, set user IDs
+	#ifndef WIN32
 	if(::geteuid() == 0)
 	{
 		#ifndef HAVE_LCHOWN
@@ -661,6 +662,7 @@
 			}
 		#endif
 	}
+	#endif
 
 	if(static_cast<int>(xattrOffset+sizeof(u_int32_t))<=mpClearAttributes->GetSize())
 	{

Modified: box/chris/merge/lib/backupclient/BackupStoreFile.cpp
===================================================================
--- box/chris/merge/lib/backupclient/BackupStoreFile.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/backupclient/BackupStoreFile.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -289,6 +289,8 @@
 			// Copy it out to the file
 			stream->CopyStreamTo(out);
 		}
+
+		out.Close();
 		
 		// Write the attributes
 		stream->GetAttributes().WriteAttributes(DecodedFilename);

Modified: box/chris/merge/lib/backupclient/BackupStoreObjectDump.cpp
===================================================================
--- box/chris/merge/lib/backupclient/BackupStoreObjectDump.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/backupclient/BackupStoreObjectDump.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -113,7 +113,13 @@
 
 		// Output item
 		int16_t f = (*i)->GetFlags();
-		OutputLine(file, ToTrace, "%06llx %4lld %016llx %4d %3d %4d%s%s%s%s%s%s\n",
+#ifdef WIN32
+		OutputLine(file, ToTrace, 
+			"%06I64x %4I64d %016I64x %4d %3d %4d%s%s%s%s%s%s\n",
+#else
+		OutputLine(file, ToTrace, 
+			"%06llx %4lld %016llx %4d %3d %4d%s%s%s%s%s%s\n",
+#endif
 			(*i)->GetObjectID(),
 			(*i)->GetSizeInBlocks(),
 			(*i)->GetAttributesHash(),

Modified: box/chris/merge/lib/backupstore/BackupStoreAccounts.cpp
===================================================================
--- box/chris/merge/lib/backupstore/BackupStoreAccounts.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/backupstore/BackupStoreAccounts.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -141,8 +141,9 @@
 std::string BackupStoreAccounts::MakeAccountRootDir(int32_t ID, int DiscSet) const
 {
 	char accid[64];	// big enough!
-	::sprintf(accid, "%08x/", ID);
-	return std::string(std::string(BOX_RAIDFILE_ROOT_BBSTORED DIRECTORY_SEPARATOR) + accid);
+	::sprintf(accid, "%08x" DIRECTORY_SEPARATOR, ID);
+	return std::string(std::string(BOX_RAIDFILE_ROOT_BBSTORED 
+		DIRECTORY_SEPARATOR) + accid);
 }
 
 

Modified: box/chris/merge/lib/backupstore/BackupStoreCheck.cpp
===================================================================
--- box/chris/merge/lib/backupstore/BackupStoreCheck.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/backupstore/BackupStoreCheck.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -328,7 +328,8 @@
 	std::string dirName;
 	StoreStructure::MakeObjectFilename(StartID, mStoreRoot, mDiscSetNumber, dirName, false /* don't make sure the dir exists */);
 	// Check expectations
-	ASSERT(dirName.size() > 4 && dirName[dirName.size() - 4] == '/');
+	ASSERT(dirName.size() > 4 && 
+		dirName[dirName.size() - 4] == DIRECTORY_SEPARATOR_ASCHAR);
 	// Remove the filename from it
 	dirName.resize(dirName.size() - 4); // four chars for "/o00"
 	
@@ -377,7 +378,9 @@
 		if(!fileOK)
 		{
 			// Unexpected or bad file, delete it
-			::printf("Spurious file %s/%s found%s\n", dirName.c_str(), (*i).c_str(), mFixErrors?", deleting":"");
+			::printf("Spurious file %s" DIRECTORY_SEPARATOR "%s "
+				"found%s\n", dirName.c_str(), (*i).c_str(), 
+				mFixErrors?", deleting":"");
 			++mNumberErrorsFound;
 			if(mFixErrors)
 			{

Modified: box/chris/merge/lib/common/BoxPlatform.h
===================================================================
--- box/chris/merge/lib/common/BoxPlatform.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/common/BoxPlatform.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -40,8 +40,8 @@
 	#endif
 #endif
 
-// Slight hack; disable interception on Darwin within raidfile test
-#ifdef __APPLE__
+// Slight hack; disable interception in raidfile test on Darwin and Windows
+#if defined __APPLE__ || defined WIN32
 	// TODO: Replace with autoconf test
 	#define PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
 #endif
@@ -138,6 +138,11 @@
 	#define INFTIM -1
 #endif
 
+// for Unix compatibility with Windows :-)
+#if !HAVE_DECL_O_BINARY
+	#define O_BINARY 0
+#endif
+
 #ifdef WIN32
 	typedef u_int64_t InodeRefType;
 #else

Modified: box/chris/merge/lib/common/FdGetLine.h
===================================================================
--- box/chris/merge/lib/common/FdGetLine.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/common/FdGetLine.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -14,6 +14,10 @@
 
 #ifdef NDEBUG
 	#define FDGETLINE_BUFFER_SIZE		1024
+#elif defined WIN32
+	// need enough space for at least one unicode character 
+	// in UTF-8 when calling console_read() from bbackupquery
+	#define FDGETLINE_BUFFER_SIZE		5
 #else
 	#define FDGETLINE_BUFFER_SIZE		4
 #endif

Modified: box/chris/merge/lib/common/Guards.h
===================================================================
--- box/chris/merge/lib/common/Guards.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/common/Guards.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -24,7 +24,7 @@
 
 #include "MemLeakFindOn.h"
 
-template <int flags = O_RDONLY, int mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)>
+template <int flags = O_RDONLY | O_BINARY, int mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)>
 class FileHandleGuard
 {
 public:

Modified: box/chris/merge/lib/common/UnixUser.cpp
===================================================================
--- box/chris/merge/lib/common/UnixUser.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/common/UnixUser.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -75,6 +75,7 @@
 // --------------------------------------------------------------------------
 UnixUser::~UnixUser()
 {
+#ifndef WIN32
 	if(mRevertOnDestruction)
 	{
 		// Revert to "real" user and group id of the process
@@ -84,6 +85,7 @@
 			THROW_EXCEPTION(CommonException, CouldNotRestoreProcessUser)
 		}
 	}
+#endif
 }
 
 
@@ -98,6 +100,7 @@
 // --------------------------------------------------------------------------
 void UnixUser::ChangeProcessUser(bool Temporary)
 {
+#ifndef WIN32
 	if(Temporary)
 	{
 		// Change temporarily (change effective only)
@@ -119,6 +122,7 @@
 			THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser)
 		}
 	}
+#endif
 }
 
 

Modified: box/chris/merge/lib/common/makeexception.pl.in
===================================================================
--- box/chris/merge/lib/common/makeexception.pl.in	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/common/makeexception.pl.in	2006-07-27 23:18:35 UTC (rev 710)
@@ -1,9 +1,11 @@
 #!@PERL@
 
+use lib "../../infrastructure";
+use BoxPlatform;
+
 # global exception list file
 my $global_list = '../../ExceptionCodes.txt';
 
-
 my @exception;
 my @exception_desc;
 my $class;
@@ -46,8 +48,8 @@
 # write the code
 print "Generating $class exception...\n";
 
-open CPP,">autogen_${class}Exception.cpp" or die "Can't open cpp file for writing";
-open H,">autogen_${class}Exception.h" or die "Can't open h file for writing";
+open CPP,">autogen_${class}Exception.cpp.new" or die "Can't open cpp file for writing";
+open H,">autogen_${class}Exception.h.new" or die "Can't open h file for writing";
 
 # write header file
 my $guardname = uc 'AUTOGEN_'.$class.'EXCEPTION_H';
@@ -200,6 +202,9 @@
 close H;
 close CPP;
 
+update_if_changed("autogen_${class}Exception.cpp");
+update_if_changed("autogen_${class}Exception.h");
+
 # update the global exception list
 my $list_before;
 my $list_after;

Modified: box/chris/merge/lib/raidfile/RaidFileRead.cpp
===================================================================
--- box/chris/merge/lib/raidfile/RaidFileRead.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/raidfile/RaidFileRead.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -14,10 +14,20 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <sys/stat.h>
+
+#ifdef HAVE_SYS_UIO_H
 #include <sys/uio.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
 #include <syslog.h>
+#endif
+
 #include <stdarg.h>
+
+#ifdef HAVE_DIRENT_H
 #include <dirent.h>
+#endif
 
 #include <stdio.h>
 #include <string.h>
@@ -583,7 +593,8 @@
 
 	// Open the parity file
 	std::string parityFilename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, (2 + startDisc) % READ_NUMBER_DISCS_REQUIRED));
-	mParityHandle = ::open(parityFilename.c_str(), O_RDONLY, 0555);
+	mParityHandle = ::open(parityFilename.c_str(), 
+		O_RDONLY | O_BINARY, 0555);
 	if(mParityHandle == -1)
 	{
 		THROW_EXCEPTION(RaidFileException, OSError)
@@ -1017,7 +1028,8 @@
 		std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, Filename));
 
 		// Attempt to open
-		int osFileHandle = ::open(writeFilename.c_str(), O_RDONLY, 0);
+		int osFileHandle = ::open(writeFilename.c_str(), 
+			O_RDONLY | O_BINARY, 0);
 		if(osFileHandle == -1)
 		{
 			THROW_EXCEPTION(RaidFileException, ErrorOpeningFileForRead)
@@ -1055,13 +1067,15 @@
 		try
 		{
 			// Open stripe1
-			stripe1 = ::open(stripe1Filename.c_str(), O_RDONLY, 0555);
+			stripe1 = ::open(stripe1Filename.c_str(), 
+				O_RDONLY | O_BINARY, 0555);
 			if(stripe1 == -1)
 			{
 				stripe1errno = errno;
 			}
 			// Open stripe2
-			stripe2 = ::open(stripe2Filename.c_str(), O_RDONLY, 0555);
+			stripe2 = ::open(stripe2Filename.c_str(), 
+				O_RDONLY | O_BINARY, 0555);
 			if(stripe2 == -1)
 			{
 				stripe2errno = errno;
@@ -1169,7 +1183,8 @@
 			// Open stripe1?
 			if(existingFiles & RaidFileUtil::Stripe1Exists)
 			{
-				stripe1 = ::open(stripe1Filename.c_str(), O_RDONLY, 0555);
+				stripe1 = ::open(stripe1Filename.c_str(), 
+					O_RDONLY | O_BINARY, 0555);
 				if(stripe1 == -1)
 				{
 					THROW_EXCEPTION(RaidFileException, OSError)
@@ -1178,14 +1193,16 @@
 			// Open stripe2?
 			if(existingFiles & RaidFileUtil::Stripe2Exists)
 			{
-				stripe2 = ::open(stripe2Filename.c_str(), O_RDONLY, 0555);
+				stripe2 = ::open(stripe2Filename.c_str(), 
+					O_RDONLY | O_BINARY, 0555);
 				if(stripe2 == -1)
 				{
 					THROW_EXCEPTION(RaidFileException, OSError)
 				}
 			}
 			// Open parity
-			parity = ::open(parityFilename.c_str(), O_RDONLY, 0555);
+			parity = ::open(parityFilename.c_str(), 
+				O_RDONLY | O_BINARY, 0555);
 			if(parity == -1)
 			{
 				THROW_EXCEPTION(RaidFileException, OSError)

Modified: box/chris/merge/lib/raidfile/RaidFileWrite.cpp
===================================================================
--- box/chris/merge/lib/raidfile/RaidFileWrite.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/raidfile/RaidFileWrite.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -104,7 +104,8 @@
 	writeFilename += 'X';
 
 	// Attempt to open
-	mOSFileHandle = ::open(writeFilename.c_str(), O_WRONLY | O_CREAT,
+	mOSFileHandle = ::open(writeFilename.c_str(), 
+		O_WRONLY | O_CREAT | O_BINARY,
 		S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
 	if(mOSFileHandle == -1)
 	{
@@ -115,7 +116,7 @@
 #ifdef HAVE_FLOCK
 	int errnoBlock = EWOULDBLOCK;
 	if(::flock(mOSFileHandle, LOCK_EX | LOCK_NB) != 0)
-#else
+#elif HAVE_DECL_F_SETLK
 	int errnoBlock = EAGAIN;
 	struct flock desc;
 	desc.l_type = F_WRLCK;
@@ -123,6 +124,9 @@
 	desc.l_start = 0;
 	desc.l_len = 0;
 	if(::fcntl(mOSFileHandle, F_SETLK, &desc) != 0)
+#else
+	int errnoBlock = ENOSYS;
+	if (0)
 #endif
 	{
 		// Lock was not obtained.
@@ -242,23 +246,46 @@
 	}
 	
 	// Rename it into place -- BEFORE it's closed so lock remains
+
+#ifdef WIN32
+	// Except on Win32 which doesn't allow renaming open files
+	// Close file...
+	if(::close(mOSFileHandle) != 0)
+	{
+		THROW_EXCEPTION(RaidFileException, OSError)
+	}
+	mOSFileHandle = -1;
+#endif // WIN32
+
 	RaidFileController &rcontroller(RaidFileController::GetController());
 	RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
 	// Get the filename for the write file
 	std::string renameTo(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
 	// And the current name
 	std::string renameFrom(renameTo + 'X');
+
+#ifdef WIN32
+	// need to delete the target first
+	if(::unlink(renameTo.c_str()) != 0 && 
+		GetLastError() != ERROR_FILE_NOT_FOUND)
+	{
+		THROW_EXCEPTION(RaidFileException, OSError)
+	}
+#endif
+
 	if(::rename(renameFrom.c_str(), renameTo.c_str()) != 0)
 	{
 		THROW_EXCEPTION(RaidFileException, OSError)
 	}
 	
+#ifndef WIN32	
 	// Close file...
 	if(::close(mOSFileHandle) != 0)
 	{
 		THROW_EXCEPTION(RaidFileException, OSError)
 	}
 	mOSFileHandle = -1;
+#endif // !WIN32
 	
 	// Raid it?
 	if(ConvertToRaidNow)
@@ -292,8 +319,15 @@
 	writeFilename += 'X';
 	
 	// Unlink and close it
-	if((::unlink(writeFilename.c_str()) != 0)
-		|| (::close(mOSFileHandle) != 0))
+
+#ifdef WIN32
+	// On Win32 we must close it first
+	if (::close(mOSFileHandle) != 0 ||
+		::unlink(writeFilename.c_str()) != 0)
+#else // !WIN32
+	if (::unlink(writeFilename.c_str()) != 0 ||
+		::close(mOSFileHandle) != 0)
+#endif // !WIN32
 	{
 		THROW_EXCEPTION(RaidFileException, OSError)
 	}
@@ -388,13 +422,13 @@
 	try
 	{
 #if HAVE_DECL_O_EXLOCK
-		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> stripe1(stripe1FilenameW.c_str());
-		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> stripe2(stripe2FilenameW.c_str());
-		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> parity(parityFilenameW.c_str());
+		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> stripe1(stripe1FilenameW.c_str());
+		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> stripe2(stripe2FilenameW.c_str());
+		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> parity(parityFilenameW.c_str());
 #else
-		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> stripe1(stripe1FilenameW.c_str());
-		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> stripe2(stripe2FilenameW.c_str());
-		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> parity(parityFilenameW.c_str());
+		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> stripe1(stripe1FilenameW.c_str());
+		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> stripe2(stripe2FilenameW.c_str());
+		FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> parity(parityFilenameW.c_str());
 #endif
 
 		// Then... read in data...
@@ -530,6 +564,21 @@
 		parity.Close();
 		stripe2.Close();
 		stripe1.Close();
+
+#ifdef WIN32
+		// Must delete before renaming
+		#define CHECK_UNLINK(file) \
+		{ \
+			if (::unlink(file) != 0 && errno != ENOENT) \
+			{ \
+				THROW_EXCEPTION(RaidFileException, OSError); \
+			} \
+		}
+		CHECK_UNLINK(stripe1Filename.c_str());
+		CHECK_UNLINK(stripe2Filename.c_str());
+		CHECK_UNLINK(parityFilename.c_str());
+		#undef CHECK_UNLINK
+#endif
 		
 		// Rename them into place
 		if(::rename(stripe1FilenameW.c_str(), stripe1Filename.c_str()) != 0

Modified: box/chris/merge/lib/server/Daemon.cpp
===================================================================
--- box/chris/merge/lib/server/Daemon.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/server/Daemon.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -23,6 +23,10 @@
 	#include <syslog.h>
 #endif
 
+#ifdef WIN32
+	#include <ws2tcpip.h>
+#endif
+
 #include "Daemon.h"
 #include "Configuration.h"
 #include "ServerException.h"
@@ -142,7 +146,7 @@
 			{
 				fprintf(stderr, "%s: failed to start: "
 					"failed to open configuration file: "
-					"%s", DaemonName(), 
+					"%s\n", DaemonName(), 
 					mConfigFileName.c_str());
 #ifdef WIN32
 				::syslog(LOG_ERR, "%s: failed to start: "
@@ -189,6 +193,7 @@
 		{
 			THROW_EXCEPTION(ServerException, DaemoniseFailed)
 		}
+#endif // !WIN32
 		
 		// Server configuration
 		const Configuration &serverConfig(
@@ -197,7 +202,8 @@
 		// Open PID file for writing
 		pidFileName = serverConfig.GetKeyValue("PidFile");
 		FileHandleGuard<(O_WRONLY | O_CREAT | O_TRUNC), (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)> pidFile(pidFileName.c_str());
-		
+	
+#ifndef WIN32	
 		// Handle changing to a different user
 		if(serverConfig.KeyExists("User"))
 		{
@@ -267,20 +273,25 @@
 
 		// open the log
 		::openlog(DaemonName(), LOG_PID, LOG_LOCAL6);
+
 		// Log the start message
 		::syslog(LOG_INFO, "Starting daemon (config: %s) (version " 
 			BOX_VERSION ")", mConfigFileName.c_str());
 
-#ifndef WIN32
 		// Write PID to file
 		char pid[32];
+
+#ifdef WIN32
+		int pidsize = sprintf(pid, "%d", (int)GetCurrentProcessId());
+#else
 		int pidsize = sprintf(pid, "%d", (int)getpid());
+#endif
+
 		if(::write(pidFile, pid, pidsize) != pidsize)
 		{
 			::syslog(LOG_ERR, "can't write pid file");
 			THROW_EXCEPTION(ServerException, DaemoniseFailed)
 		}
-#endif
 		
 		// Set up memory leak reporting
 		#ifdef BOX_MEMORY_LEAK_TESTING
@@ -352,6 +363,22 @@
 #endif
 		return 1;
 	}
+
+#ifdef WIN32
+	// Under win32 we must initialise the Winsock library
+	// before using sockets
+
+	WSADATA info;
+
+	if (WSAStartup(0x0101, &info) == SOCKET_ERROR)
+	{
+		// will not run without sockets
+		::syslog(LOG_ERR, "Failed to initialise Windows Sockets");
+		THROW_EXCEPTION(CommonException, Internal)
+	}
+#endif
+
+	int retcode = 0;
 	
 	// Main Daemon running
 	try
@@ -381,7 +408,8 @@
 						mConfigFileName.c_str(),
 						errors.c_str());
 					// And give up
-					return 1;
+					retcode = 1;
+					break;
 				}
 				
 				// delete old configuration
@@ -409,22 +437,26 @@
 		::syslog(LOG_ERR, "%s: terminating due to exception %s "
 			"(%d/%d)", DaemonName(), e.what(), e.GetType(), 
 			e.GetSubType());
-		return 1;
+		retcode = 1;
 	}
 	catch(std::exception &e)
 	{
 		::syslog(LOG_ERR, "%s: terminating due to exception %s", 
 			DaemonName(), e.what());
-		return 1;
+		retcode = 1;
 	}
 	catch(...)
 	{
 		::syslog(LOG_ERR, "%s: terminating due to unknown exception",
 			DaemonName());
-		return 1;
+		retcode = 1;
 	}
+
+#ifdef WIN32
+	WSACleanup();
+#endif
 	
-	return 0;
+	return retcode;
 }
 
 // --------------------------------------------------------------------------

Modified: box/chris/merge/lib/server/ServerStream.h
===================================================================
--- box/chris/merge/lib/server/ServerStream.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/server/ServerStream.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -56,6 +56,10 @@
 		return "generic-stream-server";
 	}
 
+	#ifdef WIN32
+	virtual void OnIdle() { }
+	#endif
+
 	virtual void Run()
 	{
 		// Set process title as appropraite
@@ -215,6 +219,7 @@
 					if(connection.get())
 					{
 						// Since this is a template parameter, the if() will be optimised out by the compiler
+						#ifndef WIN32 // no fork on Win32
 						if(ForkToHandleRequests)
 						{
 							pid_t pid = ::fork();
@@ -255,14 +260,20 @@
 						}
 						else
 						{
+						#endif // !WIN32
 							// Just handle in this connection
 							SetProcessTitle("handling");
 							HandleConnection(*connection);
 							SetProcessTitle("idle");										
+						#ifndef WIN32
 						}
+						#endif // !WIN32
 					}
 				}
-				
+
+				#ifdef WIN32
+				OnIdle();
+				#else // !WIN32
 				// Clean up child processes (if forking daemon)
 				if(ForkToHandleRequests)
 				{
@@ -277,6 +288,7 @@
 						}
 					} while(p > 0);
 				}
+				#endif // !WIN32
 			}
 		}
 		catch(...)
@@ -301,7 +313,11 @@
 	// depends on the forking model in case someone changes it later.
 	bool WillForkToHandleRequests()
 	{
+		#ifdef WIN32
+		return false;
+		#else
 		return ForkToHandleRequests;
+		#endif // WIN32
 	}
 
 private:

Modified: box/chris/merge/lib/server/SocketStream.cpp
===================================================================
--- box/chris/merge/lib/server/SocketStream.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/server/SocketStream.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -36,7 +36,7 @@
 //
 // --------------------------------------------------------------------------
 SocketStream::SocketStream()
-	: mSocketHandle(-1),
+	: mSocketHandle(INVALID_SOCKET_VALUE),
 	  mReadClosed(false),
 	  mWriteClosed(false),
 	  mBytesRead(0),
@@ -85,7 +85,7 @@
 	{
 		THROW_EXCEPTION(ServerException, BadSocketHandle);
 	}
-	if(mSocketHandle == -1)
+	if(mSocketHandle == INVALID_SOCKET_VALUE)
 	{
 		THROW_EXCEPTION(ServerException, DupError);
 	}
@@ -101,7 +101,7 @@
 // --------------------------------------------------------------------------
 SocketStream::~SocketStream()
 {
-	if(mSocketHandle != -1)
+	if(mSocketHandle != INVALID_SOCKET_VALUE)
 	{
 		Close();
 	}
@@ -117,7 +117,10 @@
 // --------------------------------------------------------------------------
 void SocketStream::Attach(int socket)
 {
-	if(mSocketHandle != -1) {THROW_EXCEPTION(ServerException, SocketAlreadyOpen)}
+	if(mSocketHandle != INVALID_SOCKET_VALUE) 
+	{
+		THROW_EXCEPTION(ServerException, SocketAlreadyOpen)
+	}
 
 	mSocketHandle = socket;
 	ResetCounters();
@@ -134,7 +137,10 @@
 // --------------------------------------------------------------------------
 void SocketStream::Open(int Type, const char *Name, int Port)
 {
-	if(mSocketHandle != -1) {THROW_EXCEPTION(ServerException, SocketAlreadyOpen)}
+	if(mSocketHandle != INVALID_SOCKET_VALUE) 
+	{
+		THROW_EXCEPTION(ServerException, SocketAlreadyOpen)
+	}
 	
 	// Setup parameters based on type, looking up names if required
 	int sockDomain = 0;
@@ -144,7 +150,7 @@
 
 	// Create the socket
 	mSocketHandle = ::socket(sockDomain, SOCK_STREAM, 0 /* let OS choose protocol */);
-	if(mSocketHandle == -1)
+	if(mSocketHandle == INVALID_SOCKET_VALUE)
 	{
 		THROW_EXCEPTION(ServerException, SocketOpenError)
 	}
@@ -158,7 +164,7 @@
 #else
 		::close(mSocketHandle);
 #endif
-		mSocketHandle = -1;
+		mSocketHandle = INVALID_SOCKET_VALUE;
 		THROW_EXCEPTION(ConnectionException, Conn_SocketConnectError)
 	}
 	ResetCounters();
@@ -174,7 +180,10 @@
 // --------------------------------------------------------------------------
 int SocketStream::Read(void *pBuffer, int NBytes, int Timeout)
 {
-	if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+	if(mSocketHandle == INVALID_SOCKET_VALUE) 
+	{
+		THROW_EXCEPTION(ServerException, BadSocketHandle)
+	}
 
 	if(Timeout != IOStream::TimeOutInfinite)
 	{
@@ -247,7 +256,10 @@
 // --------------------------------------------------------------------------
 void SocketStream::Write(const void *pBuffer, int NBytes)
 {
-	if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+	if(mSocketHandle == INVALID_SOCKET_VALUE) 
+	{
+		THROW_EXCEPTION(ServerException, BadSocketHandle)
+	}
 	
 	// Buffer in byte sized type.
 	ASSERT(sizeof(char) == 1);
@@ -311,7 +323,10 @@
 // --------------------------------------------------------------------------
 void SocketStream::Close()
 {
-	if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+	if(mSocketHandle == INVALID_SOCKET_VALUE) 
+	{
+		THROW_EXCEPTION(ServerException, BadSocketHandle)
+	}
 #ifdef WIN32
 	if(::closesocket(mSocketHandle) == -1)
 #else
@@ -320,7 +335,7 @@
 	{
 		THROW_EXCEPTION(ServerException, SocketCloseError)
 	}
-	mSocketHandle = -1;
+	mSocketHandle = INVALID_SOCKET_VALUE;
 }
 
 // --------------------------------------------------------------------------
@@ -333,7 +348,10 @@
 // --------------------------------------------------------------------------
 void SocketStream::Shutdown(bool Read, bool Write)
 {
-	if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+	if(mSocketHandle == INVALID_SOCKET_VALUE) 
+	{
+		THROW_EXCEPTION(ServerException, BadSocketHandle)
+	}
 	
 	// Do anything?
 	if(!Read && !Write) return;
@@ -388,7 +406,10 @@
 // --------------------------------------------------------------------------
 tOSSocketHandle SocketStream::GetSocketHandle()
 {
-	if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+	if(mSocketHandle == INVALID_SOCKET_VALUE) 
+	{
+		THROW_EXCEPTION(ServerException, BadSocketHandle)
+	}
 	return mSocketHandle;
 }
 

Modified: box/chris/merge/lib/server/SocketStream.h
===================================================================
--- box/chris/merge/lib/server/SocketStream.h	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/server/SocketStream.h	2006-07-27 23:18:35 UTC (rev 710)
@@ -14,8 +14,10 @@
 
 #ifdef WIN32
 	typedef SOCKET tOSSocketHandle;
+	#define INVALID_SOCKET_VALUE (tOSSocketHandle)(-1)
 #else
 	typedef int tOSSocketHandle;
+	#define INVALID_SOCKET_VALUE -1
 #endif
 
 // --------------------------------------------------------------------------

Modified: box/chris/merge/lib/server/SocketStreamTLS.cpp
===================================================================
--- box/chris/merge/lib/server/SocketStreamTLS.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/server/SocketStreamTLS.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -137,8 +137,12 @@
 		THROW_EXCEPTION(ServerException, TLSAllocationFailed)
 	}
 
-#ifndef WIN32
 	// Make the socket non-blocking so timeouts on Read work
+
+#ifdef WIN32
+	u_long nonblocking = 1;
+	ioctlsocket(socket, FIONBIO, &nonblocking);
+#else // !WIN32
 	// This is more portable than using ioctl with FIONBIO
 	int statusFlags = 0;
 	if(::fcntl(socket, F_GETFL, &statusFlags) < 0
@@ -309,7 +313,7 @@
 
 		case SSL_ERROR_WANT_READ:
 		case SSL_ERROR_WANT_WRITE:
-			// wait for the requried data
+			// wait for the required data
 			// Will only get once around this loop, so don't need to calculate timeout values
 			if(WaitWhenRetryRequired(se, Timeout) == false)
 			{

Modified: box/chris/merge/lib/server/makeprotocol.pl.in
===================================================================
--- box/chris/merge/lib/server/makeprotocol.pl.in	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/lib/server/makeprotocol.pl.in	2006-07-27 23:18:35 UTC (rev 710)
@@ -1,6 +1,9 @@
 #!@PERL@
 use strict;
 
+use lib "../../infrastructure";
+use BoxPlatform;
+
 # Make protocol C++ classes from a protocol description file
 
 # built in type info (values are is basic type, C++ typename)
@@ -167,8 +170,8 @@
 
 # open files
 my $h_filename = 'autogen_'.$protocol_name.'Protocol'.$type.'.h';
-open CPP,'>autogen_'.$protocol_name.'Protocol'.$type.'.cpp';
-open H,">$h_filename";
+open CPP,'>autogen_'.$protocol_name.'Protocol'.$type.'.cpp.new';
+open H,">$h_filename.new";
 
 print CPP <<__E;
 
@@ -912,6 +915,8 @@
 close H;
 close CPP;
 
+update_if_changed('autogen_'.$protocol_name.'Protocol'.$type.'.cpp');
+update_if_changed($h_filename);
 
 sub obj_is_type
 {
@@ -981,8 +986,15 @@
 		{
 			# need to translate it
 			my ($format,$arg) = @{$log_display_types{$ty}};
+			$arg =~ s/VAR/m$nm/g;
+
+			if ($format eq "0x%llx" and $target_windows)
+			{
+				$format = "0x%I64x";
+				$arg = "(uint64_t)$arg";
+			}
+
 			push @str,$format;
-			$arg =~ s/VAR/m$nm/g;
 			push @arg,$arg;
 		}
 		else

Modified: box/chris/merge/runtest.pl.in
===================================================================
--- box/chris/merge/runtest.pl.in	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/runtest.pl.in	2006-07-27 23:18:35 UTC (rev 710)
@@ -1,11 +1,14 @@
 #!@PERL@
 
+use strict;
+use warnings;
+
 use lib 'infrastructure';
 use BoxPlatform;
 
 my ($test_name,$test_mode) = @ARGV;
 
-$test_mode = 'debug' if $test_mode eq '';
+$test_mode = 'debug' if not defined $test_mode or $test_mode eq '';
 
 if($test_name eq '' || ($test_mode ne 'debug' && $test_mode ne 'release'))
 {
@@ -17,15 +20,26 @@
 Mode defaults to debug.
 
 __E
-	exit(0);
+	exit(2);
 }
 
 my @results;
+my $exit_code = 0;
 
 if($test_name ne 'ALL')
 {
-	# run one test
-	runtest($test_name);
+	# run one or more specified test
+	if ($test_name =~ m/,/)
+	{
+		foreach my $test (split m/,/, $test_name)
+		{
+			runtest($test);
+		}
+	}
+	else
+	{
+		runtest($test_name);
+	}
 }
 else
 {
@@ -57,6 +71,8 @@
 # report results
 print "--------\n",join("\n", at results),"\n";
 
+exit $exit_code;
+
 sub runtest
 {
 	my ($t) = @_;
@@ -67,6 +83,7 @@
 	if($make_res != 0)
 	{
 		push @results,"$t: make failed";
+		$exit_code = 2;
 		return;
 	}
 	
@@ -82,8 +99,14 @@
 			$last = $_ if m/\w/;
 		}
 		close RESULTS;
+
 		chomp $last;
 		push @results,"$t: $last";
+
+		if ($last ne "PASSED") 
+		{ 
+			$exit_code = 1;
+		}
 	}
 	else
 	{

Modified: box/chris/merge/test/backupdiff/testbackupdiff.cpp
===================================================================
--- box/chris/merge/test/backupdiff/testbackupdiff.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/backupdiff/testbackupdiff.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -66,23 +66,21 @@
 
 void make_file_of_zeros(const char *filename, size_t size)
 {
-	static const size_t bs = 0x10000;
-	size_t remSize = size;
-	void *b = malloc(bs);
-	memset(b, 0, bs);
-	FILE *f = fopen(filename, "wb");
+	#ifdef WIN32
+	HANDLE handle = openfile(filename, O_WRONLY | O_CREAT | O_EXCL, 0);
+	TEST_THAT(handle != INVALID_HANDLE_VALUE);
+	SetFilePointer(handle, size, NULL, FILE_BEGIN);
+	TEST_THAT(GetLastError() == NO_ERROR);
+	TEST_THAT(SetEndOfFile(handle) == true);
+	TEST_THAT(CloseHandle(handle)  == true);
+	#else
+	int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600);
+	if (fd < 0) perror(filename);
+	TEST_THAT(fd >= 0);
+	TEST_THAT(ftruncate(fd, size) == 0);
+	TEST_THAT(close(fd) == 0);
+	#endif
 
-	// Using largish blocks like this is much faster, while not consuming too much RAM
-	while(remSize > bs)
-	{
-		fwrite(b, bs, 1, f);
-		remSize -= bs;
-	}
-	fwrite(b, remSize, 1, f);
-
-	fclose(f);
-	free(b);
-
 	TEST_THAT((size_t)TestGetFileSize(filename) == size);
 }
 
@@ -118,12 +116,20 @@
 		if(s > 0)
 		{
 			nnew++;
+			#ifdef WIN32
+			TRACE2("%8I64d this  s=%8I64d", b, s);
+			#else
 			TRACE2("%8lld this  s=%8lld", b, s);
+			#endif
 		}
 		else
 		{
 			nold++;
+			#ifdef WIN32
+			TRACE2("%8I64d other i=%8I64d", b, 0 - s);		
+			#else
 			TRACE2("%8lld other i=%8lld", b, 0 - s);		
+			#endif
 		}
 		// Decode the rest
 		uint64_t iv = box_ntoh64(hdr.mEntryIVBase);
@@ -207,10 +213,18 @@
 	}
 	else
 	{
+#ifdef WIN32
 		// Emulate the above stage!
+		char src[256], dst[256];
+		sprintf(src, "testfiles\\f%d.diff", to);
+		sprintf(dst, "testfiles\\f%d.encoded", to);
+		TEST_THAT(CopyFile(src, dst, FALSE) != 0)
+#else
+		// Emulate the above stage!
 		char cmd[256];
 		sprintf(cmd, "cp testfiles/f%d.diff testfiles/f%d.encoded", to, to);
 		::system(cmd);
+#endif
 	}
 
 	// Decode it
@@ -355,8 +369,10 @@
 {
 	// Want to trace out all the details
 	#ifndef NDEBUG
+	#ifndef WIN32
 	BackupStoreFile::TraceDetailsOfDiffProcess = true;
 	#endif
+	#endif
 
 	// Create all the test files
 	create_test_files();
@@ -370,6 +386,7 @@
 		FileStream out("testfiles/f0.encoded", O_WRONLY | O_CREAT | O_EXCL);
 		std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/f0", 1 /* dir ID */, f0name));
 		encoded->CopyStreamTo(out);
+		out.Close();
 		check_encoded_file("testfiles/f0.encoded", 0, 33, 0);
 	}
 	
@@ -430,6 +447,7 @@
 			FileStream out("testfiles/f9.zerotest", O_WRONLY | O_CREAT | O_EXCL);
 			std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/f9", 1 /* dir ID */, fn));
 			encoded->CopyStreamTo(out);
+			out.Close();
 			check_encoded_file("testfiles/f9.zerotest", 0, 0, 0);		
 		}
 		{
@@ -440,6 +458,7 @@
 		}
 	}
 	
+#ifndef WIN32	
 	// Check that symlinks aren't diffed
 	TEST_THAT(::symlink("f2", "testfiles/f2.symlink") == 0)
 	// And go and diff it against the previous encoded file
@@ -467,8 +486,10 @@
 		TEST_THAT(completelyDifferent == true);
 		check_encoded_file("testfiles/f2.symlink.diff", 0, 0, 0);		
 	}
+#endif
 
-	// Check that diffing against a file which isn't "complete" and referes another isn't allowed
+	// Check that diffing against a file which isn't "complete" and 
+	// references another isn't allowed
 	{
 		FileStream blockindex("testfiles/f1.diff");
 		BackupStoreFile::MoveStreamPositionToBlockIndex(blockindex);
@@ -480,10 +501,19 @@
 			0, 0), BackupStoreException, CannotDiffAnIncompleteStoreFile);
 	}
 
-	// Found a nasty case where files of lots of the same thing sock up lots of processor
-	// time -- because of lots of matches found. Check this out!
+	// Found a nasty case where files of lots of the same thing 
+	// suck up lots of processor time -- because of lots of matches 
+	// found. Check this out!
+
+	#ifdef WIN32
+	::fprintf(stdout, "Testing diffing two large streams, "
+		"may take a while!\n");
+	::fflush(stdout);
+	#endif
+
 	make_file_of_zeros("testfiles/zero.0", 20*1024*1024);
 	make_file_of_zeros("testfiles/zero.1", 200*1024*1024);
+
 	// Generate a first encoded file
 	{
 		BackupStoreFilenameClear f0name("zero.0");
@@ -503,7 +533,14 @@
 			2000 /* object ID of the file diffing from */, blockindex, IOStream::TimeOutInfinite,
 			0, 0));
 		encoded->CopyStreamTo(out);
+
+		printf("Time taken: %d seconds\n", (int)(time(0) - beginTime));
+
+		#ifdef WIN32
+		TEST_THAT(time(0) < (beginTime + 300));
+		#else
 		TEST_THAT(time(0) < (beginTime + 40));
+		#endif
 	}
 	// Remove zero-files to save disk space
 	remove("testfiles/zero.0");

Modified: box/chris/merge/test/backupstore/testbackupstore.cpp
===================================================================
--- box/chris/merge/test/backupstore/testbackupstore.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/backupstore/testbackupstore.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -425,7 +425,8 @@
 	}
 	
 	free(data);
-	unlink("testfiles/test_download");
+	in.Close();
+	TEST_THAT(unlink("testfiles/test_download") == 0);
 }
 
 void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
@@ -930,6 +931,7 @@
 		// Check marker is 0
 		TEST_THAT(loginConf->GetClientStoreMarker() == 0);
 
+#ifndef WIN32
 		// Check that we can't open a new connection which requests write permissions
 		{
 			SocketStreamTLS conn;
@@ -941,10 +943,12 @@
 				ConnectionException, Conn_Protocol_UnexpectedReply);
 			protocol.QueryFinished();
 		}
+#endif
 		
 		// Set the client store marker
 		protocol.QuerySetClientStoreMarker(0x8732523ab23aLL);
 
+#ifndef WIN32
 		// Open a new connection which is read only
 		SocketStreamTLS connReadOnly;
 		connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED);
@@ -963,10 +967,11 @@
 			// Check client store marker
 			TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL);
 		}
+#else // WIN32
+		BackupProtocolClient& protocolReadOnly(protocol);
+#endif
 
 		test_server_1(protocol, protocolReadOnly);
-
-
 		// Create and upload some test files
 		int64_t maxID = 0;
 		for(int t = 0; t < UPLOAD_NUM; ++t)
@@ -1438,11 +1443,15 @@
 		}
 			
 		// Finish the connections
+#ifndef WIN32
 		protocolReadOnly.QueryFinished();
+#endif
 		protocol.QueryFinished();
 		
 		// Close logs
+#ifndef WIN32
 		::fclose(protocolReadOnlyLog);
+#endif
 		::fclose(protocolLog);
 	}
 	
@@ -1520,35 +1529,48 @@
 		
 		// The test block to a file
 		{
-			FileStream f("testfiles/testenc1", O_WRONLY | O_CREAT | O_EXCL);
+			FileStream f("testfiles" DIRECTORY_SEPARATOR 
+				"testenc1", O_WRONLY | O_CREAT | O_EXCL);
 			f.Write(encfile, sizeof(encfile));
 		}
 		
 		// Encode it
 		{
-			FileStream out("testfiles/testenc1_enc", O_WRONLY | O_CREAT | O_EXCL);
-			BackupStoreFilenameClear name("testfiles/testenc1");
+			FileStream out("testfiles" DIRECTORY_SEPARATOR 
+				"testenc1_enc", O_WRONLY | O_CREAT | O_EXCL);
+			BackupStoreFilenameClear name("testfiles"
+				DIRECTORY_SEPARATOR "testenc1");
 
-			std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/testenc1", 32, name));
+			std::auto_ptr<IOStream> encoded(
+				BackupStoreFile::EncodeFile(
+					"testfiles" DIRECTORY_SEPARATOR
+					"testenc1", 32, name));
 			encoded->CopyStreamTo(out);
 		}
 		
 		// Verify it
 		{
-			FileStream enc("testfiles/testenc1_enc");
+			FileStream enc("testfiles" DIRECTORY_SEPARATOR 
+				"testenc1_enc");
 			TEST_THAT(BackupStoreFile::VerifyEncodedFileFormat(enc) == true);
 		}
 		
 		// Decode it
 		{
-			FileStream enc("testfiles/testenc1_enc");
-			BackupStoreFile::DecodeFile(enc, "testfiles/testenc1_orig", IOStream::TimeOutInfinite);
+			FileStream enc("testfiles" DIRECTORY_SEPARATOR 
+				"testenc1_enc");
+			BackupStoreFile::DecodeFile(enc, "testfiles"
+				DIRECTORY_SEPARATOR "testenc1_orig", 
+				IOStream::TimeOutInfinite);
 		}
 		
 		// Read in rebuilt original, and compare contents
 		{
-			TEST_THAT(TestGetFileSize("testfiles/testenc1_orig") == sizeof(encfile));
-			FileStream in("testfiles/testenc1_orig");
+			TEST_THAT(TestGetFileSize("testfiles" 
+				DIRECTORY_SEPARATOR "testenc1_orig") 
+				== sizeof(encfile));
+			FileStream in("testfiles" DIRECTORY_SEPARATOR 
+				"testenc1_orig");
 			int encfile_i[ENCFILE_SIZE];
 			in.Read(encfile_i, sizeof(encfile_i));
 			TEST_THAT(memcmp(encfile, encfile_i, sizeof(encfile)) == 0);
@@ -1556,7 +1578,8 @@
 		
 		// Check how many blocks it had, and test the stream based interface
 		{
-			FileStream enc("testfiles/testenc1_enc");
+			FileStream enc("testfiles" DIRECTORY_SEPARATOR 
+				"testenc1_enc");
 			std::auto_ptr<BackupStoreFile::DecodedStream> decoded(BackupStoreFile::DecodeFileStream(enc, IOStream::TimeOutInfinite));
 			CollectInBufferStream d;
 			decoded->CopyStreamTo(d, IOStream::TimeOutInfinite, 971 /* buffer block size */);
@@ -1570,10 +1593,15 @@
 		// Test that the last block in a file, if less than 256 bytes, gets put into the last block
 		{
 			#define FILE_SIZE_JUST_OVER	((4096*2)+58)
-			FileStream f("testfiles/testenc2", O_WRONLY | O_CREAT | O_EXCL);
+			FileStream f("testfiles" DIRECTORY_SEPARATOR 
+				"testenc2", O_WRONLY | O_CREAT | O_EXCL);
 			f.Write(encfile + 2, FILE_SIZE_JUST_OVER);
+			f.Close();
 			BackupStoreFilenameClear name("testenc2");
-			std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/testenc2", 32, name));
+			std::auto_ptr<IOStream> encoded(
+				BackupStoreFile::EncodeFile(
+					"testfiles" DIRECTORY_SEPARATOR
+					"testenc2", 32, name));
 			CollectInBufferStream e;
 			encoded->CopyStreamTo(e);
 			e.SetForReading();
@@ -1589,7 +1617,8 @@
 		
 		// Test that reordered streams work too
 		{
-			FileStream enc("testfiles/testenc1_enc");
+			FileStream enc("testfiles" DIRECTORY_SEPARATOR 
+				"testenc1_enc");
 			std::auto_ptr<IOStream> reordered(BackupStoreFile::ReorderFileToStreamOrder(&enc, false));
 			std::auto_ptr<BackupStoreFile::DecodedStream> decoded(BackupStoreFile::DecodeFileStream(*reordered, IOStream::TimeOutInfinite));
 			CollectInBufferStream d;
@@ -1601,6 +1630,7 @@
 			TEST_THAT(decoded->GetNumBlocks() == 3);
 		}
 		
+#ifndef WIN32		
 		// Try out doing this on a symlink
 		{
 			TEST_THAT(::symlink("does/not/exist", "testfiles/testsymlink") == 0);
@@ -1614,14 +1644,20 @@
 			// Decode it
 			BackupStoreFile::DecodeFile(b, "testfiles/testsymlink_2", IOStream::TimeOutInfinite);
 		}
+#endif
 	}
 
 	// Store info
 	{
 		RaidFileWrite::CreateDirectory(0, "test-info");
-		BackupStoreInfo::CreateNew(76, "test-info/", 0, 3461231233455433LL, 2934852487LL);
-		TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, "test-info/", 0, 0, 0), RaidFileException, CannotOverwriteExistingFile);
-		std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, "test-info/", 0, true));
+		BackupStoreInfo::CreateNew(76, "test-info" DIRECTORY_SEPARATOR, 
+			0, 3461231233455433LL, 2934852487LL);
+		TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, 
+			"test-info" DIRECTORY_SEPARATOR, 0, 0, 0), 
+			RaidFileException, CannotOverwriteExistingFile);
+		std::auto_ptr<BackupStoreInfo> info(
+			BackupStoreInfo::Load(76, 
+				"test-info" DIRECTORY_SEPARATOR, 0, true));
 		TEST_CHECK_THROWS(info->Save(), BackupStoreException, StoreInfoIsReadOnly);
 		TEST_CHECK_THROWS(info->ChangeBlocksUsed(1), BackupStoreException, StoreInfoIsReadOnly);
 		TEST_CHECK_THROWS(info->ChangeBlocksInOldFiles(1), BackupStoreException, StoreInfoIsReadOnly);
@@ -1630,7 +1666,8 @@
 		TEST_CHECK_THROWS(info->AddDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly);
 	}
 	{
-		std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, "test-info/", 0, false));
+		std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, 
+			"test-info" DIRECTORY_SEPARATOR, 0, false));
 		info->ChangeBlocksUsed(8);
 		info->ChangeBlocksInOldFiles(9);
 		info->ChangeBlocksInDeletedFiles(10);
@@ -1648,7 +1685,8 @@
 		info->Save();
 	}
 	{
-		std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, "test-info/", 0, true));
+		std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, 
+			"test-info" DIRECTORY_SEPARATOR, 0, true));
 		TEST_THAT(info->GetBlocksUsed() == 7);
 		TEST_THAT(info->GetBlocksInOldFiles() == 5);
 		TEST_THAT(info->GetBlocksInDeletedFiles() == 1);
@@ -1666,12 +1704,18 @@
 	// Context
 	TLSContext context;
 	context.Initialise(false /* client */,
-			"testfiles/clientCerts.pem",
-			"testfiles/clientPrivKey.pem",
-			"testfiles/clientTrustedCAs.pem");
+			"testfiles" DIRECTORY_SEPARATOR "clientCerts.pem",
+			"testfiles" DIRECTORY_SEPARATOR "clientPrivKey.pem",
+			"testfiles" DIRECTORY_SEPARATOR "clientTrustedCAs.pem");
 
 	// First, try logging in without an account having been created... just make sure login fails.
+
+#ifdef WIN32
+	int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+#else
 	int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+#endif
+
 	TEST_THAT(pid != -1 && pid != 0);
 	if(pid > 0)
 	{
@@ -1700,8 +1744,13 @@
 		}
 
 		// Create an account for the test client
+#ifdef WIN32
+		TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0);
+#else
 		TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0);
 		TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+#endif
+
 		TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567"));
 		TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567"));
 		TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567"));
@@ -1725,15 +1774,27 @@
 		TEST_THAT(KillServer(pid));
 		::sleep(1);
 		TEST_THAT(!ServerIsAlive(pid));
+#ifndef WIN32
 		TestRemoteProcessMemLeaks("bbstored.memleaks");
+#endif
 		
 		// Set a new limit on the account -- leave the hard limit high to make sure the target for
 		// freeing space is the soft limit.
+
+#ifdef WIN32
+		TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0);
+#else
 		TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0);
 		TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+#endif
 
 		// Start things up
+#ifdef WIN32
+		pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+#else
 		pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+#endif
+
 		::sleep(1);
 		TEST_THAT(ServerIsAlive(pid));
 		
@@ -1758,8 +1819,12 @@
 		TEST_THAT(after.old == 0);
 		
 		// Set a really small hard limit
+#ifdef WIN32
+		TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0);
+#else
 		TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0);
 		TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+#endif
 
 		// Try to upload a file and create a directory, and check an error is generated
 		{
@@ -1808,7 +1873,10 @@
 		TEST_THAT(KillServer(pid));
 		::sleep(1);
 		TEST_THAT(!ServerIsAlive(pid));
+
+#ifndef WIN32
 		TestRemoteProcessMemLeaks("bbstored.memleaks");
+#endif
 	}
 
 	return 0;
@@ -1820,10 +1888,19 @@
 
 	// Create an account for the test client
 	TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0);
+
+#ifndef WIN32
 	TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+#endif
 
 	// First, try logging in without an account having been created... just make sure login fails.
+
+#ifdef WIN32
+	int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid");
+#else
 	int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid");
+#endif
+
 	TEST_THAT(pid != -1 && pid != 0);
 	if(pid > 0)
 	{
@@ -1840,15 +1917,63 @@
 		TEST_THAT(KillServer(pid));
 		::sleep(1);
 		TEST_THAT(!ServerIsAlive(pid));
+#ifndef WIN32
 		TestRemoteProcessMemLeaks("bbstored.memleaks");
+#endif
 	}
 
 
 	return 0;
 }
 
+#ifdef WIN32
+WCHAR* ConvertUtf8ToWideString(const char* pString);
+std::string ConvertPathToAbsoluteUnicode(const char *pFileName);
+#endif
+
 int test(int argc, const char *argv[])
 {
+#ifdef WIN32
+	// Under win32 we must initialise the Winsock library
+	// before using sockets
+
+	WSADATA info;
+	TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR)
+
+	// this had better work, or bbstored will die when combining diffs
+	char* file = "foo";
+	std::string abs = ConvertPathToAbsoluteUnicode(file);
+	WCHAR* wfile = ConvertUtf8ToWideString(abs.c_str());
+
+	DWORD accessRights = FILE_READ_ATTRIBUTES | 
+		FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_WRITE_ATTRIBUTES |
+		FILE_WRITE_DATA | FILE_WRITE_EA /*| FILE_ALL_ACCESS*/;
+	DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+	HANDLE h1 = CreateFileW(wfile, accessRights, shareMode,
+		NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+	assert(h1 != INVALID_HANDLE_VALUE);
+	TEST_THAT(h1 != INVALID_HANDLE_VALUE);
+
+	accessRights = FILE_READ_ATTRIBUTES | 
+		FILE_LIST_DIRECTORY | FILE_READ_EA;
+
+	HANDLE h2 = CreateFileW(wfile, accessRights, shareMode,
+		NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+	assert(h2 != INVALID_HANDLE_VALUE);
+	TEST_THAT(h2 != INVALID_HANDLE_VALUE);
+
+	CloseHandle(h2);
+	CloseHandle(h1);
+
+	h1 = openfile("foo", O_CREAT | O_RDWR, 0);
+	TEST_THAT(h1 != INVALID_HANDLE_VALUE);
+	h2 = openfile("foo", O_RDWR, 0);
+	TEST_THAT(h2 != INVALID_HANDLE_VALUE);
+	CloseHandle(h2);
+	CloseHandle(h1);
+#endif
+
 	// SSL library
 	SSLLib::Initialise();
 	
@@ -1865,7 +1990,11 @@
 
 	// Use the setup crypto command to set up all these keys, so that the bbackupquery command can be used
 	// for seeing what's going on.
+#ifdef WIN32
+	BackupClientCryptoKeys_Setup("testfiles\\bbackupd.keys");	
+#else
 	BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys");	
+#endif
 	
 	// encode in some filenames -- can't do static initialisation because the key won't be set up when these are initialised
 	for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l)

Modified: box/chris/merge/test/backupstorefix/testfiles/testbackupstorefix.pl.in
===================================================================
--- box/chris/merge/test/backupstorefix/testfiles/testbackupstorefix.pl.in	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/backupstorefix/testfiles/testbackupstorefix.pl.in	2006-07-27 23:18:35 UTC (rev 710)
@@ -54,7 +54,7 @@
 	open INITIAL,'testfiles/initial-listing.txt' or die "Can't open original listing";
 	while(<INITIAL>)
 	{
-		chomp;
+		chomp; s/\r//;
 		$expected{$_} = 1;
 		m/\A(.+?) .+? (.+)\Z/;
 		$filenames{$2} = $_;
@@ -99,7 +99,7 @@
 	while(<LISTING>)
 	{
 		print LISTING_COPY;
-		chomp;
+		chomp; s/\r//;
 		s/\[FILENAME NOT ENCRYPTED\]//;
 		if(exists $expected{$_})
 		{

Modified: box/chris/merge/test/backupstorepatch/testbackupstorepatch.cpp
===================================================================
--- box/chris/merge/test/backupstorepatch/testbackupstorepatch.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/backupstorepatch/testbackupstorepatch.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -283,6 +283,14 @@
 
 int test(int argc, const char *argv[])
 {
+#ifdef WIN32
+	// Under win32 we must initialise the Winsock library
+	// before using sockets
+
+	WSADATA info;
+	TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR)
+#endif
+
 	// Allocate a buffer
 	buffer = ::malloc(BUFFER_SIZE);
 	TEST_THAT(buffer != 0);
@@ -309,8 +317,12 @@
 			"testfiles/clientTrustedCAs.pem");
 
 	// Create an account
+#ifdef WIN32
+	TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0);
+#else
 	TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0);
 	TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+#endif
 
 	// Create test files
 	create_test_files();
@@ -319,7 +331,12 @@
 	test_depends_in_dirs();
 
 	// First, try logging in without an account having been created... just make sure login fails.
+#ifdef WIN32
+	int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+#else
 	int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+#endif
+
 	TEST_THAT(pid != -1 && pid != 0);
 	if(pid > 0)
 	{
@@ -397,7 +414,13 @@
 					// Store details
 					test_files[f].IDOnServer = stored->GetObjectID();
 					test_files[f].IsCompletelyDifferent = isCompletelyDifferent;
-					printf("ID %lld, completely different: %s\n", test_files[f].IDOnServer,
+
+#ifdef WIN32
+					printf("ID %I64d, completely different: %s\n",
+#else
+					printf("ID %lld, completely different: %s\n", 
+#endif
+						test_files[f].IDOnServer,
 						test_files[f].IsCompletelyDifferent?"yes":"no");			
 				}
 				else
@@ -565,9 +588,14 @@
 				writedir.Commit(true);
 			}
 
-			// Send the server a restart signal, so it does housekeeping immedaitely, and wait for it to happen
+#ifdef WIN32
+			wait_for_operation(12);
+#else
+			// Send the server a restart signal, so it does housekeeping immediately, and wait for it to happen
 			::sleep(1);	// wait for old connections to terminate
 			::kill(pid, SIGHUP);
+#endif
+
 			// Get the revision number of the info file
 			int64_t first_revision = 0;
 			RaidFileRead::FileExists(0, "backup/01234567/o01", &first_revision);
@@ -611,7 +639,10 @@
 		// Kill store server
 		TEST_THAT(KillServer(pid));
 		TEST_THAT(!ServerIsAlive(pid));
+
+		#ifndef WIN32
 		TestRemoteProcessMemLeaks("bbstored.memleaks");
+		#endif
 	}
 	
 	::free(buffer);

Modified: box/chris/merge/test/basicserver/TestCommands.cpp
===================================================================
--- box/chris/merge/test/basicserver/TestCommands.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/basicserver/TestCommands.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -1,7 +1,9 @@
 
 #include "Box.h"
 
+#ifdef HAVE_SYSLOG_H
 #include <syslog.h>
+#endif
 
 #include "autogen_TestProtocolServer.h"
 #include "CollectInBufferStream.h"

Modified: box/chris/merge/test/basicserver/testbasicserver.cpp
===================================================================
--- box/chris/merge/test/basicserver/testbasicserver.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/basicserver/testbasicserver.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -31,7 +31,6 @@
 
 #include "MemLeakFindOn.h"
 
-
 #define SERVER_LISTEN_PORT	2003
 
 // in ms
@@ -62,10 +61,14 @@
 
 void testservers_pause_before_reply()
 {
-	 struct timespec t;
-	 t.tv_sec = 0;
-	 t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000;	// convert to ns
-	 ::nanosleep(&t, NULL);
+#ifdef WIN32
+	Sleep(COMMS_SERVER_WAIT_BEFORE_REPLYING);
+#else
+	struct timespec t;
+	t.tv_sec = 0;
+	t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000;	// convert to ns
+	::nanosleep(&t, NULL);
+#endif
 }
 
 #define LARGE_DATA_BLOCK_SIZE 19870
@@ -427,84 +430,138 @@
 		}
 	}
 
+#ifdef WIN32
+	// Under win32 we must initialise the Winsock library
+	// before using sockets
+
+	WSADATA info;
+	TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR)
+#endif
+
 //printf("SKIPPING TESTS------------------------\n");
 //goto protocolserver;
 
 	// Launch a basic server
 	{
-		int pid = LaunchServer("./test srv1 testfiles/srv1.conf", "testfiles/srv1.pid");
+#ifdef WIN32
+		int pid = LaunchServer("test srv1 testfiles\\srv1.conf", 
+			"testfiles\\srv1.pid");
+#else
+		int pid = LaunchServer("./test srv1 testfiles/srv1.conf", 
+			"testfiles/srv1.pid");
+#endif
+
 		TEST_THAT(pid != -1 && pid != 0);
 		if(pid > 0)
 		{
 			// Check that it's written the expected file
-			TEST_THAT(TestFileExists("testfiles/srv1.test1"));
+			TEST_THAT(TestFileExists("testfiles" 
+				DIRECTORY_SEPARATOR "srv1.test1"));
 			TEST_THAT(ServerIsAlive(pid));
 			// Move the config file over
-			TEST_THAT(::rename("testfiles/srv1b.conf", "testfiles/srv1.conf") != -1);
+#ifdef WIN32
+			TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR 
+				"srv1.conf") != -1);
+#endif
+			TEST_THAT(::rename(
+				"testfiles" DIRECTORY_SEPARATOR "srv1b.conf", 
+				"testfiles" DIRECTORY_SEPARATOR "srv1.conf") 
+				!= -1);
+#ifndef WIN32
 			// Get it to reread the config file
 			TEST_THAT(HUPServer(pid));
 			::sleep(1);
 			TEST_THAT(ServerIsAlive(pid));
 			// Check that new file exists
-			TEST_THAT(TestFileExists("testfiles/srv1.test2"));
+			TEST_THAT(TestFileExists("testfiles" 
+				DIRECTORY_SEPARATOR "srv1.test2"));
+#endif // !WIN32
 			// Kill it off
 			TEST_THAT(KillServer(pid));
+#ifndef WIN32
 			TestRemoteProcessMemLeaks("generic-daemon.memleaks");
+#endif // !WIN32
 		}
 	}
 	
 	// Launch a test forking server
 	{
-		int pid = LaunchServer("./test srv2 testfiles/srv2.conf", "testfiles/srv2.pid");
+#ifdef WIN32
+		int pid = LaunchServer("test srv2 testfiles\\srv2.conf", 
+			"testfiles\\srv2.pid");
+#else
+		int pid = LaunchServer("./test srv2 testfiles/srv2.conf", 
+			"testfiles/srv2.pid");
+#endif
+
 		TEST_THAT(pid != -1 && pid != 0);
 		if(pid > 0)
 		{
 			// Will it restart?
 			TEST_THAT(ServerIsAlive(pid));
+#ifndef WIN32
 			TEST_THAT(HUPServer(pid));
 			::sleep(1);
 			TEST_THAT(ServerIsAlive(pid));
+#endif // !WIN32
 			// Make some connections
 			{
 				SocketStream conn1;
 				conn1.Open(Socket::TypeINET, "localhost", 2003);
+#ifndef WIN32
 				SocketStream conn2;
 				conn2.Open(Socket::TypeUNIX, "testfiles/srv2.sock");
 				SocketStream conn3;
 				conn3.Open(Socket::TypeINET, "localhost", 2003);
+#endif // !WIN32
 				// Quick check that reconnections fail
 				TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX, "testfiles/srv2.sock");, ServerException, SocketAlreadyOpen);
 				// Stuff some data around
 				std::vector<IOStream *> conns;
 				conns.push_back(&conn1);
+#ifndef WIN32
 				conns.push_back(&conn2);
 				conns.push_back(&conn3);
+#endif // !WIN32
 				Srv2TestConversations(conns);
 				// Implicit close
 			}
+#ifndef WIN32
 			// HUP again
 			TEST_THAT(HUPServer(pid));
 			::sleep(1);
 			TEST_THAT(ServerIsAlive(pid));
+#endif // !WIN32
 			// Kill it
 			TEST_THAT(KillServer(pid));
 			::sleep(1);
 			TEST_THAT(!ServerIsAlive(pid));
+#ifndef WIN32
 			TestRemoteProcessMemLeaks("test-srv2.memleaks");
+#endif // !WIN32
 		}
 	}
 
 	// Launch a test SSL server
 	{
+#ifdef WIN32
+		int pid = LaunchServer("test srv3 testfiles\\srv3.conf", 
+			"testfiles\\srv3.pid");
+#else
 		int pid = LaunchServer("./test srv3 testfiles/srv3.conf", "testfiles/srv3.pid");
+#endif
 		TEST_THAT(pid != -1 && pid != 0);
 		if(pid > 0)
 		{
 			// Will it restart?
 			TEST_THAT(ServerIsAlive(pid));
+
+#ifndef WIN32
 			TEST_THAT(HUPServer(pid));
 			::sleep(1);
 			TEST_THAT(ServerIsAlive(pid));
+#endif
+
 			// Make some connections
 			{
 				// SSL library
@@ -519,36 +576,50 @@
 
 				SocketStreamTLS conn1;
 				conn1.Open(context, Socket::TypeINET, "localhost", 2003);
+#ifndef WIN32
 				SocketStreamTLS conn2;
 				conn2.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock");
 				SocketStreamTLS conn3;
 				conn3.Open(context, Socket::TypeINET, "localhost", 2003);
+#endif
 				// Quick check that reconnections fail
 				TEST_CHECK_THROWS(conn1.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock");, ServerException, SocketAlreadyOpen);
 				// Stuff some data around
 				std::vector<IOStream *> conns;
 				conns.push_back(&conn1);
+#ifndef WIN32
 				conns.push_back(&conn2);
 				conns.push_back(&conn3);
+#endif
 				Srv2TestConversations(conns);
 				// Implicit close
 			}
+#ifndef WIN32
 			// HUP again
 			TEST_THAT(HUPServer(pid));
 			::sleep(1);
 			TEST_THAT(ServerIsAlive(pid));
+#endif
 			// Kill it
 			TEST_THAT(KillServer(pid));
 			::sleep(1);
 			TEST_THAT(!ServerIsAlive(pid));
+#ifndef WIN32
 			TestRemoteProcessMemLeaks("test-srv3.memleaks");
+#endif
 		}
 	}
 	
 //protocolserver:
 	// Launch a test protocol handling server
 	{
-		int pid = LaunchServer("./test srv4 testfiles/srv4.conf", "testfiles/srv4.pid");
+#ifdef WIN32
+		int pid = LaunchServer("test srv4 testfiles\\srv4.conf", 
+			"testfiles\\srv4.pid");
+#else
+		int pid = LaunchServer("./test srv4 testfiles/srv4.conf", 
+			"testfiles/srv4.pid");
+#endif
 		TEST_THAT(pid != -1 && pid != 0);
 		if(pid > 0)
 		{
@@ -557,7 +628,11 @@
 
 			// Open a connection to it		
 			SocketStream conn;
+#ifdef WIN32
+			conn.Open(Socket::TypeINET, "localhost", 2003);
+#else
 			conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock");
+#endif
 			
 			// Create a protocol
 			TestProtocolClient protocol(conn);
@@ -620,7 +695,9 @@
 			TEST_THAT(KillServer(pid));
 			::sleep(1);
 			TEST_THAT(!ServerIsAlive(pid));
+#ifndef WIN32
 			TestRemoteProcessMemLeaks("test-srv4.memleaks");
+#endif
 		}
 	}
 

Modified: box/chris/merge/test/bbackupd/testbbackupd.cpp
===================================================================
--- box/chris/merge/test/bbackupd/testbbackupd.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/bbackupd/testbbackupd.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -718,7 +718,7 @@
 			// Wait and test...
 			wait_for_backup_operation();
 			compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit");
-			TEST_THAT(compareReturnValue == 2*256);	// should find differences
+			TEST_THAT(compareReturnValue == 3*256);	// should find differences
 			TestRemoteProcessMemLeaks("bbackupquery.memleaks");
 			// Check that it was reported correctly
 			TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1"));

Deleted: box/chris/merge/test/bbackupd/testfiles/bbackupd.conf
===================================================================
--- box/chris/merge/test/bbackupd/testfiles/bbackupd.conf	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/bbackupd/testfiles/bbackupd.conf	2006-07-27 23:18:35 UTC (rev 710)
@@ -1,50 +0,0 @@
-
-CertificateFile = testfiles/clientCerts.pem
-PrivateKeyFile = testfiles/clientPrivKey.pem
-TrustedCAsFile = testfiles/clientTrustedCAs.pem
-
-KeysFile = testfiles/bbackupd.keys
-
-DataDirectory = testfiles/bbackupd-data
-
-StoreHostname = localhost
-AccountNumber = 0x01234567
-
-UpdateStoreInterval = 3
-MinimumFileAge = 4
-MaxUploadWait = 24
-
-FileTrackingSizeThreshold = 1024
-DiffingUploadSizeThreshold = 1024
-
-MaximumDiffingTime = 8
-
-ExtendedLogging = yes
-
-CommandSocket = testfiles/bbackupd.sock
-
-NotifyScript = @PERL@ testfiles/notifyscript.pl
-
-Server
-{
-	PidFile = testfiles/bbackupd.pid
-}
-
-BackupLocations
-{
-	Test1
-	{
-		Path = testfiles/TestDir1
-
-		ExcludeFile = testfiles/TestDir1/excluded_1
-		ExcludeFile = testfiles/TestDir1/excluded_2
-		ExcludeFilesRegex = \.excludethis$
-		ExcludeFilesRegex = EXCLUDE
-		AlwaysIncludeFile = testfiles/TestDir1/dont.excludethis
-		ExcludeDir = testfiles/TestDir1/exclude_dir
-		ExcludeDir = testfiles/TestDir1/exclude_dir_2
-		ExcludeDirsRegex = not_this_dir
-		AlwaysIncludeDirsRegex = ALWAYSINCLUDE
-	}
-}
-

Copied: box/chris/merge/test/bbackupd/testfiles/bbackupd.conf.in (from rev 568, box/trunk/test/bbackupd/testfiles/bbackupd.conf)

Modified: box/chris/merge/test/bbackupd/testfiles/extcheck1.pl.in
===================================================================
--- box/chris/merge/test/bbackupd/testfiles/extcheck1.pl.in	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/bbackupd/testfiles/extcheck1.pl.in	2006-07-27 23:18:35 UTC (rev 710)
@@ -1,7 +1,9 @@
 #!@PERL@
 use strict;
 
-unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit|")
+my $flags = $ARGV[0] or "";
+
+unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit|")
 {
 	print "Couldn't open compare utility\n";
 	exit 2;
@@ -15,14 +17,23 @@
 	next unless m/\S/;
 	if(m/continousupdate/)
 	{
-		$ret = 2 unless m/exists/;
+		unless (/exists/)
+		{
+			print "FAIL: continousupdate line does not match\n";
+			$ret = 2;
+		}
 		$seen = 1;
 	}
 	else
 	{
-		$ret = 2 unless m/\AWARNING/ || m/\ADifferences/ || /might be reason/ || /probably due to file mod/;
+		unless (/\AWARNING/ or /\ADifferences/ or /might be reason/
+			or /probably due to file mod/)
+		{
+			print "FAIL: Summary line does not match\n";
+			$ret = 2;
+		}
 	}
-	print;
+	print "READ: $_";
 }
 
 close IN;

Modified: box/chris/merge/test/bbackupd/testfiles/extcheck2.pl.in
===================================================================
--- box/chris/merge/test/bbackupd/testfiles/extcheck2.pl.in	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/bbackupd/testfiles/extcheck2.pl.in	2006-07-27 23:18:35 UTC (rev 710)
@@ -1,7 +1,9 @@
 #!@PERL@
 use strict;
 
-unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit|")
+my $flags = $ARGV[0] or "";
+
+unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit|")
 {
 	print "Couldn't open compare utility\n";
 	exit 2;
@@ -14,13 +16,23 @@
 	next unless m/\S/;
 	if(m/continousupdate/)
 	{
-		$ret = 2 unless m/contents/ || m/attributes/;
+		unless (m/contents/ or m/attributes/)
+		{
+			print "FAIL: continuousupdate line does not match\n";
+			$ret = 2;
+		}
 	}
 	else
 	{
-		$ret = 2 unless m/\AWARNING/ || m/\ADifferences/ || /might be reason/ || /probably due to file mod/;
+		unless (/\AWARNING/ or /\ADifferences/ or /might be reason/ 
+			or /probably due to file mod/)
+		{
+			print "FAIL: summary line does not match\n";
+			$ret = 2;
+		}
 	}
-	print;
+
+	print "READ: $_";
 }
 
 close IN;

Modified: box/chris/merge/test/common/testcommon.cpp
===================================================================
--- box/chris/merge/test/common/testcommon.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/common/testcommon.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -24,6 +24,8 @@
 #include "CommonException.h"
 #include "Conversion.h"
 #include "autogen_ConversionException.h"
+#include "CollectInBufferStream.h"
+#include "Archive.h"
 
 #include "MemLeakFindOn.h"
 
@@ -565,5 +567,63 @@
 
 	test_conversions();
 
+	// test that we can use Archive and CollectInBufferStream
+	// to read and write arbitrary types to a memory buffer
+
+	{
+		CollectInBufferStream buffer;
+		ASSERT(buffer.GetPosition() == 0);
+
+		{
+			Archive archive(buffer, 0);
+			ASSERT(buffer.GetPosition() == 0);
+
+			archive.Write((bool) true);
+			archive.Write((bool) false);
+			archive.Write((int) 0x12345678);
+			archive.Write((int) 0x87654321);
+			archive.Write((int64_t)  0x0badfeedcafebabeLL);
+			archive.Write((uint64_t) 0xfeedfacedeadf00dLL);
+			archive.Write((uint8_t)  0x01);
+			archive.Write((uint8_t)  0xfe);
+			archive.Write(std::string("hello world!"));
+			archive.Write(std::string("goodbye cruel world!"));
+		}
+
+		CollectInBufferStream buf2;
+		buf2.Write(buffer.GetBuffer(), buffer.GetSize());
+		TEST_THAT(buf2.GetPosition() == buffer.GetSize());
+
+		buf2.SetForReading();
+		TEST_THAT(buf2.GetPosition() == 0);
+
+		{
+			Archive archive(buf2, 0);
+			TEST_THAT(buf2.GetPosition() == 0);
+
+			bool b;
+			archive.Read(b); TEST_THAT(b == true);
+			archive.Read(b); TEST_THAT(b == false);
+
+			int i;
+			archive.Read(i); TEST_THAT(i == 0x12345678);
+			archive.Read(i); TEST_THAT((unsigned int)i == 0x87654321);
+
+			uint64_t i64;
+			archive.Read(i64); TEST_THAT(i64 == 0x0badfeedcafebabeLL);
+			archive.Read(i64); TEST_THAT(i64 == 0xfeedfacedeadf00dLL);
+
+			uint8_t i8;
+			archive.Read(i8); TEST_THAT(i8 == 0x01);
+			archive.Read(i8); TEST_THAT(i8 == 0xfe);
+
+			std::string s;
+			archive.Read(s); TEST_THAT(s == "hello world!");
+			archive.Read(s); TEST_THAT(s == "goodbye cruel world!");
+
+			TEST_THAT(!buf2.StreamDataLeft());
+		}
+	}
+
 	return 0;
 }

Modified: box/chris/merge/test/raidfile/intercept.cpp
===================================================================
--- box/chris/merge/test/raidfile/intercept.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/raidfile/intercept.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -14,7 +14,11 @@
 #endif
 #include <sys/types.h>
 #include <unistd.h>
+
+#ifdef HAVE_SYS_UIO_H
 #include <sys/uio.h>
+#endif
+
 #include <errno.h>
 
 #ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE

Modified: box/chris/merge/test/raidfile/testraidfile.cpp
===================================================================
--- box/chris/merge/test/raidfile/testraidfile.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/raidfile/testraidfile.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -12,7 +12,10 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
+
+#ifdef HAVE_SYSCALL
 #include <sys/syscall.h>
+#endif
 
 #include <string.h>
 
@@ -207,16 +210,24 @@
 		bytesread += r;
 	}
 	TEST_THAT(!readstream4.StreamDataLeft());		// check IOStream interface is correct
+	pread.reset();
 
 	// Be nasty, and create some errors for the RAID stuff to recover from...
 	if(TestRAIDProperties)
 	{
 		char stripe1fn[256], stripe1fnRename[256];
-		sprintf(stripe1fn, "testfiles/%d_%d/%s.rf", set, startDisc, filename);
-		sprintf(stripe1fnRename, "testfiles/%d_%d/%s.rf-REMOVED", set, startDisc, filename);
+		sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename);
+		sprintf(stripe1fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, startDisc, 
+			filename);
 		char stripe2fn[256], stripe2fnRename[256];
-		sprintf(stripe2fn, "testfiles/%d_%d/%s.rf", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename);
-		sprintf(stripe2fnRename, "testfiles/%d_%d/%s.rf-REMOVED", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename);
+		sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR "%s.rf", set, 
+			(startDisc + 1) % RAID_NUMBER_DISCS, filename);
+		sprintf(stripe2fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, 
+			(startDisc + 1) % RAID_NUMBER_DISCS, filename);
 
 		// Read with stripe1 + parity		
 		TEST_THAT(::rename(stripe2fn, stripe2fnRename) == 0);
@@ -252,9 +263,15 @@
 		}
 		mungefilename[m++] = '\0';
 		char stripe1munge[256];
-		sprintf(stripe1munge, "testfiles/%d_%d/.raidfile-unreadable/%s", set, startDisc, mungefilename);
+		sprintf(stripe1munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR ".raidfile-unreadable"
+			DIRECTORY_SEPARATOR "%s", set, startDisc, 
+			mungefilename);
 		char stripe2munge[256];
-		sprintf(stripe2munge, "testfiles/%d_%d/.raidfile-unreadable/%s", set, (startDisc + 1) % RAID_NUMBER_DISCS, mungefilename);
+		sprintf(stripe2munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR ".raidfile-unreadable"
+			DIRECTORY_SEPARATOR "%s", set, 
+			(startDisc + 1) % RAID_NUMBER_DISCS, mungefilename);
 		
 
 #ifdef TRF_CAN_INTERCEPT
@@ -359,10 +376,12 @@
 	write4.Write(data, datasize);
 	// This time, don't discard and transform it to a RAID File
 	char writefnPre[256];
-	sprintf(writefnPre, "testfiles/%d_%d/%s.rfwX", set, startDisc, filename);
+	sprintf(writefnPre, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+		DIRECTORY_SEPARATOR "%s.rfwX", set, startDisc, filename);
 	TEST_THAT(TestFileExists(writefnPre));
 	char writefn[256];
-	sprintf(writefn, "testfiles/%d_%d/%s.rfw", set, startDisc, filename);
+	sprintf(writefn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+		DIRECTORY_SEPARATOR "%s.rfw", set, startDisc, filename);
 	int usageInBlocks = write4.GetDiscUsageInBlocks();
 	write4.Commit(DoTransform);
 	// Check that files are nicely done...
@@ -390,14 +409,19 @@
 			fs1 = ((fullblocks / 2)+1) * RAID_BLOCK_SIZE;
 		}
 		char stripe1fn[256];
-		sprintf(stripe1fn, "testfiles/%d_%d/%s.rf", set, startDisc, filename);
+		sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename);
 		TEST_THAT(TestGetFileSize(stripe1fn) == fs1);
 		char stripe2fn[256];
-		sprintf(stripe2fn, "testfiles/%d_%d/%s.rf", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename);
+		sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR "%s.rf", set, 
+			(startDisc + 1) % RAID_NUMBER_DISCS, filename);
 		TEST_THAT(TestGetFileSize(stripe2fn) == (int)(datasize - fs1));
 		// Parity file size
 		char parityfn[256];
-		sprintf(parityfn, "testfiles/%d_%d/%s.rf", set, (startDisc + 2) % RAID_NUMBER_DISCS, filename);
+		sprintf(parityfn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+			DIRECTORY_SEPARATOR "%s.rf", set, 
+			(startDisc + 2) % RAID_NUMBER_DISCS, filename);
 		// Mildly complex calculation
 		unsigned int blocks = datasize / RAID_BLOCK_SIZE;
 		unsigned int bytesOver = datasize % RAID_BLOCK_SIZE;
@@ -436,14 +460,16 @@
 		if(datasize > (3*1024))
 		{
 			int f;
-			TEST_THAT((f = ::open(stripe1fn, O_RDONLY, 0)) != -1);
+			TEST_THAT((f = ::open(stripe1fn, O_RDONLY | O_BINARY, 
+				0)) != -1);
 			TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock)));
 			for(unsigned int q = 0; q < sizeof(testblock); ++q)
 			{
 				TEST_THAT(testblock[q] == ((char*)data)[q]);
 			}
 			::close(f);
-			TEST_THAT((f = ::open(stripe2fn, O_RDONLY, 0)) != -1);
+			TEST_THAT((f = ::open(stripe2fn, O_RDONLY | O_BINARY, 
+				0)) != -1);
 			TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock)));
 			for(unsigned int q = 0; q < sizeof(testblock); ++q)
 			{
@@ -536,7 +562,9 @@
 	
 	// Generate a random pre-existing write file (and ensure that it doesn't exist already)
 	int f;
-	TEST_THAT((f = ::open("testfiles/0_2/overwrite_B.rfwX", O_WRONLY | O_CREAT | O_EXCL, 0755)) != -1);
+	TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" 
+		DIRECTORY_SEPARATOR "overwrite_B.rfwX", 
+		O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0755)) != -1);
 	TEST_THAT(::write(f, "TESTTEST", 8) == 8);
 	::close(f);
 
@@ -557,7 +585,7 @@
 
 	// Initialise the controller
 	RaidFileController &rcontroller = RaidFileController::GetController();
-	rcontroller.Initialise("testfiles/raidfile.conf");
+	rcontroller.Initialise("testfiles" DIRECTORY_SEPARATOR "raidfile.conf");
 
 	// some data
 	char data[TEST_DATA_SIZE];
@@ -574,9 +602,12 @@
 	
 	// Try creating a directory
 	RaidFileWrite::CreateDirectory(0, "test-dir");
-	TEST_THAT(TestDirExists("testfiles/0_0/test-dir"));
-	TEST_THAT(TestDirExists("testfiles/0_1/test-dir"));
-	TEST_THAT(TestDirExists("testfiles/0_2/test-dir"));
+	TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_0" 
+		DIRECTORY_SEPARATOR "test-dir"));
+	TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_1"
+		DIRECTORY_SEPARATOR "test-dir"));
+	TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_2"
+		DIRECTORY_SEPARATOR "test-dir"));
 	TEST_THAT(RaidFileRead::DirectoryExists(0, "test-dir"));
 	TEST_THAT(!RaidFileRead::DirectoryExists(0, "test-dir-not"));
 
@@ -608,9 +639,12 @@
 	
 	// Before it's deleted, check to see the contents are as expected
 	int f;
-	TEST_THAT((f = ::open("testfiles/0_2/test1.rfwX", O_RDONLY, 0)) >= 0);
+	TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
+		DIRECTORY_SEPARATOR "test1.rfwX", O_RDONLY | O_BINARY, 0)) 
+		>= 0);
 	char buffer[sizeof(data)];
-	TEST_THAT(::read(f, buffer, sizeof(buffer)) == sizeof(buffer));
+	int bytes_read = ::read(f, buffer, sizeof(buffer));
+	TEST_THAT(bytes_read == sizeof(buffer));
 	for(unsigned int l = 0; l < 1024; ++l)
 	{
 		TEST_THAT(buffer[l] == data[l]);
@@ -624,7 +658,8 @@
 		TEST_THAT(buffer[l+2048+sizeof(data2)] == data2[l]);
 	}
 	TEST_THAT(::lseek(f, sizeof(data), SEEK_SET) == sizeof(buffer));
-	TEST_THAT(::read(f, buffer, sizeof(buffer)) == sizeof(buffer));
+	bytes_read = ::read(f, buffer, sizeof(buffer));
+	TEST_THAT(bytes_read == sizeof(buffer));
 	for(unsigned int l = 0; l < 1024; ++l)
 	{
 		TEST_THAT(buffer[l] == data[l]);
@@ -635,7 +670,9 @@
 	
 	// Commit the data
 	write1.Commit();
-	TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) >= 0);
+	TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
+		DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) 
+		>= 0);
 	::close(f);
 
 	// Now try and read it
@@ -687,7 +724,9 @@
 	write2.Write(data, sizeof(data));
 	// This time, discard it
 	write2.Discard();
-	TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) == -1);
+	TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
+		DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) 
+		== -1);
 	
 	// And leaving it there...
 	RaidFileWrite writeLeave(0, "test1");
@@ -695,7 +734,9 @@
 	writeLeave.Write(data, sizeof(data));
 	// This time, commit it
 	writeLeave.Commit();
-	TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) != -1);
+	TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" 
+		DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) 
+		!= -1);
 	::close(f);
 	
 	// Then check that the thing will refuse to open it again.
@@ -712,7 +753,8 @@
 	write3b.Write(data + 3, sizeof(data) - 3);
 	write3b.Commit();
 	// Test it
-	testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false /*TestRAIDProperties*/);
+	testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false 
+		/* TestRAIDProperties */);
 
 	// And once again, but this time making it a raid file
 	RaidFileWrite write3c(0, "test1");
@@ -721,7 +763,8 @@
 	write3c.Write(data + 7, sizeof(data) - 7);
 	write3c.Commit(true);	// make RAID
 	// Test it
-	testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false /*TestRAIDProperties*/);
+	testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false 
+		/*TestRAIDProperties*/);
 
 	// Test opening a file which doesn't exist
 	TEST_CHECK_THROWS(
@@ -736,20 +779,23 @@
 		w.Commit(true);
 
 		// Try removing the parity file
-		TEST_THAT(::rename("testfiles/0_0/damage.rf", "testfiles/0_0/damage.rf-NT") == 0);
+		TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0"
+			DIRECTORY_SEPARATOR "damage.rf", 
+			"testfiles" DIRECTORY_SEPARATOR "0_0"
+			DIRECTORY_SEPARATOR "damage.rf-NT") == 0);
 		{
 			std::auto_ptr<RaidFileRead> pr0 = RaidFileRead::Open(0, "damage");
 			pr0->Read(buffer, sizeof(data));
 		}		
-		TEST_THAT(::rename("testfiles/0_0/damage.rf-NT", "testfiles/0_0/damage.rf") == 0);
-		
+		TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf-NT", "testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0);
+	
 		// Delete one of the files
-		TEST_THAT(::unlink("testfiles/0_1/damage.rf") == 0);	// stripe 1
+		TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "damage.rf") == 0); // stripe 1
 		
 #ifdef TRF_CAN_INTERCEPT
 		// Open it and read...
 		{
-			intercept_setup_error("testfiles/0_2/damage.rf", 0, EIO, SYS_read);	// stripe 2
+			intercept_setup_error("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "damage.rf", 0, EIO, SYS_read);	// stripe 2
 			std::auto_ptr<RaidFileRead> pr1 = RaidFileRead::Open(0, "damage");
 			TEST_CHECK_THROWS(
 				pr1->Read(buffer, sizeof(data)),
@@ -761,7 +807,7 @@
 #endif //TRF_CAN_INTERCEPT
 
 		// Delete another
-		TEST_THAT(::unlink("testfiles/0_0/damage.rf") == 0);		// parity
+		TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0); // parity
 		
 		TEST_CHECK_THROWS(
 			std::auto_ptr<RaidFileRead> pread2 = RaidFileRead::Open(0, "damage"),
@@ -772,22 +818,22 @@
 	{
 		RaidFileWrite::CreateDirectory(0, "dirread");
 		// Make some contents
-		RaidFileWrite::CreateDirectory(0, "dirread/dfsdf1");
-		RaidFileWrite::CreateDirectory(0, "dirread/ponwq2");
+		RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "dfsdf1");
+		RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "ponwq2");
 		{
-			RaidFileWrite w(0, "dirread/sdf9873241");
+			RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "sdf9873241");
 			w.Open();
 			w.Write(data, sizeof(data));
 			w.Commit(true);
 		}
 		{
-			RaidFileWrite w(0, "dirread/fsdcxjni3242");
+			RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "fsdcxjni3242");
 			w.Open();
 			w.Write(data, sizeof(data));
 			w.Commit(true);
 		}
 		{
-			RaidFileWrite w(0, "dirread/cskjnds3");
+			RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "cskjnds3");
 			w.Open();
 			w.Write(data, sizeof(data));
 			w.Commit(false);
@@ -803,15 +849,15 @@
 		TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_DirsOnly, names));
 		TEST_THAT(list_matches(names, dir_list1));
 		// Delete things
-		TEST_THAT(::unlink("testfiles/0_0/dirread/sdf9873241.rf") == 0);
+		TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
 		TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
 		TEST_THAT(list_matches(names, file_list1));
 		// Delete something else so that it's not recoverable
-		TEST_THAT(::unlink("testfiles/0_1/dirread/sdf9873241.rf") == 0);
+		TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
 		TEST_THAT(false == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
 		TEST_THAT(list_matches(names, file_list1));
 		// And finally...
-		TEST_THAT(::unlink("testfiles/0_2/dirread/sdf9873241.rf") == 0);
+		TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
 		TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
 		TEST_THAT(list_matches(names, file_list2));
 	}

Modified: box/chris/merge/test/win32/testlibwin32.cpp
===================================================================
--- box/chris/merge/test/win32/testlibwin32.cpp	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/test/win32/testlibwin32.cpp	2006-07-27 23:18:35 UTC (rev 710)
@@ -6,12 +6,214 @@
 
 #ifdef WIN32
 
+#include <assert.h>
+#include <AccCtrl.h>
+#include <Aclapi.h>
+
 #include "../../bin/bbackupd/BackupDaemon.h"
 #include "BoxPortsAndFiles.h"
 #include "emu.h"
 
 int main(int argc, char* argv[])
 {
+	// ACL tests
+	char* exename = getenv("WINDIR");
+
+	PSID psidOwner;
+	PSID psidGroup;
+	PACL pDacl;
+	PSECURITY_DESCRIPTOR pSecurityDesc;
+
+	DWORD result = GetNamedSecurityInfo(
+		exename, // pObjectName
+		SE_FILE_OBJECT, // ObjectType
+		DACL_SECURITY_INFORMATION | // SecurityInfo
+		GROUP_SECURITY_INFORMATION |
+		OWNER_SECURITY_INFORMATION,
+		&psidOwner, // ppsidOwner,
+		&psidGroup, // ppsidGroup,
+		&pDacl,     // ppDacl,
+		NULL,       // ppSacl,
+		&pSecurityDesc // ppSecurityDescriptor
+	);
+	if (result != ERROR_SUCCESS)
+	{
+		printf("Error getting security info for '%s': error %d",
+			exename, result);
+	}
+	assert(result == ERROR_SUCCESS);
+
+	char namebuf[1024];
+	char domainbuf[1024];
+	SID_NAME_USE nametype;
+	DWORD namelen = sizeof(namebuf);
+	DWORD domainlen = sizeof(domainbuf);
+
+	assert(LookupAccountSid(NULL, psidOwner, namebuf, &namelen,
+		domainbuf, &domainlen, &nametype));
+
+	printf("Owner:\n");
+	printf("User name:   %s\n", namebuf);
+	printf("Domain name: %s\n", domainbuf);
+	printf("Name type:   %d\n", nametype);
+	printf("\n");
+
+	namelen = sizeof(namebuf);
+	domainlen = sizeof(domainbuf);
+
+	assert(LookupAccountSid(NULL, psidGroup, namebuf, &namelen,
+		domainbuf, &domainlen, &nametype));
+
+	printf("Group:\n");
+	printf("User name:   %s\n", namebuf);
+	printf("Domain name: %s\n", domainbuf);
+	printf("Name type:   %d\n", nametype);
+	printf("\n");
+
+	ULONG numEntries;
+	PEXPLICIT_ACCESS pEntries;
+	result = GetExplicitEntriesFromAcl
+	(
+		pDacl,       // pAcl
+		&numEntries, // pcCountOfExplicitEntries,
+		&pEntries    // pListOfExplicitEntries
+	);
+	assert(result == ERROR_SUCCESS);
+
+	printf("Found %lu explicit DACL entries for '%s'\n\n",
+		(unsigned long)numEntries, exename);
+
+	for (ULONG i = 0; i < numEntries; i++)
+	{
+		EXPLICIT_ACCESS* pEntry = &(pEntries[i]);
+		printf("DACL entry %lu:\n", (unsigned long)i);
+
+		DWORD perms = pEntry->grfAccessPermissions;
+		printf("  Access permissions: ", perms);
+
+		#define PRINT_PERM(name) \
+		if (perms & name) \
+		{ \
+			printf(#name " "); \
+			perms &= ~name; \
+		}
+
+		PRINT_PERM(FILE_ADD_FILE);
+		PRINT_PERM(FILE_ADD_SUBDIRECTORY);
+		PRINT_PERM(FILE_ALL_ACCESS);
+		PRINT_PERM(FILE_APPEND_DATA);
+		PRINT_PERM(FILE_CREATE_PIPE_INSTANCE);
+		PRINT_PERM(FILE_DELETE_CHILD);
+		PRINT_PERM(FILE_EXECUTE);
+		PRINT_PERM(FILE_LIST_DIRECTORY);
+		PRINT_PERM(FILE_READ_ATTRIBUTES);
+		PRINT_PERM(FILE_READ_DATA);
+		PRINT_PERM(FILE_READ_EA);
+		PRINT_PERM(FILE_TRAVERSE);
+		PRINT_PERM(FILE_WRITE_ATTRIBUTES);
+		PRINT_PERM(FILE_WRITE_DATA);
+		PRINT_PERM(FILE_WRITE_EA);
+		PRINT_PERM(STANDARD_RIGHTS_READ);
+		PRINT_PERM(STANDARD_RIGHTS_WRITE);
+		PRINT_PERM(SYNCHRONIZE);
+		PRINT_PERM(DELETE);
+		PRINT_PERM(READ_CONTROL);
+		PRINT_PERM(WRITE_DAC);
+		PRINT_PERM(WRITE_OWNER);
+		PRINT_PERM(MAXIMUM_ALLOWED);
+		PRINT_PERM(GENERIC_ALL);
+		PRINT_PERM(GENERIC_EXECUTE);
+		PRINT_PERM(GENERIC_WRITE);
+		PRINT_PERM(GENERIC_READ);
+		printf("\n");
+
+		if (perms)
+		{
+			printf("  Bits left over: %08x\n", perms);
+		}
+		assert(!perms);
+
+		printf("  Access mode: ");
+		switch(pEntry->grfAccessMode)
+		{
+		case NOT_USED_ACCESS:
+			printf("NOT_USED_ACCESS\n"); break;
+		case GRANT_ACCESS:
+			printf("GRANT_ACCESS\n"); break;
+		case DENY_ACCESS:
+			printf("DENY_ACCESS\n"); break;
+		case REVOKE_ACCESS:
+			printf("REVOKE_ACCESS\n"); break;
+		case SET_AUDIT_SUCCESS:
+			printf("SET_AUDIT_SUCCESS\n"); break;
+		case SET_AUDIT_FAILURE:
+			printf("SET_AUDIT_FAILURE\n"); break;
+		default:
+			printf("Unknown (%08x)\n", pEntry->grfAccessMode);
+		}
+
+		printf("  Trustee: ");
+		assert(pEntry->Trustee.pMultipleTrustee == NULL);
+		assert(pEntry->Trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE);
+		switch(pEntry->Trustee.TrusteeForm)
+		{
+		case TRUSTEE_IS_SID:
+			{
+				PSID trusteeSid = (PSID)(pEntry->Trustee.ptstrName);
+
+				namelen = sizeof(namebuf);
+				domainlen = sizeof(domainbuf);
+
+				assert(LookupAccountSid(NULL, trusteeSid, namebuf, &namelen,
+					domainbuf, &domainlen, &nametype));
+
+				printf("SID of %s\\%s (%d)\n", domainbuf, namebuf, nametype);
+			}
+			break;
+		case TRUSTEE_IS_NAME:
+			printf("Name\n"); break;
+		case TRUSTEE_BAD_FORM:
+			printf("Bad form\n"); assert(0);
+		case TRUSTEE_IS_OBJECTS_AND_SID:
+			printf("Objects and SID\n"); break;
+		case TRUSTEE_IS_OBJECTS_AND_NAME:
+			printf("Objects and name\n"); break;
+		default:
+			printf("Unknown form\n"); assert(0);
+		}
+
+		printf("  Trustee type: ");
+		switch(pEntry->Trustee.TrusteeType)
+		{
+		case TRUSTEE_IS_UNKNOWN:
+			printf("Unknown type.\n"); break;
+		case TRUSTEE_IS_USER:
+			printf("User\n"); break;
+		case TRUSTEE_IS_GROUP:
+			printf("Group\n"); break;
+		case TRUSTEE_IS_DOMAIN:
+			printf("Domain\n"); break;
+		case TRUSTEE_IS_ALIAS:
+			printf("Alias\n"); break;
+		case TRUSTEE_IS_WELL_KNOWN_GROUP:
+			printf("Well-known group\n"); break;
+		case TRUSTEE_IS_DELETED:
+			printf("Deleted account\n"); break;
+		case TRUSTEE_IS_INVALID:
+			printf("Invalid trustee type\n"); break;
+		case TRUSTEE_IS_COMPUTER:
+			printf("Computer\n"); break;
+		default:
+			printf("Unknown type %d\n", pEntry->Trustee.TrusteeType); 
+			assert(0);
+		}
+
+		printf("\n");
+	}
+
+	assert(LocalFree((HLOCAL)pEntries) == 0);
+	assert(LocalFree((HLOCAL)pSecurityDesc) == 0);
+
 	chdir("c:\\tmp");
 	openfile("test", O_CREAT, 0);
 	struct stat ourfs;
@@ -25,12 +227,11 @@
 		do
 		{
 			info = readdir(ourDir);
-			if ( info ) printf("File/Dir name is : %s\r\n", info->d_name);
+			if (info) printf("File/Dir name is : %s\r\n", info->d_name);
+		}
+		while (info != NULL);
 
-		}while ( info != NULL );
-
 		closedir(ourDir);
-
 	}
 	
 	std::string diry("C:\\Projects\\boxbuild\\testfiles\\");
@@ -41,60 +242,83 @@
 		do
 		{
 			info = readdir(ourDir);
-			if ( info == NULL ) break;
+			if (info == NULL) break;
 			std::string file(diry + info->d_name);
 			stat(file.c_str(), &ourfs);
-			if ( info ) printf("File/Dir name is : %s\r\n", info->d_name);
+			if (info) printf("File/Dir name is : %s\r\n", info->d_name);
+		}
+		while ( info != NULL );
 
-		}while ( info != NULL );
-
 		closedir(ourDir);
 
 	}
 
 	stat("c:\\windows", &ourfs);
 	stat("c:\\autoexec.bat", &ourfs);
-	printf("Finished dir read");
-#if 0
-	//remove - sleepycat include a version of getopt - mine never REALLY worked !
+	printf("Finished dir read\n");
+
 	//test our getopt function
-	std::string commline("-q -c fgfgfg -f -l hello");
+	char * test_argv[] = 
+	{
+		"foobar.exe",
+		"-qwc",
+		"-",
+		"-c",
+		"fgfgfg",
+		"-f",
+		"-l",
+		"hello",
+		"-",
+		"force-sync",
+		NULL
+	};
+	int test_argc;
+	for (test_argc = 0; test_argv[test_argc]; test_argc++) { }
+	const char* opts = "qwc:l:";
 
-	int c;
-	while((c = getopt(commline.size(), (char * const *)commline.c_str(), "qwc:l:")) != -1)
-	{
-		printf("switch = %c, param is %s\r\n", c, optarg);
-	}
-#endif
+	assert(getopt(test_argc, test_argv, opts) == 'q');
+	assert(getopt(test_argc, test_argv, opts) == 'w');
+	assert(getopt(test_argc, test_argv, opts) == 'c');
+	assert(strcmp(optarg, "-") == 0);
+	assert(getopt(test_argc, test_argv, opts) == 'c');
+	assert(strcmp(optarg, "fgfgfg") == 0);
+	assert(getopt(test_argc, test_argv, opts) == '?');
+	assert(optopt == 'f');
+	assert(getopt(test_argc, test_argv, opts) == 'l');
+	assert(strcmp(optarg, "hello") == 0);
+	assert(getopt(test_argc, test_argv, opts) == -1);
+	// assert(optopt == 0); // no more options
+	assert(strcmp(test_argv[optind], "-") == 0);
+	assert(strcmp(test_argv[optind+1], "force-sync") == 0);
 	//end of getopt test
 	
 	//now test our statfs funct
 	stat("c:\\cert.cer", &ourfs);
-	
-	
 
 	char *timee;
 	
 	timee = ctime(&ourfs.st_mtime);
 
-	if ( S_ISREG(ourfs.st_mode))
+	if (S_ISREG(ourfs.st_mode))
 	{
-		printf("is a normal file");
+		printf("is a normal file\n");
 	}
 	else
 	{
-		printf("is a directory?");
+		printf("is a directory?\n");
+		exit(1);
 	}
 
-	lstat("c:\\windows", &ourfs);
+	lstat(getenv("WINDIR"), &ourfs);
 
 	if ( S_ISDIR(ourfs.st_mode))
 	{
-		printf("is a directory");
+		printf("is a directory\n");
 	}
 	else
 	{
-		printf("is a file?");
+		printf("is a file?\n");
+		exit(1);
 	}
 
 	//test the syslog functions
@@ -105,6 +329,7 @@
 
 	closelog();
 
+	/*
 	//first off get the path name for the default 
 	char buf[MAX_PATH];
 	
@@ -112,8 +337,8 @@
 	std::string buffer(buf);
 	std::string conf("-c " + buffer.substr(0,(buffer.find("win32test.exe"))) + "bbackupd.conf");
 	//std::string conf( "-c " + buffer.substr(0,(buffer.find("bbackupd.exe"))) + "bbackupd.conf");
+	*/
 
-
 	return 0;
 }
 

Modified: box/chris/merge/win32.bat
===================================================================
--- box/chris/merge/win32.bat	2006-07-27 23:15:09 UTC (rev 709)
+++ box/chris/merge/win32.bat	2006-07-27 23:18:35 UTC (rev 710)
@@ -3,6 +3,8 @@
 echo quick and dirty to get up and running by generating the required files 
 echo using Cygwin and Perl
 
+copy .\infrastructure\BoxPlatform.pm.in .\infrastructure\BoxPlatform.pm
+
 cd .\bin\bbackupquery\ & perl ./../../bin/bbackupquery/makedocumentation.pl
 cd ..\..\
 
@@ -25,4 +27,4 @@
 cd .\lib\server & perl ./../../lib/common/makeexception.pl ServerException.txt & perl ./../../lib/common/makeexception.pl ConnectionException.txt
 cd ..\..\
 
-copy lib\win32\config.h.win32 lib\common\BoxConfig.h
+perl -i.orig -pe 's/@PERL@/perl/' ./test/bbackupd/testfiles/bbackupd.conf




More information about the Boxbackup-dev mailing list