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.h
47 //		Purpose: Backup daemon
48 //		Created: 2003/10/08
49 //
50 // --------------------------------------------------------------------------
51 
52 #ifndef BACKUPDAEMON__H
53 #define BACKUPDAEMON__H
54 
55 #include <vector>
56 #include <string>
57 #include <memory>
58 
59 #include "BackupClientContext.h"
60 #include "BackupClientDirectoryRecord.h"
61 #include "BoxTime.h"
62 #include "Daemon.h"
63 #include "Logging.h"
64 #include "Socket.h"
65 #include "SocketListen.h"
66 #include "SocketStream.h"
67 #include "TLSContext.h"
68 
69 #include "autogen_BackupProtocolClient.h"
70 
71 #ifdef WIN32
72 	#include "WinNamedPipeListener.h"
73 	#include "WinNamedPipeStream.h"
74 #endif
75 
76 #ifdef ENABLE_VSS
77 #	include <comdef.h>
78 #	include <Vss.h>
79 #	include <VsWriter.h>
80 #	include <VsBackup.h>
81 #endif
82 
83 class BackupClientDirectoryRecord;
84 class BackupClientContext;
85 class Configuration;
86 class BackupClientInodeToIDMap;
87 class ExcludeList;
88 class IOStreamGetLine;
89 class Archive;
90 
91 // --------------------------------------------------------------------------
92 //
93 // Class
94 //		Name:    BackupDaemon
95 //		Purpose: Backup daemon
96 //		Created: 2003/10/08
97 //
98 // --------------------------------------------------------------------------
99 class BackupDaemon : public Daemon, ProgressNotifier, LocationResolver,
100 RunStatusProvider, SysadminNotifier
101 {
102 public:
103 	BackupDaemon();
104 	~BackupDaemon();
105 
106 private:
107 	// methods below do partial (specialized) serialization of
108 	// client state only
109 	bool SerializeStoreObjectInfo(box_time_t theLastSyncTime,
110 		box_time_t theNextSyncTime) const;
111 	bool DeserializeStoreObjectInfo(box_time_t & theLastSyncTime,
112 		box_time_t & theNextSyncTime);
113 	bool DeleteStoreObjectInfo() const;
114 	BackupDaemon(const BackupDaemon &);
115 
116 public:
117 	#ifdef WIN32
118 		// add command-line options to handle Windows services
119 		std::string GetOptionString();
120 		int ProcessOption(signed int option);
121 		int Main(const std::string &rConfigFileName);
122 
123 		// This shouldn't be here, but apparently gcc on
124 		// Windows has no idea about inherited methods...
Main(const char * DefaultConfigFile,int argc,const char * argv[])125 		virtual int Main(const char *DefaultConfigFile, int argc,
126 			const char *argv[])
127 		{
128 			return Daemon::Main(DefaultConfigFile, argc, argv);
129 		}
130 	#endif
131 
132 	void Run();
133 	virtual const char *DaemonName() const;
134 	virtual std::string DaemonBanner() const;
135 	virtual void Usage();
136 	const ConfigurationVerify *GetConfigVerify() const;
137 
138 	bool FindLocationPathName(const std::string &rLocationName, std::string &rPathOut) const;
139 
140 	enum
141 	{
142 		// Add stuff to this, make sure the textual equivalents in SetState() are changed too.
143 		State_Initialising = -1,
144 		State_Idle = 0,
145 		State_Connected = 1,
146 		State_Error = 2,
147 		State_StorageLimitExceeded = 3
148 	};
149 
GetState()150 	int GetState() {return mState;}
151 
152 	// Allow other classes to call this too
153 	void NotifySysadmin(SysadminNotifier::EventCode Event);
154 
155 private:
156 	void Run2();
157 
158 public:
159 	void InitCrypto();
160 	void RunSyncNowWithExceptionHandling();
161 	void RunSyncNow();
162 	void OnBackupStart();
163 	void OnBackupFinish();
164 	// TouchFileInWorkingDir is only here for use by Boxi.
165 	// This does NOT constitute an API!
166 	void TouchFileInWorkingDir(const char *Filename);
167 
168 private:
169 	void DeleteAllLocations();
170 	void SetupLocations(BackupClientContext &rClientContext, const Configuration &rLocationsConf);
171 
172 	void DeleteIDMapVector(std::vector<BackupClientInodeToIDMap *> &rVector);
DeleteAllIDMaps()173 	void DeleteAllIDMaps()
174 	{
175 		DeleteIDMapVector(mCurrentIDMaps);
176 		DeleteIDMapVector(mNewIDMaps);
177 	}
178 	void FillIDMapVector(std::vector<BackupClientInodeToIDMap *> &rVector, bool NewMaps);
179 
180 	void SetupIDMapsForSync();
181 	void CommitIDMapsAfterSync();
182 	void DeleteCorruptBerkelyDbFiles();
183 
184 	void MakeMapBaseName(unsigned int MountNumber, std::string &rNameOut) const;
185 
186 	void SetState(int State);
187 
188 	void WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut);
189 	void CloseCommandConnection();
190 	void SendSyncStartOrFinish(bool SendStart);
191 
192 	void DeleteUnusedRootDirEntries(BackupClientContext &rContext);
193 
194 #ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
195 	// For warning user about potential security hole
196 	virtual void SetupInInitialProcess();
197 #endif
198 
199 	int UseScriptToSeeIfSyncAllowed();
200 
201 public:
202 	class Location
203 	{
204 	public:
205 		Location();
206 		~Location();
207 
208 		void Deserialize(Archive & rArchive);
209 		void Serialize(Archive & rArchive) const;
210 	private:
211 		Location(const Location &);	// copy not allowed
212 		Location &operator=(const Location &);
213 	public:
214 		std::string mName;
215 		std::string mPath;
216 		std::auto_ptr<BackupClientDirectoryRecord> mpDirectoryRecord;
217 		int mIDMapIndex;
218 		ExcludeList *mpExcludeFiles;
219 		ExcludeList *mpExcludeDirs;
220 
221 #ifdef ENABLE_VSS
222 		bool mIsSnapshotCreated;
223 		VSS_ID mSnapshotVolumeId;
224 		std::string mSnapshotPath;
225 #endif
226 	};
227 
228 	typedef const std::vector<Location *> Locations;
GetLocations()229 	Locations GetLocations() { return mLocations; }
230 
231 private:
232 	int mState;		// what the daemon is currently doing
233 
234 	std::vector<Location *> mLocations;
235 
236 	std::vector<std::string> mIDMapMounts;
237 	std::vector<BackupClientInodeToIDMap *> mCurrentIDMaps;
238 	std::vector<BackupClientInodeToIDMap *> mNewIDMaps;
239 
240 	int mDeleteRedundantLocationsAfter;
241 
242 	// For the command socket
243 	class CommandSocketInfo
244 	{
245 	public:
246 		CommandSocketInfo();
247 		~CommandSocketInfo();
248 	private:
249 		CommandSocketInfo(const CommandSocketInfo &);	// no copying
250 		CommandSocketInfo &operator=(const CommandSocketInfo &);
251 	public:
252 #ifdef WIN32
253 		WinNamedPipeListener<1 /* listen backlog */> mListeningSocket;
254 		std::auto_ptr<WinNamedPipeStream> mpConnectedSocket;
255 #else
256 		SocketListen<SocketStream, 1 /* listen backlog */> mListeningSocket;
257 		std::auto_ptr<SocketStream> mpConnectedSocket;
258 #endif
259 		IOStreamGetLine *mpGetLine;
260 	};
261 
262 	// Using a socket?
263 	std::auto_ptr<CommandSocketInfo> mapCommandSocketInfo;
264 
265 	// Stop notifications being repeated.
266 	SysadminNotifier::EventCode mLastNotifiedEvent;
267 
268 	// Unused entries in the root directory wait a while before being deleted
269 	box_time_t mDeleteUnusedRootDirEntriesAfter;	// time to delete them
270 	std::vector<std::pair<int64_t,std::string> > mUnusedRootDirEntries;
271 
272 	int64_t mClientStoreMarker;
273 	bool mStorageLimitExceeded;
274 	bool mReadErrorsOnFilesystemObjects;
275 	box_time_t mLastSyncTime, mNextSyncTime;
276 	box_time_t mCurrentSyncStartTime, mUpdateStoreInterval;
277 	TLSContext mTlsContext;
278 	bool mDeleteStoreObjectInfoFile;
279 	bool mDoSyncForcedByPreviousSyncError;
280 
281 public:
StopRun()282  	bool StopRun() { return this->Daemon::StopRun(); }
StorageLimitExceeded()283 	bool StorageLimitExceeded() { return mStorageLimitExceeded; }
284 
285 private:
286 	bool mLogAllFileAccess;
287 
288 public:
GetProgressNotifier()289 	ProgressNotifier*  GetProgressNotifier()  { return mpProgressNotifier; }
GetLocationResolver()290 	LocationResolver*  GetLocationResolver()  { return mpLocationResolver; }
GetRunStatusProvider()291 	RunStatusProvider* GetRunStatusProvider() { return mpRunStatusProvider; }
GetSysadminNotifier()292 	SysadminNotifier*  GetSysadminNotifier()  { return mpSysadminNotifier; }
SetProgressNotifier(ProgressNotifier * p)293 	void SetProgressNotifier (ProgressNotifier*  p) { mpProgressNotifier = p; }
SetLocationResolver(LocationResolver * p)294 	void SetLocationResolver (LocationResolver*  p) { mpLocationResolver = p; }
SetRunStatusProvider(RunStatusProvider * p)295 	void SetRunStatusProvider(RunStatusProvider* p) { mpRunStatusProvider = p; }
SetSysadminNotifier(SysadminNotifier * p)296 	void SetSysadminNotifier (SysadminNotifier*  p) { mpSysadminNotifier = p; }
297 
298 private:
299 	ProgressNotifier* mpProgressNotifier;
300 	LocationResolver* mpLocationResolver;
301 	RunStatusProvider* mpRunStatusProvider;
302 	SysadminNotifier* mpSysadminNotifier;
303 
304  	/* ProgressNotifier implementation */
305 public:
NotifyIDMapsSetup(BackupClientContext & rContext)306 	virtual void NotifyIDMapsSetup(BackupClientContext& rContext) { }
307 
NotifyScanDirectory(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)308  	virtual void NotifyScanDirectory(
309  		const BackupClientDirectoryRecord* pDirRecord,
310  		const std::string& rLocalPath)
311 	{
312 		if (mLogAllFileAccess)
313 		{
314 			BOX_INFO("Scanning directory: " << rLocalPath);
315 		}
316 	}
NotifyDirStatFailed(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath,const std::string & rErrorMsg)317  	virtual void NotifyDirStatFailed(
318  		const BackupClientDirectoryRecord* pDirRecord,
319  		const std::string& rLocalPath,
320  		const std::string& rErrorMsg)
321  	{
322 		BOX_WARNING("Failed to access directory: " << rLocalPath
323 			<< ": " << rErrorMsg);
324  	}
NotifyFileStatFailed(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath,const std::string & rErrorMsg)325  	virtual void NotifyFileStatFailed(
326  		const BackupClientDirectoryRecord* pDirRecord,
327  		const std::string& rLocalPath,
328  		const std::string& rErrorMsg)
329  	{
330 		BOX_WARNING("Failed to access file: " << rLocalPath
331 			<< ": " << rErrorMsg);
332  	}
NotifyDirListFailed(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath,const std::string & rErrorMsg)333  	virtual void NotifyDirListFailed(
334  		const BackupClientDirectoryRecord* pDirRecord,
335  		const std::string& rLocalPath,
336  		const std::string& rErrorMsg)
337  	{
338 		BOX_WARNING("Failed to list directory: " << rLocalPath
339 			<< ": " << rErrorMsg);
340  	}
NotifyMountPointSkipped(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)341 	virtual void NotifyMountPointSkipped(
342 		const BackupClientDirectoryRecord* pDirRecord,
343 		const std::string& rLocalPath)
344 	{
345 		#ifdef WIN32
346 			BOX_WARNING("Ignored directory: " << rLocalPath <<
347 				": is an NTFS junction/reparse point; create "
348 				"a new location if you want to back it up");
349 		#else
350 			BOX_WARNING("Ignored directory: " << rLocalPath <<
351 				": is a mount point; create a new location "
352 				"if you want to back it up");
353 		#endif
354 	}
NotifyFileExcluded(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)355 	virtual void NotifyFileExcluded(
356 		const BackupClientDirectoryRecord* pDirRecord,
357 		const std::string& rLocalPath)
358 	{
359 		if (mLogAllFileAccess)
360 		{
361 			BOX_INFO("Skipping excluded file: " << rLocalPath);
362 		}
363 	}
NotifyDirExcluded(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)364 	virtual void NotifyDirExcluded(
365 		const BackupClientDirectoryRecord* pDirRecord,
366 		const std::string& rLocalPath)
367 	{
368 		if (mLogAllFileAccess)
369 		{
370 			BOX_INFO("Skipping excluded directory: " << rLocalPath);
371 		}
372 	}
NotifyUnsupportedFileType(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)373 	virtual void NotifyUnsupportedFileType(
374 		const BackupClientDirectoryRecord* pDirRecord,
375 		const std::string& rLocalPath)
376 	{
377 		BOX_WARNING("Ignoring file of unknown type: " << rLocalPath);
378 	}
NotifyFileReadFailed(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath,const std::string & rErrorMsg)379  	virtual void NotifyFileReadFailed(
380  		const BackupClientDirectoryRecord* pDirRecord,
381  		const std::string& rLocalPath,
382  		const std::string& rErrorMsg)
383  	{
384 		BOX_WARNING("Error reading file: " << rLocalPath
385 			<< ": " << rErrorMsg);
386  	}
NotifyFileModifiedInFuture(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)387  	virtual void NotifyFileModifiedInFuture(
388  		const BackupClientDirectoryRecord* pDirRecord,
389  		const std::string& rLocalPath)
390  	{
391 		BOX_WARNING("Some files have modification times excessively "
392 			"in the future. Check clock synchronisation. "
393 			"Example file (only one shown): " << rLocalPath);
394  	}
NotifyFileSkippedServerFull(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)395  	virtual void NotifyFileSkippedServerFull(
396  		const BackupClientDirectoryRecord* pDirRecord,
397  		const std::string& rLocalPath)
398 	{
399 		BOX_WARNING("Skipped file: server is full: " << rLocalPath);
400 	}
NotifyFileUploadException(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath,const BoxException & rException)401  	virtual void NotifyFileUploadException(
402  		const BackupClientDirectoryRecord* pDirRecord,
403  		const std::string& rLocalPath,
404  		const BoxException& rException)
405  	{
406 		if (rException.GetType() == CommonException::ExceptionType &&
407 			rException.GetSubType() == CommonException::AccessDenied)
408 		{
409 			BOX_ERROR("Failed to upload file: " << rLocalPath
410 				<< ": Access denied");
411 		}
412 		else
413 		{
414 			BOX_ERROR("Failed to upload file: " << rLocalPath
415 				<< ": caught exception: " << rException.what()
416 				<< " (" << rException.GetType()
417 				<< "/"  << rException.GetSubType() << ")");
418 		}
419  	}
NotifyFileUploadServerError(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath,int type,int subtype)420   	virtual void NotifyFileUploadServerError(
421  		const BackupClientDirectoryRecord* pDirRecord,
422  		const std::string& rLocalPath,
423  		int type, int subtype)
424  	{
425 		std::ostringstream msgs;
426 		if (type != BackupProtocolClientError::ErrorType)
427 		{
428 			msgs << "unknown error type " << type;
429 		}
430 		else
431 		{
432 			switch(subtype)
433 			{
434 			case BackupProtocolClientError::Err_WrongVersion:
435 				msgs << "WrongVersion";
436 				break;
437 			case BackupProtocolClientError::Err_NotInRightProtocolPhase:
438 				msgs << "NotInRightProtocolPhase";
439 				break;
440 			case BackupProtocolClientError::Err_BadLogin:
441 				msgs << "BadLogin";
442 				break;
443 			case BackupProtocolClientError::Err_CannotLockStoreForWriting:
444 				msgs << "CannotLockStoreForWriting";
445 				break;
446 			case BackupProtocolClientError::Err_SessionReadOnly:
447 				msgs << "SessionReadOnly";
448 				break;
449 			case BackupProtocolClientError::Err_FileDoesNotVerify:
450 				msgs << "FileDoesNotVerify";
451 				break;
452 			case BackupProtocolClientError::Err_DoesNotExist:
453 				msgs << "DoesNotExist";
454 				break;
455 			case BackupProtocolClientError::Err_DirectoryAlreadyExists:
456 				msgs << "DirectoryAlreadyExists";
457 				break;
458 			case BackupProtocolClientError::Err_CannotDeleteRoot:
459 				msgs << "CannotDeleteRoot";
460 				break;
461 			case BackupProtocolClientError::Err_TargetNameExists:
462 				msgs << "TargetNameExists";
463 				break;
464 			case BackupProtocolClientError::Err_StorageLimitExceeded:
465 				msgs << "StorageLimitExceeded";
466 				break;
467 			case BackupProtocolClientError::Err_DiffFromFileDoesNotExist:
468 				msgs << "DiffFromFileDoesNotExist";
469 				break;
470 			case BackupProtocolClientError::Err_DoesNotExistInDirectory:
471 				msgs << "DoesNotExistInDirectory";
472 				break;
473 			case BackupProtocolClientError::Err_PatchConsistencyError:
474 				msgs << "PatchConsistencyError";
475 				break;
476 			default:
477 				msgs << "unknown error subtype " << subtype;
478 			}
479 		}
480 
481 		BOX_ERROR("Failed to upload file: " << rLocalPath
482 			<< ": server error: " << msgs.str());
483  	}
NotifyFileUploading(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)484  	virtual void NotifyFileUploading(
485  		const BackupClientDirectoryRecord* pDirRecord,
486  		const std::string& rLocalPath)
487 	{
488 		if (mLogAllFileAccess)
489 		{
490 			BOX_NOTICE("Uploading complete file: " << rLocalPath);
491 		}
492 	}
NotifyFileUploadingPatch(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)493  	virtual void NotifyFileUploadingPatch(
494  		const BackupClientDirectoryRecord* pDirRecord,
495  		const std::string& rLocalPath)
496 	{
497 		if (mLogAllFileAccess)
498 		{
499 			BOX_NOTICE("Uploading patch to file: " << rLocalPath);
500 		}
501 	}
NotifyFileUploadingAttributes(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath)502  	virtual void NotifyFileUploadingAttributes(
503  		const BackupClientDirectoryRecord* pDirRecord,
504  		const std::string& rLocalPath)
505 	{
506 		if (mLogAllFileAccess)
507 		{
508 			BOX_NOTICE("Uploading new file attributes: " <<
509 				rLocalPath);
510 		}
511 	}
NotifyFileUploaded(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath,int64_t FileSize,int64_t UploadedSize)512  	virtual void NotifyFileUploaded(
513  		const BackupClientDirectoryRecord* pDirRecord,
514  		const std::string& rLocalPath,
515  		int64_t FileSize, int64_t UploadedSize)
516 	{
517 		if (mLogAllFileAccess)
518 		{
519 			BOX_NOTICE("Uploaded file: " << rLocalPath << ", "
520 				"total size = " << FileSize << ", "
521 				"uploaded size = " << UploadedSize);
522 		}
523 	}
NotifyFileSynchronised(const BackupClientDirectoryRecord * pDirRecord,const std::string & rLocalPath,int64_t FileSize)524  	virtual void NotifyFileSynchronised(
525  		const BackupClientDirectoryRecord* pDirRecord,
526  		const std::string& rLocalPath,
527  		int64_t FileSize)
528 	{
529 		if (mLogAllFileAccess)
530 		{
531 			BOX_INFO("Synchronised file: " << rLocalPath);
532 		}
533 	}
NotifyDirectoryDeleted(int64_t ObjectID,const std::string & rRemotePath)534 	virtual void NotifyDirectoryDeleted(
535 		int64_t ObjectID,
536 		const std::string& rRemotePath)
537 	{
538 		if (mLogAllFileAccess)
539 		{
540 			BOX_NOTICE("Deleted directory: " << rRemotePath <<
541 				" (ID " << BOX_FORMAT_OBJECTID(ObjectID) <<
542 				")");
543 		}
544 	}
NotifyFileDeleted(int64_t ObjectID,const std::string & rRemotePath)545 	virtual void NotifyFileDeleted(
546 		int64_t ObjectID,
547 		const std::string& rRemotePath)
548 	{
549 		if (mLogAllFileAccess)
550 		{
551 			BOX_NOTICE("Deleted file: " << rRemotePath <<
552 				" (ID " << BOX_FORMAT_OBJECTID(ObjectID) <<
553 				")");
554 		}
555 	}
NotifyReadProgress(int64_t readSize,int64_t offset,int64_t length,box_time_t elapsed,box_time_t finish)556 	virtual void NotifyReadProgress(int64_t readSize, int64_t offset,
557 		int64_t length, box_time_t elapsed, box_time_t finish)
558 	{
559 		BOX_TRACE("Read " << readSize << " bytes at " << offset <<
560 			", " << (length - offset) << " remain, eta " <<
561 			BoxTimeToSeconds(finish - elapsed) << "s");
562 	}
NotifyReadProgress(int64_t readSize,int64_t offset,int64_t length)563 	virtual void NotifyReadProgress(int64_t readSize, int64_t offset,
564 		int64_t length)
565 	{
566 		BOX_TRACE("Read " << readSize << " bytes at " << offset <<
567 			", " << (length - offset) << " remain");
568 	}
NotifyReadProgress(int64_t readSize,int64_t offset)569 	virtual void NotifyReadProgress(int64_t readSize, int64_t offset)
570 	{
571 		BOX_TRACE("Read " << readSize << " bytes at " << offset <<
572 			", unknown bytes remaining");
573 	}
574 
575 #ifdef WIN32
576 	private:
577 	bool mInstallService, mRemoveService, mRunAsService;
578 	std::string mServiceName;
579 #endif
580 
581 #ifdef ENABLE_VSS
582 	IVssBackupComponents* mpVssBackupComponents;
583 	void CreateVssBackupComponents();
584 	bool WaitForAsync(IVssAsync *pAsync, const std::string& description);
585 	typedef HRESULT (__stdcall IVssBackupComponents::*AsyncMethod)(IVssAsync**);
586 	bool CallAndWaitForAsync(AsyncMethod method,
587 		const std::string& description);
588 	void CleanupVssBackupComponents();
589 #endif
590 };
591 
592 #endif // BACKUPDAEMON__H
593