1 // distribution boxbackup-0.11_trunk_2979 (svn version: 2979)
2 // Box Backup, http://www.boxbackup.org/
3 //
4 // Copyright (c) 2003-2010, Ben Summers and contributors.
5 // All rights reserved.
6 //
7 // Note that this project uses mixed licensing. Any file with this license
8 // attached, or where the code LICENSE-GPL appears on the first line, falls
9 // under the "Box Backup GPL" license. See the file COPYING.txt for more
10 // information about this license.
11 //
12 // ---------------------------------------------------------------------
13 // This program is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU General Public License
15 // as published by the Free Software Foundation; either version 2
16 // of the License, or (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26 //
27 // [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC4]
28 //
29 // As a special exception to the GPLv2, the Box Backup Project gives
30 // permission to link any code falling under this license (the Box Backup
31 // GPL) with any software that can be downloaded from
32 // the OpenSSL website [http://www.openssl.org] under either the
33 // "OpenSSL License" or the "Original SSLeay License", and to distribute
34 // the linked executables under the terms of the "Box Backup GPL" license.
35 //
36 // As a special exception to the GPLv2, the Box Backup Project gives
37 // permission to link any code falling under this license (the Box Backup
38 // GPL) with any version of Microsoft's Volume Shadow Copy Service 7.2 SDK
39 // or Microsoft Windows Software Development Kit (SDK), including
40 // vssapi.lib, that can be downloaded from the Microsoft website
41 // [*.microsoft.com], and to distribute the linked executables under the
42 // terms of the "Box Backup GPL" license.
43 // --------------------------------------------------------------------------
44 //
45 // File
46 //		Name:    BackupDaemon.cpp
47 //		Purpose: Backup daemon
48 //		Created: 2003/10/08
49 //
50 // --------------------------------------------------------------------------
51 
52 #include "Box.h"
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #ifdef HAVE_UNISTD_H
59 	#include <unistd.h>
60 #endif
61 #ifdef HAVE_SIGNAL_H
62 	#include <signal.h>
63 #endif
64 #ifdef HAVE_SYS_PARAM_H
65 	#include <sys/param.h>
66 #endif
67 #ifdef HAVE_SYS_WAIT_H
68 	#include <sys/wait.h>
69 #endif
70 #ifdef HAVE_SYS_MOUNT_H
71 	#include <sys/mount.h>
72 #endif
73 #ifdef HAVE_MNTENT_H
74 	#include <mntent.h>
75 #endif
76 #ifdef HAVE_SYS_MNTTAB_H
77 	#include <cstdio>
78 	#include <sys/mnttab.h>
79 #endif
80 #ifdef HAVE_PROCESS_H
81 	#include <process.h>
82 #endif
83 
84 #include <iostream>
85 #include <set>
86 
87 #include "Configuration.h"
88 #include "IOStream.h"
89 #include "MemBlockStream.h"
90 #include "CommonException.h"
91 #include "BoxPortsAndFiles.h"
92 
93 #include "SSLLib.h"
94 
95 #include "autogen_BackupProtocolClient.h"
96 #include "autogen_ClientException.h"
97 #include "autogen_ConversionException.h"
98 #include "Archive.h"
99 #include "BackupClientContext.h"
100 #include "BackupClientCryptoKeys.h"
101 #include "BackupClientDirectoryRecord.h"
102 #include "BackupClientFileAttributes.h"
103 #include "BackupClientInodeToIDMap.h"
104 #include "BackupClientMakeExcludeList.h"
105 #include "BackupDaemon.h"
106 #include "BackupDaemonConfigVerify.h"
107 #include "BackupStoreConstants.h"
108 #include "BackupStoreDirectory.h"
109 #include "BackupStoreException.h"
110 #include "BackupStoreFile.h"
111 #include "BackupStoreFilenameClear.h"
112 #include "BannerText.h"
113 #include "Conversion.h"
114 #include "ExcludeList.h"
115 #include "FileStream.h"
116 #include "IOStreamGetLine.h"
117 #include "LocalProcessStream.h"
118 #include "Logging.h"
119 #include "Random.h"
120 #include "Timer.h"
121 #include "Utils.h"
122 
123 #ifdef WIN32
124 	#include "Win32ServiceFunctions.h"
125 	#include "Win32BackupService.h"
126 
127 	extern Win32BackupService* gpDaemonService;
128 
129 #	ifdef ENABLE_VSS
130 #		include <comdef.h>
131 #		include <Vss.h>
132 #		include <VsWriter.h>
133 #		include <VsBackup.h>
134 
135 		// http://www.flounder.com/cstring.htm
GetMsgForHresult(HRESULT hr)136 		std::string GetMsgForHresult(HRESULT hr)
137 		{
138 			std::ostringstream buf;
139 
140 			if(hr == VSS_S_ASYNC_CANCELLED)
141 			{
142 				buf << "VSS async operation cancelled";
143 			}
144 			else if(hr == VSS_S_ASYNC_FINISHED)
145 			{
146 				buf << "VSS async operation finished";
147 			}
148 			else if(hr == VSS_S_ASYNC_PENDING)
149 			{
150 				buf << "VSS async operation pending";
151 			}
152 			else
153 			{
154 				buf << _com_error(hr).ErrorMessage();
155 			}
156 
157 			buf << " (" << BOX_FORMAT_HEX32(hr) << ")";
158 			return buf.str();
159 		}
160 
WideStringToString(WCHAR * buf)161 		std::string WideStringToString(WCHAR *buf)
162 		{
163 			char* pStr = ConvertFromWideString(buf, CP_UTF8);
164 
165 			if(pStr == NULL)
166 			{
167 				return "conversion failed";
168 			}
169 
170 			std::string result(pStr);
171 			free(pStr);
172 			return result;
173 		}
174 
GuidToString(GUID guid)175 		std::string GuidToString(GUID guid)
176 		{
177 			wchar_t buf[64];
178 			StringFromGUID2(guid, buf, sizeof(buf));
179 			return WideStringToString(buf);
180 		}
181 
BstrToString(const BSTR arg)182 		std::string BstrToString(const BSTR arg)
183 		{
184 			if(arg == NULL)
185 			{
186 				return std::string("(null)");
187 			}
188 			else
189 			{
190 				// Extract the *long* before where the arg points to
191 				long len = ((long *)arg)[-1] / 2;
192 				std::wstring wstr((WCHAR *)arg, len);
193 				std::string str;
194 				if(!ConvertFromWideString(wstr, &str, CP_UTF8))
195 				{
196 					throw std::exception("string conversion failed");
197 				}
198 				return str;
199 			}
200 		}
201 #	endif
202 #endif
203 
204 #include "MemLeakFindOn.h"
205 
206 static const time_t MAX_SLEEP_TIME = 1024;
207 
208 // Make the actual sync period have a little bit of extra time, up to a 64th of the main sync period.
209 // This prevents repetative cycles of load on the server
210 #define		SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY	6
211 
212 // --------------------------------------------------------------------------
213 //
214 // Function
215 //		Name:    BackupDaemon::BackupDaemon()
216 //		Purpose: constructor
217 //		Created: 2003/10/08
218 //
219 // --------------------------------------------------------------------------
BackupDaemon()220 BackupDaemon::BackupDaemon()
221 	: mState(BackupDaemon::State_Initialising),
222 	  mDeleteRedundantLocationsAfter(0),
223 	  mLastNotifiedEvent(SysadminNotifier::MAX),
224 	  mDeleteUnusedRootDirEntriesAfter(0),
225 	  mClientStoreMarker(BackupClientContext::ClientStoreMarker_NotKnown),
226 	  mStorageLimitExceeded(false),
227 	  mReadErrorsOnFilesystemObjects(false),
228 	  mLastSyncTime(0),
229 	  mNextSyncTime(0),
230 	  mCurrentSyncStartTime(0),
231 	  mUpdateStoreInterval(0),
232 	  mDeleteStoreObjectInfoFile(false),
233 	  mDoSyncForcedByPreviousSyncError(false),
234 	  mLogAllFileAccess(false),
235 	  mpProgressNotifier(this),
236 	  mpLocationResolver(this),
237 	  mpRunStatusProvider(this),
238 	  mpSysadminNotifier(this)
239 	#ifdef WIN32
240 	, mInstallService(false),
241 	  mRemoveService(false),
242 	  mRunAsService(false),
243 	  mServiceName("bbackupd")
244 	#endif
245 #ifdef ENABLE_VSS
246 	, mpVssBackupComponents(NULL)
247 #endif
248 {
249 	// Only ever one instance of a daemon
250 	SSLLib::Initialise();
251 }
252 
253 // --------------------------------------------------------------------------
254 //
255 // Function
256 //		Name:    BackupDaemon::~BackupDaemon()
257 //		Purpose: Destructor
258 //		Created: 2003/10/08
259 //
260 // --------------------------------------------------------------------------
~BackupDaemon()261 BackupDaemon::~BackupDaemon()
262 {
263 	DeleteAllLocations();
264 	DeleteAllIDMaps();
265 }
266 
267 // --------------------------------------------------------------------------
268 //
269 // Function
270 //		Name:    BackupDaemon::DaemonName()
271 //		Purpose: Get name of daemon
272 //		Created: 2003/10/08
273 //
274 // --------------------------------------------------------------------------
DaemonName() const275 const char *BackupDaemon::DaemonName() const
276 {
277 	return "bbackupd";
278 }
279 
280 
281 // --------------------------------------------------------------------------
282 //
283 // Function
284 //		Name:    BackupDaemon::DaemonBanner()
285 //		Purpose: Daemon banner
286 //		Created: 1/1/04
287 //
288 // --------------------------------------------------------------------------
DaemonBanner() const289 std::string BackupDaemon::DaemonBanner() const
290 {
291 	return BANNER_TEXT("Backup Client");
292 }
293 
Usage()294 void BackupDaemon::Usage()
295 {
296 	this->Daemon::Usage();
297 
298 #ifdef WIN32
299 	std::cout <<
300 	"  -s         Run as a Windows Service, for internal use only\n"
301 	"  -i         Install Windows Service (you may want to specify a config file)\n"
302 	"  -r         Remove Windows Service\n"
303 	"  -S <name>  Service name for -i and -r options\n";
304 #endif
305 }
306 
307 
308 // --------------------------------------------------------------------------
309 //
310 // Function
311 //		Name:    BackupDaemon::GetConfigVerify()
312 //		Purpose: Get configuration specification
313 //		Created: 2003/10/08
314 //
315 // --------------------------------------------------------------------------
GetConfigVerify() const316 const ConfigurationVerify *BackupDaemon::GetConfigVerify() const
317 {
318 	// Defined elsewhere
319 	return &BackupDaemonConfigVerify;
320 }
321 
322 #ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
323 // --------------------------------------------------------------------------
324 //
325 // Function
326 //		Name:    BackupDaemon::SetupInInitialProcess()
327 //		Purpose: Platforms with non-checkable credentials on
328 //			local sockets only.
329 //			Prints a warning if the command socket is used.
330 //		Created: 25/2/04
331 //
332 // --------------------------------------------------------------------------
SetupInInitialProcess()333 void BackupDaemon::SetupInInitialProcess()
334 {
335 	// Print a warning on this platform if the CommandSocket is used.
336 	if(GetConfiguration().KeyExists("CommandSocket"))
337 	{
338 		BOX_WARNING(
339 			"==============================================================================\n"
340 			"SECURITY WARNING: This platform cannot check the credentials of connections to\n"
341 			"the command socket. This is a potential DoS security problem.\n"
342 			"Remove the CommandSocket directive from the bbackupd.conf file if bbackupctl\n"
343 			"is not used.\n"
344 			"==============================================================================\n"
345 			);
346 	}
347 }
348 #endif
349 
350 
351 // --------------------------------------------------------------------------
352 //
353 // Function
354 //		Name:    BackupDaemon::DeleteAllLocations()
355 //		Purpose: Deletes all records stored
356 //		Created: 2003/10/08
357 //
358 // --------------------------------------------------------------------------
DeleteAllLocations()359 void BackupDaemon::DeleteAllLocations()
360 {
361 	// Run through, and delete everything
362 	for(std::vector<Location *>::iterator i = mLocations.begin();
363 		i != mLocations.end(); ++i)
364 	{
365 		delete *i;
366 	}
367 
368 	// Clear the contents of the map, so it is empty
369 	mLocations.clear();
370 
371 	// And delete everything from the associated mount vector
372 	mIDMapMounts.clear();
373 }
374 
375 #ifdef WIN32
GetOptionString()376 std::string BackupDaemon::GetOptionString()
377 {
378 	std::string oldOpts = this->Daemon::GetOptionString();
379 	ASSERT(oldOpts.find("s") == std::string::npos);
380 	ASSERT(oldOpts.find("S") == std::string::npos);
381 	ASSERT(oldOpts.find("i") == std::string::npos);
382 	ASSERT(oldOpts.find("r") == std::string::npos);
383 	return oldOpts + "sS:ir";
384 }
385 
ProcessOption(signed int option)386 int BackupDaemon::ProcessOption(signed int option)
387 {
388 	switch(option)
389 	{
390 		case 's':
391 		{
392 			mRunAsService = true;
393 			return 0;
394 		}
395 
396 		case 'S':
397 		{
398 			mServiceName = optarg;
399 			Logging::SetProgramName(mServiceName);
400 			return 0;
401 		}
402 
403 		case 'i':
404 		{
405 			mInstallService = true;
406 			return 0;
407 		}
408 
409 		case 'r':
410 		{
411 			mRemoveService = true;
412 			return 0;
413 		}
414 
415 		default:
416 		{
417 			return this->Daemon::ProcessOption(option);
418 		}
419 	}
420 }
421 
Main(const std::string & rConfigFileName)422 int BackupDaemon::Main(const std::string &rConfigFileName)
423 {
424 	if (mInstallService)
425 	{
426 		return InstallService(rConfigFileName.c_str(), mServiceName);
427 	}
428 
429 	if (mRemoveService)
430 	{
431 		return RemoveService(mServiceName);
432 	}
433 
434 #ifdef ENABLE_VSS
435 	HRESULT result = CoInitialize(NULL);
436 	if(result != S_OK)
437 	{
438 		BOX_ERROR("VSS: Failed to initialize COM: " <<
439 			GetMsgForHresult(result));
440 		return 1;
441 	}
442 #endif
443 
444 	int returnCode;
445 
446 	if (mRunAsService)
447 	{
448 		// We will be called reentrantly by the Service Control
449 		// Manager, and we had better not call OurService again!
450 		mRunAsService = false;
451 
452 		BOX_INFO("Box Backup service starting");
453 		returnCode = OurService(rConfigFileName.c_str());
454 		BOX_INFO("Box Backup service shut down");
455 	}
456 	else
457 	{
458 		returnCode = this->Daemon::Main(rConfigFileName);
459 	}
460 
461 	return returnCode;
462 }
463 #endif
464 
465 // --------------------------------------------------------------------------
466 //
467 // Function
468 //		Name:    BackupDaemon::Run()
469 //		Purpose: Run function for daemon
470 //		Created: 18/2/04
471 //
472 // --------------------------------------------------------------------------
Run()473 void BackupDaemon::Run()
474 {
475 	// initialise global timer mechanism
476 	Timers::Init();
477 
478 	#ifndef WIN32
479 		// Ignore SIGPIPE so that if a command connection is broken,
480 		// the daemon doesn't terminate.
481 		::signal(SIGPIPE, SIG_IGN);
482 	#endif
483 
484 	// Create a command socket?
485 	const Configuration &conf(GetConfiguration());
486 	if(conf.KeyExists("CommandSocket"))
487 	{
488 		// Yes, create a local UNIX socket
489 		mapCommandSocketInfo.reset(new CommandSocketInfo);
490 		const char *socketName =
491 			conf.GetKeyValue("CommandSocket").c_str();
492 		#ifdef WIN32
493 			mapCommandSocketInfo->mListeningSocket.Listen(
494 				socketName);
495 		#else
496 			::unlink(socketName);
497 			mapCommandSocketInfo->mListeningSocket.Listen(
498 				Socket::TypeUNIX, socketName);
499 		#endif
500 	}
501 
502 	// Handle things nicely on exceptions
503 	try
504 	{
505 		Run2();
506 	}
507 	catch(...)
508 	{
509 		if(mapCommandSocketInfo.get())
510 		{
511 			try
512 			{
513 				mapCommandSocketInfo.reset();
514 			}
515 			catch(std::exception &e)
516 			{
517 				BOX_WARNING("Internal error while "
518 					"closing command socket after "
519 					"another exception: " << e.what());
520 			}
521 			catch(...)
522 			{
523 				BOX_WARNING("Error closing command socket "
524 					"after exception, ignored.");
525 			}
526 		}
527 
528 		Timers::Cleanup();
529 
530 		throw;
531 	}
532 
533 	// Clean up
534 	mapCommandSocketInfo.reset();
535 	Timers::Cleanup();
536 }
537 
InitCrypto()538 void BackupDaemon::InitCrypto()
539 {
540 	// Read in the certificates creating a TLS context
541 	const Configuration &conf(GetConfiguration());
542 	std::string certFile(conf.GetKeyValue("CertificateFile"));
543 	std::string keyFile(conf.GetKeyValue("PrivateKeyFile"));
544 	std::string caFile(conf.GetKeyValue("TrustedCAsFile"));
545 	mTlsContext.Initialise(false /* as client */, certFile.c_str(),
546 		keyFile.c_str(), caFile.c_str());
547 
548 	// Set up the keys for various things
549 	BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile").c_str());
550 }
551 
552 // --------------------------------------------------------------------------
553 //
554 // Function
555 //		Name:    BackupDaemon::Run2()
556 //		Purpose: Run function for daemon (second stage)
557 //		Created: 2003/10/08
558 //
559 // --------------------------------------------------------------------------
Run2()560 void BackupDaemon::Run2()
561 {
562 	InitCrypto();
563 
564 	const Configuration &conf(GetConfiguration());
565 
566 	// How often to connect to the store (approximate)
567 	mUpdateStoreInterval = SecondsToBoxTime(
568 		conf.GetKeyValueInt("UpdateStoreInterval"));
569 
570 	// But are we connecting automatically?
571 	bool automaticBackup = conf.GetKeyValueBool("AutomaticBackup");
572 
573 	// When the next sync should take place -- which is ASAP
574 	mNextSyncTime = 0;
575 
576 	// When the last sync started (only updated if the store was not full when the sync ended)
577 	mLastSyncTime = 0;
578 
579  	// --------------------------------------------------------------------------------------------
580 
581  	mDeleteStoreObjectInfoFile = DeserializeStoreObjectInfo(
582 		mLastSyncTime, mNextSyncTime);
583 
584 	// --------------------------------------------------------------------------------------------
585 
586 
587 	// Set state
588 	SetState(State_Idle);
589 
590 	mDoSyncForcedByPreviousSyncError = false;
591 
592 	// Loop around doing backups
593 	do
594 	{
595 		// Flags used below
596 		bool storageLimitExceeded = false;
597 		bool doSync = false;
598 		bool mDoSyncForcedByCommand = false;
599 
600 		// Is a delay necessary?
601 		box_time_t currentTime;
602 
603 		do
604 		{
605 			// Check whether we should be stopping,
606 			// and don't run a sync if so.
607 			if(StopRun()) break;
608 
609 			currentTime = GetCurrentBoxTime();
610 
611 			// Pause a while, but no more than
612 			// MAX_SLEEP_TIME seconds (use the conditional
613 			// because times are unsigned)
614 			box_time_t requiredDelay =
615 				(mNextSyncTime < currentTime)
616 				? (0)
617 				: (mNextSyncTime - currentTime);
618 
619 			// If there isn't automatic backup happening,
620 			// set a long delay. And limit delays at the
621 			// same time.
622 			if(!automaticBackup && !mDoSyncForcedByPreviousSyncError)
623 			{
624 				requiredDelay = SecondsToBoxTime(MAX_SLEEP_TIME);
625 			}
626 			else if(requiredDelay > SecondsToBoxTime(MAX_SLEEP_TIME))
627 			{
628 				requiredDelay = SecondsToBoxTime(MAX_SLEEP_TIME);
629 			}
630 
631 			// Only delay if necessary
632 			if(requiredDelay > 0)
633 			{
634 				// Sleep somehow. There are choices
635 				// on how this should be done,
636 				// depending on the state of the
637 				// control connection
638 				if(mapCommandSocketInfo.get() != 0)
639 				{
640 					// A command socket exists,
641 					// so sleep by waiting on it
642 					WaitOnCommandSocket(requiredDelay,
643 						doSync, mDoSyncForcedByCommand);
644 				}
645 				else
646 				{
647 					// No command socket or
648 					// connection, just do a
649 					// normal sleep
650 					time_t sleepSeconds =
651 						BoxTimeToSeconds(requiredDelay);
652 					::sleep((sleepSeconds <= 0)
653 						? 1 : sleepSeconds);
654 				}
655 			}
656 
657 			if ((automaticBackup || mDoSyncForcedByPreviousSyncError)
658 				&& currentTime >= mNextSyncTime)
659 			{
660 				doSync = true;
661 			}
662 		}
663 		while(!doSync && !StopRun());
664 
665 		// Time of sync start, and if it's time for another sync
666 		// (and we're doing automatic syncs), set the flag
667 		mCurrentSyncStartTime = GetCurrentBoxTime();
668 		if((automaticBackup || mDoSyncForcedByPreviousSyncError) &&
669 			mCurrentSyncStartTime >= mNextSyncTime)
670 		{
671 			doSync = true;
672 		}
673 
674 		// Use a script to see if sync is allowed now?
675 		if(!mDoSyncForcedByCommand && doSync && !StopRun())
676 		{
677 			int d = UseScriptToSeeIfSyncAllowed();
678 			if(d > 0)
679 			{
680 				// Script has asked for a delay
681 				mNextSyncTime = GetCurrentBoxTime() +
682 					SecondsToBoxTime(d);
683 				doSync = false;
684 			}
685 		}
686 
687 		// Ready to sync? (but only if we're not supposed
688 		// to be stopping)
689 		if(doSync && !StopRun())
690 		{
691 			RunSyncNowWithExceptionHandling();
692 		}
693 
694 		// Set state
695 		SetState(storageLimitExceeded?State_StorageLimitExceeded:State_Idle);
696 
697 	} while(!StopRun());
698 
699 	// Make sure we have a clean start next time round (if restart)
700 	DeleteAllLocations();
701 	DeleteAllIDMaps();
702 }
703 
RunSyncNowWithExceptionHandling()704 void BackupDaemon::RunSyncNowWithExceptionHandling()
705 {
706 	bool errorOccurred = false;
707 	int errorCode = 0, errorSubCode = 0;
708 	const char* errorString = "unknown";
709 
710 	try
711 	{
712 		OnBackupStart();
713 		// Do sync
714 		RunSyncNow();
715 	}
716 	catch(BoxException &e)
717 	{
718 		errorOccurred = true;
719 		errorString = e.what();
720 		errorCode = e.GetType();
721 		errorSubCode = e.GetSubType();
722 	}
723 	catch(std::exception &e)
724 	{
725 		BOX_ERROR("Internal error during backup run: " << e.what());
726 		errorOccurred = true;
727 		errorString = e.what();
728 	}
729 	catch(...)
730 	{
731 		// TODO: better handling of exceptions here...
732 		// need to be very careful
733 		errorOccurred = true;
734 	}
735 
736 	// do not retry immediately without a good reason
737 	mDoSyncForcedByPreviousSyncError = false;
738 
739 	if(errorOccurred)
740 	{
741 		// Is it a berkely db failure?
742 		bool isBerkelyDbFailure = false;
743 
744 		if (errorCode == BackupStoreException::ExceptionType
745 			&& errorSubCode == BackupStoreException::BerkelyDBFailure)
746 		{
747 			isBerkelyDbFailure = true;
748 		}
749 
750 		if(isBerkelyDbFailure)
751 		{
752 			// Delete corrupt files
753 			DeleteCorruptBerkelyDbFiles();
754 		}
755 
756 		// Clear state data
757 		// Go back to beginning of time
758 		mLastSyncTime = 0;
759 		mClientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown;	// no store marker, so download everything
760 		DeleteAllLocations();
761 		DeleteAllIDMaps();
762 
763 		// Handle restart?
764 		if(StopRun())
765 		{
766 			BOX_NOTICE("Exception (" << errorCode
767 				<< "/" << errorSubCode
768 				<< ") due to signal");
769 			OnBackupFinish();
770 			return;
771 		}
772 
773 		NotifySysadmin(SysadminNotifier::BackupError);
774 
775 		// If the Berkely db files get corrupted,
776 		// delete them and try again immediately.
777 		if(isBerkelyDbFailure)
778 		{
779 			BOX_ERROR("Berkely db inode map files corrupted, "
780 				"deleting and restarting scan. Renamed files "
781 				"and directories will not be tracked until "
782 				"after this scan.");
783 			::sleep(1);
784 		}
785 		else
786 		{
787 			// Not restart/terminate, pause and retry
788 			// Notify administrator
789 			SetState(State_Error);
790 			BOX_ERROR("Exception caught (" << errorString <<
791 				" " << errorCode << "/" << errorSubCode <<
792 				"), reset state and waiting to retry...");
793 			::sleep(10);
794 			mNextSyncTime = mCurrentSyncStartTime +
795 				SecondsToBoxTime(100) +
796 				Random::RandomInt(mUpdateStoreInterval >>
797 					SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY);
798 		}
799 	}
800 	// Notify system administrator about the final state of the backup
801 	else if(mReadErrorsOnFilesystemObjects)
802 	{
803 		NotifySysadmin(SysadminNotifier::ReadError);
804 	}
805 	else if(mStorageLimitExceeded)
806 	{
807 		NotifySysadmin(SysadminNotifier::StoreFull);
808 	}
809 	else
810 	{
811 		NotifySysadmin(SysadminNotifier::BackupOK);
812 	}
813 
814 	// If we were retrying after an error, and this backup succeeded,
815 	// then now would be a good time to stop :-)
816 	mDoSyncForcedByPreviousSyncError = errorOccurred;
817 
818 	OnBackupFinish();
819 }
820 
RunSyncNow()821 void BackupDaemon::RunSyncNow()
822 {
823 	// Delete the serialised store object file,
824 	// so that we don't try to reload it after a
825 	// partially completed backup
826 	if(mDeleteStoreObjectInfoFile &&
827 		!DeleteStoreObjectInfo())
828 	{
829 		BOX_ERROR("Failed to delete the StoreObjectInfoFile, "
830 			"backup cannot continue safely.");
831 		THROW_EXCEPTION(ClientException,
832 			FailedToDeleteStoreObjectInfoFile);
833 	}
834 
835 	// In case the backup throws an exception,
836 	// we should not try to delete the store info
837 	// object file again.
838 	mDeleteStoreObjectInfoFile = false;
839 
840 	const Configuration &conf(GetConfiguration());
841 
842 	std::auto_ptr<FileLogger> fileLogger;
843 
844 	if (conf.KeyExists("LogFile"))
845 	{
846 		Log::Level level = Log::INFO;
847 		if (conf.KeyExists("LogFileLevel"))
848 		{
849 			level = Logging::GetNamedLevel(
850 				conf.GetKeyValue("LogFileLevel"));
851 		}
852 		fileLogger.reset(new FileLogger(conf.GetKeyValue("LogFile"),
853 			level));
854 	}
855 
856 	std::string extendedLogFile;
857 	if (conf.KeyExists("ExtendedLogFile"))
858 	{
859 		extendedLogFile = conf.GetKeyValue("ExtendedLogFile");
860 	}
861 
862 	if (conf.KeyExists("LogAllFileAccess"))
863 	{
864 		mLogAllFileAccess = conf.GetKeyValueBool("LogAllFileAccess");
865 	}
866 
867 	// Then create a client context object (don't
868 	// just connect, as this may be unnecessary)
869 	BackupClientContext clientContext
870 	(
871 		*mpLocationResolver,
872 		mTlsContext,
873 		conf.GetKeyValue("StoreHostname"),
874 		conf.GetKeyValueInt("StorePort"),
875 		conf.GetKeyValueUint32("AccountNumber"),
876 		conf.GetKeyValueBool("ExtendedLogging"),
877 		conf.KeyExists("ExtendedLogFile"),
878 		extendedLogFile, *mpProgressNotifier
879 	);
880 
881 	// The minimum age a file needs to be before it will be
882 	// considered for uploading
883 	box_time_t minimumFileAge = SecondsToBoxTime(
884 		conf.GetKeyValueInt("MinimumFileAge"));
885 
886 	// The maximum time we'll wait to upload a file, regardless
887 	// of how often it's modified
888 	box_time_t maxUploadWait = SecondsToBoxTime(
889 		conf.GetKeyValueInt("MaxUploadWait"));
890 	// Adjust by subtracting the minimum file age, so is relative
891 	// to sync period end in comparisons
892 	if (maxUploadWait > minimumFileAge)
893 	{
894 		maxUploadWait -= minimumFileAge;
895 	}
896 	else
897 	{
898 		maxUploadWait = 0;
899 	}
900 
901 	// Calculate the sync period of files to examine
902 	box_time_t syncPeriodStart = mLastSyncTime;
903 	box_time_t syncPeriodEnd = GetCurrentBoxTime() - minimumFileAge;
904 
905 	if(syncPeriodStart >= syncPeriodEnd &&
906 		syncPeriodStart - syncPeriodEnd < minimumFileAge)
907 	{
908 		// This can happen if we receive a force-sync command less
909 		// than minimumFileAge after the last sync. Deal with it by
910 		// moving back syncPeriodStart, which should not do any
911 		// damage.
912 		syncPeriodStart = syncPeriodEnd -
913 			SecondsToBoxTime(1);
914 	}
915 
916 	if(syncPeriodStart >= syncPeriodEnd)
917 	{
918 		BOX_ERROR("Invalid (negative) sync period: "
919 			"perhaps your clock is going "
920 			"backwards (" << syncPeriodStart <<
921 			" to " << syncPeriodEnd << ")");
922 		THROW_EXCEPTION(ClientException,
923 			ClockWentBackwards);
924 	}
925 
926 	// Check logic
927 	ASSERT(syncPeriodEnd > syncPeriodStart);
928 	// Paranoid check on sync times
929 	if(syncPeriodStart >= syncPeriodEnd) return;
930 
931 	// Adjust syncPeriodEnd to emulate snapshot
932 	// behaviour properly
933 	box_time_t syncPeriodEndExtended = syncPeriodEnd;
934 
935 	// Using zero min file age?
936 	if(minimumFileAge == 0)
937 	{
938 		// Add a year on to the end of the end time,
939 		// to make sure we sync files which are
940 		// modified after the scan run started.
941 		// Of course, they may be eligible to be
942 		// synced again the next time round,
943 		// but this should be OK, because the changes
944 		// only upload should upload no data.
945 		syncPeriodEndExtended += SecondsToBoxTime(
946 			(time_t)(356*24*3600));
947 	}
948 
949 	// Set up the sync parameters
950 	BackupClientDirectoryRecord::SyncParams params(*mpRunStatusProvider,
951 		*mpSysadminNotifier, *mpProgressNotifier, clientContext);
952 	params.mSyncPeriodStart = syncPeriodStart;
953 	params.mSyncPeriodEnd = syncPeriodEndExtended;
954 	// use potentially extended end time
955 	params.mMaxUploadWait = maxUploadWait;
956 	params.mFileTrackingSizeThreshold =
957 		conf.GetKeyValueInt("FileTrackingSizeThreshold");
958 	params.mDiffingUploadSizeThreshold =
959 		conf.GetKeyValueInt("DiffingUploadSizeThreshold");
960 	params.mMaxFileTimeInFuture =
961 		SecondsToBoxTime(conf.GetKeyValueInt("MaxFileTimeInFuture"));
962 
963 	if(conf.KeyExists("MaxUploadRate"))
964 	{
965 		params.mMaxUploadRate = conf.GetKeyValueInt("MaxUploadRate");
966 	}
967 
968 	mDeleteRedundantLocationsAfter =
969 		conf.GetKeyValueInt("DeleteRedundantLocationsAfter");
970 	mStorageLimitExceeded = false;
971 	mReadErrorsOnFilesystemObjects = false;
972 
973 	// Setup various timings
974 	int maximumDiffingTime = 600;
975 	int keepAliveTime = 60;
976 
977 	// max diffing time, keep-alive time
978 	if(conf.KeyExists("MaximumDiffingTime"))
979 	{
980 		maximumDiffingTime = conf.GetKeyValueInt("MaximumDiffingTime");
981 	}
982 	if(conf.KeyExists("KeepAliveTime"))
983 	{
984 		keepAliveTime = conf.GetKeyValueInt("KeepAliveTime");
985 	}
986 
987 	clientContext.SetMaximumDiffingTime(maximumDiffingTime);
988 	clientContext.SetKeepAliveTime(keepAliveTime);
989 
990 	// Set store marker
991 	clientContext.SetClientStoreMarker(mClientStoreMarker);
992 
993 	// Set up the locations, if necessary --
994 	// need to do it here so we have a
995 	// (potential) connection to use
996 	if(mLocations.empty())
997 	{
998 		const Configuration &locations(
999 			conf.GetSubConfiguration(
1000 				"BackupLocations"));
1001 
1002 		// Make sure all the directory records
1003 		// are set up
1004 		SetupLocations(clientContext, locations);
1005 	}
1006 
1007 	mpProgressNotifier->NotifyIDMapsSetup(clientContext);
1008 
1009 	// Get some ID maps going
1010 	SetupIDMapsForSync();
1011 
1012 	// Delete any unused directories?
1013 	DeleteUnusedRootDirEntries(clientContext);
1014 
1015 #ifdef ENABLE_VSS
1016 	CreateVssBackupComponents();
1017 #endif
1018 
1019 	// Go through the records, syncing them
1020 	for(std::vector<Location *>::const_iterator
1021 		i(mLocations.begin());
1022 		i != mLocations.end(); ++i)
1023 	{
1024 		// Set current and new ID map pointers
1025 		// in the context
1026 		clientContext.SetIDMaps(mCurrentIDMaps[(*i)->mIDMapIndex],
1027 			mNewIDMaps[(*i)->mIDMapIndex]);
1028 
1029 		// Set exclude lists (context doesn't
1030 		// take ownership)
1031 		clientContext.SetExcludeLists(
1032 			(*i)->mpExcludeFiles,
1033 			(*i)->mpExcludeDirs);
1034 
1035 		// Sync the directory
1036 		std::string locationPath = (*i)->mPath;
1037 #ifdef ENABLE_VSS
1038 		if((*i)->mIsSnapshotCreated)
1039 		{
1040 			locationPath = (*i)->mSnapshotPath;
1041 		}
1042 #endif
1043 
1044 		(*i)->mpDirectoryRecord->SyncDirectory(params,
1045 			BackupProtocolClientListDirectory::RootDirectory,
1046 			locationPath, std::string("/") + (*i)->mName);
1047 
1048 		// Unset exclude lists (just in case)
1049 		clientContext.SetExcludeLists(0, 0);
1050 	}
1051 
1052 	// Perform any deletions required -- these are
1053 	// delayed until the end to allow renaming to
1054 	// happen neatly.
1055 	clientContext.PerformDeletions();
1056 
1057 	// Close any open connection
1058 	clientContext.CloseAnyOpenConnection();
1059 
1060 #ifdef ENABLE_VSS
1061 	CleanupVssBackupComponents();
1062 #endif
1063 
1064 	// Get the new store marker
1065 	mClientStoreMarker = clientContext.GetClientStoreMarker();
1066 	mStorageLimitExceeded = clientContext.StorageLimitExceeded();
1067 	mReadErrorsOnFilesystemObjects =
1068 		params.mReadErrorsOnFilesystemObjects;
1069 
1070 	if(!mStorageLimitExceeded)
1071 	{
1072 		// The start time of the next run is the end time of this
1073 		// run. This is only done if the storage limit wasn't
1074 		// exceeded (as things won't have been done properly if
1075 		// it was)
1076 		mLastSyncTime = syncPeriodEnd;
1077 	}
1078 
1079 	// Commit the ID Maps
1080 	CommitIDMapsAfterSync();
1081 
1082 	// Calculate when the next sync run should be
1083 	mNextSyncTime = mCurrentSyncStartTime +
1084 		mUpdateStoreInterval +
1085 		Random::RandomInt(mUpdateStoreInterval >>
1086 		SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY);
1087 
1088 	// --------------------------------------------------------------------------------------------
1089 
1090 	// We had a successful backup, save the store
1091 	// info. If we save successfully, we must
1092 	// delete the file next time we start a backup
1093 
1094 	mDeleteStoreObjectInfoFile =
1095 		SerializeStoreObjectInfo(mLastSyncTime,
1096 			mNextSyncTime);
1097 
1098 	// --------------------------------------------------------------------------------------------
1099 }
1100 
1101 #ifdef ENABLE_VSS
WaitForAsync(IVssAsync * pAsync,const std::string & description)1102 bool BackupDaemon::WaitForAsync(IVssAsync *pAsync,
1103 	const std::string& description)
1104 {
1105 	BOX_INFO("VSS: waiting for " << description << " to complete");
1106 	HRESULT result;
1107 
1108 	do
1109 	{
1110 		result = pAsync->Wait(1000);
1111 		if(result != S_OK)
1112 		{
1113 			BOX_ERROR("VSS: Failed to wait for " << description <<
1114 				" to complete: " << GetMsgForHresult(result));
1115 			break;
1116 		}
1117 
1118 		HRESULT result2;
1119 		result = pAsync->QueryStatus(&result2, NULL);
1120 		if(result != S_OK)
1121 		{
1122 			BOX_ERROR("VSS: Failed to query " << description <<
1123 				" status: " << GetMsgForHresult(result));
1124 			break;
1125 		}
1126 
1127 		result = result2;
1128 		BOX_INFO("VSS: " << description << " status: " <<
1129 			GetMsgForHresult(result));
1130 	}
1131 	while(result == VSS_S_ASYNC_PENDING);
1132 
1133 	pAsync->Release();
1134 
1135 	return (result == VSS_S_ASYNC_FINISHED);
1136 }
1137 
1138 #define CALL_MEMBER_FN(object, method) ((object).*(method))
1139 
CallAndWaitForAsync(AsyncMethod method,const std::string & description)1140 bool BackupDaemon::CallAndWaitForAsync(AsyncMethod method,
1141 	const std::string& description)
1142 {
1143 	IVssAsync *pAsync;
1144 	HRESULT result = CALL_MEMBER_FN(*mpVssBackupComponents, method)(&pAsync);
1145 	if(result != S_OK)
1146 	{
1147 		BOX_ERROR("VSS: " << description << " failed: " <<
1148 			GetMsgForHresult(result));
1149 		return false;
1150 	}
1151 
1152 	return WaitForAsync(pAsync, description);
1153 }
1154 
FreeSnapshotProp(VSS_SNAPSHOT_PROP * pSnap)1155 void FreeSnapshotProp(VSS_SNAPSHOT_PROP *pSnap)
1156 {
1157 	CoTaskMemFree(pSnap->m_pwszSnapshotDeviceObject);
1158 	CoTaskMemFree(pSnap->m_pwszOriginalVolumeName);
1159 	CoTaskMemFree(pSnap->m_pwszOriginatingMachine);
1160 	CoTaskMemFree(pSnap->m_pwszServiceMachine);
1161 	CoTaskMemFree(pSnap->m_pwszExposedName);
1162 	CoTaskMemFree(pSnap->m_pwszExposedPath);
1163 }
1164 
CreateVssBackupComponents()1165 void BackupDaemon::CreateVssBackupComponents()
1166 {
1167 	std::map<char, VSS_ID> volumesIncluded;
1168 
1169 	HRESULT result = ::CreateVssBackupComponents(&mpVssBackupComponents);
1170 	if(result != S_OK)
1171 	{
1172 		BOX_ERROR("VSS: Failed to create backup components: " <<
1173 			GetMsgForHresult(result));
1174 		return;
1175 	}
1176 
1177 	result = mpVssBackupComponents->InitializeForBackup(NULL);
1178 	if(result != S_OK)
1179 	{
1180 		std::string message = GetMsgForHresult(result);
1181 
1182 		if (result == VSS_E_UNEXPECTED)
1183 		{
1184 			message = "Check the Application Log for details, and ensure "
1185 				"that the Volume Shadow Copy, COM+ System Application, "
1186 				"and Distributed Transaction Coordinator services "
1187 				"are running";
1188 		}
1189 
1190 		BOX_ERROR("VSS: Failed to initialize for backup: " << message);
1191 		return;
1192 	}
1193 
1194 	result = mpVssBackupComponents->SetContext(VSS_CTX_BACKUP);
1195 	if(result == E_NOTIMPL)
1196 	{
1197 		BOX_INFO("VSS: Failed to set context to VSS_CTX_BACKUP: "
1198 			"not implemented, probably Windows XP, ignored.");
1199 	}
1200 	else if(result != S_OK)
1201 	{
1202 		BOX_ERROR("VSS: Failed to set context to VSS_CTX_BACKUP: " <<
1203 			GetMsgForHresult(result));
1204 		return;
1205 	}
1206 
1207 	result = mpVssBackupComponents->SetBackupState(
1208 		false, /* no components for now */
1209 		true, /* might as well ask for a bootable backup */
1210 		VSS_BT_FULL,
1211 		false /* what is Partial File Support? */);
1212 	if(result != S_OK)
1213 	{
1214 		BOX_ERROR("VSS: Failed to set backup state: " <<
1215 			GetMsgForHresult(result));
1216 		return;
1217 	}
1218 
1219 	if(!CallAndWaitForAsync(&IVssBackupComponents::GatherWriterMetadata,
1220 		"GatherWriterMetadata()"))
1221 	{
1222 		goto CreateVssBackupComponents_cleanup_WriterMetadata;
1223 	}
1224 
1225 	UINT writerCount;
1226 	result = mpVssBackupComponents->GetWriterMetadataCount(&writerCount);
1227 	if(result != S_OK)
1228 	{
1229 		BOX_ERROR("VSS: Failed to get writer count: " <<
1230 			GetMsgForHresult(result));
1231 		goto CreateVssBackupComponents_cleanup_WriterMetadata;
1232 	}
1233 
1234 	for(UINT iWriter = 0; iWriter < writerCount; iWriter++)
1235 	{
1236 		BOX_INFO("VSS: Getting metadata from writer " << iWriter);
1237 		VSS_ID writerInstance;
1238 		IVssExamineWriterMetadata* pMetadata;
1239 		result = mpVssBackupComponents->GetWriterMetadata(iWriter,
1240 			&writerInstance, &pMetadata);
1241 		if(result != S_OK)
1242 		{
1243 			BOX_ERROR("Failed to get VSS metadata from writer " << iWriter <<
1244 				": " << GetMsgForHresult(result));
1245 			continue;
1246 		}
1247 
1248 		UINT includeFiles, excludeFiles, numComponents;
1249 		result = pMetadata->GetFileCounts(&includeFiles, &excludeFiles,
1250 			&numComponents);
1251 		if(result != S_OK)
1252 		{
1253 			BOX_ERROR("VSS: Failed to get metadata file counts from "
1254 				"writer " << iWriter <<	": " <<
1255 				GetMsgForHresult(result));
1256 			pMetadata->Release();
1257 			continue;
1258 		}
1259 
1260 		for(UINT iComponent = 0; iComponent < numComponents; iComponent++)
1261 		{
1262 			IVssWMComponent* pComponent;
1263 			result = pMetadata->GetComponent(iComponent, &pComponent);
1264 			if(result != S_OK)
1265 			{
1266 				BOX_ERROR("VSS: Failed to get metadata component " <<
1267 					iComponent << " from writer " << iWriter << ": " <<
1268 					GetMsgForHresult(result));
1269 				continue;
1270 			}
1271 
1272 			PVSSCOMPONENTINFO pComponentInfo;
1273 			result = pComponent->GetComponentInfo(&pComponentInfo);
1274 			if(result != S_OK)
1275 			{
1276 				BOX_ERROR("VSS: Failed to get metadata component " <<
1277 					iComponent << " info from writer " << iWriter << ": " <<
1278 					GetMsgForHresult(result));
1279 				pComponent->Release();
1280 				continue;
1281 			}
1282 
1283 			BOX_TRACE("VSS: writer " << iWriter << " component " <<
1284 				iComponent << " info:");
1285 			switch(pComponentInfo->type)
1286 			{
1287 			case VSS_CT_UNDEFINED: BOX_INFO("VSS: type: undefined"); break;
1288 			case VSS_CT_DATABASE:  BOX_INFO("VSS: type: database"); break;
1289 			case VSS_CT_FILEGROUP: BOX_INFO("VSS: type: filegroup"); break;
1290 			default:
1291 				BOX_WARNING("VSS: type: unknown (" << pComponentInfo->type << ")");
1292 			}
1293 
1294 			BOX_TRACE("VSS: logical path: " <<
1295 				BstrToString(pComponentInfo->bstrLogicalPath));
1296 			BOX_TRACE("VSS: component name: " <<
1297 				BstrToString(pComponentInfo->bstrComponentName));
1298 			BOX_TRACE("VSS: caption: " <<
1299 				BstrToString(pComponentInfo->bstrCaption));
1300 			BOX_TRACE("VSS: restore metadata: " <<
1301 				pComponentInfo->bRestoreMetadata);
1302 			BOX_TRACE("VSS: notify on complete: " <<
1303 				pComponentInfo->bRestoreMetadata);
1304 			BOX_TRACE("VSS: selectable: " <<
1305 				pComponentInfo->bSelectable);
1306 			BOX_TRACE("VSS: selectable for restore: " <<
1307 				pComponentInfo->bSelectableForRestore);
1308 			BOX_TRACE("VSS: component flags: " <<
1309 				BOX_FORMAT_HEX32(pComponentInfo->dwComponentFlags));
1310 			BOX_TRACE("VSS: file count: " <<
1311 				pComponentInfo->cFileCount);
1312 			BOX_TRACE("VSS: databases: " <<
1313 				pComponentInfo->cDatabases);
1314 			BOX_TRACE("VSS: log files: " <<
1315 				pComponentInfo->cLogFiles);
1316 			BOX_TRACE("VSS: dependencies: " <<
1317 				pComponentInfo->cDependencies);
1318 
1319 			pComponent->FreeComponentInfo(pComponentInfo);
1320 			pComponent->Release();
1321 		}
1322 
1323 		pMetadata->Release();
1324 	}
1325 
1326 	VSS_ID snapshotSetId;
1327 	result = mpVssBackupComponents->StartSnapshotSet(&snapshotSetId);
1328 	if(result != S_OK)
1329 	{
1330 		BOX_ERROR("VSS: Failed to start snapshot set: " <<
1331 			GetMsgForHresult(result));
1332 		goto CreateVssBackupComponents_cleanup_WriterMetadata;
1333 	}
1334 
1335 	// Add all volumes included as backup locations to the snapshot set
1336 	for(std::vector<Location *>::iterator
1337 		iLocation  = mLocations.begin();
1338 		iLocation != mLocations.end();
1339 		iLocation++)
1340 	{
1341 		Location& rLocation(**iLocation);
1342 		std::string path = rLocation.mPath;
1343 		// convert to absolute and remove Unicode prefix
1344 		path = ConvertPathToAbsoluteUnicode(path.c_str()).substr(4);
1345 
1346 		if(path.length() >= 3 && path[1] == ':' && path[2] == '\\')
1347 		{
1348 			std::string volumeRoot = path.substr(0, 3);
1349 
1350 			std::map<char, VSS_ID>::iterator i =
1351 				volumesIncluded.find(path[0]);
1352 
1353 			if(i == volumesIncluded.end())
1354 			{
1355 				std::wstring volumeRootWide;
1356 				volumeRootWide.push_back((WCHAR) path[0]);
1357 				volumeRootWide.push_back((WCHAR) ':');
1358 				volumeRootWide.push_back((WCHAR) '\\');
1359 				VSS_ID newVolumeId;
1360 				result = mpVssBackupComponents->AddToSnapshotSet(
1361 					(VSS_PWSZ)(volumeRootWide.c_str()), GUID_NULL,
1362 					&newVolumeId);
1363 				if(result == S_OK)
1364 				{
1365 					BOX_TRACE("VSS: Added volume " << volumeRoot <<
1366 						" for backup location " << path <<
1367 						" to snapshot set");
1368 					volumesIncluded[path[0]] = newVolumeId;
1369 					rLocation.mSnapshotVolumeId = newVolumeId;
1370 					rLocation.mIsSnapshotCreated = true;
1371 					rLocation.mSnapshotPath = path;
1372 				}
1373 				else
1374 				{
1375 					BOX_ERROR("VSS: Failed to add volume " <<
1376 						volumeRoot << " to snapshot set: " <<
1377 						GetMsgForHresult(result));
1378 					goto CreateVssBackupComponents_cleanup_WriterMetadata;
1379 				}
1380 			}
1381 			else
1382 			{
1383 				BOX_TRACE("VSS: Skipping already included volume " <<
1384 					volumeRoot << " for backup location " << path);
1385 				rLocation.mSnapshotVolumeId = i->second;
1386 				rLocation.mIsSnapshotCreated = true;
1387 			}
1388 		}
1389 		else
1390 		{
1391 			BOX_WARNING("VSS: Skipping backup location " << path <<
1392 				" which does not start with a volume specification");
1393 		}
1394 	}
1395 
1396 	if(!CallAndWaitForAsync(&IVssBackupComponents::PrepareForBackup,
1397 		"PrepareForBackup()"))
1398 	{
1399 		goto CreateVssBackupComponents_cleanup_WriterMetadata;
1400 	}
1401 
1402 	if(!CallAndWaitForAsync(&IVssBackupComponents::DoSnapshotSet,
1403 		"DoSnapshotSet()"))
1404 	{
1405 		goto CreateVssBackupComponents_cleanup_WriterMetadata;
1406 	}
1407 
1408 	if(!CallAndWaitForAsync(&IVssBackupComponents::GatherWriterStatus,
1409 		"GatherWriterStatus()"))
1410 	{
1411 		goto CreateVssBackupComponents_cleanup_WriterStatus;
1412 	}
1413 
1414 	result = mpVssBackupComponents->GetWriterStatusCount(&writerCount);
1415 	if(result != S_OK)
1416 	{
1417 		BOX_ERROR("VSS: Failed to get writer status count: " <<
1418 			GetMsgForHresult(result));
1419 		goto CreateVssBackupComponents_cleanup_WriterStatus;
1420 	}
1421 
1422 	for(UINT iWriter = 0; iWriter < writerCount; iWriter++)
1423 	{
1424 		VSS_ID instance, writer;
1425 		BSTR writerNameBstr;
1426 		VSS_WRITER_STATE writerState;
1427 		HRESULT writerResult;
1428 
1429 		result = mpVssBackupComponents->GetWriterStatus(iWriter,
1430 			&instance, &writer, &writerNameBstr, &writerState,
1431 			&writerResult);
1432 		if(result != S_OK)
1433 		{
1434 			BOX_ERROR("VSS: Failed to query writer " << iWriter <<
1435 				" status: " << GetMsgForHresult(result));
1436 			goto CreateVssBackupComponents_cleanup_WriterStatus;
1437 		}
1438 
1439 		std::string writerName = BstrToString(writerNameBstr);
1440 		::SysFreeString(writerNameBstr);
1441 
1442 		if(writerResult != S_OK)
1443 		{
1444 			BOX_ERROR("VSS: Writer " << iWriter << " (" <<
1445 				writerName << ") failed: " <<
1446 				GetMsgForHresult(writerResult));
1447 			continue;
1448 		}
1449 
1450 		std::string stateName;
1451 
1452 		switch(writerState)
1453 		{
1454 #define WRITER_STATE(code) \
1455 		case code: stateName = #code; break;
1456 		WRITER_STATE(VSS_WS_UNKNOWN);
1457 		WRITER_STATE(VSS_WS_STABLE);
1458 		WRITER_STATE(VSS_WS_WAITING_FOR_FREEZE);
1459 		WRITER_STATE(VSS_WS_WAITING_FOR_THAW);
1460 		WRITER_STATE(VSS_WS_WAITING_FOR_POST_SNAPSHOT);
1461 		WRITER_STATE(VSS_WS_WAITING_FOR_BACKUP_COMPLETE);
1462 		WRITER_STATE(VSS_WS_FAILED_AT_IDENTIFY);
1463 		WRITER_STATE(VSS_WS_FAILED_AT_PREPARE_BACKUP);
1464 		WRITER_STATE(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT);
1465 		WRITER_STATE(VSS_WS_FAILED_AT_FREEZE);
1466 		WRITER_STATE(VSS_WS_FAILED_AT_THAW);
1467 		WRITER_STATE(VSS_WS_FAILED_AT_POST_SNAPSHOT);
1468 		WRITER_STATE(VSS_WS_FAILED_AT_BACKUP_COMPLETE);
1469 		WRITER_STATE(VSS_WS_FAILED_AT_PRE_RESTORE);
1470 		WRITER_STATE(VSS_WS_FAILED_AT_POST_RESTORE);
1471 		WRITER_STATE(VSS_WS_FAILED_AT_BACKUPSHUTDOWN);
1472 #undef WRITER_STATE
1473 		default:
1474 			std::ostringstream o;
1475 			o << "unknown (" << writerState << ")";
1476 			stateName = o.str();
1477 		}
1478 
1479 		BOX_TRACE("VSS: Writer " << iWriter << " (" <<
1480 			writerName << ") is in state " << stateName);
1481 	}
1482 
1483 	// lookup new snapshot volume for each location that has a snapshot
1484 	for(std::vector<Location *>::iterator
1485 		iLocation  = mLocations.begin();
1486 		iLocation != mLocations.end();
1487 		iLocation++)
1488 	{
1489 		Location& rLocation(**iLocation);
1490 		if(rLocation.mIsSnapshotCreated)
1491 		{
1492 			VSS_SNAPSHOT_PROP prop;
1493 			result = mpVssBackupComponents->GetSnapshotProperties(
1494 				rLocation.mSnapshotVolumeId, &prop);
1495 			if(result != S_OK)
1496 			{
1497 				BOX_ERROR("VSS: Failed to get snapshot properties "
1498 					"for volume " << GuidToString(rLocation.mSnapshotVolumeId) <<
1499 					" for location " << rLocation.mPath << ": " <<
1500 					GetMsgForHresult(result));
1501 				rLocation.mIsSnapshotCreated = false;
1502 				continue;
1503 			}
1504 
1505 			rLocation.mSnapshotPath =
1506 				WideStringToString(prop.m_pwszSnapshotDeviceObject) +
1507 				DIRECTORY_SEPARATOR + rLocation.mSnapshotPath;
1508 			FreeSnapshotProp(&prop);
1509 
1510 			BOX_INFO("VSS: Location " << rLocation.mPath << " using "
1511 				"snapshot path " << rLocation.mSnapshotPath);
1512 		}
1513 	}
1514 
1515 	IVssEnumObject *pEnum;
1516 	result = mpVssBackupComponents->Query(GUID_NULL, VSS_OBJECT_NONE,
1517 		VSS_OBJECT_SNAPSHOT, &pEnum);
1518 	if(result != S_OK)
1519 	{
1520 		BOX_ERROR("VSS: Failed to query snapshot list: " <<
1521 			GetMsgForHresult(result));
1522 		goto CreateVssBackupComponents_cleanup_WriterStatus;
1523 	}
1524 
1525 	while(result == S_OK)
1526 	{
1527 		VSS_OBJECT_PROP rgelt;
1528 		ULONG count;
1529 		result = pEnum->Next(1, &rgelt, &count);
1530 
1531 		if(result == S_FALSE)
1532 		{
1533 			// end of list, break out of the loop
1534 			break;
1535 		}
1536 		else if(result != S_OK)
1537 		{
1538 			BOX_ERROR("VSS: Failed to enumerate snapshot: " <<
1539 				GetMsgForHresult(result));
1540 		}
1541 		else if(count != 1)
1542 		{
1543 			BOX_ERROR("VSS: Failed to enumerate snapshot: " <<
1544 				"Next() returned " << count << " objects instead of 1");
1545 		}
1546 		else if(rgelt.Type != VSS_OBJECT_SNAPSHOT)
1547 		{
1548 			BOX_ERROR("VSS: Failed to enumerate snapshot: " <<
1549 				"Next() returned a type " << rgelt.Type << " object "
1550 				"instead of VSS_OBJECT_SNAPSHOT");
1551 		}
1552 		else
1553 		{
1554 			VSS_SNAPSHOT_PROP *pSnap = &rgelt.Obj.Snap;
1555 			BOX_TRACE("VSS: Snapshot ID: " <<
1556 				GuidToString(pSnap->m_SnapshotId));
1557 			BOX_TRACE("VSS: Snapshot set ID: " <<
1558 				GuidToString(pSnap->m_SnapshotSetId));
1559 			BOX_TRACE("VSS: Number of volumes: " <<
1560 				pSnap->m_lSnapshotsCount);
1561 			BOX_TRACE("VSS: Snapshot device object: " <<
1562 				WideStringToString(pSnap->m_pwszSnapshotDeviceObject));
1563 			BOX_TRACE("VSS: Original volume name: " <<
1564 				WideStringToString(pSnap->m_pwszOriginalVolumeName));
1565 			BOX_TRACE("VSS: Originating machine: " <<
1566 				WideStringToString(pSnap->m_pwszOriginatingMachine));
1567 			BOX_TRACE("VSS: Service machine: " <<
1568 				WideStringToString(pSnap->m_pwszServiceMachine));
1569 			BOX_TRACE("VSS: Exposed name: " <<
1570 				WideStringToString(pSnap->m_pwszExposedName));
1571 			BOX_TRACE("VSS: Exposed path: " <<
1572 				WideStringToString(pSnap->m_pwszExposedPath));
1573 			BOX_TRACE("VSS: Provider ID: " <<
1574 				GuidToString(pSnap->m_ProviderId));
1575 			BOX_TRACE("VSS: Snapshot attributes: " <<
1576 				BOX_FORMAT_HEX32(pSnap->m_lSnapshotAttributes));
1577 			BOX_TRACE("VSS: Snapshot creation time: " <<
1578 				BOX_FORMAT_HEX32(pSnap->m_tsCreationTimestamp));
1579 
1580 			std::string status;
1581 			switch(pSnap->m_eStatus)
1582 			{
1583 			case VSS_SS_UNKNOWN:                     status = "Unknown (error)"; break;
1584 			case VSS_SS_PREPARING:                   status = "Preparing"; break;
1585 			case VSS_SS_PROCESSING_PREPARE:          status = "Preparing (processing)"; break;
1586 			case VSS_SS_PREPARED:                    status = "Prepared"; break;
1587 			case VSS_SS_PROCESSING_PRECOMMIT:        status = "Precommitting"; break;
1588 			case VSS_SS_PRECOMMITTED:                status = "Precommitted"; break;
1589 			case VSS_SS_PROCESSING_COMMIT:           status = "Commiting"; break;
1590 			case VSS_SS_COMMITTED:                   status = "Committed"; break;
1591 			case VSS_SS_PROCESSING_POSTCOMMIT:       status = "Postcommitting"; break;
1592 			case VSS_SS_PROCESSING_PREFINALCOMMIT:   status = "Pre final committing"; break;
1593 			case VSS_SS_PREFINALCOMMITTED:           status = "Pre final committed"; break;
1594 			case VSS_SS_PROCESSING_POSTFINALCOMMIT:  status = "Post final committing"; break;
1595 			case VSS_SS_CREATED:                     status = "Created"; break;
1596 			case VSS_SS_ABORTED:                     status = "Aborted"; break;
1597 			case VSS_SS_DELETED:                     status = "Deleted"; break;
1598 			case VSS_SS_POSTCOMMITTED:               status = "Postcommitted"; break;
1599 			default:
1600 				std::ostringstream buf;
1601 				buf << "Unknown code: " << pSnap->m_eStatus;
1602 				status = buf.str();
1603 			}
1604 
1605 			BOX_TRACE("VSS: Snapshot status: " << status);
1606 			FreeSnapshotProp(pSnap);
1607 		}
1608 	}
1609 
1610 	pEnum->Release();
1611 
1612 CreateVssBackupComponents_cleanup_WriterStatus:
1613 	result = mpVssBackupComponents->FreeWriterStatus();
1614 	if(result != S_OK)
1615 	{
1616 		BOX_ERROR("VSS: Failed to free writer status: " <<
1617 			GetMsgForHresult(result));
1618 	}
1619 
1620 CreateVssBackupComponents_cleanup_WriterMetadata:
1621 	result = mpVssBackupComponents->FreeWriterMetadata();
1622 	if(result != S_OK)
1623 	{
1624 		BOX_ERROR("VSS: Failed to free writer metadata: " <<
1625 			GetMsgForHresult(result));
1626 	}
1627 }
1628 
CleanupVssBackupComponents()1629 void BackupDaemon::CleanupVssBackupComponents()
1630 {
1631 	if(mpVssBackupComponents == NULL)
1632 	{
1633 		return;
1634 	}
1635 
1636 	CallAndWaitForAsync(&IVssBackupComponents::BackupComplete,
1637 		"BackupComplete()");
1638 
1639 	mpVssBackupComponents->Release();
1640 	mpVssBackupComponents = NULL;
1641 }
1642 #endif
1643 
OnBackupStart()1644 void BackupDaemon::OnBackupStart()
1645 {
1646 	// Touch a file to record times in filesystem
1647 	TouchFileInWorkingDir("last_sync_start");
1648 
1649 	// Reset statistics on uploads
1650 	BackupStoreFile::ResetStats();
1651 
1652 	// Tell anything connected to the command socket
1653 	SendSyncStartOrFinish(true /* start */);
1654 
1655 	// Notify administrator
1656 	NotifySysadmin(SysadminNotifier::BackupStart);
1657 
1658 	// Set state and log start
1659 	SetState(State_Connected);
1660 	BOX_NOTICE("Beginning scan of local files");
1661 }
1662 
OnBackupFinish()1663 void BackupDaemon::OnBackupFinish()
1664 {
1665 	try
1666 	{
1667 		// Log
1668 		BOX_NOTICE("Finished scan of local files");
1669 
1670 		// Log the stats
1671 		BOX_NOTICE("File statistics: total file size uploaded "
1672 			<< BackupStoreFile::msStats.mBytesInEncodedFiles
1673 			<< ", bytes already on server "
1674 			<< BackupStoreFile::msStats.mBytesAlreadyOnServer
1675 			<< ", encoded size "
1676 			<< BackupStoreFile::msStats.mTotalFileStreamSize);
1677 
1678 		// Reset statistics again
1679 		BackupStoreFile::ResetStats();
1680 
1681 		// Notify administrator
1682 		NotifySysadmin(SysadminNotifier::BackupFinish);
1683 
1684 		// Tell anything connected to the command socket
1685 		SendSyncStartOrFinish(false /* finish */);
1686 
1687 		// Touch a file to record times in filesystem
1688 		TouchFileInWorkingDir("last_sync_finish");
1689 	}
1690 	catch (std::exception &e)
1691 	{
1692 		BOX_ERROR("Failed to perform backup finish actions: " << e.what());
1693 	}
1694 }
1695 
1696 // --------------------------------------------------------------------------
1697 //
1698 // Function
1699 //		Name:    BackupDaemon::UseScriptToSeeIfSyncAllowed()
1700 //		Purpose: Private. Use a script to see if the sync should be
1701 //			 allowed now (if configured). Returns -1 if it's
1702 //			 allowed, time in seconds to wait otherwise.
1703 //		Created: 21/6/04
1704 //
1705 // --------------------------------------------------------------------------
UseScriptToSeeIfSyncAllowed()1706 int BackupDaemon::UseScriptToSeeIfSyncAllowed()
1707 {
1708 	const Configuration &conf(GetConfiguration());
1709 
1710 	// Got a script to run?
1711 	if(!conf.KeyExists("SyncAllowScript"))
1712 	{
1713 		// No. Do sync.
1714 		return -1;
1715 	}
1716 
1717 	// If there's no result, try again in five minutes
1718 	int waitInSeconds = (60*5);
1719 
1720 	std::string script(conf.GetKeyValue("SyncAllowScript") +
1721 		" \"" + GetConfigFileName() + "\"");
1722 
1723 	// Run it?
1724 	pid_t pid = 0;
1725 	try
1726 	{
1727 		std::auto_ptr<IOStream> pscript(LocalProcessStream(script,
1728 			pid));
1729 
1730 		// Read in the result
1731 		IOStreamGetLine getLine(*pscript);
1732 		std::string line;
1733 		if(getLine.GetLine(line, true, 30000)) // 30 seconds should be enough
1734 		{
1735 			// Got a string, interpret
1736 			if(line == "now")
1737 			{
1738 				// Script says do it now. Obey.
1739 				waitInSeconds = -1;
1740 			}
1741 			else
1742 			{
1743 				try
1744 				{
1745 					// How many seconds to wait?
1746 					waitInSeconds = BoxConvert::Convert<int32_t, const std::string&>(line);
1747 				}
1748 				catch(ConversionException &e)
1749 				{
1750 					BOX_ERROR("Invalid output from "
1751 						"SyncAllowScript: '" <<
1752 						line << "' (" << script << ")");
1753 					throw;
1754 				}
1755 
1756 				BOX_NOTICE("Delaying sync by " << waitInSeconds
1757 					<< " seconds due to SyncAllowScript "
1758 					<< "(" << script << ")");
1759 			}
1760 		}
1761 
1762 	}
1763 	catch(std::exception &e)
1764 	{
1765 		BOX_ERROR("Internal error running SyncAllowScript: "
1766 			<< e.what() << " (" << script << ")");
1767 	}
1768 	catch(...)
1769 	{
1770 		// Ignore any exceptions
1771 		// Log that something bad happened
1772 		BOX_ERROR("Unknown error running SyncAllowScript (" <<
1773 			script << ")");
1774 	}
1775 
1776 	// Wait and then cleanup child process, if any
1777 	if(pid != 0)
1778 	{
1779 		int status = 0;
1780 		::waitpid(pid, &status, 0);
1781 	}
1782 
1783 	return waitInSeconds;
1784 }
1785 
1786 
1787 
1788 // --------------------------------------------------------------------------
1789 //
1790 // Function
1791 //		Name:    BackupDaemon::WaitOnCommandSocket(box_time_t, bool &, bool &)
1792 //		Purpose: Waits on a the command socket for a time of UP TO the required time
1793 //				 but may be much less, and handles a command if necessary.
1794 //		Created: 18/2/04
1795 //
1796 // --------------------------------------------------------------------------
WaitOnCommandSocket(box_time_t RequiredDelay,bool & DoSyncFlagOut,bool & SyncIsForcedOut)1797 void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut)
1798 {
1799 	ASSERT(mapCommandSocketInfo.get());
1800 	if(!mapCommandSocketInfo.get())
1801 	{
1802 		// failure case isn't too bad
1803 		::sleep(1);
1804 		return;
1805 	}
1806 
1807 	BOX_TRACE("Wait on command socket, delay = " << RequiredDelay);
1808 
1809 	try
1810 	{
1811 		// Timeout value for connections and things
1812 		int timeout = ((int)BoxTimeToMilliSeconds(RequiredDelay)) + 1;
1813 		// Handle bad boundary cases
1814 		if(timeout <= 0) timeout = 1;
1815 		if(timeout == INFTIM) timeout = 100000;
1816 
1817 		// Wait for socket connection, or handle a command?
1818 		if(mapCommandSocketInfo->mpConnectedSocket.get() == 0)
1819 		{
1820 			// No connection, listen for a new one
1821 			mapCommandSocketInfo->mpConnectedSocket.reset(mapCommandSocketInfo->mListeningSocket.Accept(timeout).release());
1822 
1823 			if(mapCommandSocketInfo->mpConnectedSocket.get() == 0)
1824 			{
1825 				// If a connection didn't arrive, there was a timeout, which means we've
1826 				// waited long enough and it's time to go.
1827 				return;
1828 			}
1829 			else
1830 			{
1831 #ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
1832 				bool uidOK = true;
1833 				BOX_WARNING("On this platform, no security check can be made on the credentials of peers connecting to the command socket. (bbackupctl)");
1834 #else
1835 				// Security check -- does the process connecting to this socket have
1836 				// the same UID as this process?
1837 				bool uidOK = false;
1838 				// BLOCK
1839 				{
1840 					uid_t remoteEUID = 0xffff;
1841 					gid_t remoteEGID = 0xffff;
1842 					if(mapCommandSocketInfo->mpConnectedSocket->GetPeerCredentials(remoteEUID, remoteEGID))
1843 					{
1844 						// Credentials are available -- check UID
1845 						if(remoteEUID == ::getuid())
1846 						{
1847 							// Acceptable
1848 							uidOK = true;
1849 						}
1850 					}
1851 				}
1852 #endif // PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
1853 
1854 				// Is this an acceptable connection?
1855 				if(!uidOK)
1856 				{
1857 					// Dump the connection
1858 					BOX_ERROR("Incoming command connection from peer had different user ID than this process, or security check could not be completed.");
1859 					mapCommandSocketInfo->mpConnectedSocket.reset();
1860 					return;
1861 				}
1862 				else
1863 				{
1864 					// Log
1865 					BOX_INFO("Connection from command socket");
1866 
1867 					// Send a header line summarising the configuration and current state
1868 					const Configuration &conf(GetConfiguration());
1869 					char summary[256];
1870 					int summarySize = sprintf(summary, "bbackupd: %d %d %d %d\nstate %d\n",
1871 						conf.GetKeyValueBool("AutomaticBackup"),
1872 						conf.GetKeyValueInt("UpdateStoreInterval"),
1873 						conf.GetKeyValueInt("MinimumFileAge"),
1874 						conf.GetKeyValueInt("MaxUploadWait"),
1875 						mState);
1876 					mapCommandSocketInfo->mpConnectedSocket->Write(summary, summarySize);
1877 
1878 					// Set the timeout to something very small, so we don't wait too long on waiting
1879 					// for any incoming data
1880 					timeout = 10; // milliseconds
1881 				}
1882 			}
1883 		}
1884 
1885 		// So there must be a connection now.
1886 		ASSERT(mapCommandSocketInfo->mpConnectedSocket.get() != 0);
1887 
1888 		// Is there a getline object ready?
1889 		if(mapCommandSocketInfo->mpGetLine == 0)
1890 		{
1891 			// Create a new one
1892 			mapCommandSocketInfo->mpGetLine = new IOStreamGetLine(*(mapCommandSocketInfo->mpConnectedSocket.get()));
1893 		}
1894 
1895 		// Ping the remote side, to provide errors which will mean the socket gets closed
1896 		mapCommandSocketInfo->mpConnectedSocket->Write("ping\n", 5);
1897 
1898 		// Wait for a command or something on the socket
1899 		std::string command;
1900 		while(mapCommandSocketInfo->mpGetLine != 0 && !mapCommandSocketInfo->mpGetLine->IsEOF()
1901 			&& mapCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout))
1902 		{
1903 			BOX_TRACE("Receiving command '" << command
1904 				<< "' over command socket");
1905 
1906 			bool sendOK = false;
1907 			bool sendResponse = true;
1908 
1909 			// Command to process!
1910 			if(command == "quit" || command == "")
1911 			{
1912 				// Close the socket.
1913 				CloseCommandConnection();
1914 				sendResponse = false;
1915 			}
1916 			else if(command == "sync")
1917 			{
1918 				// Sync now!
1919 				DoSyncFlagOut = true;
1920 				SyncIsForcedOut = false;
1921 				sendOK = true;
1922 			}
1923 			else if(command == "force-sync")
1924 			{
1925 				// Sync now (forced -- overrides any SyncAllowScript)
1926 				DoSyncFlagOut = true;
1927 				SyncIsForcedOut = true;
1928 				sendOK = true;
1929 			}
1930 			else if(command == "reload")
1931 			{
1932 				// Reload the configuration
1933 				SetReloadConfigWanted();
1934 				sendOK = true;
1935 			}
1936 			else if(command == "terminate")
1937 			{
1938 				// Terminate the daemon cleanly
1939 				SetTerminateWanted();
1940 				sendOK = true;
1941 			}
1942 
1943 			// Send a response back?
1944 			if(sendResponse)
1945 			{
1946 				mapCommandSocketInfo->mpConnectedSocket->Write(sendOK?"ok\n":"error\n", sendOK?3:6);
1947 			}
1948 
1949 			// Set timeout to something very small, so this just checks for data which is waiting
1950 			timeout = 1;
1951 		}
1952 
1953 		// Close on EOF?
1954 		if(mapCommandSocketInfo->mpGetLine != 0 && mapCommandSocketInfo->mpGetLine->IsEOF())
1955 		{
1956 			CloseCommandConnection();
1957 		}
1958 	}
1959 	catch(ConnectionException &ce)
1960 	{
1961 		BOX_NOTICE("Failed to write to command socket: " << ce.what());
1962 
1963 		// If an error occurs, and there is a connection active,
1964 		// just close that connection and continue. Otherwise,
1965 		// let the error propagate.
1966 
1967 		if(mapCommandSocketInfo->mpConnectedSocket.get() == 0)
1968 		{
1969 			throw; // thread will die
1970 		}
1971 		else
1972 		{
1973 			// Close socket and ignore error
1974 			CloseCommandConnection();
1975 		}
1976 	}
1977 	catch(std::exception &e)
1978 	{
1979 		BOX_ERROR("Failed to write to command socket: " <<
1980 			e.what());
1981 
1982 		// If an error occurs, and there is a connection active,
1983 		// just close that connection and continue. Otherwise,
1984 		// let the error propagate.
1985 
1986 		if(mapCommandSocketInfo->mpConnectedSocket.get() == 0)
1987 		{
1988 			throw; // thread will die
1989 		}
1990 		else
1991 		{
1992 			// Close socket and ignore error
1993 			CloseCommandConnection();
1994 		}
1995 	}
1996 	catch(...)
1997 	{
1998 		BOX_ERROR("Failed to write to command socket: unknown error");
1999 
2000 		// If an error occurs, and there is a connection active,
2001 		// just close that connection and continue. Otherwise,
2002 		// let the error propagate.
2003 
2004 		if(mapCommandSocketInfo->mpConnectedSocket.get() == 0)
2005 		{
2006 			throw; // thread will die
2007 		}
2008 		else
2009 		{
2010 			// Close socket and ignore error
2011 			CloseCommandConnection();
2012 		}
2013 	}
2014 }
2015 
2016 
2017 // --------------------------------------------------------------------------
2018 //
2019 // Function
2020 //		Name:    BackupDaemon::CloseCommandConnection()
2021 //		Purpose: Close the command connection, ignoring any errors
2022 //		Created: 18/2/04
2023 //
2024 // --------------------------------------------------------------------------
CloseCommandConnection()2025 void BackupDaemon::CloseCommandConnection()
2026 {
2027 	try
2028 	{
2029 		BOX_TRACE("Closing command connection");
2030 
2031 		if(mapCommandSocketInfo->mpGetLine)
2032 		{
2033 			delete mapCommandSocketInfo->mpGetLine;
2034 			mapCommandSocketInfo->mpGetLine = 0;
2035 		}
2036 		mapCommandSocketInfo->mpConnectedSocket.reset();
2037 	}
2038 	catch(std::exception &e)
2039 	{
2040 		BOX_ERROR("Internal error while closing command "
2041 			"socket: " << e.what());
2042 	}
2043 	catch(...)
2044 	{
2045 		// Ignore any errors
2046 	}
2047 }
2048 
2049 
2050 // --------------------------------------------------------------------------
2051 //
2052 // File
2053 //		Name:    BackupDaemon.cpp
2054 //		Purpose: Send a start or finish sync message to the command socket, if it's connected.
2055 //
2056 //		Created: 18/2/04
2057 //
2058 // --------------------------------------------------------------------------
SendSyncStartOrFinish(bool SendStart)2059 void BackupDaemon::SendSyncStartOrFinish(bool SendStart)
2060 {
2061 	// The bbackupctl program can't rely on a state change, because it
2062 	// may never change if the server doesn't need to be contacted.
2063 
2064 	if(mapCommandSocketInfo.get() &&
2065 		mapCommandSocketInfo->mpConnectedSocket.get() != 0)
2066 	{
2067 		std::string message = SendStart ? "start-sync" : "finish-sync";
2068 		try
2069 		{
2070 			message += "\n";
2071 			mapCommandSocketInfo->mpConnectedSocket->Write(
2072 				message.c_str(), message.size());
2073 		}
2074 		catch(std::exception &e)
2075 		{
2076 			BOX_ERROR("Internal error while sending to "
2077 				"command socket client: " << e.what());
2078 			CloseCommandConnection();
2079 		}
2080 		catch(...)
2081 		{
2082 			CloseCommandConnection();
2083 		}
2084 	}
2085 }
2086 
2087 
2088 
2089 
2090 #if !defined(HAVE_STRUCT_STATFS_F_MNTONNAME) && !defined(HAVE_STRUCT_STATVFS_F_NMTONNAME)
2091 	// string comparison ordering for when mount points are handled
2092 	// by code, rather than the OS.
2093 	typedef struct
2094 	{
operator ()__anon11c601ea01082095 		bool operator()(const std::string &s1, const std::string &s2)
2096 		{
2097 			if(s1.size() == s2.size())
2098 			{
2099 				// Equal size, sort according to natural sort order
2100 				return s1 < s2;
2101 			}
2102 			else
2103 			{
2104 				// Make sure longer strings go first
2105 				return s1.size() > s2.size();
2106 			}
2107 		}
2108 	} mntLenCompare;
2109 #endif
2110 
2111 // --------------------------------------------------------------------------
2112 //
2113 // Function
2114 //		Name:    BackupDaemon::SetupLocations(BackupClientContext &, const Configuration &)
2115 //		Purpose: Makes sure that the list of directories records is correctly set up
2116 //		Created: 2003/10/08
2117 //
2118 // --------------------------------------------------------------------------
SetupLocations(BackupClientContext & rClientContext,const Configuration & rLocationsConf)2119 void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Configuration &rLocationsConf)
2120 {
2121 	if(!mLocations.empty())
2122 	{
2123 		// Looks correctly set up
2124 		return;
2125 	}
2126 
2127 	// Make sure that if a directory is reinstated, then it doesn't get deleted
2128 	mDeleteUnusedRootDirEntriesAfter = 0;
2129 	mUnusedRootDirEntries.clear();
2130 
2131 	// Just a check to make sure it's right.
2132 	DeleteAllLocations();
2133 
2134 	// Going to need a copy of the root directory. Get a connection,
2135 	// and fetch it.
2136 	BackupProtocolClient &connection(rClientContext.GetConnection());
2137 
2138 	// Ask server for a list of everything in the root directory,
2139 	// which is a directory itself
2140 	std::auto_ptr<BackupProtocolClientSuccess> dirreply(
2141 		connection.QueryListDirectory(
2142 			BackupProtocolClientListDirectory::RootDirectory,
2143 			// only directories
2144 			BackupProtocolClientListDirectory::Flags_Dir,
2145 			// exclude old/deleted stuff
2146 			BackupProtocolClientListDirectory::Flags_Deleted |
2147 			BackupProtocolClientListDirectory::Flags_OldVersion,
2148 			false /* no attributes */));
2149 
2150 	// Retrieve the directory from the stream following
2151 	BackupStoreDirectory dir;
2152 	std::auto_ptr<IOStream> dirstream(connection.ReceiveStream());
2153 	dir.ReadFromStream(*dirstream, connection.GetTimeout());
2154 
2155 	// Map of mount names to ID map index
2156 	std::map<std::string, int> mounts;
2157 	int numIDMaps = 0;
2158 
2159 #ifdef HAVE_MOUNTS
2160 #if !defined(HAVE_STRUCT_STATFS_F_MNTONNAME) && !defined(HAVE_STRUCT_STATVFS_F_MNTONNAME)
2161 	// Linux and others can't tell you where a directory is mounted. So we
2162 	// have to read the mount entries from /etc/mtab! Bizarre that the OS
2163 	// itself can't tell you, but there you go.
2164 	std::set<std::string, mntLenCompare> mountPoints;
2165 	// BLOCK
2166 	FILE *mountPointsFile = 0;
2167 
2168 #ifdef HAVE_STRUCT_MNTENT_MNT_DIR
2169 	// Open mounts file
2170 	mountPointsFile = ::setmntent("/proc/mounts", "r");
2171 	if(mountPointsFile == 0)
2172 	{
2173 		mountPointsFile = ::setmntent("/etc/mtab", "r");
2174 	}
2175 	if(mountPointsFile == 0)
2176 	{
2177 		THROW_EXCEPTION(CommonException, OSFileError);
2178 	}
2179 
2180 	try
2181 	{
2182 		// Read all the entries, and put them in the set
2183 		struct mntent *entry = 0;
2184 		while((entry = ::getmntent(mountPointsFile)) != 0)
2185 		{
2186 			BOX_TRACE("Found mount point at " << entry->mnt_dir);
2187 			mountPoints.insert(std::string(entry->mnt_dir));
2188 		}
2189 
2190 		// Close mounts file
2191 		::endmntent(mountPointsFile);
2192 	}
2193 	catch(...)
2194 	{
2195 		::endmntent(mountPointsFile);
2196 		throw;
2197 	}
2198 #else // ! HAVE_STRUCT_MNTENT_MNT_DIR
2199 	// Open mounts file
2200 	mountPointsFile = ::fopen("/etc/mnttab", "r");
2201 	if(mountPointsFile == 0)
2202 	{
2203 		THROW_EXCEPTION(CommonException, OSFileError);
2204 	}
2205 
2206 	try
2207 	{
2208 		// Read all the entries, and put them in the set
2209 		struct mnttab entry;
2210 		while(getmntent(mountPointsFile, &entry) == 0)
2211 		{
2212 			BOX_TRACE("Found mount point at " << entry.mnt_mountp);
2213 			mountPoints.insert(std::string(entry.mnt_mountp));
2214 		}
2215 
2216 		// Close mounts file
2217 		::fclose(mountPointsFile);
2218 	}
2219 	catch(...)
2220 	{
2221 		::fclose(mountPointsFile);
2222 		throw;
2223 	}
2224 #endif // HAVE_STRUCT_MNTENT_MNT_DIR
2225 	// Check sorting and that things are as we expect
2226 	ASSERT(mountPoints.size() > 0);
2227 #ifndef BOX_RELEASE_BUILD
2228 	{
2229 		std::set<std::string, mntLenCompare>::reverse_iterator i(mountPoints.rbegin());
2230 		ASSERT(*i == "/");
2231 	}
2232 #endif // n BOX_RELEASE_BUILD
2233 #endif // n HAVE_STRUCT_STATFS_F_MNTONNAME || n HAVE_STRUCT_STATVFS_F_MNTONNAME
2234 #endif // HAVE_MOUNTS
2235 
2236 	// Then... go through each of the entries in the configuration,
2237 	// making sure there's a directory created for it.
2238 	std::vector<std::string> locNames =
2239 		rLocationsConf.GetSubConfigurationNames();
2240 
2241 	for(std::vector<std::string>::iterator
2242 		pLocName  = locNames.begin();
2243 		pLocName != locNames.end();
2244 		pLocName++)
2245 	{
2246 		const Configuration& rConfig(
2247 			rLocationsConf.GetSubConfiguration(*pLocName));
2248 		BOX_TRACE("new location: " << *pLocName);
2249 
2250 		// Create a record for it
2251 		std::auto_ptr<Location> apLoc(new Location);
2252 
2253 		try
2254 		{
2255 			// Setup names in the location record
2256 			apLoc->mName = *pLocName;
2257 			apLoc->mPath = rConfig.GetKeyValue("Path");
2258 
2259 			// Read the exclude lists from the Configuration
2260 			apLoc->mpExcludeFiles = BackupClientMakeExcludeList_Files(rConfig);
2261 			apLoc->mpExcludeDirs = BackupClientMakeExcludeList_Dirs(rConfig);
2262 
2263 			// Does this exist on the server?
2264 			// Remove from dir object early, so that if we fail
2265 			// to stat the local directory, we still don't
2266 			// consider to remote one for deletion.
2267 			BackupStoreDirectory::Iterator iter(dir);
2268 			BackupStoreFilenameClear dirname(apLoc->mName);	// generate the filename
2269 			BackupStoreDirectory::Entry *en = iter.FindMatchingClearName(dirname);
2270 			int64_t oid = 0;
2271 			if(en != 0)
2272 			{
2273 				oid = en->GetObjectID();
2274 
2275 				// Delete the entry from the directory, so we get a list of
2276 				// unused root directories at the end of this.
2277 				dir.DeleteEntry(oid);
2278 			}
2279 
2280 			// Do a fsstat on the pathname to find out which mount it's on
2281 			{
2282 
2283 #if defined HAVE_STRUCT_STATFS_F_MNTONNAME || defined HAVE_STRUCT_STATVFS_F_MNTONNAME || defined WIN32
2284 
2285 				// BSD style statfs -- includes mount point, which is nice.
2286 #ifdef HAVE_STRUCT_STATVFS_F_MNTONNAME
2287 				struct statvfs s;
2288 				if(::statvfs(apLoc->mPath.c_str(), &s) != 0)
2289 #else // HAVE_STRUCT_STATVFS_F_MNTONNAME
2290 				struct statfs s;
2291 				if(::statfs(apLoc->mPath.c_str(), &s) != 0)
2292 #endif // HAVE_STRUCT_STATVFS_F_MNTONNAME
2293 				{
2294 					BOX_LOG_SYS_WARNING("Failed to stat location "
2295 						"path '" << apLoc->mPath <<
2296 						"', skipping location '" <<
2297 						apLoc->mName << "'");
2298 					continue;
2299 				}
2300 
2301 				// Where the filesystem is mounted
2302 				std::string mountName(s.f_mntonname);
2303 
2304 #else // !HAVE_STRUCT_STATFS_F_MNTONNAME && !WIN32
2305 
2306 				// Warn in logs if the directory isn't absolute
2307 				if(apLoc->mPath[0] != '/')
2308 				{
2309 					BOX_WARNING("Location path '"
2310 						<< apLoc->mPath
2311 						<< "' is not absolute");
2312 				}
2313 				// Go through the mount points found, and find a suitable one
2314 				std::string mountName("/");
2315 				{
2316 					std::set<std::string, mntLenCompare>::const_iterator i(mountPoints.begin());
2317 					BOX_TRACE(mountPoints.size()
2318 						<< " potential mount points");
2319 					for(; i != mountPoints.end(); ++i)
2320 					{
2321 						// Compare first n characters with the filename
2322 						// If it matches, the file belongs in that mount point
2323 						// (sorting order ensures this)
2324 						BOX_TRACE("checking against mount point " << *i);
2325 						if(::strncmp(i->c_str(), apLoc->mPath.c_str(), i->size()) == 0)
2326 						{
2327 							// Match
2328 							mountName = *i;
2329 							break;
2330 						}
2331 					}
2332 					BOX_TRACE("mount point chosen for "
2333 						<< apLoc->mPath << " is "
2334 						<< mountName);
2335 				}
2336 
2337 #endif
2338 
2339 				// Got it?
2340 				std::map<std::string, int>::iterator f(mounts.find(mountName));
2341 				if(f != mounts.end())
2342 				{
2343 					// Yes -- store the index
2344 					apLoc->mIDMapIndex = f->second;
2345 				}
2346 				else
2347 				{
2348 					// No -- new index
2349 					apLoc->mIDMapIndex = numIDMaps;
2350 					mounts[mountName] = numIDMaps;
2351 
2352 					// Store the mount name
2353 					mIDMapMounts.push_back(mountName);
2354 
2355 					// Increment number of maps
2356 					++numIDMaps;
2357 				}
2358 			}
2359 
2360 			// Does this exist on the server?
2361 			if(en == 0)
2362 			{
2363 				// Doesn't exist, so it has to be created on the server. Let's go!
2364 				// First, get the directory's attributes and modification time
2365 				box_time_t attrModTime = 0;
2366 				BackupClientFileAttributes attr;
2367 				try
2368 				{
2369 					attr.ReadAttributes(apLoc->mPath.c_str(),
2370 						true /* directories have zero mod times */,
2371 						0 /* not interested in mod time */,
2372 						&attrModTime /* get the attribute modification time */);
2373 				}
2374 				catch (BoxException &e)
2375 				{
2376 					BOX_ERROR("Failed to get attributes "
2377 						"for path '" << apLoc->mPath
2378 						<< "', skipping location '" <<
2379 						apLoc->mName << "'");
2380 					continue;
2381 				}
2382 
2383 				// Execute create directory command
2384 				try
2385 				{
2386 					MemBlockStream attrStream(attr);
2387 					std::auto_ptr<BackupProtocolClientSuccess>
2388 						dirCreate(connection.QueryCreateDirectory(
2389 						BackupProtocolClientListDirectory::RootDirectory,
2390 						attrModTime, dirname, attrStream));
2391 
2392 					// Object ID for later creation
2393 					oid = dirCreate->GetObjectID();
2394 				}
2395 				catch (BoxException &e)
2396 				{
2397 					BOX_ERROR("Failed to create remote "
2398 						"directory '/" << apLoc->mName <<
2399 						"', skipping location '" <<
2400 						apLoc->mName << "'");
2401 					continue;
2402 				}
2403 
2404 			}
2405 
2406 			// Create and store the directory object for the root of this location
2407 			ASSERT(oid != 0);
2408 			BackupClientDirectoryRecord *precord =
2409 				new BackupClientDirectoryRecord(oid, *pLocName);
2410 			apLoc->mpDirectoryRecord.reset(precord);
2411 
2412 			// Push it back on the vector of locations
2413 			mLocations.push_back(apLoc.release());
2414 		}
2415 		catch (std::exception &e)
2416 		{
2417 			BOX_ERROR("Failed to configure location '"
2418 				<< apLoc->mName << "' path '"
2419 				<< apLoc->mPath << "': " << e.what() <<
2420 				": please check for previous errors");
2421 			throw;
2422 		}
2423 		catch(...)
2424 		{
2425 			BOX_ERROR("Failed to configure location '"
2426 				<< apLoc->mName << "' path '"
2427 				<< apLoc->mPath << "': please check for "
2428 				"previous errors");
2429 			throw;
2430 		}
2431 	}
2432 
2433 	// Any entries in the root directory which need deleting?
2434 	if(dir.GetNumberOfEntries() > 0 &&
2435 		mDeleteRedundantLocationsAfter == 0)
2436 	{
2437 		BOX_NOTICE(dir.GetNumberOfEntries() << " redundant locations "
2438 			"in root directory found, but will not delete because "
2439 			"DeleteRedundantLocationsAfter = 0");
2440 	}
2441 	else if(dir.GetNumberOfEntries() > 0)
2442 	{
2443 		box_time_t now = GetCurrentBoxTime();
2444 
2445 		// This should reset the timer if the list of unused
2446 		// locations changes, but it will not if the number of
2447 		// unused locations does not change, but the locations
2448 		// do change, e.g. one mysteriously appears and another
2449 		// mysteriously appears. (FIXME)
2450 		if (dir.GetNumberOfEntries() != mUnusedRootDirEntries.size() ||
2451 			mDeleteUnusedRootDirEntriesAfter == 0)
2452 		{
2453 			mDeleteUnusedRootDirEntriesAfter = now +
2454 				SecondsToBoxTime(mDeleteRedundantLocationsAfter);
2455 		}
2456 
2457 		int secs = BoxTimeToSeconds(mDeleteUnusedRootDirEntriesAfter
2458 			- now);
2459 
2460 		BOX_NOTICE(dir.GetNumberOfEntries() << " redundant locations "
2461 			"in root directory found, will delete from store "
2462 			"after " << secs << " seconds.");
2463 
2464 		// Store directories in list of things to delete
2465 		mUnusedRootDirEntries.clear();
2466 		BackupStoreDirectory::Iterator iter(dir);
2467 		BackupStoreDirectory::Entry *en = 0;
2468 		while((en = iter.Next()) != 0)
2469 		{
2470 			// Add name to list
2471 			BackupStoreFilenameClear clear(en->GetName());
2472 			const std::string &name(clear.GetClearFilename());
2473 			mUnusedRootDirEntries.push_back(
2474 				std::pair<int64_t,std::string>
2475 				(en->GetObjectID(), name));
2476 			// Log this
2477 			BOX_INFO("Unused location in root: " << name);
2478 		}
2479 		ASSERT(mUnusedRootDirEntries.size() > 0);
2480 	}
2481 }
2482 
2483 
2484 // --------------------------------------------------------------------------
2485 //
2486 // Function
2487 //		Name:    BackupDaemon::SetupIDMapsForSync()
2488 //		Purpose: Sets up ID maps for the sync process -- make sure they're all there
2489 //		Created: 11/11/03
2490 //
2491 // --------------------------------------------------------------------------
SetupIDMapsForSync()2492 void BackupDaemon::SetupIDMapsForSync()
2493 {
2494 	// Make sure we have some blank, empty ID maps
2495 	DeleteIDMapVector(mNewIDMaps);
2496 	FillIDMapVector(mNewIDMaps, true /* new maps */);
2497 	DeleteIDMapVector(mCurrentIDMaps);
2498 	FillIDMapVector(mCurrentIDMaps, false /* new maps */);
2499 }
2500 
2501 
2502 // --------------------------------------------------------------------------
2503 //
2504 // Function
2505 //		Name:    BackupDaemon::FillIDMapVector(std::vector<BackupClientInodeToIDMap *> &)
2506 //		Purpose: Fills the vector with the right number of empty ID maps
2507 //		Created: 11/11/03
2508 //
2509 // --------------------------------------------------------------------------
FillIDMapVector(std::vector<BackupClientInodeToIDMap * > & rVector,bool NewMaps)2510 void BackupDaemon::FillIDMapVector(std::vector<BackupClientInodeToIDMap *> &rVector, bool NewMaps)
2511 {
2512 	ASSERT(rVector.size() == 0);
2513 	rVector.reserve(mIDMapMounts.size());
2514 
2515 	for(unsigned int l = 0; l < mIDMapMounts.size(); ++l)
2516 	{
2517 		// Create the object
2518 		BackupClientInodeToIDMap *pmap = new BackupClientInodeToIDMap();
2519 		try
2520 		{
2521 			// Get the base filename of this map
2522 			std::string filename;
2523 			MakeMapBaseName(l, filename);
2524 
2525 			// If it's a new one, add a suffix
2526 			if(NewMaps)
2527 			{
2528 				filename += ".n";
2529 			}
2530 
2531 			// If it's not a new map, it may not exist in which case an empty map should be created
2532 			if(!NewMaps && !FileExists(filename.c_str()))
2533 			{
2534 				pmap->OpenEmpty();
2535 			}
2536 			else
2537 			{
2538 				// Open the map
2539 				pmap->Open(filename.c_str(), !NewMaps /* read only */, NewMaps /* create new */);
2540 			}
2541 
2542 			// Store on vector
2543 			rVector.push_back(pmap);
2544 		}
2545 		catch(...)
2546 		{
2547 			delete pmap;
2548 			throw;
2549 		}
2550 	}
2551 }
2552 
2553 
2554 // --------------------------------------------------------------------------
2555 //
2556 // Function
2557 //		Name:    BackupDaemon::DeleteCorruptBerkelyDbFiles()
2558 //		Purpose: Delete the Berkely db files from disc after they have been corrupted.
2559 //		Created: 14/9/04
2560 //
2561 // --------------------------------------------------------------------------
DeleteCorruptBerkelyDbFiles()2562 void BackupDaemon::DeleteCorruptBerkelyDbFiles()
2563 {
2564 	for(unsigned int l = 0; l < mIDMapMounts.size(); ++l)
2565 	{
2566 		// Get the base filename of this map
2567 		std::string filename;
2568 		MakeMapBaseName(l, filename);
2569 
2570 		// Delete the file
2571 		BOX_TRACE("Deleting " << filename);
2572 		::unlink(filename.c_str());
2573 
2574 		// Add a suffix for the new map
2575 		filename += ".n";
2576 
2577 		// Delete that too
2578 		BOX_TRACE("Deleting " << filename);
2579 		::unlink(filename.c_str());
2580 	}
2581 }
2582 
2583 
2584 // --------------------------------------------------------------------------
2585 //
2586 // Function
2587 //		Name:    MakeMapBaseName(unsigned int, std::string &)
2588 //		Purpose: Makes the base name for a inode map
2589 //		Created: 20/11/03
2590 //
2591 // --------------------------------------------------------------------------
MakeMapBaseName(unsigned int MountNumber,std::string & rNameOut) const2592 void BackupDaemon::MakeMapBaseName(unsigned int MountNumber, std::string &rNameOut) const
2593 {
2594 	// Get the directory for the maps
2595 	const Configuration &config(GetConfiguration());
2596 	std::string dir(config.GetKeyValue("DataDirectory"));
2597 
2598 	// Make a leafname
2599 	std::string leaf(mIDMapMounts[MountNumber]);
2600 	for(unsigned int z = 0; z < leaf.size(); ++z)
2601 	{
2602 		if(leaf[z] == DIRECTORY_SEPARATOR_ASCHAR)
2603 		{
2604 			leaf[z] = '_';
2605 		}
2606 	}
2607 
2608 	// Build the final filename
2609 	rNameOut = dir + DIRECTORY_SEPARATOR "mnt" + leaf;
2610 }
2611 
2612 
2613 
2614 
2615 // --------------------------------------------------------------------------
2616 //
2617 // Function
2618 //		Name:    BackupDaemon::CommitIDMapsAfterSync()
2619 //		Purpose: Commits the new ID maps, so the 'new' maps are now the 'current' maps.
2620 //		Created: 11/11/03
2621 //
2622 // --------------------------------------------------------------------------
CommitIDMapsAfterSync()2623 void BackupDaemon::CommitIDMapsAfterSync()
2624 {
2625 	// Get rid of the maps in memory (leaving them on disc of course)
2626 	DeleteIDMapVector(mCurrentIDMaps);
2627 	DeleteIDMapVector(mNewIDMaps);
2628 
2629 	// Then move the old maps into the new places
2630 	for(unsigned int l = 0; l < mIDMapMounts.size(); ++l)
2631 	{
2632 		std::string target;
2633 		MakeMapBaseName(l, target);
2634 		std::string newmap(target + ".n");
2635 
2636 		// Try to rename
2637 #ifdef WIN32
2638 		// win32 rename doesn't overwrite existing files
2639 		::remove(target.c_str());
2640 #endif
2641 		if(::rename(newmap.c_str(), target.c_str()) != 0)
2642 		{
2643 			BOX_LOG_SYS_ERROR("Failed to rename ID map: " <<
2644 				newmap << " to " << target);
2645 			THROW_EXCEPTION(CommonException, OSFileError)
2646 		}
2647 	}
2648 }
2649 
2650 
2651 
2652 // --------------------------------------------------------------------------
2653 //
2654 // Function
2655 //		Name:    BackupDaemon::DeleteIDMapVector(std::vector<BackupClientInodeToIDMap *> &)
2656 //		Purpose: Deletes the contents of a vector of ID maps
2657 //		Created: 11/11/03
2658 //
2659 // --------------------------------------------------------------------------
DeleteIDMapVector(std::vector<BackupClientInodeToIDMap * > & rVector)2660 void BackupDaemon::DeleteIDMapVector(std::vector<BackupClientInodeToIDMap *> &rVector)
2661 {
2662 	while(!rVector.empty())
2663 	{
2664 		// Pop off list
2665 		BackupClientInodeToIDMap *toDel = rVector.back();
2666 		rVector.pop_back();
2667 
2668 		// Close and delete
2669 		delete toDel;
2670 	}
2671 	ASSERT(rVector.size() == 0);
2672 }
2673 
2674 
2675 // --------------------------------------------------------------------------
2676 //
2677 // Function
2678 //		Name:    BackupDaemon::FindLocationPathName(const std::string &, std::string &) const
2679 //		Purpose: Tries to find the path of the root of a backup location. Returns true (and path in rPathOut)
2680 //				 if it can be found, false otherwise.
2681 //		Created: 12/11/03
2682 //
2683 // --------------------------------------------------------------------------
FindLocationPathName(const std::string & rLocationName,std::string & rPathOut) const2684 bool BackupDaemon::FindLocationPathName(const std::string &rLocationName, std::string &rPathOut) const
2685 {
2686 	// Search for the location
2687 	for(std::vector<Location *>::const_iterator i(mLocations.begin()); i != mLocations.end(); ++i)
2688 	{
2689 		if((*i)->mName == rLocationName)
2690 		{
2691 			rPathOut = (*i)->mPath;
2692 			return true;
2693 		}
2694 	}
2695 
2696 	// Didn't find it
2697 	return false;
2698 }
2699 
2700 
2701 // --------------------------------------------------------------------------
2702 //
2703 // Function
2704 //		Name:    BackupDaemon::SetState(int)
2705 //		Purpose: Record current action of daemon, and update process title to reflect this
2706 //		Created: 11/12/03
2707 //
2708 // --------------------------------------------------------------------------
SetState(int State)2709 void BackupDaemon::SetState(int State)
2710 {
2711 	// Two little checks
2712 	if(State == mState) return;
2713 	if(State < 0) return;
2714 
2715 	// Update
2716 	mState = State;
2717 
2718 	// Set process title
2719 	const static char *stateText[] = {"idle", "connected", "error -- waiting for retry", "over limit on server -- not backing up"};
2720 	SetProcessTitle(stateText[State]);
2721 
2722 	// If there's a command socket connected, then inform it -- disconnecting from the
2723 	// command socket if there's an error
2724 
2725 	char newState[64];
2726 	sprintf(newState, "state %d", State);
2727 	std::string message = newState;
2728 
2729 	message += "\n";
2730 
2731 	if(!mapCommandSocketInfo.get())
2732 	{
2733 		return;
2734 	}
2735 
2736 	if(mapCommandSocketInfo->mpConnectedSocket.get() == 0)
2737 	{
2738 		return;
2739 	}
2740 
2741 	// Something connected to the command socket, tell it about the new state
2742 	try
2743 	{
2744 		mapCommandSocketInfo->mpConnectedSocket->Write(message.c_str(),
2745 			message.length());
2746 	}
2747 	catch(ConnectionException &ce)
2748 	{
2749 		BOX_NOTICE("Failed to write state to command socket: " <<
2750 			ce.what());
2751 		CloseCommandConnection();
2752 	}
2753 	catch(std::exception &e)
2754 	{
2755 		BOX_ERROR("Failed to write state to command socket: " <<
2756 			e.what());
2757 		CloseCommandConnection();
2758 	}
2759 	catch(...)
2760 	{
2761 		BOX_ERROR("Failed to write state to command socket: "
2762 			"unknown error");
2763 		CloseCommandConnection();
2764 	}
2765 }
2766 
2767 
2768 // --------------------------------------------------------------------------
2769 //
2770 // Function
2771 //		Name:    BackupDaemon::TouchFileInWorkingDir(const char *)
2772 //		Purpose: Make sure a zero length file of the name exists in the working directory.
2773 //				 Use for marking times of events in the filesystem.
2774 //		Created: 21/2/04
2775 //
2776 // --------------------------------------------------------------------------
TouchFileInWorkingDir(const char * Filename)2777 void BackupDaemon::TouchFileInWorkingDir(const char *Filename)
2778 {
2779 	// Filename
2780 	const Configuration &config(GetConfiguration());
2781 	std::string fn(config.GetKeyValue("DataDirectory") + DIRECTORY_SEPARATOR_ASCHAR);
2782 	fn += Filename;
2783 
2784 	// Open and close it to update the timestamp
2785 	try
2786 	{
2787 		FileStream touch(fn, O_WRONLY | O_CREAT | O_TRUNC,
2788 			S_IRUSR | S_IWUSR);
2789 	}
2790 	catch (std::exception &e)
2791 	{
2792 		BOX_ERROR("Failed to write to timestamp file: " << fn << ": " <<
2793 			e.what());
2794 	}
2795 }
2796 
2797 
2798 // --------------------------------------------------------------------------
2799 //
2800 // Function
2801 //		Name:    BackupDaemon::NotifySysadmin(int)
2802 //		Purpose: Run the script to tell the sysadmin about events
2803 //			 which need attention.
2804 //		Created: 25/2/04
2805 //
2806 // --------------------------------------------------------------------------
NotifySysadmin(SysadminNotifier::EventCode Event)2807 void BackupDaemon::NotifySysadmin(SysadminNotifier::EventCode Event)
2808 {
2809 	static const char *sEventNames[] =
2810 	{
2811 		"store-full",
2812 		"read-error",
2813 		"backup-error",
2814 		"backup-start",
2815 		"backup-finish",
2816 		"backup-ok",
2817 		0
2818 	};
2819 
2820 	// BOX_TRACE("sizeof(sEventNames)  == " << sizeof(sEventNames));
2821 	// BOX_TRACE("sizeof(*sEventNames) == " << sizeof(*sEventNames));
2822 	// BOX_TRACE("NotifyEvent__MAX == " << NotifyEvent__MAX);
2823 	ASSERT((sizeof(sEventNames)/sizeof(*sEventNames)) == SysadminNotifier::MAX + 1);
2824 
2825 	if(Event < 0 || Event >= SysadminNotifier::MAX)
2826 	{
2827 		BOX_ERROR("BackupDaemon::NotifySysadmin() called for "
2828 			"invalid event code " << Event);
2829 		THROW_EXCEPTION(BackupStoreException,
2830 			BadNotifySysadminEventCode);
2831 	}
2832 
2833 	BOX_TRACE("BackupDaemon::NotifySysadmin() called, event = " <<
2834 		sEventNames[Event]);
2835 
2836 	if(!GetConfiguration().KeyExists("NotifyAlways") ||
2837 		!GetConfiguration().GetKeyValueBool("NotifyAlways"))
2838 	{
2839 		// Don't send lots of repeated messages
2840 		// Note: backup-start and backup-finish will always be
2841 		// logged, because mLastNotifiedEvent is never set to
2842 		// these values and therefore they are never "duplicates".
2843 		if(mLastNotifiedEvent == Event)
2844 		{
2845 			if(Event == SysadminNotifier::BackupOK)
2846 			{
2847 				BOX_INFO("Suppressing duplicate notification "
2848 					"about " << sEventNames[Event]);
2849 			}
2850 			else
2851 			{
2852 				BOX_WARNING("Suppressing duplicate notification "
2853 					"about " << sEventNames[Event]);
2854 			}
2855 			return;
2856 		}
2857 	}
2858 
2859 	// Is there a notification script?
2860 	const Configuration &conf(GetConfiguration());
2861 	if(!conf.KeyExists("NotifyScript"))
2862 	{
2863 		// Log, and then return
2864 		if(Event != SysadminNotifier::BackupStart &&
2865 			Event != SysadminNotifier::BackupFinish)
2866 		{
2867 			BOX_INFO("Not notifying administrator about event "
2868 				<< sEventNames[Event] << ", set NotifyScript "
2869 				"to do this in future");
2870 		}
2871 		return;
2872 	}
2873 
2874 	// Script to run
2875 	std::string script(conf.GetKeyValue("NotifyScript") + " " +
2876 		sEventNames[Event] + " \"" + GetConfigFileName() + "\"");
2877 
2878 	// Log what we're about to do
2879 	BOX_INFO("About to notify administrator about event "
2880 		<< sEventNames[Event] << ", running script '" << script << "'");
2881 
2882 	// Then do it
2883 	int returnCode = ::system(script.c_str());
2884 	if(returnCode != 0)
2885 	{
2886 		BOX_WARNING("Notify script returned error code: " <<
2887 			returnCode << " (" << script << ")");
2888 	}
2889 	else if(Event != SysadminNotifier::BackupStart &&
2890 		Event != SysadminNotifier::BackupFinish)
2891 	{
2892 		mLastNotifiedEvent = Event;
2893 	}
2894 }
2895 
2896 
2897 // --------------------------------------------------------------------------
2898 //
2899 // Function
2900 //		Name:    BackupDaemon::DeleteUnusedRootDirEntries(BackupClientContext &)
2901 //		Purpose: Deletes any unused entries in the root directory, if they're scheduled to be deleted.
2902 //		Created: 13/5/04
2903 //
2904 // --------------------------------------------------------------------------
DeleteUnusedRootDirEntries(BackupClientContext & rContext)2905 void BackupDaemon::DeleteUnusedRootDirEntries(BackupClientContext &rContext)
2906 {
2907 	if(mUnusedRootDirEntries.empty())
2908 	{
2909 		BOX_INFO("Not deleting unused entries - none in list");
2910 		return;
2911 	}
2912 
2913 	if(mDeleteUnusedRootDirEntriesAfter == 0)
2914 	{
2915 		BOX_INFO("Not deleting unused entries - "
2916 			"zero delete time (bad)");
2917 		return;
2918 	}
2919 
2920 	// Check time
2921 	box_time_t now = GetCurrentBoxTime();
2922 	if(now < mDeleteUnusedRootDirEntriesAfter)
2923 	{
2924 		int secs = BoxTimeToSeconds(mDeleteUnusedRootDirEntriesAfter
2925 			- now);
2926 		BOX_INFO("Not deleting unused entries - too early ("
2927 			<< secs << " seconds remaining)");
2928 		return;
2929 	}
2930 
2931 	// Entries to delete, and it's the right time to do so...
2932 	BOX_NOTICE("Deleting unused locations from store root...");
2933 	BackupProtocolClient &connection(rContext.GetConnection());
2934 	for(std::vector<std::pair<int64_t,std::string> >::iterator
2935 		i(mUnusedRootDirEntries.begin());
2936 		i != mUnusedRootDirEntries.end(); ++i)
2937 	{
2938 		connection.QueryDeleteDirectory(i->first);
2939 		rContext.GetProgressNotifier().NotifyFileDeleted(
2940 			i->first, i->second);
2941 	}
2942 
2943 	// Reset state
2944 	mDeleteUnusedRootDirEntriesAfter = 0;
2945 	mUnusedRootDirEntries.clear();
2946 }
2947 
2948 // --------------------------------------------------------------------------
2949 
2950 typedef struct
2951 {
2952 	int32_t mMagicValue;	// also the version number
2953 	int32_t mNumEntries;
2954 	int64_t mObjectID;		// this object ID
2955 	int64_t mContainerID;	// ID of container
2956 	uint64_t mAttributesModTime;
2957 	int32_t mOptionsPresent;	// bit mask of optional sections / features present
2958 
2959 } loc_StreamFormat;
2960 
2961 // --------------------------------------------------------------------------
2962 //
2963 // Function
2964 //		Name:    BackupDaemon::Location::Location()
2965 //		Purpose: Constructor
2966 //		Created: 11/11/03
2967 //
2968 // --------------------------------------------------------------------------
Location()2969 BackupDaemon::Location::Location()
2970 	: mIDMapIndex(0),
2971 	  mpExcludeFiles(0),
2972 	  mpExcludeDirs(0)
2973 {
2974 }
2975 
2976 // --------------------------------------------------------------------------
2977 //
2978 // Function
2979 //		Name:    BackupDaemon::Location::~Location()
2980 //		Purpose: Destructor
2981 //		Created: 11/11/03
2982 //
2983 // --------------------------------------------------------------------------
~Location()2984 BackupDaemon::Location::~Location()
2985 {
2986 	// Clean up exclude locations
2987 	if(mpExcludeDirs != 0)
2988 	{
2989 		delete mpExcludeDirs;
2990 		mpExcludeDirs = 0;
2991 	}
2992 	if(mpExcludeFiles != 0)
2993 	{
2994 		delete mpExcludeFiles;
2995 		mpExcludeFiles = 0;
2996 	}
2997 }
2998 
2999 // --------------------------------------------------------------------------
3000 //
3001 // Function
3002 //		Name:    BackupDaemon::Location::Deserialize(Archive & rArchive)
3003 //		Purpose: Deserializes this object instance from a stream of bytes, using an Archive abstraction.
3004 //
3005 //		Created: 2005/04/11
3006 //
3007 // --------------------------------------------------------------------------
Deserialize(Archive & rArchive)3008 void BackupDaemon::Location::Deserialize(Archive &rArchive)
3009 {
3010 	//
3011 	//
3012 	//
3013 	mpDirectoryRecord.reset(NULL);
3014 	if(mpExcludeFiles)
3015 	{
3016 		delete mpExcludeFiles;
3017 		mpExcludeFiles = NULL;
3018 	}
3019 	if(mpExcludeDirs)
3020 	{
3021 		delete mpExcludeDirs;
3022 		mpExcludeDirs = NULL;
3023 	}
3024 
3025 	//
3026 	//
3027 	//
3028 	rArchive.Read(mName);
3029 	rArchive.Read(mPath);
3030 	rArchive.Read(mIDMapIndex);
3031 
3032 	//
3033 	//
3034 	//
3035 	int64_t aMagicMarker = 0;
3036 	rArchive.Read(aMagicMarker);
3037 
3038 	if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
3039 	{
3040 		// NOOP
3041 	}
3042 	else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
3043 	{
3044 		BackupClientDirectoryRecord *pSubRecord = new BackupClientDirectoryRecord(0, "");
3045 		if(!pSubRecord)
3046 		{
3047 			throw std::bad_alloc();
3048 		}
3049 
3050 		mpDirectoryRecord.reset(pSubRecord);
3051 		mpDirectoryRecord->Deserialize(rArchive);
3052 	}
3053 	else
3054 	{
3055 		// there is something going on here
3056 		THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile);
3057 	}
3058 
3059 	//
3060 	//
3061 	//
3062 	rArchive.Read(aMagicMarker);
3063 
3064 	if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
3065 	{
3066 		// NOOP
3067 	}
3068 	else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
3069 	{
3070 		mpExcludeFiles = new ExcludeList;
3071 		if(!mpExcludeFiles)
3072 		{
3073 			throw std::bad_alloc();
3074 		}
3075 
3076 		mpExcludeFiles->Deserialize(rArchive);
3077 	}
3078 	else
3079 	{
3080 		// there is something going on here
3081 		THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile);
3082 	}
3083 
3084 	//
3085 	//
3086 	//
3087 	rArchive.Read(aMagicMarker);
3088 
3089 	if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
3090 	{
3091 		// NOOP
3092 	}
3093 	else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
3094 	{
3095 		mpExcludeDirs = new ExcludeList;
3096 		if(!mpExcludeDirs)
3097 		{
3098 			throw std::bad_alloc();
3099 		}
3100 
3101 		mpExcludeDirs->Deserialize(rArchive);
3102 	}
3103 	else
3104 	{
3105 		// there is something going on here
3106 		THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile);
3107 	}
3108 }
3109 
3110 // --------------------------------------------------------------------------
3111 //
3112 // Function
3113 //		Name:    BackupDaemon::Location::Serialize(Archive & rArchive)
3114 //		Purpose: Serializes this object instance into a stream of bytes, using an Archive abstraction.
3115 //
3116 //		Created: 2005/04/11
3117 //
3118 // --------------------------------------------------------------------------
Serialize(Archive & rArchive) const3119 void BackupDaemon::Location::Serialize(Archive & rArchive) const
3120 {
3121 	//
3122 	//
3123 	//
3124 	rArchive.Write(mName);
3125 	rArchive.Write(mPath);
3126 	rArchive.Write(mIDMapIndex);
3127 
3128 	//
3129 	//
3130 	//
3131 	if(mpDirectoryRecord.get() == NULL)
3132 	{
3133 		int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
3134 		rArchive.Write(aMagicMarker);
3135 	}
3136 	else
3137 	{
3138 		int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_RECURSE; // be explicit about whether recursion follows
3139 		rArchive.Write(aMagicMarker);
3140 
3141 		mpDirectoryRecord->Serialize(rArchive);
3142 	}
3143 
3144 	//
3145 	//
3146 	//
3147 	if(!mpExcludeFiles)
3148 	{
3149 		int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
3150 		rArchive.Write(aMagicMarker);
3151 	}
3152 	else
3153 	{
3154 		int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_RECURSE; // be explicit about whether recursion follows
3155 		rArchive.Write(aMagicMarker);
3156 
3157 		mpExcludeFiles->Serialize(rArchive);
3158 	}
3159 
3160 	//
3161 	//
3162 	//
3163 	if(!mpExcludeDirs)
3164 	{
3165 		int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
3166 		rArchive.Write(aMagicMarker);
3167 	}
3168 	else
3169 	{
3170 		int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_RECURSE; // be explicit about whether recursion follows
3171 		rArchive.Write(aMagicMarker);
3172 
3173 		mpExcludeDirs->Serialize(rArchive);
3174 	}
3175 }
3176 
3177 // --------------------------------------------------------------------------
3178 //
3179 // Function
3180 //		Name:    BackupDaemon::CommandSocketInfo::CommandSocketInfo()
3181 //		Purpose: Constructor
3182 //		Created: 18/2/04
3183 //
3184 // --------------------------------------------------------------------------
CommandSocketInfo()3185 BackupDaemon::CommandSocketInfo::CommandSocketInfo()
3186 	: mpGetLine(0)
3187 {
3188 }
3189 
3190 
3191 // --------------------------------------------------------------------------
3192 //
3193 // Function
3194 //		Name:    BackupDaemon::CommandSocketInfo::~CommandSocketInfo()
3195 //		Purpose: Destructor
3196 //		Created: 18/2/04
3197 //
3198 // --------------------------------------------------------------------------
~CommandSocketInfo()3199 BackupDaemon::CommandSocketInfo::~CommandSocketInfo()
3200 {
3201 	if(mpGetLine)
3202 	{
3203 		delete mpGetLine;
3204 		mpGetLine = 0;
3205 	}
3206 }
3207 
3208 // --------------------------------------------------------------------------
3209 //
3210 // Function
3211 //		Name:    BackupDaemon::SerializeStoreObjectInfo(
3212 //			 box_time_t theLastSyncTime,
3213 //			 box_time_t theNextSyncTime)
3214 //		Purpose: Serializes remote directory and file information
3215 //			 into a stream of bytes, using an Archive
3216 //			 abstraction.
3217 //		Created: 2005/04/11
3218 //
3219 // --------------------------------------------------------------------------
3220 
3221 static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F;
3222 static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE";
3223 static const int STOREOBJECTINFO_VERSION = 2;
3224 
SerializeStoreObjectInfo(box_time_t theLastSyncTime,box_time_t theNextSyncTime) const3225 bool BackupDaemon::SerializeStoreObjectInfo(box_time_t theLastSyncTime,
3226 	box_time_t theNextSyncTime) const
3227 {
3228 	if(!GetConfiguration().KeyExists("StoreObjectInfoFile"))
3229 	{
3230 		return false;
3231 	}
3232 
3233 	std::string StoreObjectInfoFile =
3234 		GetConfiguration().GetKeyValue("StoreObjectInfoFile");
3235 
3236 	if(StoreObjectInfoFile.size() <= 0)
3237 	{
3238 		return false;
3239 	}
3240 
3241 	bool created = false;
3242 
3243 	try
3244 	{
3245 		FileStream aFile(StoreObjectInfoFile.c_str(),
3246 			O_WRONLY | O_CREAT | O_TRUNC);
3247 		created = true;
3248 
3249 		Archive anArchive(aFile, 0);
3250 
3251 		anArchive.Write(STOREOBJECTINFO_MAGIC_ID_VALUE);
3252 		anArchive.Write(STOREOBJECTINFO_MAGIC_ID_STRING);
3253 		anArchive.Write(STOREOBJECTINFO_VERSION);
3254 		anArchive.Write(GetLoadedConfigModifiedTime());
3255 		anArchive.Write(mClientStoreMarker);
3256 		anArchive.Write(theLastSyncTime);
3257 		anArchive.Write(theNextSyncTime);
3258 
3259 		//
3260 		//
3261 		//
3262 		int64_t iCount = mLocations.size();
3263 		anArchive.Write(iCount);
3264 
3265 		for(int v = 0; v < iCount; v++)
3266 		{
3267 			ASSERT(mLocations[v]);
3268 			mLocations[v]->Serialize(anArchive);
3269 		}
3270 
3271 		//
3272 		//
3273 		//
3274 		iCount = mIDMapMounts.size();
3275 		anArchive.Write(iCount);
3276 
3277 		for(int v = 0; v < iCount; v++)
3278 			anArchive.Write(mIDMapMounts[v]);
3279 
3280 		//
3281 		//
3282 		//
3283 		iCount = mUnusedRootDirEntries.size();
3284 		anArchive.Write(iCount);
3285 
3286 		for(int v = 0; v < iCount; v++)
3287 		{
3288 			anArchive.Write(mUnusedRootDirEntries[v].first);
3289 			anArchive.Write(mUnusedRootDirEntries[v].second);
3290 		}
3291 
3292 		if (iCount > 0)
3293 		{
3294 			anArchive.Write(mDeleteUnusedRootDirEntriesAfter);
3295 		}
3296 
3297 		//
3298 		//
3299 		//
3300 		aFile.Close();
3301 		BOX_INFO("Saved store object info file version " <<
3302 			STOREOBJECTINFO_VERSION << " (" <<
3303 			StoreObjectInfoFile << ")");
3304 	}
3305 	catch(std::exception &e)
3306 	{
3307 		BOX_ERROR("Failed to write StoreObjectInfoFile: " <<
3308 			StoreObjectInfoFile << ": " << e.what());
3309 	}
3310 	catch(...)
3311 	{
3312 		BOX_ERROR("Failed to write StoreObjectInfoFile: " <<
3313 			StoreObjectInfoFile << ": unknown error");
3314 	}
3315 
3316 	return created;
3317 }
3318 
3319 // --------------------------------------------------------------------------
3320 //
3321 // Function
3322 //		Name:    BackupDaemon::DeserializeStoreObjectInfo(
3323 //			 box_time_t & theLastSyncTime,
3324 //			 box_time_t & theNextSyncTime)
3325 //		Purpose: Deserializes remote directory and file information
3326 //			 from a stream of bytes, using an Archive
3327 //			 abstraction.
3328 //		Created: 2005/04/11
3329 //
3330 // --------------------------------------------------------------------------
DeserializeStoreObjectInfo(box_time_t & theLastSyncTime,box_time_t & theNextSyncTime)3331 bool BackupDaemon::DeserializeStoreObjectInfo(box_time_t & theLastSyncTime,
3332 	box_time_t & theNextSyncTime)
3333 {
3334 	//
3335 	//
3336 	//
3337 	DeleteAllLocations();
3338 
3339 	//
3340 	//
3341 	//
3342 	if(!GetConfiguration().KeyExists("StoreObjectInfoFile"))
3343 	{
3344 		return false;
3345 	}
3346 
3347 	std::string StoreObjectInfoFile =
3348 		GetConfiguration().GetKeyValue("StoreObjectInfoFile");
3349 
3350 	if(StoreObjectInfoFile.size() <= 0)
3351 	{
3352 		return false;
3353 	}
3354 
3355 	try
3356 	{
3357 		FileStream aFile(StoreObjectInfoFile.c_str(), O_RDONLY);
3358 		Archive anArchive(aFile, 0);
3359 
3360 		//
3361 		// see if the content looks like a valid serialised archive
3362 		//
3363 		int iMagicValue = 0;
3364 		anArchive.Read(iMagicValue);
3365 
3366 		if(iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE)
3367 		{
3368 			BOX_WARNING("Store object info file "
3369 				"is not a valid or compatible serialised "
3370 				"archive. Will re-cache from store. "
3371 				"(" << StoreObjectInfoFile << ")");
3372 			return false;
3373 		}
3374 
3375 		//
3376 		// get a bit optimistic and read in a string identifier
3377 		//
3378 		std::string strMagicValue;
3379 		anArchive.Read(strMagicValue);
3380 
3381 		if(strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING)
3382 		{
3383 			BOX_WARNING("Store object info file "
3384 				"is not a valid or compatible serialised "
3385 				"archive. Will re-cache from store. "
3386 				"(" << StoreObjectInfoFile << ")");
3387 			return false;
3388 		}
3389 
3390 		//
3391 		// check if we are loading some future format
3392 		// version by mistake
3393 		//
3394 		int iVersion = 0;
3395 		anArchive.Read(iVersion);
3396 
3397 		if(iVersion != STOREOBJECTINFO_VERSION)
3398 		{
3399 			BOX_WARNING("Store object info file "
3400 				"version " << iVersion << " unsupported. "
3401 				"Will re-cache from store. "
3402 				"(" << StoreObjectInfoFile << ")");
3403 			return false;
3404 		}
3405 
3406 		//
3407 		// check if this state file is even valid
3408 		// for the loaded bbackupd.conf file
3409 		//
3410 		box_time_t lastKnownConfigModTime;
3411 		anArchive.Read(lastKnownConfigModTime);
3412 
3413 		if(lastKnownConfigModTime != GetLoadedConfigModifiedTime())
3414 		{
3415 			BOX_WARNING("Store object info file "
3416 				"out of date. Will re-cache from store. "
3417 				"(" << StoreObjectInfoFile << ")");
3418 			return false;
3419 		}
3420 
3421 		//
3422 		// this is it, go at it
3423 		//
3424 		anArchive.Read(mClientStoreMarker);
3425 		anArchive.Read(theLastSyncTime);
3426 		anArchive.Read(theNextSyncTime);
3427 
3428 		//
3429 		//
3430 		//
3431 		int64_t iCount = 0;
3432 		anArchive.Read(iCount);
3433 
3434 		for(int v = 0; v < iCount; v++)
3435 		{
3436 			Location* pLocation = new Location;
3437 			if(!pLocation)
3438 			{
3439 				throw std::bad_alloc();
3440 			}
3441 
3442 			pLocation->Deserialize(anArchive);
3443 			mLocations.push_back(pLocation);
3444 		}
3445 
3446 		//
3447 		//
3448 		//
3449 		iCount = 0;
3450 		anArchive.Read(iCount);
3451 
3452 		for(int v = 0; v < iCount; v++)
3453 		{
3454 			std::string strItem;
3455 			anArchive.Read(strItem);
3456 
3457 			mIDMapMounts.push_back(strItem);
3458 		}
3459 
3460 		//
3461 		//
3462 		//
3463 		iCount = 0;
3464 		anArchive.Read(iCount);
3465 
3466 		for(int v = 0; v < iCount; v++)
3467 		{
3468 			int64_t anId;
3469 			anArchive.Read(anId);
3470 
3471 			std::string aName;
3472 			anArchive.Read(aName);
3473 
3474 			mUnusedRootDirEntries.push_back(std::pair<int64_t, std::string>(anId, aName));
3475 		}
3476 
3477 		if (iCount > 0)
3478 			anArchive.Read(mDeleteUnusedRootDirEntriesAfter);
3479 
3480 		//
3481 		//
3482 		//
3483 		aFile.Close();
3484 		BOX_INFO("Loaded store object info file version " << iVersion
3485 			<< " (" << StoreObjectInfoFile << ")");
3486 
3487 		return true;
3488 	}
3489 	catch(std::exception &e)
3490 	{
3491 		BOX_ERROR("Internal error reading store object info file: "
3492 			<< StoreObjectInfoFile << ": " << e.what());
3493 	}
3494 	catch(...)
3495 	{
3496 		BOX_ERROR("Internal error reading store object info file: "
3497 			<< StoreObjectInfoFile << ": unknown error");
3498 	}
3499 
3500 	DeleteAllLocations();
3501 
3502 	mClientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown;
3503 	theLastSyncTime = 0;
3504 	theNextSyncTime = 0;
3505 
3506 	BOX_WARNING("Store object info file is missing, not accessible, "
3507 		"or inconsistent. Will re-cache from store. "
3508 		"(" << StoreObjectInfoFile << ")");
3509 
3510 	return false;
3511 }
3512 
3513 // --------------------------------------------------------------------------
3514 //
3515 // Function
3516 //		Name:    BackupDaemon::DeleteStoreObjectInfo()
3517 //		Purpose: Deletes the serialised state file, to prevent us
3518 //			 from using it again if a backup is interrupted.
3519 //
3520 //		Created: 2006/02/12
3521 //
3522 // --------------------------------------------------------------------------
3523 
DeleteStoreObjectInfo() const3524 bool BackupDaemon::DeleteStoreObjectInfo() const
3525 {
3526 	if(!GetConfiguration().KeyExists("StoreObjectInfoFile"))
3527 	{
3528 		return false;
3529 	}
3530 
3531 	std::string storeObjectInfoFile(GetConfiguration().GetKeyValue("StoreObjectInfoFile"));
3532 
3533 	// Check to see if the file exists
3534 	if(!FileExists(storeObjectInfoFile.c_str()))
3535 	{
3536 		// File doesn't exist -- so can't be deleted. But something
3537 		// isn't quite right, so log a message
3538 		BOX_WARNING("StoreObjectInfoFile did not exist when it "
3539 			"was supposed to: " << storeObjectInfoFile);
3540 
3541 		// Return true to stop things going around in a loop
3542 		return true;
3543 	}
3544 
3545 	// Actually delete it
3546 	if(::unlink(storeObjectInfoFile.c_str()) != 0)
3547 	{
3548 		BOX_LOG_SYS_ERROR("Failed to delete the old "
3549 			"StoreObjectInfoFile: " << storeObjectInfoFile);
3550 		return false;
3551 	}
3552 
3553 	return true;
3554 }
3555