summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.svnrevision1
-rw-r--r--VERSION.txt4
-rw-r--r--bin/bbstored/BackupCommands.cpp970
-rw-r--r--bin/bbstored/BackupConstants.h21
-rw-r--r--bin/bbstored/BackupStoreContext.cpp1785
-rw-r--r--bin/bbstored/BackupStoreContext.h186
-rw-r--r--bin/bbstored/HousekeepStoreAccount.cpp1067
-rw-r--r--bin/bbstored/HousekeepStoreAccount.h111
-rw-r--r--bin/bbstored/Makefile.extra9
-rw-r--r--bin/bbstored/backupprotocol.txt234
-rw-r--r--contrib/mac_osx/org.boxbackup.bbackupd.plist.in3
-rw-r--r--contrib/mac_osx/org.boxbackup.bbstored.plist.in7
-rwxr-xr-xcontrib/windows/installer/boxbackup.mpi.in2345
-rwxr-xr-xcontrib/windows/installer/tools/RemoteControl.exebin0 -> 156536 bytes
-rw-r--r--debian/NEWS24
-rw-r--r--debian/NEWS.upstream124
-rw-r--r--debian/README.Debian125
-rw-r--r--debian/boxbackup-client.config117
-rw-r--r--debian/boxbackup-client.cron.d2
-rw-r--r--debian/boxbackup-client.dirs5
-rw-r--r--debian/boxbackup-client.docs3
-rw-r--r--debian/boxbackup-client.init69
-rw-r--r--debian/boxbackup-client.install4
-rw-r--r--debian/boxbackup-client.manpages6
-rw-r--r--debian/boxbackup-client.postinst349
-rw-r--r--debian/boxbackup-client.postrm15
-rw-r--r--debian/boxbackup-client.templates137
-rw-r--r--debian/boxbackup-server.config110
-rw-r--r--debian/boxbackup-server.dirs6
-rw-r--r--debian/boxbackup-server.docs3
-rw-r--r--debian/boxbackup-server.init80
-rw-r--r--debian/boxbackup-server.install8
-rw-r--r--debian/boxbackup-server.logcheck.ignore10
-rw-r--r--debian/boxbackup-server.manpages7
-rw-r--r--debian/boxbackup-server.postinst212
-rw-r--r--debian/boxbackup-server.postrm22
-rw-r--r--debian/boxbackup-server.templates77
-rw-r--r--debian/changelog338
-rw-r--r--debian/clean146
-rw-r--r--debian/clean.sh8
-rw-r--r--debian/compat1
-rw-r--r--debian/control57
-rw-r--r--debian/copyright48
-rw-r--r--debian/get-orig-source.sh86
-rw-r--r--debian/patches/03-adjust-syslog-facility.diff50
-rw-r--r--debian/patches/05-dont_use_net_for_docs.diff12
-rw-r--r--debian/patches/06-gcc_4.4_fixes.diff17
-rw-r--r--debian/patches/series3
-rw-r--r--debian/po/POTFILES.in2
-rw-r--r--debian/po/cs.po512
-rw-r--r--debian/po/da.po515
-rw-r--r--debian/po/de.po526
-rw-r--r--debian/po/es.po549
-rw-r--r--debian/po/eu.po527
-rw-r--r--debian/po/fi.po504
-rw-r--r--debian/po/fr.po526
-rw-r--r--debian/po/gl.po516
-rw-r--r--debian/po/it.po525
-rw-r--r--debian/po/ja.po509
-rw-r--r--debian/po/nl.po528
-rw-r--r--debian/po/pt.po519
-rw-r--r--debian/po/pt_BR.po522
-rw-r--r--debian/po/ru.po519
-rw-r--r--debian/po/sv.po515
-rw-r--r--debian/po/templates.pot446
-rw-r--r--debian/po/vi.po514
-rwxr-xr-xdebian/rules102
-rw-r--r--debian/source/format1
-rw-r--r--debian/watch4
-rw-r--r--distribution/boxbackup/DISTRIBUTION-MANIFEST.txt8
-rw-r--r--distribution/boxbackup/VERSION.txt4
-rw-r--r--infrastructure/BoxPlatform.pm.in22
-rw-r--r--infrastructure/buildenv-testmain-template.cpp57
-rw-r--r--infrastructure/m4/ax_check_ssl.m44
-rw-r--r--infrastructure/m4/vl_lib_readline.m420
-rwxr-xr-xinfrastructure/makebuildenv.pl.in71
-rwxr-xr-xinfrastructure/makeparcels.pl.in60
-rwxr-xr-xinfrastructure/mingw/configure.sh13
-rw-r--r--infrastructure/msvc/getversion.pl8
-rw-r--r--lib/backupclient/BackupClientFileAttributes.cpp1186
-rw-r--r--lib/backupclient/BackupClientFileAttributes.h78
-rw-r--r--lib/backupclient/BackupClientRestore.cpp17
-rw-r--r--lib/backupclient/BackupClientRestore.h10
-rw-r--r--lib/backupclient/BackupDaemonConfigVerify.cpp6
-rw-r--r--lib/backupclient/BackupStoreConstants.h44
-rw-r--r--lib/backupclient/BackupStoreDirectory.cpp568
-rw-r--r--lib/backupclient/BackupStoreDirectory.h268
-rw-r--r--lib/backupclient/BackupStoreException.h17
-rw-r--r--lib/backupclient/BackupStoreException.txt71
-rw-r--r--lib/backupclient/BackupStoreFile.cpp1556
-rw-r--r--lib/backupclient/BackupStoreFile.h228
-rw-r--r--lib/backupclient/BackupStoreFileCmbDiff.cpp326
-rw-r--r--lib/backupclient/BackupStoreFileCmbIdx.cpp324
-rw-r--r--lib/backupclient/BackupStoreFileCombine.cpp410
-rw-r--r--lib/backupclient/BackupStoreFileCryptVar.cpp31
-rw-r--r--lib/backupclient/BackupStoreFileCryptVar.h39
-rw-r--r--lib/backupclient/BackupStoreFileDiff.cpp1046
-rw-r--r--lib/backupclient/BackupStoreFileEncodeStream.cpp715
-rw-r--r--lib/backupclient/BackupStoreFileEncodeStream.h135
-rw-r--r--lib/backupclient/BackupStoreFileRevDiff.cpp258
-rw-r--r--lib/backupclient/BackupStoreFileWire.h74
-rw-r--r--lib/backupclient/BackupStoreFilename.cpp281
-rw-r--r--lib/backupclient/BackupStoreFilename.h107
-rw-r--r--lib/backupclient/BackupStoreFilenameClear.cpp335
-rw-r--r--lib/backupclient/BackupStoreFilenameClear.h60
-rw-r--r--lib/backupclient/BackupStoreObjectMagic.h31
-rw-r--r--lib/backupclient/Makefile.extra16
-rw-r--r--lib/backupclient/RunStatusProvider.h29
-rw-r--r--lib/backupstore/BackupStoreAccountDatabase.cpp8
-rw-r--r--lib/backupstore/BackupStoreAccountDatabase.h8
-rw-r--r--lib/backupstore/BackupStoreAccounts.cpp23
-rw-r--r--lib/backupstore/BackupStoreAccounts.h10
-rw-r--r--lib/backupstore/BackupStoreCheck.cpp304
-rw-r--r--lib/backupstore/BackupStoreCheck.h36
-rw-r--r--lib/backupstore/BackupStoreCheck2.cpp104
-rw-r--r--lib/backupstore/BackupStoreCheckData.cpp17
-rw-r--r--lib/backupstore/BackupStoreConfigVerify.cpp10
-rw-r--r--lib/backupstore/BackupStoreInfo.cpp267
-rw-r--r--lib/backupstore/BackupStoreInfo.h47
-rw-r--r--lib/backupstore/BackupStoreRefCountDatabase.cpp117
-rw-r--r--lib/common/Archive.h19
-rw-r--r--lib/common/BannerText.h6
-rw-r--r--lib/common/Box.h31
-rw-r--r--lib/common/BoxConfig-MSVC.h7
-rw-r--r--lib/common/BoxException.h3
-rw-r--r--lib/common/BoxPlatform.h8
-rw-r--r--lib/common/BoxPortsAndFiles.h.in9
-rw-r--r--lib/common/BoxTime.cpp3
-rw-r--r--lib/common/BoxTime.h19
-rw-r--r--lib/common/CommonException.txt3
-rw-r--r--lib/common/DebugMemLeakFinder.cpp32
-rw-r--r--lib/common/ExcludeList.cpp22
-rw-r--r--lib/common/FdGetLine.cpp150
-rw-r--r--lib/common/FdGetLine.h43
-rw-r--r--lib/common/FileModificationTime.cpp12
-rw-r--r--lib/common/FileModificationTime.h6
-rw-r--r--lib/common/FileStream.cpp70
-rw-r--r--lib/common/IOStreamGetLine.cpp134
-rw-r--r--lib/common/IOStreamGetLine.h44
-rw-r--r--lib/common/Logging.cpp31
-rw-r--r--lib/common/Logging.h74
-rw-r--r--lib/common/MainHelper.h17
-rw-r--r--lib/common/MemBlockStream.cpp7
-rw-r--r--lib/common/MemBlockStream.h6
-rw-r--r--lib/common/MemLeakFinder.h9
-rw-r--r--lib/common/StreamableMemBlock.cpp3
-rw-r--r--lib/common/StreamableMemBlock.h4
-rw-r--r--lib/common/TemporaryDirectory.h46
-rw-r--r--lib/common/Test.cpp44
-rw-r--r--lib/common/Test.h44
-rw-r--r--lib/common/Timer.cpp202
-rw-r--r--lib/common/Timer.h12
-rw-r--r--lib/common/UnixUser.cpp8
-rw-r--r--lib/common/UnixUser.h4
-rw-r--r--lib/common/Utils.cpp93
-rw-r--r--lib/common/Utils.h3
-rw-r--r--lib/common/ZeroStream.cpp4
-rwxr-xr-xlib/common/makeexception.pl.in4
-rw-r--r--lib/crypto/CipherAES.h3
-rw-r--r--lib/crypto/CipherBlowfish.h3
-rw-r--r--lib/crypto/CipherContext.cpp110
-rw-r--r--lib/crypto/CipherContext.h16
-rw-r--r--lib/crypto/CipherDescription.h7
-rw-r--r--lib/raidfile/RaidFileController.cpp8
-rw-r--r--lib/raidfile/RaidFileController.h4
-rw-r--r--lib/raidfile/RaidFileRead.cpp64
-rw-r--r--lib/raidfile/RaidFileWrite.cpp129
-rw-r--r--lib/raidfile/RaidFileWrite.h8
-rw-r--r--lib/server/Daemon.cpp108
-rw-r--r--lib/server/Daemon.h8
-rw-r--r--lib/server/Protocol.cpp77
-rw-r--r--lib/server/Protocol.h42
-rw-r--r--lib/server/ProtocolObject.cpp125
-rw-r--r--lib/server/ProtocolObject.h41
-rw-r--r--lib/server/SSLLib.cpp31
-rw-r--r--lib/server/SSLLib.h4
-rw-r--r--lib/server/ServerException.txt4
-rw-r--r--lib/server/ServerStream.h18
-rw-r--r--lib/server/Socket.cpp39
-rw-r--r--lib/server/SocketListen.h44
-rw-r--r--lib/server/SocketStream.cpp21
-rw-r--r--lib/server/SocketStream.h7
-rw-r--r--lib/server/SocketStreamTLS.cpp36
-rw-r--r--lib/server/TLSContext.cpp20
-rwxr-xr-xlib/server/makeprotocol.pl.in789
-rw-r--r--lib/win32/emu.cpp103
-rw-r--r--lib/win32/emu.h59
-rwxr-xr-xlib/win32/getopt_long.cpp3
-rw-r--r--modules.txt18
-rw-r--r--parcels.txt10
-rwxr-xr-xruntest.pl.in4
-rw-r--r--test/backupstore/Makefile.extra4
-rw-r--r--test/backupstore/testbackupstore.cpp717
-rw-r--r--test/backupstorefix/testbackupstorefix.cpp389
-rwxr-xr-xtest/backupstorefix/testfiles/testbackupstorefix.pl.in4
-rw-r--r--test/backupstorepatch/testbackupstorepatch.cpp48
-rw-r--r--test/basicserver/Makefile.extra20
-rw-r--r--test/basicserver/TestCommands.cpp53
-rw-r--r--test/basicserver/testbasicserver.cpp38
-rw-r--r--test/bbackupd/Makefile.extra9
-rw-r--r--test/bbackupd/testbbackupd.cpp981
-rw-r--r--test/bbackupd/testfiles/bbackupd-temploc.conf55
-rw-r--r--test/common/testcommon.cpp28
-rw-r--r--win32.bat18
204 files changed, 32952 insertions, 0 deletions
diff --git a/.svnrevision b/.svnrevision
new file mode 100644
index 00000000..f1293228
--- /dev/null
+++ b/.svnrevision
@@ -0,0 +1 @@
+2837
diff --git a/VERSION.txt b/VERSION.txt
index 0188cacd..2201711b 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1,2 +1,6 @@
+<<<<<<< HEAD
+USE_SVN_VERSION
+=======
0.12
+>>>>>>> 0.12
boxbackup
diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp
new file mode 100644
index 00000000..c27cb7ab
--- /dev/null
+++ b/bin/bbstored/BackupCommands.cpp
@@ -0,0 +1,970 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupCommands.cpp
+// Purpose: Implement commands for the Backup store protocol
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <set>
+#include <sstream>
+
+#include "autogen_BackupProtocolServer.h"
+#include "autogen_RaidFileException.h"
+#include "BackupConstants.h"
+#include "BackupStoreContext.h"
+#include "BackupStoreConstants.h"
+#include "BackupStoreDirectory.h"
+#include "BackupStoreException.h"
+#include "BackupStoreFile.h"
+#include "BackupStoreInfo.h"
+#include "BufferedStream.h"
+#include "CollectInBufferStream.h"
+#include "FileStream.h"
+#include "InvisibleTempFileStream.h"
+#include "RaidFileController.h"
+#include "StreamableMemBlock.h"
+
+#include "MemLeakFindOn.h"
+
+#define CHECK_PHASE(phase) \
+ if(rContext.GetPhase() != BackupStoreContext::phase) \
+ { \
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( \
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_NotInRightProtocolPhase)); \
+ }
+
+#define CHECK_WRITEABLE_SESSION \
+ if(rContext.SessionIsReadOnly()) \
+ { \
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( \
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_SessionReadOnly)); \
+ }
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerVersion::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Return the current version, or an error if the requested version isn't allowed
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerVersion::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Version)
+
+ // Correct version?
+ if(mVersion != BACKUP_STORE_SERVER_VERSION)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_WrongVersion));
+ }
+
+ // Mark the next phase
+ rContext.SetPhase(BackupStoreContext::Phase_Login);
+
+ // Return our version
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerVersion(BACKUP_STORE_SERVER_VERSION));
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerLogin::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Return the current version, or an error if the requested version isn't allowed
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Login)
+
+ // Check given client ID against the ID in the certificate certificate
+ // and that the client actually has an account on this machine
+ if(mClientID != rContext.GetClientID())
+ {
+ BOX_WARNING("Failed login from client ID " <<
+ BOX_FORMAT_ACCOUNT(mClientID) <<
+ ": wrong certificate for this account");
+ return std::auto_ptr<ProtocolObject>(
+ new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType,
+ BackupProtocolServerError::Err_BadLogin));
+ }
+
+ if(!rContext.GetClientHasAccount())
+ {
+ BOX_WARNING("Failed login from client ID " <<
+ BOX_FORMAT_ACCOUNT(mClientID) <<
+ ": no such account on this server");
+ return std::auto_ptr<ProtocolObject>(
+ new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType,
+ BackupProtocolServerError::Err_BadLogin));
+ }
+
+ // If we need to write, check that nothing else has got a write lock
+ if((mFlags & Flags_ReadOnly) != Flags_ReadOnly)
+ {
+ // See if the context will get the lock
+ if(!rContext.AttemptToGetWriteLock())
+ {
+ BOX_WARNING("Failed to get write lock for Client ID " <<
+ BOX_FORMAT_ACCOUNT(mClientID));
+ return std::auto_ptr<ProtocolObject>(
+ new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType,
+ BackupProtocolServerError::Err_CannotLockStoreForWriting));
+ }
+
+ // Debug: check we got the lock
+ ASSERT(!rContext.SessionIsReadOnly());
+ }
+
+ // Load the store info
+ rContext.LoadStoreInfo();
+
+ // Get the last client store marker
+ int64_t clientStoreMarker = rContext.GetClientStoreMarker();
+
+ // Mark the next phase
+ rContext.SetPhase(BackupStoreContext::Phase_Commands);
+
+ // Log login
+ BOX_NOTICE("Login from Client ID " <<
+ BOX_FORMAT_ACCOUNT(mClientID) <<
+ " " <<
+ (((mFlags & Flags_ReadOnly) != Flags_ReadOnly)
+ ?"Read/Write":"Read-only"));
+
+ // Get the usage info for reporting to the client
+ int64_t blocksUsed = 0, blocksSoftLimit = 0, blocksHardLimit = 0;
+ rContext.GetStoreDiscUsageInfo(blocksUsed, blocksSoftLimit, blocksHardLimit);
+
+ // Return success
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerLoginConfirmed(clientStoreMarker, blocksUsed, blocksSoftLimit, blocksHardLimit));
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerFinished::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Marks end of conversation (Protocol framework handles this)
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerFinished::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ BOX_NOTICE("Session finished for Client ID " <<
+ BOX_FORMAT_ACCOUNT(rContext.GetClientID()));
+
+ // Let the context know about it
+ rContext.ReceivedFinishCommand();
+
+ // can be called in any phase
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerFinished);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerListDirectory::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Command to list a directory
+// Created: 2003/09/02
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerListDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ // Store the listing to a stream
+ std::auto_ptr<CollectInBufferStream> stream(new CollectInBufferStream);
+
+ try
+ {
+ // Ask the context for a directory
+ const BackupStoreDirectory &rdir(
+ rContext.GetDirectory(mObjectID));
+ rdir.WriteToStream(*stream, mFlagsMustBeSet,
+ mFlagsNotToBeSet, mSendAttributes,
+ false /* never send dependency info to the client */);
+ }
+ catch (RaidFileException &e)
+ {
+ if (e.GetSubType() == RaidFileException::RaidFileDoesntExist)
+ {
+ return std::auto_ptr<ProtocolObject>(
+ new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType,
+ BackupProtocolServerError::Err_DoesNotExist));
+ }
+ throw;
+ }
+
+ stream->SetForReading();
+
+ // Get the protocol to send the stream
+ rProtocol.SendStreamAfterCommand(stream.release());
+
+ return std::auto_ptr<ProtocolObject>(
+ new BackupProtocolServerSuccess(mObjectID));
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerStoreFile::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Command to store a file on the server
+// Created: 2003/09/02
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerStoreFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ std::auto_ptr<ProtocolObject> hookResult =
+ rContext.StartCommandHook(*this);
+ if(hookResult.get())
+ {
+ return hookResult;
+ }
+
+ // Check that the diff from file actually exists, if it's specified
+ if(mDiffFromFileID != 0)
+ {
+ if(!rContext.ObjectExists(mDiffFromFileID, BackupStoreContext::ObjectExists_File))
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_DiffFromFileDoesNotExist));
+ }
+ }
+
+ // A stream follows, which contains the file
+ std::auto_ptr<IOStream> dirstream(rProtocol.ReceiveStream());
+
+ // Ask the context to store it
+ int64_t id = 0;
+ try
+ {
+ id = rContext.AddFile(*dirstream, mDirectoryObjectID, mModificationTime, mAttributesHash, mDiffFromFileID,
+ mFilename, true /* mark files with same name as old versions */);
+ }
+ catch(BackupStoreException &e)
+ {
+ if(e.GetSubType() == BackupStoreException::AddedFileDoesNotVerify)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_FileDoesNotVerify));
+ }
+ else if(e.GetSubType() == BackupStoreException::AddedFileExceedsStorageLimit)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_StorageLimitExceeded));
+ }
+ else
+ {
+ throw;
+ }
+ }
+
+ // Tell the caller what the file was
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(id));
+}
+
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetObject::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Command to get an arbitary object from the server
+// Created: 2003/09/03
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetObject::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ // Check the object exists
+ if(!rContext.ObjectExists(mObjectID))
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(NoObject));
+ }
+
+ // Open the object
+ std::auto_ptr<IOStream> object(rContext.OpenObject(mObjectID));
+
+ // Stream it to the peer
+ rProtocol.SendStreamAfterCommand(object.release());
+
+ // Tell the caller what the file was
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetFile::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Command to get an file object from the server -- may have to do a bit of
+// work to get the object.
+// Created: 2003/09/03
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ // Check the objects exist
+ if(!rContext.ObjectExists(mObjectID)
+ || !rContext.ObjectExists(mInDirectory))
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_DoesNotExist));
+ }
+
+ // Get the directory it's in
+ const BackupStoreDirectory &rdir(rContext.GetDirectory(mInDirectory));
+
+ // Find the object within the directory
+ BackupStoreDirectory::Entry *pfileEntry = rdir.FindEntryByID(mObjectID);
+ if(pfileEntry == 0)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_DoesNotExistInDirectory));
+ }
+
+ // The result
+ std::auto_ptr<IOStream> stream;
+
+ // Does this depend on anything?
+ if(pfileEntry->GetDependsNewer() != 0)
+ {
+ // File exists, but is a patch from a new version. Generate the older version.
+ std::vector<int64_t> patchChain;
+ int64_t id = mObjectID;
+ BackupStoreDirectory::Entry *en = 0;
+ do
+ {
+ patchChain.push_back(id);
+ en = rdir.FindEntryByID(id);
+ if(en == 0)
+ {
+ BOX_ERROR("Object " <<
+ BOX_FORMAT_OBJECTID(mObjectID) <<
+ " in dir " <<
+ BOX_FORMAT_OBJECTID(mInDirectory) <<
+ " for account " <<
+ BOX_FORMAT_ACCOUNT(rContext.GetClientID()) <<
+ " references object " <<
+ BOX_FORMAT_OBJECTID(id) <<
+ " which does not exist in dir");
+ return std::auto_ptr<ProtocolObject>(
+ new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType,
+ BackupProtocolServerError::Err_PatchConsistencyError));
+ }
+ id = en->GetDependsNewer();
+ }
+ while(en != 0 && id != 0);
+
+ // OK! The last entry in the chain is the full file, the others are patches back from it.
+ // Open the last one, which is the current from file
+ std::auto_ptr<IOStream> from(rContext.OpenObject(patchChain[patchChain.size() - 1]));
+
+ // Then, for each patch in the chain, do a combine
+ for(int p = ((int)patchChain.size()) - 2; p >= 0; --p)
+ {
+ // ID of patch
+ int64_t patchID = patchChain[p];
+
+ // Open it a couple of times
+ std::auto_ptr<IOStream> diff(rContext.OpenObject(patchID));
+ std::auto_ptr<IOStream> diff2(rContext.OpenObject(patchID));
+
+ // Choose a temporary filename for the result of the combination
+ std::ostringstream fs;
+ fs << rContext.GetStoreRoot() << ".recombinetemp." << p;
+ std::string tempFn =
+ RaidFileController::DiscSetPathToFileSystemPath(
+ rContext.GetStoreDiscSet(), fs.str(),
+ p + 16);
+
+ // Open the temporary file
+ std::auto_ptr<IOStream> combined;
+ try
+ {
+ {
+ // Write nastily to allow this to work with gcc 2.x
+ std::auto_ptr<IOStream> t(
+ new InvisibleTempFileStream(
+ tempFn.c_str(),
+ O_RDWR | O_CREAT |
+ O_EXCL | O_BINARY |
+ O_TRUNC));
+ combined = t;
+ }
+ }
+ catch(...)
+ {
+ // Make sure it goes
+ ::unlink(tempFn.c_str());
+ throw;
+ }
+
+ // Do the combining
+ BackupStoreFile::CombineFile(*diff, *diff2, *from, *combined);
+
+ // Move to the beginning of the combined file
+ combined->Seek(0, IOStream::SeekType_Absolute);
+
+ // Then shuffle round for the next go
+ if (from.get()) from->Close();
+ from = combined;
+ }
+
+ // Now, from contains a nice file to send to the client. Reorder it
+ {
+ // Write nastily to allow this to work with gcc 2.x
+ std::auto_ptr<IOStream> t(BackupStoreFile::ReorderFileToStreamOrder(from.get(), true /* take ownership */));
+ stream = t;
+ }
+
+ // Release from file to avoid double deletion
+ from.release();
+ }
+ else
+ {
+ // Simple case: file already exists on disc ready to go
+
+ // Open the object
+ std::auto_ptr<IOStream> object(rContext.OpenObject(mObjectID));
+ BufferedStream buf(*object);
+
+ // Verify it
+ if(!BackupStoreFile::VerifyEncodedFileFormat(buf))
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_FileDoesNotVerify));
+ }
+
+ // Reset stream -- seek to beginning
+ object->Seek(0, IOStream::SeekType_Absolute);
+
+ // Reorder the stream/file into stream order
+ {
+ // Write nastily to allow this to work with gcc 2.x
+ std::auto_ptr<IOStream> t(BackupStoreFile::ReorderFileToStreamOrder(object.get(), true /* take ownership */));
+ stream = t;
+ }
+
+ // Object will be deleted when the stream is deleted,
+ // so can release the object auto_ptr here to avoid
+ // premature deletion
+ object.release();
+ }
+
+ // Stream the reordered stream to the peer
+ rProtocol.SendStreamAfterCommand(stream.get());
+
+ // Don't delete the stream here
+ stream.release();
+
+ // Tell the caller what the file was
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerCreateDirectory::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Create directory command
+// Created: 2003/09/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerCreateDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Get the stream containing the attributes
+ std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
+ // Collect the attributes -- do this now so no matter what the outcome,
+ // the data has been absorbed.
+ StreamableMemBlock attr;
+ attr.Set(*attrstream, rProtocol.GetTimeout());
+
+ // Check to see if the hard limit has been exceeded
+ if(rContext.HardLimitExceeded())
+ {
+ // Won't allow creation if the limit has been exceeded
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_StorageLimitExceeded));
+ }
+
+ bool alreadyExists = false;
+ int64_t id = rContext.AddDirectory(mContainingDirectoryID, mDirectoryName, attr, mAttributesModTime, alreadyExists);
+
+ if(alreadyExists)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_DirectoryAlreadyExists));
+ }
+
+ // Tell the caller what the file was
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(id));
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerChangeDirAttributes::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Change attributes on directory
+// Created: 2003/09/06
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerChangeDirAttributes::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Get the stream containing the attributes
+ std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
+ // Collect the attributes -- do this now so no matter what the outcome,
+ // the data has been absorbed.
+ StreamableMemBlock attr;
+ attr.Set(*attrstream, rProtocol.GetTimeout());
+
+ // Get the context to do it's magic
+ rContext.ChangeDirAttributes(mObjectID, attr, mAttributesModTime);
+
+ // Tell the caller what the file was
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerSetReplacementFileAttributes::DoCommand(Protocol &, BackupStoreContext &)
+// Purpose: Change attributes on directory
+// Created: 2003/09/06
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerSetReplacementFileAttributes::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Get the stream containing the attributes
+ std::auto_ptr<IOStream> attrstream(rProtocol.ReceiveStream());
+ // Collect the attributes -- do this now so no matter what the outcome,
+ // the data has been absorbed.
+ StreamableMemBlock attr;
+ attr.Set(*attrstream, rProtocol.GetTimeout());
+
+ // Get the context to do it's magic
+ int64_t objectID = 0;
+ if(!rContext.ChangeFileAttributes(mFilename, mInDirectory, attr, mAttributesHash, objectID))
+ {
+ // Didn't exist
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_DoesNotExist));
+ }
+
+ // Tell the caller what the file was
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(objectID));
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerDeleteFile::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Delete a file
+// Created: 2003/10/21
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Context handles this
+ int64_t objectID = 0;
+ rContext.DeleteFile(mFilename, mInDirectory, objectID);
+
+ // return the object ID or zero for not found
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(objectID));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerUndeleteFile::DoCommand(
+// BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Undelete a file
+// Created: 2008-09-12
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerUndeleteFile::DoCommand(
+ BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Context handles this
+ bool result = rContext.UndeleteFile(mObjectID, mInDirectory);
+
+ // return the object ID or zero for not found
+ return std::auto_ptr<ProtocolObject>(
+ new BackupProtocolServerSuccess(result ? mObjectID : 0));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerDeleteDirectory::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Delete a directory
+// Created: 2003/10/21
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Check it's not asking for the root directory to be deleted
+ if(mObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_CannotDeleteRoot));
+ }
+
+ // Context handles this
+ rContext.DeleteDirectory(mObjectID);
+
+ // return the object ID
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerUndeleteDirectory::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Undelete a directory
+// Created: 23/11/03
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerUndeleteDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Check it's not asking for the root directory to be deleted
+ if(mObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_CannotDeleteRoot));
+ }
+
+ // Context handles this
+ rContext.DeleteDirectory(mObjectID, true /* undelete */);
+
+ // return the object ID
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerSetClientStoreMarker::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Command to set the client's store marker
+// Created: 2003/10/29
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerSetClientStoreMarker::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Set the marker
+ rContext.SetClientStoreMarker(mClientStoreMarker);
+
+ // return store marker set
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mClientStoreMarker));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerMoveObject::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Command to move an object from one directory to another
+// Created: 2003/11/12
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerMoveObject::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+ CHECK_WRITEABLE_SESSION
+
+ // Let context do this, but modify error reporting on exceptions...
+ try
+ {
+ rContext.MoveObject(mObjectID, mMoveFromDirectory, mMoveToDirectory,
+ mNewFilename, (mFlags & Flags_MoveAllWithSameName) == Flags_MoveAllWithSameName,
+ (mFlags & Flags_AllowMoveOverDeletedObject) == Flags_AllowMoveOverDeletedObject);
+ }
+ catch(BackupStoreException &e)
+ {
+ if(e.GetSubType() == BackupStoreException::CouldNotFindEntryInDirectory)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_DoesNotExist));
+ }
+ else if(e.GetSubType() == BackupStoreException::NameAlreadyExistsInDirectory)
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
+ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_TargetNameExists));
+ }
+ else
+ {
+ throw;
+ }
+ }
+
+ // Return the object ID
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetObjectName::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Command to find the name of an object
+// Created: 12/11/03
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetObjectName::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ // Create a stream for the list of filenames
+ std::auto_ptr<CollectInBufferStream> stream(new CollectInBufferStream);
+
+ // Object and directory IDs
+ int64_t objectID = mObjectID;
+ int64_t dirID = mContainingDirectoryID;
+
+ // Data to return in the reply
+ int32_t numNameElements = 0;
+ int16_t objectFlags = 0;
+ int64_t modTime = 0;
+ uint64_t attrModHash = 0;
+ bool haveModTimes = false;
+
+ do
+ {
+ // Check the directory really exists
+ if(!rContext.ObjectExists(dirID, BackupStoreContext::ObjectExists_Directory))
+ {
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerObjectName(BackupProtocolServerObjectName::NumNameElements_ObjectDoesntExist, 0, 0, 0));
+ }
+
+ // Load up the directory
+ const BackupStoreDirectory &rdir(rContext.GetDirectory(dirID));
+
+ // Find the element in this directory and store it's name
+ if(objectID != ObjectID_DirectoryOnly)
+ {
+ const BackupStoreDirectory::Entry *en = rdir.FindEntryByID(objectID);
+
+ // If this can't be found, then there is a problem... tell the caller it can't be found
+ if(en == 0)
+ {
+ // Abort!
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerObjectName(BackupProtocolServerObjectName::NumNameElements_ObjectDoesntExist, 0, 0, 0));
+ }
+
+ // Store flags?
+ if(objectFlags == 0)
+ {
+ objectFlags = en->GetFlags();
+ }
+
+ // Store modification times?
+ if(!haveModTimes)
+ {
+ modTime = en->GetModificationTime();
+ attrModHash = en->GetAttributesHash();
+ haveModTimes = true;
+ }
+
+ // Store the name in the stream
+ en->GetName().WriteToStream(*stream);
+
+ // Count of name elements
+ ++numNameElements;
+ }
+
+ // Setup for next time round
+ objectID = dirID;
+ dirID = rdir.GetContainerID();
+
+ } while(objectID != 0 && objectID != BACKUPSTORE_ROOT_DIRECTORY_ID);
+
+ // Stream to send?
+ if(numNameElements > 0)
+ {
+ // Get the stream ready to go
+ stream->SetForReading();
+ // Tell the protocol to send the stream
+ rProtocol.SendStreamAfterCommand(stream.release());
+ }
+
+ // Make reply
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerObjectName(numNameElements, modTime, attrModHash, objectFlags));
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetBlockIndexByID::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Get the block index from a file, by ID
+// Created: 19/1/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByID::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ // Open the file
+ std::auto_ptr<IOStream> stream(rContext.OpenObject(mObjectID));
+
+ // Move the file pointer to the block index
+ BackupStoreFile::MoveStreamPositionToBlockIndex(*stream);
+
+ // Return the stream to the client
+ rProtocol.SendStreamAfterCommand(stream.release());
+
+ // Return the object ID
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetBlockIndexByName::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Get the block index from a file, by name within a directory
+// Created: 19/1/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByName::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ // Get the directory
+ const BackupStoreDirectory &dir(rContext.GetDirectory(mInDirectory));
+
+ // Find the latest object ID within it which has the same name
+ int64_t objectID = 0;
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = 0;
+ while((en = i.Next(BackupStoreDirectory::Entry::Flags_File)) != 0)
+ {
+ if(en->GetName() == mFilename)
+ {
+ // Store the ID, if it's a newer ID than the last one
+ if(en->GetObjectID() > objectID)
+ {
+ objectID = en->GetObjectID();
+ }
+ }
+ }
+
+ // Found anything?
+ if(objectID == 0)
+ {
+ // No... return a zero object ID
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(0));
+ }
+
+ // Open the file
+ std::auto_ptr<IOStream> stream(rContext.OpenObject(objectID));
+
+ // Move the file pointer to the block index
+ BackupStoreFile::MoveStreamPositionToBlockIndex(*stream);
+
+ // Return the stream to the client
+ rProtocol.SendStreamAfterCommand(stream.release());
+
+ // Return the object ID
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(objectID));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetAccountUsage::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Return the amount of disc space used
+// Created: 19/4/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetAccountUsage::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ // Get store info from context
+ const BackupStoreInfo &rinfo(rContext.GetBackupStoreInfo());
+
+ // Find block size
+ RaidFileController &rcontroller(RaidFileController::GetController());
+ RaidFileDiscSet &rdiscSet(rcontroller.GetDiscSet(rinfo.GetDiscSetNumber()));
+
+ // Return info
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerAccountUsage(
+ rinfo.GetBlocksUsed(),
+ rinfo.GetBlocksInOldFiles(),
+ rinfo.GetBlocksInDeletedFiles(),
+ rinfo.GetBlocksInDirectories(),
+ rinfo.GetBlocksSoftLimit(),
+ rinfo.GetBlocksHardLimit(),
+ rdiscSet.GetBlockSize()
+ ));
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &, BackupStoreContext &)
+// Purpose: Return the amount of disc space used
+// Created: 19/4/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ //
+ // NOOP
+ //
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerIsAlive());
+}
diff --git a/bin/bbstored/BackupConstants.h b/bin/bbstored/BackupConstants.h
new file mode 100644
index 00000000..19d06a15
--- /dev/null
+++ b/bin/bbstored/BackupConstants.h
@@ -0,0 +1,21 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupConstants.h
+// Purpose: Constants for the backup server and client
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPCONSTANTS__H
+#define BACKUPCONSTANTS__H
+
+// 15 minutes to timeout (milliseconds)
+#define BACKUP_STORE_TIMEOUT (15*60*1000)
+
+// Should the store daemon convert files to Raid immediately?
+#define BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY true
+
+#endif // BACKUPCONSTANTS__H
+
+
diff --git a/bin/bbstored/BackupStoreContext.cpp b/bin/bbstored/BackupStoreContext.cpp
new file mode 100644
index 00000000..5ee13faa
--- /dev/null
+++ b/bin/bbstored/BackupStoreContext.cpp
@@ -0,0 +1,1785 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreContext.cpp
+// Purpose: Context for backup store server
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <stdio.h>
+
+#include "BackupConstants.h"
+#include "BackupStoreContext.h"
+#include "BackupStoreDaemon.h"
+#include "BackupStoreDirectory.h"
+#include "BackupStoreException.h"
+#include "BackupStoreFile.h"
+#include "BackupStoreInfo.h"
+#include "BackupStoreObjectMagic.h"
+#include "BufferedStream.h"
+#include "BufferedWriteStream.h"
+#include "FileStream.h"
+#include "InvisibleTempFileStream.h"
+#include "RaidFileController.h"
+#include "RaidFileRead.h"
+#include "RaidFileWrite.h"
+#include "StoreStructure.h"
+
+#include "MemLeakFindOn.h"
+
+
+// Maximum number of directories to keep in the cache
+// When the cache is bigger than this, everything gets
+// deleted.
+#ifdef BOX_RELEASE_BUILD
+ #define MAX_CACHE_SIZE 32
+#else
+ #define MAX_CACHE_SIZE 2
+#endif
+
+// Allow the housekeeping process 4 seconds to release an account
+#define MAX_WAIT_FOR_HOUSEKEEPING_TO_RELEASE_ACCOUNT 4
+
+// Maximum amount of store info updates before it's actually saved to disc.
+#define STORE_INFO_SAVE_DELAY 96
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::BackupStoreContext()
+// Purpose: Constructor
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+BackupStoreContext::BackupStoreContext(int32_t ClientID,
+ HousekeepingInterface &rDaemon)
+ : mClientID(ClientID),
+ mrDaemon(rDaemon),
+ mProtocolPhase(Phase_START),
+ mClientHasAccount(false),
+ mStoreDiscSet(-1),
+ mReadOnly(true),
+ mSaveStoreInfoDelay(STORE_INFO_SAVE_DELAY),
+ mpTestHook(NULL)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::~BackupStoreContext()
+// Purpose: Destructor
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+BackupStoreContext::~BackupStoreContext()
+{
+ // Delete the objects in the cache
+ for(std::map<int64_t, BackupStoreDirectory*>::iterator i(mDirectoryCache.begin()); i != mDirectoryCache.end(); ++i)
+ {
+ delete (i->second);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::CleanUp()
+// Purpose: Clean up after a connection
+// Created: 16/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::CleanUp()
+{
+ // Make sure the store info is saved, if it has been loaded, isn't read only and has been modified
+ if(mpStoreInfo.get() && !(mpStoreInfo->IsReadOnly()) && mpStoreInfo->IsModified())
+ {
+ mpStoreInfo->Save();
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::ReceivedFinishCommand()
+// Purpose: Called when the finish command is received by the protocol
+// Created: 16/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::ReceivedFinishCommand()
+{
+ if(!mReadOnly && mpStoreInfo.get())
+ {
+ // Save the store info, not delayed
+ SaveStoreInfo(false);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::AttemptToGetWriteLock()
+// Purpose: Attempt to get a write lock for the store, and if so, unset the read only flags
+// Created: 2003/09/02
+//
+// --------------------------------------------------------------------------
+bool BackupStoreContext::AttemptToGetWriteLock()
+{
+ // Make the filename of the write lock file
+ std::string writeLockFile;
+ StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, writeLockFile);
+
+ // Request the lock
+ bool gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */);
+
+ if(!gotLock)
+ {
+ // The housekeeping process might have the thing open -- ask it to stop
+ char msg[256];
+ int msgLen = sprintf(msg, "r%x\n", mClientID);
+ // Send message
+ mrDaemon.SendMessageToHousekeepingProcess(msg, msgLen);
+
+ // Then try again a few times
+ int tries = MAX_WAIT_FOR_HOUSEKEEPING_TO_RELEASE_ACCOUNT;
+ do
+ {
+ ::sleep(1 /* second */);
+ --tries;
+ gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */);
+
+ } while(!gotLock && tries > 0);
+ }
+
+ if(gotLock)
+ {
+ // Got the lock, mark as not read only
+ mReadOnly = false;
+ }
+
+ return gotLock;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::LoadStoreInfo()
+// Purpose: Load the store info from disc
+// Created: 2003/09/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::LoadStoreInfo()
+{
+ if(mpStoreInfo.get() != 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoAlreadyLoaded)
+ }
+
+ // Load it up!
+ std::auto_ptr<BackupStoreInfo> i(BackupStoreInfo::Load(mClientID, mStoreRoot, mStoreDiscSet, mReadOnly));
+
+ // Check it
+ if(i->GetAccountID() != mClientID)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoForWrongAccount)
+ }
+
+ // Keep the pointer to it
+ mpStoreInfo = i;
+
+ BackupStoreAccountDatabase::Entry account(mClientID, mStoreDiscSet);
+
+ // try to load the reference count database
+ try
+ {
+ mapRefCount = BackupStoreRefCountDatabase::Load(account, false);
+ }
+ catch(BoxException &e)
+ {
+ BOX_WARNING("Reference count database is missing or corrupted, "
+ "creating a new one, expect housekeeping to find and "
+ "fix problems with reference counts later.");
+
+ BackupStoreRefCountDatabase::CreateForRegeneration(account);
+ mapRefCount = BackupStoreRefCountDatabase::Load(account, false);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::SaveStoreInfo(bool)
+// Purpose: Potentially delayed saving of the store info
+// Created: 16/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::SaveStoreInfo(bool AllowDelay)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ // Can delay saving it a little while?
+ if(AllowDelay)
+ {
+ --mSaveStoreInfoDelay;
+ if(mSaveStoreInfoDelay > 0)
+ {
+ return;
+ }
+ }
+
+ // Want to save now
+ mpStoreInfo->Save();
+
+ // Set count for next delay
+ mSaveStoreInfoDelay = STORE_INFO_SAVE_DELAY;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::MakeObjectFilename(int64_t, std::string &, bool)
+// Purpose: Create the filename of an object in the store, optionally creating the
+// containing directory if it doesn't already exist.
+// Created: 2003/09/02
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::MakeObjectFilename(int64_t ObjectID, std::string &rOutput, bool EnsureDirectoryExists)
+{
+ // Delegate to utility function
+ StoreStructure::MakeObjectFilename(ObjectID, mStoreRoot, mStoreDiscSet, rOutput, EnsureDirectoryExists);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::GetDirectoryInternal(int64_t)
+// Purpose: Return a reference to a directory. Valid only until the
+// next time a function which affects directories is called.
+// Mainly this funciton, and creation of files.
+// Private version of this, which returns non-const directories.
+// Created: 2003/09/02
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory &BackupStoreContext::GetDirectoryInternal(int64_t ObjectID)
+{
+ // Get the filename
+ std::string filename;
+ MakeObjectFilename(ObjectID, filename);
+
+ // Already in cache?
+ std::map<int64_t, BackupStoreDirectory*>::iterator item(mDirectoryCache.find(ObjectID));
+ if(item != mDirectoryCache.end())
+ {
+ // Check the revision ID of the file -- does it need refreshing?
+ int64_t revID = 0;
+ if(!RaidFileRead::FileExists(mStoreDiscSet, filename, &revID))
+ {
+ THROW_EXCEPTION(BackupStoreException, DirectoryHasBeenDeleted)
+ }
+
+ if(revID == item->second->GetRevisionID())
+ {
+ // Looks good... return the cached object
+ BOX_TRACE("Returning object " <<
+ BOX_FORMAT_OBJECTID(ObjectID) <<
+ " from cache, modtime = " << revID);
+ return *(item->second);
+ }
+
+ BOX_TRACE("Refreshing object " <<
+ BOX_FORMAT_OBJECTID(ObjectID) <<
+ " in cache, modtime changed from " <<
+ item->second->GetRevisionID() << " to " << revID);
+
+ // Delete this cached object
+ delete item->second;
+ mDirectoryCache.erase(item);
+ }
+
+ // Need to load it up
+
+ // First check to see if the cache is too big
+ if(mDirectoryCache.size() > MAX_CACHE_SIZE)
+ {
+ // Very simple. Just delete everything!
+ for(std::map<int64_t, BackupStoreDirectory*>::iterator i(mDirectoryCache.begin()); i != mDirectoryCache.end(); ++i)
+ {
+ delete (i->second);
+ }
+ mDirectoryCache.clear();
+ }
+
+ // Get a RaidFileRead to read it
+ int64_t revID = 0;
+ std::auto_ptr<RaidFileRead> objectFile(RaidFileRead::Open(mStoreDiscSet, filename, &revID));
+ ASSERT(revID != 0);
+
+ // New directory object
+ std::auto_ptr<BackupStoreDirectory> dir(new BackupStoreDirectory);
+
+ // Read it from the stream, then set it's revision ID
+ BufferedStream buf(*objectFile);
+ dir->ReadFromStream(buf, IOStream::TimeOutInfinite);
+ dir->SetRevisionID(revID);
+
+ // Make sure the size of the directory is available for writing the dir back
+ int64_t dirSize = objectFile->GetDiscUsageInBlocks();
+ ASSERT(dirSize > 0);
+ dir->SetUserInfo1_SizeInBlocks(dirSize);
+
+ // Store in cache
+ BackupStoreDirectory *pdir = dir.release();
+ try
+ {
+ mDirectoryCache[ObjectID] = pdir;
+ }
+ catch(...)
+ {
+ delete pdir;
+ throw;
+ }
+
+ // Return it
+ return *pdir;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::AllocateObjectID()
+// Purpose: Allocate a new object ID, tolerant of failures to save store info
+// Created: 16/12/03
+//
+// --------------------------------------------------------------------------
+int64_t BackupStoreContext::AllocateObjectID()
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ // Given that the store info may not be saved for STORE_INFO_SAVE_DELAY
+ // times after it has been updated, this is a reasonable number of times
+ // to try for finding an unused ID.
+ // (Sizes used in the store info are fixed by the housekeeping process)
+ int retryLimit = (STORE_INFO_SAVE_DELAY * 2);
+
+ while(retryLimit > 0)
+ {
+ // Attempt to allocate an ID from the store
+ int64_t id = mpStoreInfo->AllocateObjectID();
+
+ // Generate filename
+ std::string filename;
+ MakeObjectFilename(id, filename);
+ // Check it doesn't exist
+ if(!RaidFileRead::FileExists(mStoreDiscSet, filename))
+ {
+ // Success!
+ return id;
+ }
+
+ // Decrement retry count, and try again
+ --retryLimit;
+
+ // Mark that the store info should be saved as soon as possible
+ mSaveStoreInfoDelay = 0;
+
+ BOX_WARNING("When allocating object ID, found that " <<
+ BOX_FORMAT_OBJECTID(id) << " is already in use");
+ }
+
+ THROW_EXCEPTION(BackupStoreException, CouldNotFindUnusedIDDuringAllocation)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::AddFile(IOStream &, int64_t,
+// int64_t, int64_t, const BackupStoreFilename &, bool)
+// Purpose: Add a file to the store, from a given stream, into
+// a specified directory. Returns object ID of the new
+// file.
+// Created: 2003/09/03
+//
+// --------------------------------------------------------------------------
+int64_t BackupStoreContext::AddFile(IOStream &rFile, int64_t InDirectory,
+ int64_t ModificationTime, int64_t AttributesHash,
+ int64_t DiffFromFileID, const BackupStoreFilename &rFilename,
+ bool MarkFileWithSameNameAsOldVersions)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ // This is going to be a bit complex to make sure it copes OK
+ // with things going wrong.
+ // The only thing which isn't safe is incrementing the object ID
+ // and keeping the blocks used entirely accurate -- but these
+ // aren't big problems if they go horribly wrong. The sizes will
+ // be corrected the next time the account has a housekeeping run,
+ // and the object ID allocation code is tolerant of missed IDs.
+ // (the info is written lazily, so these are necessary)
+
+ // Get the directory we want to modify
+ BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
+
+ // Allocate the next ID
+ int64_t id = AllocateObjectID();
+
+ // Stream the file to disc
+ std::string fn;
+ MakeObjectFilename(id, fn, true /* make sure the directory it's in exists */);
+ int64_t blocksUsed = 0;
+ RaidFileWrite *ppreviousVerStoreFile = 0;
+ bool reversedDiffIsCompletelyDifferent = false;
+ int64_t oldVersionNewBlocksUsed = 0;
+ try
+ {
+ RaidFileWrite storeFile(mStoreDiscSet, fn);
+ storeFile.Open(false /* no overwriting */);
+ int64_t spaceAdjustFromDiff = 0; // size adjustment from use of patch in old file
+
+ // Diff or full file?
+ if(DiffFromFileID == 0)
+ {
+ // A full file, just store to disc
+ if(!rFile.CopyStreamTo(storeFile, BACKUP_STORE_TIMEOUT))
+ {
+ THROW_EXCEPTION(BackupStoreException, ReadFileFromStreamTimedOut)
+ }
+ }
+ else
+ {
+ // Check that the diffed from ID actually exists in the directory
+ if(dir.FindEntryByID(DiffFromFileID) == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, DiffFromIDNotFoundInDirectory)
+ }
+
+ // Diff file, needs to be recreated.
+ // Choose a temporary filename.
+ std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(mStoreDiscSet, fn + ".difftemp",
+ 1 /* NOT the same disc as the write file, to avoid using lots of space on the same disc unnecessarily */));
+
+ try
+ {
+ // Open it twice
+#ifdef WIN32
+ InvisibleTempFileStream diff(tempFn.c_str(),
+ O_RDWR | O_CREAT | O_BINARY);
+ InvisibleTempFileStream diff2(tempFn.c_str(),
+ O_RDWR | O_BINARY);
+#else
+ FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL);
+ FileStream diff2(tempFn.c_str(), O_RDONLY);
+
+ // Unlink it immediately, so it definitely goes away
+ if(::unlink(tempFn.c_str()) != 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+#endif
+
+ // Stream the incoming diff to this temporary file
+ if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT))
+ {
+ THROW_EXCEPTION(BackupStoreException, ReadFileFromStreamTimedOut)
+ }
+
+ // Verify the diff
+ diff.Seek(0, IOStream::SeekType_Absolute);
+ if(!BackupStoreFile::VerifyEncodedFileFormat(diff))
+ {
+ THROW_EXCEPTION(BackupStoreException, AddedFileDoesNotVerify)
+ }
+
+ // Seek to beginning of diff file
+ diff.Seek(0, IOStream::SeekType_Absolute);
+
+ // Filename of the old version
+ std::string oldVersionFilename;
+ MakeObjectFilename(DiffFromFileID, oldVersionFilename, false /* no need to make sure the directory it's in exists */);
+
+ // Reassemble that diff -- open previous file, and combine the patch and file
+ std::auto_ptr<RaidFileRead> from(RaidFileRead::Open(mStoreDiscSet, oldVersionFilename));
+ BackupStoreFile::CombineFile(diff, diff2, *from, storeFile);
+
+ // Then... reverse the patch back (open the from file again, and create a write file to overwrite it)
+ std::auto_ptr<RaidFileRead> from2(RaidFileRead::Open(mStoreDiscSet, oldVersionFilename));
+ ppreviousVerStoreFile = new RaidFileWrite(mStoreDiscSet, oldVersionFilename);
+ ppreviousVerStoreFile->Open(true /* allow overwriting */);
+ from->Seek(0, IOStream::SeekType_Absolute);
+ diff.Seek(0, IOStream::SeekType_Absolute);
+ BackupStoreFile::ReverseDiffFile(diff, *from, *from2, *ppreviousVerStoreFile,
+ DiffFromFileID, &reversedDiffIsCompletelyDifferent);
+
+ // Store disc space used
+ oldVersionNewBlocksUsed = ppreviousVerStoreFile->GetDiscUsageInBlocks();
+
+ // And make a space adjustment for the size calculation
+ spaceAdjustFromDiff = from->GetDiscUsageInBlocks() - oldVersionNewBlocksUsed;
+
+ // Everything cleans up here...
+ }
+ catch(...)
+ {
+ // Be very paranoid about deleting this temp file -- we could only leave a zero byte file anyway
+ ::unlink(tempFn.c_str());
+ throw;
+ }
+ }
+
+ // Get the blocks used
+ blocksUsed = storeFile.GetDiscUsageInBlocks();
+
+ // Exceeds the hard limit?
+ if((mpStoreInfo->GetBlocksUsed() + blocksUsed - spaceAdjustFromDiff) > mpStoreInfo->GetBlocksHardLimit())
+ {
+ THROW_EXCEPTION(BackupStoreException, AddedFileExceedsStorageLimit)
+ // The store file will be deleted automatically by the RaidFile object
+ }
+
+ // Commit the file
+ storeFile.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
+ }
+ catch(...)
+ {
+ // Delete any previous version store file
+ if(ppreviousVerStoreFile != 0)
+ {
+ delete ppreviousVerStoreFile;
+ ppreviousVerStoreFile = 0;
+ }
+
+ throw;
+ }
+
+ // Verify the file -- only necessary for non-diffed versions
+ // NOTE: No need to catch exceptions and delete ppreviousVerStoreFile, because
+ // in the non-diffed code path it's never allocated.
+ if(DiffFromFileID == 0)
+ {
+ std::auto_ptr<RaidFileRead> checkFile(RaidFileRead::Open(mStoreDiscSet, fn));
+ if(!BackupStoreFile::VerifyEncodedFileFormat(*checkFile))
+ {
+ // Error! Delete the file
+ RaidFileWrite del(mStoreDiscSet, fn);
+ del.Delete();
+
+ // Exception
+ THROW_EXCEPTION(BackupStoreException, AddedFileDoesNotVerify)
+ }
+ }
+
+ // Modify the directory -- first make all files with the same name
+ // marked as an old version
+ int64_t blocksInOldFiles = 0;
+ try
+ {
+ if(MarkFileWithSameNameAsOldVersions)
+ {
+ BackupStoreDirectory::Iterator i(dir);
+
+ BackupStoreDirectory::Entry *e = 0;
+ while((e = i.Next()) != 0)
+ {
+ // First, check it's not an old version (cheaper comparison)
+ if((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0)
+ {
+ // Compare name
+ if(e->GetName() == rFilename)
+ {
+ // Check that it's definately not an old version
+ ASSERT((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0);
+ // Set old version flag
+ e->AddFlags(BackupStoreDirectory::Entry::Flags_OldVersion);
+ // Can safely do this, because we know we won't be here if it's already
+ // an old version
+ blocksInOldFiles += e->GetSizeInBlocks();
+ }
+ }
+ }
+ }
+
+ // Then the new entry
+ BackupStoreDirectory::Entry *pnewEntry = dir.AddEntry(rFilename,
+ ModificationTime, id, blocksUsed, BackupStoreDirectory::Entry::Flags_File, AttributesHash);
+
+ // Adjust for the patch back stuff?
+ if(DiffFromFileID != 0)
+ {
+ // Get old version entry
+ BackupStoreDirectory::Entry *poldEntry = dir.FindEntryByID(DiffFromFileID);
+ ASSERT(poldEntry != 0);
+
+ // Adjust dependency info of file?
+ if(!reversedDiffIsCompletelyDifferent)
+ {
+ poldEntry->SetDependsNewer(id);
+ pnewEntry->SetDependsOlder(DiffFromFileID);
+ }
+
+ // Adjust size of old entry
+ int64_t oldSize = poldEntry->GetSizeInBlocks();
+ poldEntry->SetSizeInBlocks(oldVersionNewBlocksUsed);
+
+ // And adjust blocks used count, for later adjustment
+ blocksUsed += (oldVersionNewBlocksUsed - oldSize);
+ blocksInOldFiles += (oldVersionNewBlocksUsed - oldSize);
+ }
+
+ // Write the directory back to disc
+ SaveDirectory(dir, InDirectory);
+
+ // Commit the old version's new patched version, now that the directory safely reflects
+ // the state of the files on disc.
+ if(ppreviousVerStoreFile != 0)
+ {
+ ppreviousVerStoreFile->Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
+ delete ppreviousVerStoreFile;
+ ppreviousVerStoreFile = 0;
+ }
+ }
+ catch(...)
+ {
+ // Back out on adding that file
+ RaidFileWrite del(mStoreDiscSet, fn);
+ del.Delete();
+
+ // Remove this entry from the cache
+ RemoveDirectoryFromCache(InDirectory);
+
+ // Delete any previous version store file
+ if(ppreviousVerStoreFile != 0)
+ {
+ delete ppreviousVerStoreFile;
+ ppreviousVerStoreFile = 0;
+ }
+
+ // Don't worry about the incremented number in the store info
+ throw;
+ }
+
+ // Check logic
+ ASSERT(ppreviousVerStoreFile == 0);
+
+ // Modify the store info
+ mpStoreInfo->ChangeBlocksUsed(blocksUsed);
+ mpStoreInfo->ChangeBlocksInOldFiles(blocksInOldFiles);
+
+ // Increment reference count on the new directory to one
+ mapRefCount->AddReference(id);
+
+ // Save the store info -- can cope if this exceptions because infomation
+ // will be rebuilt by housekeeping, and ID allocation can recover.
+ SaveStoreInfo();
+
+ // Return the ID to the caller
+ return id;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &)
+// Purpose: Deletes a file, returning true if the file existed. Object ID returned too, set to zero if not found.
+// Created: 2003/10/21
+//
+// --------------------------------------------------------------------------
+bool BackupStoreContext::DeleteFile(const BackupStoreFilename &rFilename, int64_t InDirectory, int64_t &rObjectIDOut)
+{
+ // Essential checks!
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ // Find the directory the file is in (will exception if it fails)
+ BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
+
+ // Setup flags
+ bool fileExisted = false;
+ bool madeChanges = false;
+ rObjectIDOut = 0; // not found
+
+ // Count of deleted blocks
+ int64_t blocksDel = 0;
+
+ try
+ {
+ // Iterate through directory, only looking at files which haven't been deleted
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *e = 0;
+ while((e = i.Next(BackupStoreDirectory::Entry::Flags_File,
+ BackupStoreDirectory::Entry::Flags_Deleted)) != 0)
+ {
+ // Compare name
+ if(e->GetName() == rFilename)
+ {
+ // Check that it's definately not already deleted
+ ASSERT((e->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) == 0);
+ // Set deleted flag
+ e->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
+ // Mark as made a change
+ madeChanges = true;
+ // Can safely do this, because we know we won't be here if it's already
+ // an old version
+ blocksDel += e->GetSizeInBlocks();
+ // Is this the last version?
+ if((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0)
+ {
+ // Yes. It's been found.
+ rObjectIDOut = e->GetObjectID();
+ fileExisted = true;
+ }
+ }
+ }
+
+ // Save changes?
+ if(madeChanges)
+ {
+ // Save the directory back
+ SaveDirectory(dir, InDirectory);
+
+ // Modify the store info, and write
+ mpStoreInfo->ChangeBlocksInDeletedFiles(blocksDel);
+
+ // Maybe postponed save of store info
+ SaveStoreInfo();
+ }
+ }
+ catch(...)
+ {
+ RemoveDirectoryFromCache(InDirectory);
+ throw;
+ }
+
+ return fileExisted;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::UndeleteFile(int64_t, int64_t)
+// Purpose: Undeletes a file, if it exists, returning true if
+// the file existed.
+// Created: 2003/10/21
+//
+// --------------------------------------------------------------------------
+bool BackupStoreContext::UndeleteFile(int64_t ObjectID, int64_t InDirectory)
+{
+ // Essential checks!
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ // Find the directory the file is in (will exception if it fails)
+ BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
+
+ // Setup flags
+ bool fileExisted = false;
+ bool madeChanges = false;
+
+ // Count of deleted blocks
+ int64_t blocksDel = 0;
+
+ try
+ {
+ // Iterate through directory, only looking at files which have been deleted
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *e = 0;
+ while((e = i.Next(BackupStoreDirectory::Entry::Flags_File |
+ BackupStoreDirectory::Entry::Flags_Deleted, 0)) != 0)
+ {
+ // Compare name
+ if(e->GetObjectID() == ObjectID)
+ {
+ // Check that it's definitely already deleted
+ ASSERT((e->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) != 0);
+ // Clear deleted flag
+ e->RemoveFlags(BackupStoreDirectory::Entry::Flags_Deleted);
+ // Mark as made a change
+ madeChanges = true;
+ blocksDel -= e->GetSizeInBlocks();
+
+ // Is this the last version?
+ if((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0)
+ {
+ // Yes. It's been found.
+ fileExisted = true;
+ }
+ }
+ }
+
+ // Save changes?
+ if(madeChanges)
+ {
+ // Save the directory back
+ SaveDirectory(dir, InDirectory);
+
+ // Modify the store info, and write
+ mpStoreInfo->ChangeBlocksInDeletedFiles(blocksDel);
+
+ // Maybe postponed save of store info
+ SaveStoreInfo();
+ }
+ }
+ catch(...)
+ {
+ RemoveDirectoryFromCache(InDirectory);
+ throw;
+ }
+
+ return fileExisted;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::RemoveDirectoryFromCache(int64_t)
+// Purpose: Remove directory from cache
+// Created: 2003/09/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::RemoveDirectoryFromCache(int64_t ObjectID)
+{
+ std::map<int64_t, BackupStoreDirectory*>::iterator item(mDirectoryCache.find(ObjectID));
+ if(item != mDirectoryCache.end())
+ {
+ // Delete this cached object
+ delete item->second;
+ // Erase the entry form the map
+ mDirectoryCache.erase(item);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::SaveDirectory(BackupStoreDirectory &, int64_t)
+// Purpose: Save directory back to disc, update time in cache
+// Created: 2003/09/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+ if(rDir.GetObjectID() != ObjectID)
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ try
+ {
+ // Write to disc, adjust size in store info
+ std::string dirfn;
+ MakeObjectFilename(ObjectID, dirfn);
+ {
+ RaidFileWrite writeDir(mStoreDiscSet, dirfn);
+ writeDir.Open(true /* allow overwriting */);
+
+ BufferedWriteStream buffer(writeDir);
+ rDir.WriteToStream(buffer);
+ buffer.Flush();
+
+ // get the disc usage (must do this before commiting it)
+ int64_t dirSize = writeDir.GetDiscUsageInBlocks();
+
+ // Commit directory
+ writeDir.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
+
+ // Make sure the size of the directory is available for writing the dir back
+ ASSERT(dirSize > 0);
+ int64_t sizeAdjustment = dirSize - rDir.GetUserInfo1_SizeInBlocks();
+ mpStoreInfo->ChangeBlocksUsed(sizeAdjustment);
+ mpStoreInfo->ChangeBlocksInDirectories(sizeAdjustment);
+ // Update size stored in directory
+ rDir.SetUserInfo1_SizeInBlocks(dirSize);
+ }
+ // Refresh revision ID in cache
+ {
+ int64_t revid = 0;
+ if(!RaidFileRead::FileExists(mStoreDiscSet, dirfn, &revid))
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+ rDir.SetRevisionID(revid);
+ }
+ }
+ catch(...)
+ {
+ // Remove it from the cache if anything went wrong
+ RemoveDirectoryFromCache(ObjectID);
+ throw;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::AddDirectory(int64_t,
+// const BackupStoreFilename &, bool &)
+// Purpose: Creates a directory (or just returns the ID of an
+// existing one). rAlreadyExists set appropraitely.
+// Created: 2003/09/04
+//
+// --------------------------------------------------------------------------
+int64_t BackupStoreContext::AddDirectory(int64_t InDirectory, const BackupStoreFilename &rFilename, const StreamableMemBlock &Attributes, int64_t AttributesModTime, bool &rAlreadyExists)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ // Flags as not already existing
+ rAlreadyExists = false;
+
+ // Get the directory we want to modify
+ BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
+
+ // Scan the directory for the name (only looking for directories which already exist)
+ {
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = 0;
+ while((en = i.Next(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING,
+ BackupStoreDirectory::Entry::Flags_Deleted | BackupStoreDirectory::Entry::Flags_OldVersion)) != 0) // Ignore deleted and old directories
+ {
+ if(en->GetName() == rFilename)
+ {
+ // Already exists
+ rAlreadyExists = true;
+ return en->GetObjectID();
+ }
+ }
+ }
+
+ // Allocate the next ID
+ int64_t id = AllocateObjectID();
+
+ // Create an empty directory with the given attributes on disc
+ std::string fn;
+ MakeObjectFilename(id, fn, true /* make sure the directory it's in exists */);
+ {
+ BackupStoreDirectory emptyDir(id, InDirectory);
+ // add the atttribues
+ emptyDir.SetAttributes(Attributes, AttributesModTime);
+
+ // Write...
+ RaidFileWrite dirFile(mStoreDiscSet, fn);
+ dirFile.Open(false /* no overwriting */);
+ emptyDir.WriteToStream(dirFile);
+ // Get disc usage, before it's commited
+ int64_t dirSize = dirFile.GetDiscUsageInBlocks();
+ // Commit the file
+ dirFile.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
+
+ // Make sure the size of the directory is added to the usage counts in the info
+ ASSERT(dirSize > 0);
+ mpStoreInfo->ChangeBlocksUsed(dirSize);
+ mpStoreInfo->ChangeBlocksInDirectories(dirSize);
+ // Not added to cache, so don't set the size in the directory
+ }
+
+ // Then add it into the parent directory
+ try
+ {
+ dir.AddEntry(rFilename, 0 /* modification time */, id, 0 /* blocks used */, BackupStoreDirectory::Entry::Flags_Dir, 0 /* attributes mod time */);
+ SaveDirectory(dir, InDirectory);
+
+ // Increment reference count on the new directory to one
+ mapRefCount->AddReference(id);
+ }
+ catch(...)
+ {
+ // Back out on adding that directory
+ RaidFileWrite del(mStoreDiscSet, fn);
+ del.Delete();
+
+ // Remove this entry from the cache
+ RemoveDirectoryFromCache(InDirectory);
+
+ // Don't worry about the incremented number in the store info
+ throw;
+ }
+
+ // Save the store info (may be postponed)
+ SaveStoreInfo();
+
+ // tell caller what the ID was
+ return id;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &, bool)
+// Purpose: Recusively deletes a directory (or undeletes if Undelete = true)
+// Created: 2003/10/21
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::DeleteDirectory(int64_t ObjectID, bool Undelete)
+{
+ // Essential checks!
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ // Containing directory
+ int64_t InDirectory = 0;
+
+ // Count of blocks deleted
+ int64_t blocksDeleted = 0;
+
+ try
+ {
+ // Get the directory that's to be deleted
+ {
+ // In block, because dir may not be valid after the delete directory call
+ BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
+
+ // Store the directory it's in for later
+ InDirectory = dir.GetContainerID();
+
+ // Depth first delete of contents
+ DeleteDirectoryRecurse(ObjectID, blocksDeleted, Undelete);
+ }
+
+ // Remove the entry from the directory it's in
+ ASSERT(InDirectory != 0);
+ BackupStoreDirectory &parentDir(GetDirectoryInternal(InDirectory));
+
+ BackupStoreDirectory::Iterator i(parentDir);
+ BackupStoreDirectory::Entry *en = 0;
+ while((en = i.Next(Undelete?(BackupStoreDirectory::Entry::Flags_Deleted):(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING),
+ Undelete?(0):(BackupStoreDirectory::Entry::Flags_Deleted))) != 0) // Ignore deleted directories (or not deleted if Undelete)
+ {
+ if(en->GetObjectID() == ObjectID)
+ {
+ // This is the one to delete
+ if(Undelete)
+ {
+ en->RemoveFlags(BackupStoreDirectory::Entry::Flags_Deleted);
+ }
+ else
+ {
+ en->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
+ }
+
+ // Save it
+ SaveDirectory(parentDir, InDirectory);
+
+ // Done
+ break;
+ }
+ }
+
+ // Update blocks deleted count
+ mpStoreInfo->ChangeBlocksInDeletedFiles(Undelete?(0 - blocksDeleted):(blocksDeleted));
+
+ // Save store info, may be postponed
+ SaveStoreInfo();
+ }
+ catch(...)
+ {
+ RemoveDirectoryFromCache(InDirectory);
+ throw;
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::DeleteDirectoryRecurse(BackupStoreDirectory &, int64_t)
+// Purpose: Private. Deletes a directory depth-first recusively.
+// Created: 2003/10/21
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::DeleteDirectoryRecurse(int64_t ObjectID, int64_t &rBlocksDeletedOut, bool Undelete)
+{
+ try
+ {
+ // Does things carefully to avoid using a directory in the cache after recursive call
+ // because it may have been deleted.
+
+ // Do sub directories
+ {
+ // Get the directory...
+ BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
+
+ // Then scan it for directories
+ std::vector<int64_t> subDirs;
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = 0;
+ if(Undelete)
+ {
+ while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir | BackupStoreDirectory::Entry::Flags_Deleted, // deleted dirs
+ BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING)) != 0)
+ {
+ // Store the directory ID.
+ subDirs.push_back(en->GetObjectID());
+ }
+ }
+ else
+ {
+ while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir, // dirs only
+ BackupStoreDirectory::Entry::Flags_Deleted)) != 0) // but not deleted ones
+ {
+ // Store the directory ID.
+ subDirs.push_back(en->GetObjectID());
+ }
+ }
+
+ // Done with the directory for now. Recurse to sub directories
+ for(std::vector<int64_t>::const_iterator i = subDirs.begin(); i != subDirs.end(); ++i)
+ {
+ DeleteDirectoryRecurse((*i), rBlocksDeletedOut, Undelete);
+ }
+ }
+
+ // Then, delete the files. Will need to load the directory again because it might have
+ // been removed from the cache.
+ {
+ // Get the directory...
+ BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
+
+ // Changes made?
+ bool changesMade = false;
+
+ // Run through files
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = 0;
+
+ while((en = i.Next(Undelete?(BackupStoreDirectory::Entry::Flags_Deleted):(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING),
+ Undelete?(0):(BackupStoreDirectory::Entry::Flags_Deleted))) != 0) // Ignore deleted directories (or not deleted if Undelete)
+ {
+ // Add/remove the deleted flags
+ if(Undelete)
+ {
+ en->RemoveFlags(BackupStoreDirectory::Entry::Flags_Deleted);
+ }
+ else
+ {
+ en->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
+ }
+
+ // Keep count of the deleted blocks
+ if((en->GetFlags() & BackupStoreDirectory::Entry::Flags_File) != 0)
+ {
+ rBlocksDeletedOut += en->GetSizeInBlocks();
+ }
+
+ // Did something
+ changesMade = true;
+ }
+
+ // Save the directory
+ if(changesMade)
+ {
+ SaveDirectory(dir, ObjectID);
+ }
+ }
+ }
+ catch(...)
+ {
+ RemoveDirectoryFromCache(ObjectID);
+ throw;
+ }
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::ChangeDirAttributes(int64_t, const StreamableMemBlock &, int64_t)
+// Purpose: Change the attributes of a directory
+// Created: 2003/09/06
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::ChangeDirAttributes(int64_t Directory, const StreamableMemBlock &Attributes, int64_t AttributesModTime)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ try
+ {
+ // Get the directory we want to modify
+ BackupStoreDirectory &dir(GetDirectoryInternal(Directory));
+
+ // Set attributes
+ dir.SetAttributes(Attributes, AttributesModTime);
+
+ // Save back
+ SaveDirectory(dir, Directory);
+ }
+ catch(...)
+ {
+ RemoveDirectoryFromCache(Directory);
+ throw;
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::ChangeFileAttributes(int64_t, int64_t, const StreamableMemBlock &, int64_t)
+// Purpose: Sets the attributes on a directory entry. Returns true if the object existed, false if it didn't.
+// Created: 2003/09/06
+//
+// --------------------------------------------------------------------------
+bool BackupStoreContext::ChangeFileAttributes(const BackupStoreFilename &rFilename, int64_t InDirectory, const StreamableMemBlock &Attributes, int64_t AttributesHash, int64_t &rObjectIDOut)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ try
+ {
+ // Get the directory we want to modify
+ BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
+
+ // Find the file entry
+ BackupStoreDirectory::Entry *en = 0;
+ // Iterate through current versions of files, only
+ BackupStoreDirectory::Iterator i(dir);
+ while((en = i.Next(
+ BackupStoreDirectory::Entry::Flags_File,
+ BackupStoreDirectory::Entry::Flags_Deleted | BackupStoreDirectory::Entry::Flags_OldVersion)
+ ) != 0)
+ {
+ if(en->GetName() == rFilename)
+ {
+ // Set attributes
+ en->SetAttributes(Attributes, AttributesHash);
+
+ // Tell caller the object ID
+ rObjectIDOut = en->GetObjectID();
+
+ // Done
+ break;
+ }
+ }
+ if(en == 0)
+ {
+ // Didn't find it
+ return false;
+ }
+
+ // Save back
+ SaveDirectory(dir, InDirectory);
+ }
+ catch(...)
+ {
+ RemoveDirectoryFromCache(InDirectory);
+ throw;
+ }
+
+ // Changed, everything OK
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::ObjectExists(int64_t)
+// Purpose: Test to see if an object of this ID exists in the store
+// Created: 2003/09/03
+//
+// --------------------------------------------------------------------------
+bool BackupStoreContext::ObjectExists(int64_t ObjectID, int MustBe)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ // Note that we need to allow object IDs a little bit greater than the last one in the store info,
+ // because the store info may not have got saved in an error condition. Max greater ID is
+ // STORE_INFO_SAVE_DELAY in this case, *2 to be safe.
+ if(ObjectID <= 0 || ObjectID > (mpStoreInfo->GetLastObjectIDUsed() + (STORE_INFO_SAVE_DELAY * 2)))
+ {
+ // Obviously bad object ID
+ return false;
+ }
+
+ // Test to see if it exists on the disc
+ std::string filename;
+ MakeObjectFilename(ObjectID, filename);
+ if(!RaidFileRead::FileExists(mStoreDiscSet, filename))
+ {
+ // RaidFile reports no file there
+ return false;
+ }
+
+ // Do we need to be more specific?
+ if(MustBe != ObjectExists_Anything)
+ {
+ // Open the file
+ std::auto_ptr<RaidFileRead> objectFile(RaidFileRead::Open(mStoreDiscSet, filename));
+
+ // Read the first integer
+ u_int32_t magic;
+ if(!objectFile->ReadFullBuffer(&magic, sizeof(magic), 0 /* not interested in how many read if failure */))
+ {
+ // Failed to get any bytes, must have failed
+ return false;
+ }
+
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ if(MustBe == ObjectExists_File && ntohl(magic) == OBJECTMAGIC_FILE_MAGIC_VALUE_V0)
+ {
+ // Old version detected
+ return true;
+ }
+#endif
+
+ // Right one?
+ u_int32_t requiredMagic = (MustBe == ObjectExists_File)?OBJECTMAGIC_FILE_MAGIC_VALUE_V1:OBJECTMAGIC_DIR_MAGIC_VALUE;
+
+ // Check
+ if(ntohl(magic) != requiredMagic)
+ {
+ return false;
+ }
+
+ // File is implicitly closed
+ }
+
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::OpenObject(int64_t)
+// Purpose: Opens an object
+// Created: 2003/09/03
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<IOStream> BackupStoreContext::OpenObject(int64_t ObjectID)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ // Attempt to open the file
+ std::string fn;
+ MakeObjectFilename(ObjectID, fn);
+ return std::auto_ptr<IOStream>(RaidFileRead::Open(mStoreDiscSet, fn).release());
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::GetClientStoreMarker()
+// Purpose: Retrieve the client store marker
+// Created: 2003/10/29
+//
+// --------------------------------------------------------------------------
+int64_t BackupStoreContext::GetClientStoreMarker()
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ return mpStoreInfo->GetClientStoreMarker();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::GetStoreDiscUsageInfo(int64_t &, int64_t &, int64_t &)
+// Purpose: Get disc usage info from store info
+// Created: 1/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::GetStoreDiscUsageInfo(int64_t &rBlocksUsed, int64_t &rBlocksSoftLimit, int64_t &rBlocksHardLimit)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ rBlocksUsed = mpStoreInfo->GetBlocksUsed();
+ rBlocksSoftLimit = mpStoreInfo->GetBlocksSoftLimit();
+ rBlocksHardLimit = mpStoreInfo->GetBlocksHardLimit();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::HardLimitExceeded()
+// Purpose: Returns true if the hard limit has been exceeded
+// Created: 1/1/04
+//
+// --------------------------------------------------------------------------
+bool BackupStoreContext::HardLimitExceeded()
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ return mpStoreInfo->GetBlocksUsed() > mpStoreInfo->GetBlocksHardLimit();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::SetClientStoreMarker(int64_t)
+// Purpose: Sets the client store marker, and commits it to disc
+// Created: 2003/10/29
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::SetClientStoreMarker(int64_t ClientStoreMarker)
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ mpStoreInfo->SetClientStoreMarker(ClientStoreMarker);
+ SaveStoreInfo(false /* don't delay saving this */);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::MoveObject(int64_t, int64_t, int64_t, const BackupStoreFilename &, bool)
+// Purpose: Move an object (and all objects with the same name) from one directory to another
+// Created: 12/11/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreContext::MoveObject(int64_t ObjectID, int64_t MoveFromDirectory, int64_t MoveToDirectory, const BackupStoreFilename &rNewFilename, bool MoveAllWithSameName, bool AllowMoveOverDeletedObject)
+{
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
+ }
+
+ // Should deleted files be excluded when checking for the existance of objects with the target name?
+ int64_t targetSearchExcludeFlags = (AllowMoveOverDeletedObject)
+ ?(BackupStoreDirectory::Entry::Flags_Deleted)
+ :(BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING);
+
+ // Special case if the directories are the same...
+ if(MoveFromDirectory == MoveToDirectory)
+ {
+ try
+ {
+ // Get the first directory
+ BackupStoreDirectory &dir(GetDirectoryInternal(MoveFromDirectory));
+
+ // Find the file entry
+ BackupStoreDirectory::Entry *en = dir.FindEntryByID(ObjectID);
+
+ // Error if not found
+ if(en == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldNotFindEntryInDirectory)
+ }
+
+ // Check the new name doens't already exist (optionally ignoring deleted files)
+ {
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *c = 0;
+ while((c = i.Next(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING, targetSearchExcludeFlags)) != 0)
+ {
+ if(c->GetName() == rNewFilename)
+ {
+ THROW_EXCEPTION(BackupStoreException, NameAlreadyExistsInDirectory)
+ }
+ }
+ }
+
+ // Need to get all the entries with the same name?
+ if(MoveAllWithSameName)
+ {
+ // Iterate through the directory, copying all with matching names
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *c = 0;
+ while((c = i.Next()) != 0)
+ {
+ if(c->GetName() == en->GetName())
+ {
+ // Rename this one
+ c->SetName(rNewFilename);
+ }
+ }
+ }
+ else
+ {
+ // Just copy this one
+ en->SetName(rNewFilename);
+ }
+
+ // Save the directory back
+ SaveDirectory(dir, MoveFromDirectory);
+ }
+ catch(...)
+ {
+ RemoveDirectoryFromCache(MoveToDirectory); // either will do, as they're the same
+ throw;
+ }
+
+ return;
+ }
+
+ // Got to be careful how this is written, as we can't guarentte that if we have two
+ // directories open, the first won't be deleted as the second is opened. (cache)
+
+ // List of entries to move
+ std::vector<BackupStoreDirectory::Entry *> moving;
+
+ // list of directory IDs which need to have containing dir id changed
+ std::vector<int64_t> dirsToChangeContainingID;
+
+ try
+ {
+ // First of all, get copies of the entries to move to the to directory.
+
+ {
+ // Get the first directory
+ BackupStoreDirectory &from(GetDirectoryInternal(MoveFromDirectory));
+
+ // Find the file entry
+ BackupStoreDirectory::Entry *en = from.FindEntryByID(ObjectID);
+
+ // Error if not found
+ if(en == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldNotFindEntryInDirectory)
+ }
+
+ // Need to get all the entries with the same name?
+ if(MoveAllWithSameName)
+ {
+ // Iterate through the directory, copying all with matching names
+ BackupStoreDirectory::Iterator i(from);
+ BackupStoreDirectory::Entry *c = 0;
+ while((c = i.Next()) != 0)
+ {
+ if(c->GetName() == en->GetName())
+ {
+ // Copy
+ moving.push_back(new BackupStoreDirectory::Entry(*c));
+
+ // Check for containing directory correction
+ if(c->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) dirsToChangeContainingID.push_back(c->GetObjectID());
+ }
+ }
+ ASSERT(!moving.empty());
+ }
+ else
+ {
+ // Just copy this one
+ moving.push_back(new BackupStoreDirectory::Entry(*en));
+
+ // Check for containing directory correction
+ if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) dirsToChangeContainingID.push_back(en->GetObjectID());
+ }
+ }
+
+ // Secondly, insert them into the to directory, and save it
+
+ {
+ // To directory
+ BackupStoreDirectory &to(GetDirectoryInternal(MoveToDirectory));
+
+ // Check the new name doens't already exist
+ {
+ BackupStoreDirectory::Iterator i(to);
+ BackupStoreDirectory::Entry *c = 0;
+ while((c = i.Next(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING, targetSearchExcludeFlags)) != 0)
+ {
+ if(c->GetName() == rNewFilename)
+ {
+ THROW_EXCEPTION(BackupStoreException, NameAlreadyExistsInDirectory)
+ }
+ }
+ }
+
+ // Copy the entries into it, changing the name as we go
+ for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
+ {
+ BackupStoreDirectory::Entry *en = (*i);
+ en->SetName(rNewFilename);
+ to.AddEntry(*en); // adds copy
+ }
+
+ // Save back
+ SaveDirectory(to, MoveToDirectory);
+ }
+
+ // Thirdly... remove them from the first directory -- but if it fails, attempt to delete them from the to directory
+ try
+ {
+ // Get directory
+ BackupStoreDirectory &from(GetDirectoryInternal(MoveFromDirectory));
+
+ // Delete each one
+ for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
+ {
+ from.DeleteEntry((*i)->GetObjectID());
+ }
+
+ // Save back
+ SaveDirectory(from, MoveFromDirectory);
+ }
+ catch(...)
+ {
+ // UNDO modification to To directory
+
+ // Get directory
+ BackupStoreDirectory &to(GetDirectoryInternal(MoveToDirectory));
+
+ // Delete each one
+ for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
+ {
+ to.DeleteEntry((*i)->GetObjectID());
+ }
+
+ // Save back
+ SaveDirectory(to, MoveToDirectory);
+
+ // Throw the error
+ throw;
+ }
+
+ // Finally... for all the directories we moved, modify their containing directory ID
+ for(std::vector<int64_t>::iterator i(dirsToChangeContainingID.begin()); i != dirsToChangeContainingID.end(); ++i)
+ {
+ // Load the directory
+ BackupStoreDirectory &change(GetDirectoryInternal(*i));
+
+ // Modify containing dir ID
+ change.SetContainerID(MoveToDirectory);
+
+ // Save it back
+ SaveDirectory(change, *i);
+ }
+ }
+ catch(...)
+ {
+ // Make sure directories aren't in the cache, as they may have been modified
+ RemoveDirectoryFromCache(MoveToDirectory);
+ RemoveDirectoryFromCache(MoveFromDirectory);
+ for(std::vector<int64_t>::iterator i(dirsToChangeContainingID.begin()); i != dirsToChangeContainingID.end(); ++i)
+ {
+ RemoveDirectoryFromCache(*i);
+ }
+
+ while(!moving.empty())
+ {
+ delete moving.back();
+ moving.pop_back();
+ }
+ throw;
+ }
+
+ // Clean up
+ while(!moving.empty())
+ {
+ delete moving.back();
+ moving.pop_back();
+ }
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreContext::GetBackupStoreInfo()
+// Purpose: Return the backup store info object, exception if it isn't loaded
+// Created: 19/4/04
+//
+// --------------------------------------------------------------------------
+const BackupStoreInfo &BackupStoreContext::GetBackupStoreInfo() const
+{
+ if(mpStoreInfo.get() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
+ }
+
+ return *(mpStoreInfo.get());
+}
+
+
diff --git a/bin/bbstored/BackupStoreContext.h b/bin/bbstored/BackupStoreContext.h
new file mode 100644
index 00000000..6053e4b8
--- /dev/null
+++ b/bin/bbstored/BackupStoreContext.h
@@ -0,0 +1,186 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreContext.h
+// Purpose: Context for backup store server
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPCONTEXT__H
+#define BACKUPCONTEXT__H
+
+#include <string>
+#include <map>
+#include <memory>
+
+#include "BackupStoreRefCountDatabase.h"
+#include "NamedLock.h"
+#include "ProtocolObject.h"
+#include "Utils.h"
+
+class BackupStoreDirectory;
+class BackupStoreFilename;
+class BackupStoreDaemon;
+class BackupStoreInfo;
+class IOStream;
+class BackupProtocolObject;
+class StreamableMemBlock;
+
+class HousekeepingInterface
+{
+ public:
+ virtual ~HousekeepingInterface() { }
+ virtual void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: BackupStoreContext
+// Purpose: Context for backup store server
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+class BackupStoreContext
+{
+public:
+ BackupStoreContext(int32_t ClientID, HousekeepingInterface &rDaemon);
+ ~BackupStoreContext();
+private:
+ BackupStoreContext(const BackupStoreContext &rToCopy);
+public:
+
+ void ReceivedFinishCommand();
+ void CleanUp();
+
+ int32_t GetClientID() {return mClientID;}
+
+ enum
+ {
+ Phase_START = 0,
+ Phase_Version = 0,
+ Phase_Login = 1,
+ Phase_Commands = 2
+ };
+
+ int GetPhase() const {return mProtocolPhase;}
+ void SetPhase(int NewPhase) {mProtocolPhase = NewPhase;}
+
+ // Read only locking
+ bool SessionIsReadOnly() {return mReadOnly;}
+ bool AttemptToGetWriteLock();
+
+ void SetClientHasAccount(const std::string &rStoreRoot, int StoreDiscSet) {mClientHasAccount = true; mStoreRoot = rStoreRoot; mStoreDiscSet = StoreDiscSet;}
+ bool GetClientHasAccount() const {return mClientHasAccount;}
+ const std::string &GetStoreRoot() const {return mStoreRoot;}
+ int GetStoreDiscSet() const {return mStoreDiscSet;}
+
+ // Store info
+ void LoadStoreInfo();
+ void SaveStoreInfo(bool AllowDelay = true);
+ const BackupStoreInfo &GetBackupStoreInfo() const;
+
+ // Client marker
+ int64_t GetClientStoreMarker();
+ void SetClientStoreMarker(int64_t ClientStoreMarker);
+
+ // Usage information
+ void GetStoreDiscUsageInfo(int64_t &rBlocksUsed, int64_t &rBlocksSoftLimit, int64_t &rBlocksHardLimit);
+ bool HardLimitExceeded();
+
+ // Reading directories
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupStoreContext::GetDirectory(int64_t)
+ // Purpose: Return a reference to a directory. Valid only until the
+ // next time a function which affects directories is called.
+ // Mainly this funciton, and creation of files.
+ // Created: 2003/09/02
+ //
+ // --------------------------------------------------------------------------
+ const BackupStoreDirectory &GetDirectory(int64_t ObjectID)
+ {
+ // External callers aren't allowed to change it -- this function
+ // merely turns the the returned directory const.
+ return GetDirectoryInternal(ObjectID);
+ }
+
+ // Manipulating files/directories
+ int64_t AddFile(IOStream &rFile, int64_t InDirectory, int64_t ModificationTime, int64_t AttributesHash, int64_t DiffFromFileID, const BackupStoreFilename &rFilename, bool MarkFileWithSameNameAsOldVersions);
+ int64_t AddDirectory(int64_t InDirectory, const BackupStoreFilename &rFilename, const StreamableMemBlock &Attributes, int64_t AttributesModTime, bool &rAlreadyExists);
+ void ChangeDirAttributes(int64_t Directory, const StreamableMemBlock &Attributes, int64_t AttributesModTime);
+ bool ChangeFileAttributes(const BackupStoreFilename &rFilename, int64_t InDirectory, const StreamableMemBlock &Attributes, int64_t AttributesHash, int64_t &rObjectIDOut);
+ bool DeleteFile(const BackupStoreFilename &rFilename, int64_t InDirectory, int64_t &rObjectIDOut);
+ bool UndeleteFile(int64_t ObjectID, int64_t InDirectory);
+ void DeleteDirectory(int64_t ObjectID, bool Undelete = false);
+ void MoveObject(int64_t ObjectID, int64_t MoveFromDirectory, int64_t MoveToDirectory, const BackupStoreFilename &rNewFilename, bool MoveAllWithSameName, bool AllowMoveOverDeletedObject);
+
+ // Manipulating objects
+ enum
+ {
+ ObjectExists_Anything = 0,
+ ObjectExists_File = 1,
+ ObjectExists_Directory = 2
+ };
+ bool ObjectExists(int64_t ObjectID, int MustBe = ObjectExists_Anything);
+ std::auto_ptr<IOStream> OpenObject(int64_t ObjectID);
+
+ // Info
+ int32_t GetClientID() const {return mClientID;}
+
+private:
+ void MakeObjectFilename(int64_t ObjectID, std::string &rOutput, bool EnsureDirectoryExists = false);
+ BackupStoreDirectory &GetDirectoryInternal(int64_t ObjectID);
+ void SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID);
+ void RemoveDirectoryFromCache(int64_t ObjectID);
+ void DeleteDirectoryRecurse(int64_t ObjectID, int64_t &rBlocksDeletedOut, bool Undelete);
+ int64_t AllocateObjectID();
+
+ int32_t mClientID;
+ HousekeepingInterface &mrDaemon;
+ int mProtocolPhase;
+ bool mClientHasAccount;
+ std::string mStoreRoot; // has final directory separator
+ int mStoreDiscSet;
+ bool mReadOnly;
+ NamedLock mWriteLock;
+ int mSaveStoreInfoDelay; // how many times to delay saving the store info
+
+ // Store info
+ std::auto_ptr<BackupStoreInfo> mpStoreInfo;
+
+ // Refcount database
+ std::auto_ptr<BackupStoreRefCountDatabase> mapRefCount;
+
+ // Directory cache
+ std::map<int64_t, BackupStoreDirectory*> mDirectoryCache;
+
+public:
+ class TestHook
+ {
+ public:
+ virtual std::auto_ptr<ProtocolObject> StartCommand(BackupProtocolObject&
+ rCommand) = 0;
+ virtual ~TestHook() { }
+ };
+ void SetTestHook(TestHook& rTestHook)
+ {
+ mpTestHook = &rTestHook;
+ }
+ std::auto_ptr<ProtocolObject> StartCommandHook(BackupProtocolObject& rCommand)
+ {
+ if(mpTestHook)
+ {
+ return mpTestHook->StartCommand(rCommand);
+ }
+ return std::auto_ptr<ProtocolObject>();
+ }
+
+private:
+ TestHook* mpTestHook;
+};
+
+#endif // BACKUPCONTEXT__H
+
diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp
new file mode 100644
index 00000000..0ccbcf23
--- /dev/null
+++ b/bin/bbstored/HousekeepStoreAccount.cpp
@@ -0,0 +1,1067 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: HousekeepStoreAccount.cpp
+// Purpose:
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <stdio.h>
+
+#include <map>
+
+#include "HousekeepStoreAccount.h"
+#include "BackupStoreDaemon.h"
+#include "StoreStructure.h"
+#include "BackupStoreConstants.h"
+#include "RaidFileRead.h"
+#include "RaidFileWrite.h"
+#include "BackupStoreDirectory.h"
+#include "BackupStoreInfo.h"
+#include "NamedLock.h"
+#include "autogen_BackupStoreException.h"
+#include "BackupStoreFile.h"
+#include "BufferedStream.h"
+
+#include "MemLeakFindOn.h"
+
+// check every 32 directories scanned/files deleted
+#define POLL_INTERPROCESS_MSG_CHECK_FREQUENCY 32
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::HousekeepStoreAccount(int, const std::string &, int, BackupStoreDaemon &)
+// Purpose: Constructor
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+HousekeepStoreAccount::HousekeepStoreAccount(int AccountID,
+ const std::string &rStoreRoot, int StoreDiscSet,
+ HousekeepingCallback* pHousekeepingCallback)
+ : mAccountID(AccountID),
+ mStoreRoot(rStoreRoot),
+ mStoreDiscSet(StoreDiscSet),
+ mpHousekeepingCallback(pHousekeepingCallback),
+ mDeletionSizeTarget(0),
+ mPotentialDeletionsTotalSize(0),
+ mMaxSizeInPotentialDeletions(0),
+ mBlocksUsed(0),
+ mBlocksInOldFiles(0),
+ mBlocksInDeletedFiles(0),
+ mBlocksInDirectories(0),
+ mBlocksUsedDelta(0),
+ mBlocksInOldFilesDelta(0),
+ mBlocksInDeletedFilesDelta(0),
+ mBlocksInDirectoriesDelta(0),
+ mFilesDeleted(0),
+ mEmptyDirectoriesDeleted(0),
+ mSuppressRefCountChangeWarnings(false),
+ mCountUntilNextInterprocessMsgCheck(POLL_INTERPROCESS_MSG_CHECK_FREQUENCY)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::~HousekeepStoreAccount()
+// Purpose: Destructor
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+HousekeepStoreAccount::~HousekeepStoreAccount()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::DoHousekeeping()
+// Purpose: Perform the housekeeping
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+void HousekeepStoreAccount::DoHousekeeping(bool KeepTryingForever)
+{
+ // Attempt to lock the account
+ std::string writeLockFilename;
+ StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet,
+ writeLockFilename);
+ NamedLock writeLock;
+ if(!writeLock.TryAndGetLock(writeLockFilename.c_str(),
+ 0600 /* restrictive file permissions */))
+ {
+ if(KeepTryingForever)
+ {
+ BOX_WARNING("Failed to lock account for housekeeping, "
+ "still trying...");
+ while(!writeLock.TryAndGetLock(writeLockFilename,
+ 0600 /* restrictive file permissions */))
+ {
+ sleep(1);
+ }
+ }
+ else
+ {
+ // Couldn't lock the account -- just stop now
+ return;
+ }
+ }
+
+ // Load the store info to find necessary info for the housekeeping
+ std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(mAccountID,
+ mStoreRoot, mStoreDiscSet, false /* Read/Write */));
+
+ // Calculate how much should be deleted
+ mDeletionSizeTarget = info->GetBlocksUsed() - info->GetBlocksSoftLimit();
+ if(mDeletionSizeTarget < 0)
+ {
+ mDeletionSizeTarget = 0;
+ }
+
+ // initialise the refcount database
+ mNewRefCounts.clear();
+ // try to pre-allocate as much memory as we need
+ mNewRefCounts.reserve(info->GetLastObjectIDUsed());
+ // initialise the refcount of the root entry
+ mNewRefCounts.resize(BACKUPSTORE_ROOT_DIRECTORY_ID + 1, 0);
+ mNewRefCounts[BACKUPSTORE_ROOT_DIRECTORY_ID] = 1;
+
+ // Scan the directory for potential things to delete
+ // This will also remove eligible items marked with RemoveASAP
+ bool continueHousekeeping = ScanDirectory(BACKUPSTORE_ROOT_DIRECTORY_ID);
+
+ // If scan directory stopped for some reason, probably parent
+ // instructed to terminate, stop now.
+ if(!continueHousekeeping)
+ {
+ // If any files were marked "delete now", then update
+ // the size of the store.
+ if(mBlocksUsedDelta != 0 ||
+ mBlocksInOldFilesDelta != 0 ||
+ mBlocksInDeletedFilesDelta != 0)
+ {
+ info->ChangeBlocksUsed(mBlocksUsedDelta);
+ info->ChangeBlocksInOldFiles(mBlocksInOldFilesDelta);
+ info->ChangeBlocksInDeletedFiles(mBlocksInDeletedFilesDelta);
+
+ // Save the store info back
+ info->Save();
+ }
+
+ return;
+ }
+
+ // Log any difference in opinion between the values recorded in
+ // the store info, and the values just calculated for space usage.
+ // BLOCK
+ {
+ int64_t used = info->GetBlocksUsed();
+ int64_t usedOld = info->GetBlocksInOldFiles();
+ int64_t usedDeleted = info->GetBlocksInDeletedFiles();
+ int64_t usedDirectories = info->GetBlocksInDirectories();
+
+ // If the counts were wrong, taking into account RemoveASAP
+ // items deleted, log a message
+ if((used + mBlocksUsedDelta) != mBlocksUsed
+ || (usedOld + mBlocksInOldFilesDelta) != mBlocksInOldFiles
+ || (usedDeleted + mBlocksInDeletedFilesDelta) != mBlocksInDeletedFiles
+ || usedDirectories != mBlocksInDirectories)
+ {
+ // Log this
+ BOX_ERROR("Housekeeping on account " <<
+ BOX_FORMAT_ACCOUNT(mAccountID) << " found "
+ "and fixed wrong block counts: "
+ "used (" <<
+ (used + mBlocksUsedDelta) << "," <<
+ mBlocksUsed << "), old (" <<
+ (usedOld + mBlocksInOldFilesDelta) << "," <<
+ mBlocksInOldFiles << "), deleted (" <<
+ (usedDeleted + mBlocksInDeletedFilesDelta) <<
+ "," << mBlocksInDeletedFiles << "), dirs (" <<
+ usedDirectories << "," << mBlocksInDirectories
+ << ")");
+ }
+
+ // If the current values don't match, store them
+ if(used != mBlocksUsed
+ || usedOld != mBlocksInOldFiles
+ || usedDeleted != mBlocksInDeletedFiles
+ || usedDirectories != (mBlocksInDirectories + mBlocksInDirectoriesDelta))
+ {
+ // Set corrected values in store info
+ info->CorrectAllUsedValues(mBlocksUsed,
+ mBlocksInOldFiles, mBlocksInDeletedFiles,
+ mBlocksInDirectories + mBlocksInDirectoriesDelta);
+ info->Save();
+ }
+ }
+
+ // Reset the delta counts for files, as they will include
+ // RemoveASAP flagged files deleted during the initial scan.
+
+ // keep for reporting
+ int64_t removeASAPBlocksUsedDelta = mBlocksUsedDelta;
+
+ mBlocksUsedDelta = 0;
+ mBlocksInOldFilesDelta = 0;
+ mBlocksInDeletedFilesDelta = 0;
+
+ // Go and delete items from the accounts
+ bool deleteInterrupted = DeleteFiles();
+
+ // If that wasn't interrupted, remove any empty directories which
+ // are also marked as deleted in their containing directory
+ if(!deleteInterrupted)
+ {
+ deleteInterrupted = DeleteEmptyDirectories();
+ }
+
+ // Log deletion if anything was deleted
+ if(mFilesDeleted > 0 || mEmptyDirectoriesDeleted > 0)
+ {
+ BOX_INFO("Housekeeping on account " <<
+ BOX_FORMAT_ACCOUNT(mAccountID) << " "
+ "removed " <<
+ (0 - (mBlocksUsedDelta + removeASAPBlocksUsedDelta)) <<
+ " blocks (" << mFilesDeleted << " files, " <<
+ mEmptyDirectoriesDeleted << " dirs)" <<
+ (deleteInterrupted?" and was interrupted":""));
+ }
+
+ // We can only update the refcount database if we successfully
+ // finished our scan of all directories, otherwise we don't actually
+ // know which of the new counts are valid and which aren't
+ // (we might not have seen second references to some objects, etc.)
+
+ BackupStoreAccountDatabase::Entry account(mAccountID, mStoreDiscSet);
+ std::auto_ptr<BackupStoreRefCountDatabase> apReferences;
+
+ // try to load the reference count database
+ try
+ {
+ apReferences = BackupStoreRefCountDatabase::Load(account,
+ false);
+ }
+ catch(BoxException &e)
+ {
+ BOX_WARNING("Reference count database is missing or corrupted "
+ "during housekeeping, creating a new one.");
+ mSuppressRefCountChangeWarnings = true;
+ BackupStoreRefCountDatabase::CreateForRegeneration(account);
+ apReferences = BackupStoreRefCountDatabase::Load(account,
+ false);
+ }
+
+ int64_t LastUsedObjectIdOnDisk = apReferences->GetLastObjectIDUsed();
+
+ for (int64_t ObjectID = BACKUPSTORE_ROOT_DIRECTORY_ID;
+ ObjectID < mNewRefCounts.size(); ObjectID++)
+ {
+ if (ObjectID > LastUsedObjectIdOnDisk)
+ {
+ if (!mSuppressRefCountChangeWarnings)
+ {
+ BOX_WARNING("Reference count of object " <<
+ BOX_FORMAT_OBJECTID(ObjectID) <<
+ " not found in database, added"
+ " with " << mNewRefCounts[ObjectID] <<
+ " references");
+ }
+ apReferences->SetRefCount(ObjectID,
+ mNewRefCounts[ObjectID]);
+ LastUsedObjectIdOnDisk = ObjectID;
+ continue;
+ }
+
+ BackupStoreRefCountDatabase::refcount_t OldRefCount =
+ apReferences->GetRefCount(ObjectID);
+
+ if (OldRefCount != mNewRefCounts[ObjectID])
+ {
+ BOX_WARNING("Reference count of object " <<
+ BOX_FORMAT_OBJECTID(ObjectID) <<
+ " changed from " << OldRefCount <<
+ " to " << mNewRefCounts[ObjectID]);
+ apReferences->SetRefCount(ObjectID,
+ mNewRefCounts[ObjectID]);
+ }
+ }
+
+ // zero excess references in the database
+ for (int64_t ObjectID = mNewRefCounts.size();
+ ObjectID <= LastUsedObjectIdOnDisk; ObjectID++)
+ {
+ BackupStoreRefCountDatabase::refcount_t OldRefCount =
+ apReferences->GetRefCount(ObjectID);
+ BackupStoreRefCountDatabase::refcount_t NewRefCount = 0;
+
+ if (OldRefCount != NewRefCount)
+ {
+ BOX_WARNING("Reference count of object " <<
+ BOX_FORMAT_OBJECTID(ObjectID) <<
+ " changed from " << OldRefCount <<
+ " to " << NewRefCount << " (not found)");
+ apReferences->SetRefCount(ObjectID, NewRefCount);
+ }
+ }
+
+ // force file to be saved and closed before releasing the lock below
+ apReferences.reset();
+
+ // Make sure the delta's won't cause problems if the counts are
+ // really wrong, and it wasn't fixed because the store was
+ // updated during the scan.
+ if(mBlocksUsedDelta < (0 - info->GetBlocksUsed()))
+ {
+ mBlocksUsedDelta = (0 - info->GetBlocksUsed());
+ }
+ if(mBlocksInOldFilesDelta < (0 - info->GetBlocksInOldFiles()))
+ {
+ mBlocksInOldFilesDelta = (0 - info->GetBlocksInOldFiles());
+ }
+ if(mBlocksInDeletedFilesDelta < (0 - info->GetBlocksInDeletedFiles()))
+ {
+ mBlocksInDeletedFilesDelta = (0 - info->GetBlocksInDeletedFiles());
+ }
+ if(mBlocksInDirectoriesDelta < (0 - info->GetBlocksInDirectories()))
+ {
+ mBlocksInDirectoriesDelta = (0 - info->GetBlocksInDirectories());
+ }
+
+ // Update the usage counts in the store
+ info->ChangeBlocksUsed(mBlocksUsedDelta);
+ info->ChangeBlocksInOldFiles(mBlocksInOldFilesDelta);
+ info->ChangeBlocksInDeletedFiles(mBlocksInDeletedFilesDelta);
+ info->ChangeBlocksInDirectories(mBlocksInDirectoriesDelta);
+
+ // Save the store info back
+ info->Save();
+
+ // Explicity release the lock (would happen automatically on
+ // going out of scope, included for code clarity)
+ writeLock.ReleaseLock();
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::MakeObjectFilename(int64_t, std::string &)
+// Purpose: Generate and place the filename for a given object ID
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+void HousekeepStoreAccount::MakeObjectFilename(int64_t ObjectID, std::string &rFilenameOut)
+{
+ // Delegate to utility function
+ StoreStructure::MakeObjectFilename(ObjectID, mStoreRoot, mStoreDiscSet, rFilenameOut, false /* don't bother ensuring the directory exists */);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::ScanDirectory(int64_t)
+// Purpose: Private. Scan a directory for potentially deleteable
+// items, and add them to the list. Returns true if the
+// scan should continue.
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID)
+{
+#ifndef WIN32
+ if((--mCountUntilNextInterprocessMsgCheck) <= 0)
+ {
+ mCountUntilNextInterprocessMsgCheck =
+ POLL_INTERPROCESS_MSG_CHECK_FREQUENCY;
+
+ // Check for having to stop
+ // Include account ID here as the specified account is locked
+ if(mpHousekeepingCallback && mpHousekeepingCallback->CheckForInterProcessMsg(mAccountID))
+ {
+ // Need to abort now
+ return false;
+ }
+ }
+#endif
+
+ // Get the filename
+ std::string objectFilename;
+ MakeObjectFilename(ObjectID, objectFilename);
+
+ // Open it.
+ std::auto_ptr<RaidFileRead> dirStream(RaidFileRead::Open(mStoreDiscSet,
+ objectFilename));
+
+ // Add the size of the directory on disc to the size being calculated
+ int64_t originalDirSizeInBlocks = dirStream->GetDiscUsageInBlocks();
+ mBlocksInDirectories += originalDirSizeInBlocks;
+ mBlocksUsed += originalDirSizeInBlocks;
+
+ // Read the directory in
+ BackupStoreDirectory dir;
+ BufferedStream buf(*dirStream);
+ dir.ReadFromStream(buf, IOStream::TimeOutInfinite);
+ dirStream->Close();
+
+ // Is it empty?
+ if(dir.GetNumberOfEntries() == 0)
+ {
+ // Add it to the list of directories to potentially delete
+ mEmptyDirectories.push_back(dir.GetObjectID());
+ }
+
+ // Calculate reference counts first, before we start requesting
+ // files to be deleted.
+ // BLOCK
+ {
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = 0;
+
+ while((en = i.Next()) != 0)
+ {
+ // This directory references this object
+ if (mNewRefCounts.size() <= en->GetObjectID())
+ {
+ mNewRefCounts.resize(en->GetObjectID() + 1, 0);
+ }
+ mNewRefCounts[en->GetObjectID()]++;
+ }
+ }
+
+ // BLOCK
+ {
+ // Remove any files which are marked for removal as soon
+ // as they become old or deleted.
+ bool deletedSomething = false;
+ do
+ {
+ // Iterate through the directory
+ deletedSomething = false;
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = 0;
+ while((en = i.Next(BackupStoreDirectory::Entry::Flags_File)) != 0)
+ {
+ int16_t enFlags = en->GetFlags();
+ if((enFlags & BackupStoreDirectory::Entry::Flags_RemoveASAP) != 0
+ && (enFlags & (BackupStoreDirectory::Entry::Flags_Deleted | BackupStoreDirectory::Entry::Flags_OldVersion)) != 0)
+ {
+ // Delete this immediately.
+ DeleteFile(ObjectID, en->GetObjectID(), dir, objectFilename, originalDirSizeInBlocks);
+
+ // flag as having done something
+ deletedSomething = true;
+
+ // Must start the loop from the beginning again, as iterator is now
+ // probably invalid.
+ break;
+ }
+ }
+ } while(deletedSomething);
+ }
+
+ // BLOCK
+ {
+ // Add files to the list of potential deletions
+
+ // map to count the distance from the mark
+ typedef std::pair<std::string, int32_t> version_t;
+ std::map<version_t, int32_t> markVersionAges;
+ // map of pair (filename, mark number) -> version age
+
+ // NOTE: use a reverse iterator to allow the distance from mark stuff to work
+ BackupStoreDirectory::ReverseIterator i(dir);
+ BackupStoreDirectory::Entry *en = 0;
+
+ while((en = i.Next(BackupStoreDirectory::Entry::Flags_File)) != 0)
+ {
+ // Update recalculated usage sizes
+ int16_t enFlags = en->GetFlags();
+ int64_t enSizeInBlocks = en->GetSizeInBlocks();
+ mBlocksUsed += enSizeInBlocks;
+ if(enFlags & BackupStoreDirectory::Entry::Flags_OldVersion) mBlocksInOldFiles += enSizeInBlocks;
+ if(enFlags & BackupStoreDirectory::Entry::Flags_Deleted) mBlocksInDeletedFiles += enSizeInBlocks;
+
+ // Work out ages of this version from the last mark
+ int32_t enVersionAge = 0;
+ std::map<version_t, int32_t>::iterator enVersionAgeI(
+ markVersionAges.find(
+ version_t(en->GetName().GetEncodedFilename(),
+ en->GetMarkNumber())));
+ if(enVersionAgeI != markVersionAges.end())
+ {
+ enVersionAge = enVersionAgeI->second + 1;
+ enVersionAgeI->second = enVersionAge;
+ }
+ else
+ {
+ markVersionAges[version_t(en->GetName().GetEncodedFilename(), en->GetMarkNumber())] = enVersionAge;
+ }
+ // enVersionAge is now the age of this version.
+
+ // Potentially add it to the list if it's deleted, if it's an old version or deleted
+ if((enFlags & (BackupStoreDirectory::Entry::Flags_Deleted | BackupStoreDirectory::Entry::Flags_OldVersion)) != 0)
+ {
+ // Is deleted / old version.
+ DelEn d;
+ d.mObjectID = en->GetObjectID();
+ d.mInDirectory = ObjectID;
+ d.mSizeInBlocks = en->GetSizeInBlocks();
+ d.mMarkNumber = en->GetMarkNumber();
+ d.mVersionAgeWithinMark = enVersionAge;
+ d.mIsFlagDeleted = (enFlags &
+ BackupStoreDirectory::Entry::Flags_Deleted)
+ ? true : false;
+
+ // Add it to the list
+ mPotentialDeletions.insert(d);
+
+ // Update various counts
+ mPotentialDeletionsTotalSize += d.mSizeInBlocks;
+ if(d.mSizeInBlocks > mMaxSizeInPotentialDeletions) mMaxSizeInPotentialDeletions = d.mSizeInBlocks;
+
+ // Too much in the list of potential deletions?
+ // (check against the deletion target + the max size in deletions, so that we never delete things
+ // and take the total size below the deletion size target)
+ if(mPotentialDeletionsTotalSize > (mDeletionSizeTarget + mMaxSizeInPotentialDeletions))
+ {
+ int64_t sizeToRemove = mPotentialDeletionsTotalSize - (mDeletionSizeTarget + mMaxSizeInPotentialDeletions);
+ bool recalcMaxSize = false;
+
+ while(sizeToRemove > 0)
+ {
+ // Make iterator for the last element, while checking that there's something there in the first place.
+ std::set<DelEn, DelEnCompare>::iterator i(mPotentialDeletions.end());
+ if(i != mPotentialDeletions.begin())
+ {
+ // Nothing left in set
+ break;
+ }
+ // Make this into an iterator pointing to the last element in the set
+ --i;
+
+ // Delete this one?
+ if(sizeToRemove > i->mSizeInBlocks)
+ {
+ sizeToRemove -= i->mSizeInBlocks;
+ if(i->mSizeInBlocks >= mMaxSizeInPotentialDeletions)
+ {
+ // Will need to recalculate the maximum size now, because we've just deleted that element
+ recalcMaxSize = true;
+ }
+ mPotentialDeletions.erase(i);
+ }
+ else
+ {
+ // Over the size to remove, so stop now
+ break;
+ }
+ }
+
+ if(recalcMaxSize)
+ {
+ // Because an object which was the maximum size recorded was deleted from the set
+ // it's necessary to recalculate this maximum.
+ mMaxSizeInPotentialDeletions = 0;
+ std::set<DelEn, DelEnCompare>::const_iterator i(mPotentialDeletions.begin());
+ for(; i != mPotentialDeletions.end(); ++i)
+ {
+ if(i->mSizeInBlocks > mMaxSizeInPotentialDeletions)
+ {
+ mMaxSizeInPotentialDeletions = i->mSizeInBlocks;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ {
+ // Recurse into subdirectories
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = 0;
+ while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir)) != 0)
+ {
+ // Next level
+ ASSERT((en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) == BackupStoreDirectory::Entry::Flags_Dir);
+
+ if(!ScanDirectory(en->GetObjectID()))
+ {
+ // Halting operation
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::DelEnCompare::operator()(const HousekeepStoreAccount::DelEn &, const HousekeepStoreAccount::DelEnd &)
+// Purpose: Comparison function for set
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+bool HousekeepStoreAccount::DelEnCompare::operator()(const HousekeepStoreAccount::DelEn &x, const HousekeepStoreAccount::DelEn &y)
+{
+ // STL spec says this:
+ // A Strict Weak Ordering is a Binary Predicate that compares two objects, returning true if the first precedes the second.
+
+ // The sort order here is intended to preserve the entries of most value, that is, the newest objects
+ // which are on a mark boundary.
+
+ // Reverse order age, so oldest goes first
+ if(x.mVersionAgeWithinMark > y.mVersionAgeWithinMark)
+ {
+ return true;
+ }
+ else if(x.mVersionAgeWithinMark < y.mVersionAgeWithinMark)
+ {
+ return false;
+ }
+
+ // but mark number in ascending order, so that the oldest marks are deleted first
+ if(x.mMarkNumber < y.mMarkNumber)
+ {
+ return true;
+ }
+ else if(x.mMarkNumber > y.mMarkNumber)
+ {
+ return false;
+ }
+
+ // Just compare object ID now to put the oldest objects first
+ return x.mObjectID < y.mObjectID;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::DeleteFiles()
+// Purpose: Delete the files targetted for deletion, returning true if the operation was interrupted
+// Created: 15/12/03
+//
+// --------------------------------------------------------------------------
+bool HousekeepStoreAccount::DeleteFiles()
+{
+ // Only delete files if the deletion target is greater than zero
+ // (otherwise we delete one file each time round, which gradually deletes the old versions)
+ if(mDeletionSizeTarget <= 0)
+ {
+ // Not interrupted
+ return false;
+ }
+
+ // Iterate through the set of potential deletions, until enough has been deleted.
+ // (there is likely to be more in the set than should be actually deleted).
+ for(std::set<DelEn, DelEnCompare>::iterator i(mPotentialDeletions.begin()); i != mPotentialDeletions.end(); ++i)
+ {
+#ifndef WIN32
+ if((--mCountUntilNextInterprocessMsgCheck) <= 0)
+ {
+ mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY;
+ // Check for having to stop
+ if(mpHousekeepingCallback && mpHousekeepingCallback->CheckForInterProcessMsg(mAccountID)) // include account ID here as the specified account is now locked
+ {
+ // Need to abort now
+ return true;
+ }
+ }
+#endif
+
+ // Load up the directory it's in
+ // Get the filename
+ std::string dirFilename;
+ BackupStoreDirectory dir;
+ int64_t dirSizeInBlocksOrig = 0;
+ {
+ MakeObjectFilename(i->mInDirectory, dirFilename);
+ std::auto_ptr<RaidFileRead> dirStream(RaidFileRead::Open(mStoreDiscSet, dirFilename));
+ dirSizeInBlocksOrig = dirStream->GetDiscUsageInBlocks();
+ dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite);
+ }
+
+ // Delete the file
+ DeleteFile(i->mInDirectory, i->mObjectID, dir, dirFilename, dirSizeInBlocksOrig);
+ BOX_INFO("Housekeeping removed " <<
+ (i->mIsFlagDeleted ? "deleted" : "old") <<
+ " file " << BOX_FORMAT_OBJECTID(i->mObjectID) <<
+ " from dir " << BOX_FORMAT_OBJECTID(i->mInDirectory));
+
+ // Stop if the deletion target has been matched or exceeded
+ // (checking here rather than at the beginning will tend to reduce the
+ // space to slightly less than the soft limit, which will allow the backup
+ // client to start uploading files again)
+ if((0 - mBlocksUsedDelta) >= mDeletionSizeTarget)
+ {
+ break;
+ }
+ }
+
+ return false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::DeleteFile(int64_t, int64_t, BackupStoreDirectory &, const std::string &, int64_t)
+// Purpose: Delete a file. Takes the directory already loaded in and the filename,
+// for efficiency in both the usage senarios.
+// Created: 15/7/04
+//
+// --------------------------------------------------------------------------
+void HousekeepStoreAccount::DeleteFile(int64_t InDirectory, int64_t ObjectID, BackupStoreDirectory &rDirectory, const std::string &rDirectoryFilename, int64_t OriginalDirSizeInBlocks)
+{
+ // Find the entry inside the directory
+ bool wasDeleted = false;
+ bool wasOldVersion = false;
+ int64_t deletedFileSizeInBlocks = 0;
+ // A pointer to an object which requires commiting if the directory save goes OK
+ std::auto_ptr<RaidFileWrite> padjustedEntry;
+ // BLOCK
+ {
+ BackupStoreDirectory::Entry *pentry = rDirectory.FindEntryByID(ObjectID);
+ if(pentry == 0)
+ {
+ BOX_ERROR("Housekeeping on account " <<
+ BOX_FORMAT_ACCOUNT(mAccountID) << " "
+ "found error: object " <<
+ BOX_FORMAT_OBJECTID(ObjectID) << " "
+ "not found in dir " <<
+ BOX_FORMAT_OBJECTID(InDirectory) << ", "
+ "indicates logic error/corruption? Run "
+ "bbstoreaccounts check <accid> fix");
+ return;
+ }
+
+ // Record the flags it's got set
+ wasDeleted = ((pentry->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) != 0);
+ wasOldVersion = ((pentry->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) != 0);
+ // Check this should be deleted
+ if(!wasDeleted && !wasOldVersion)
+ {
+ // Things changed size we were last around
+ return;
+ }
+
+ // Record size
+ deletedFileSizeInBlocks = pentry->GetSizeInBlocks();
+
+ // If the entry is involved in a chain of patches, it needs to be handled
+ // a bit more carefully.
+ if(pentry->GetDependsNewer() != 0 && pentry->GetDependsOlder() == 0)
+ {
+ // This entry is a patch from a newer entry. Just need to update the info on that entry.
+ BackupStoreDirectory::Entry *pnewer = rDirectory.FindEntryByID(pentry->GetDependsNewer());
+ if(pnewer == 0 || pnewer->GetDependsOlder() != ObjectID)
+ {
+ THROW_EXCEPTION(BackupStoreException, PatchChainInfoBadInDirectory);
+ }
+ // Change the info in the newer entry so that this no longer points to this entry
+ pnewer->SetDependsOlder(0);
+ }
+ else if(pentry->GetDependsOlder() != 0)
+ {
+ BackupStoreDirectory::Entry *polder = rDirectory.FindEntryByID(pentry->GetDependsOlder());
+ if(pentry->GetDependsNewer() == 0)
+ {
+ // There exists an older version which depends on this one. Need to combine the two over that one.
+
+ // Adjust the other entry in the directory
+ if(polder == 0 || polder->GetDependsNewer() != ObjectID)
+ {
+ THROW_EXCEPTION(BackupStoreException, PatchChainInfoBadInDirectory);
+ }
+ // Change the info in the older entry so that this no longer points to this entry
+ polder->SetDependsNewer(0);
+ }
+ else
+ {
+ // This entry is in the middle of a chain, and two patches need combining.
+
+ // First, adjust the directory entries
+ BackupStoreDirectory::Entry *pnewer = rDirectory.FindEntryByID(pentry->GetDependsNewer());
+ if(pnewer == 0 || pnewer->GetDependsOlder() != ObjectID
+ || polder == 0 || polder->GetDependsNewer() != ObjectID)
+ {
+ THROW_EXCEPTION(BackupStoreException, PatchChainInfoBadInDirectory);
+ }
+ // Remove the middle entry from the linked list by simply using the values from this entry
+ pnewer->SetDependsOlder(pentry->GetDependsOlder());
+ polder->SetDependsNewer(pentry->GetDependsNewer());
+ }
+
+ // COMMON CODE to both cases
+
+ // Generate the filename of the older version
+ std::string objFilenameOlder;
+ MakeObjectFilename(pentry->GetDependsOlder(), objFilenameOlder);
+ // Open it twice (it's the diff)
+ std::auto_ptr<RaidFileRead> pdiff(RaidFileRead::Open(mStoreDiscSet, objFilenameOlder));
+ std::auto_ptr<RaidFileRead> pdiff2(RaidFileRead::Open(mStoreDiscSet, objFilenameOlder));
+ // Open this file
+ std::string objFilename;
+ MakeObjectFilename(ObjectID, objFilename);
+ std::auto_ptr<RaidFileRead> pobjectBeingDeleted(RaidFileRead::Open(mStoreDiscSet, objFilename));
+ // And open a write file to overwrite the other directory entry
+ padjustedEntry.reset(new RaidFileWrite(mStoreDiscSet, objFilenameOlder));
+ padjustedEntry->Open(true /* allow overwriting */);
+
+ if(pentry->GetDependsNewer() == 0)
+ {
+ // There exists an older version which depends on this one. Need to combine the two over that one.
+ BackupStoreFile::CombineFile(*pdiff, *pdiff2, *pobjectBeingDeleted, *padjustedEntry);
+ }
+ else
+ {
+ // This entry is in the middle of a chain, and two patches need combining.
+ BackupStoreFile::CombineDiffs(*pobjectBeingDeleted, *pdiff, *pdiff2, *padjustedEntry);
+ }
+ // The file will be committed later when the directory is safely commited.
+
+ // Work out the adjusted size
+ int64_t newSize = padjustedEntry->GetDiscUsageInBlocks();
+ int64_t sizeDelta = newSize - polder->GetSizeInBlocks();
+ mBlocksUsedDelta += sizeDelta;
+ if((polder->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) != 0)
+ {
+ mBlocksInDeletedFilesDelta += sizeDelta;
+ }
+ if((polder->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) != 0)
+ {
+ mBlocksInOldFilesDelta += sizeDelta;
+ }
+ polder->SetSizeInBlocks(newSize);
+ }
+
+ // pentry no longer valid
+ }
+
+ // Delete it from the directory
+ rDirectory.DeleteEntry(ObjectID);
+
+ // Save directory back to disc
+ // BLOCK
+ int64_t dirRevisedSize = 0;
+ {
+ RaidFileWrite writeDir(mStoreDiscSet, rDirectoryFilename);
+ writeDir.Open(true /* allow overwriting */);
+ rDirectory.WriteToStream(writeDir);
+
+ // get the disc usage (must do this before commiting it)
+ dirRevisedSize = writeDir.GetDiscUsageInBlocks();
+
+ // Commit directory
+ writeDir.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
+
+ // adjust usage counts for this directory
+ if(dirRevisedSize > 0)
+ {
+ int64_t adjust = dirRevisedSize - OriginalDirSizeInBlocks;
+ mBlocksUsedDelta += adjust;
+ mBlocksInDirectoriesDelta += adjust;
+ }
+ }
+
+ // Commit any new adjusted entry
+ if(padjustedEntry.get() != 0)
+ {
+ padjustedEntry->Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
+ padjustedEntry.reset(); // delete it now
+ }
+
+ // Drop reference count by one. If it reaches zero, delete the file.
+ if(--mNewRefCounts[ObjectID] == 0)
+ {
+ BOX_TRACE("Removing unreferenced object " <<
+ BOX_FORMAT_OBJECTID(ObjectID));
+ std::string objFilename;
+ MakeObjectFilename(ObjectID, objFilename);
+ RaidFileWrite del(mStoreDiscSet, objFilename);
+ del.Delete();
+ }
+ else
+ {
+ BOX_TRACE("Preserving object " <<
+ BOX_FORMAT_OBJECTID(ObjectID) << " with " <<
+ mNewRefCounts[ObjectID] << " references");
+ }
+
+ // Adjust counts for the file
+ ++mFilesDeleted;
+ mBlocksUsedDelta -= deletedFileSizeInBlocks;
+ if(wasDeleted) mBlocksInDeletedFilesDelta -= deletedFileSizeInBlocks;
+ if(wasOldVersion) mBlocksInOldFilesDelta -= deletedFileSizeInBlocks;
+
+ // Delete the directory?
+ // Do this if... dir has zero entries, and is marked as deleted in it's containing directory
+ if(rDirectory.GetNumberOfEntries() == 0)
+ {
+ // Candidate for deletion
+ mEmptyDirectories.push_back(InDirectory);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HousekeepStoreAccount::DeleteEmptyDirectories()
+// Purpose: Remove any empty directories which are also marked as deleted in their containing directory,
+// returning true if the opertaion was interrupted
+// Created: 15/12/03
+//
+// --------------------------------------------------------------------------
+bool HousekeepStoreAccount::DeleteEmptyDirectories()
+{
+ while(mEmptyDirectories.size() > 0)
+ {
+ std::vector<int64_t> toExamine;
+
+ // Go through list
+ for(std::vector<int64_t>::const_iterator i(mEmptyDirectories.begin()); i != mEmptyDirectories.end(); ++i)
+ {
+#ifndef WIN32
+ if((--mCountUntilNextInterprocessMsgCheck) <= 0)
+ {
+ mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY;
+ // Check for having to stop
+ if(mpHousekeepingCallback && mpHousekeepingCallback->CheckForInterProcessMsg(mAccountID)) // include account ID here as the specified account is now locked
+ {
+ // Need to abort now
+ return true;
+ }
+ }
+#endif
+
+ // Do not delete the root directory
+ if(*i == BACKUPSTORE_ROOT_DIRECTORY_ID)
+ {
+ continue;
+ }
+
+ DeleteEmptyDirectory(*i, toExamine);
+ }
+
+ // Remove contents of empty directories
+ mEmptyDirectories.clear();
+ // Swap in new, so it's examined next time round
+ mEmptyDirectories.swap(toExamine);
+ }
+
+ // Not interrupted
+ return false;
+}
+
+void HousekeepStoreAccount::DeleteEmptyDirectory(int64_t dirId,
+ std::vector<int64_t>& rToExamine)
+{
+ // Load up the directory to potentially delete
+ std::string dirFilename;
+ BackupStoreDirectory dir;
+ int64_t dirSizeInBlocks = 0;
+
+ // BLOCK
+ {
+ MakeObjectFilename(dirId, dirFilename);
+ // Check it actually exists (just in case it gets
+ // added twice to the list)
+ if(!RaidFileRead::FileExists(mStoreDiscSet, dirFilename))
+ {
+ // doesn't exist, next!
+ return;
+ }
+ // load
+ std::auto_ptr<RaidFileRead> dirStream(
+ RaidFileRead::Open(mStoreDiscSet, dirFilename));
+ dirSizeInBlocks = dirStream->GetDiscUsageInBlocks();
+ dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite);
+ }
+
+ // Make sure this directory is actually empty
+ if(dir.GetNumberOfEntries() != 0)
+ {
+ // Not actually empty, try next one
+ return;
+ }
+
+ // Candidate for deletion... open containing directory
+ std::string containingDirFilename;
+ BackupStoreDirectory containingDir;
+ int64_t containingDirSizeInBlocksOrig = 0;
+ {
+ MakeObjectFilename(dir.GetContainerID(), containingDirFilename);
+ std::auto_ptr<RaidFileRead> containingDirStream(
+ RaidFileRead::Open(mStoreDiscSet,
+ containingDirFilename));
+ containingDirSizeInBlocksOrig =
+ containingDirStream->GetDiscUsageInBlocks();
+ containingDir.ReadFromStream(*containingDirStream,
+ IOStream::TimeOutInfinite);
+ }
+
+ // Find the entry
+ BackupStoreDirectory::Entry *pdirentry =
+ containingDir.FindEntryByID(dir.GetObjectID());
+ if((pdirentry != 0) && ((pdirentry->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) != 0))
+ {
+ // Should be deleted
+ containingDir.DeleteEntry(dir.GetObjectID());
+
+ // Is the containing dir now a candidate for deletion?
+ if(containingDir.GetNumberOfEntries() == 0)
+ {
+ rToExamine.push_back(containingDir.GetObjectID());
+ }
+
+ // Write revised parent directory
+ RaidFileWrite writeDir(mStoreDiscSet, containingDirFilename);
+ writeDir.Open(true /* allow overwriting */);
+ containingDir.WriteToStream(writeDir);
+
+ // get the disc usage (must do this before commiting it)
+ int64_t dirSize = writeDir.GetDiscUsageInBlocks();
+
+ // Commit directory
+ writeDir.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
+
+ // adjust usage counts for this directory
+ if(dirSize > 0)
+ {
+ int64_t adjust = dirSize - containingDirSizeInBlocksOrig;
+ mBlocksUsedDelta += adjust;
+ mBlocksInDirectoriesDelta += adjust;
+ }
+
+ // Delete the directory itself
+ {
+ RaidFileWrite del(mStoreDiscSet, dirFilename);
+ del.Delete();
+ }
+
+ BOX_INFO("Housekeeping removed empty deleted dir " <<
+ BOX_FORMAT_OBJECTID(dirId));
+
+ // And adjust usage counts for the directory that's
+ // just been deleted
+ mBlocksUsedDelta -= dirSizeInBlocks;
+ mBlocksInDirectoriesDelta -= dirSizeInBlocks;
+
+ // Update count
+ ++mEmptyDirectoriesDeleted;
+ }
+}
+
diff --git a/bin/bbstored/HousekeepStoreAccount.h b/bin/bbstored/HousekeepStoreAccount.h
new file mode 100644
index 00000000..1dd6d79c
--- /dev/null
+++ b/bin/bbstored/HousekeepStoreAccount.h
@@ -0,0 +1,111 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: HousekeepStoreAccount.h
+// Purpose: Action class to perform housekeeping on a store account
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef HOUSEKEEPSTOREACCOUNT__H
+#define HOUSEKEEPSTOREACCOUNT__H
+
+#include <string>
+#include <set>
+#include <vector>
+
+class BackupStoreDaemon;
+class BackupStoreDirectory;
+
+class HousekeepingCallback
+{
+ public:
+ virtual ~HousekeepingCallback() {}
+ virtual bool CheckForInterProcessMsg(int AccountNum = 0, int MaximumWaitTime = 0) = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: HousekeepStoreAccount
+// Purpose: Action class to perform housekeeping on a store account
+// Created: 11/12/03
+//
+// --------------------------------------------------------------------------
+class HousekeepStoreAccount
+{
+public:
+ HousekeepStoreAccount(int AccountID, const std::string &rStoreRoot,
+ int StoreDiscSet, HousekeepingCallback* pHousekeepingCallback);
+ ~HousekeepStoreAccount();
+
+ void DoHousekeeping(bool KeepTryingForever = false);
+
+
+private:
+ // utility functions
+ void MakeObjectFilename(int64_t ObjectID, std::string &rFilenameOut);
+
+ bool ScanDirectory(int64_t ObjectID);
+ bool DeleteFiles();
+ bool DeleteEmptyDirectories();
+ void DeleteEmptyDirectory(int64_t dirId,
+ std::vector<int64_t>& rToExamine);
+ void DeleteFile(int64_t InDirectory, int64_t ObjectID, BackupStoreDirectory &rDirectory, const std::string &rDirectoryFilename, int64_t OriginalDirSizeInBlocks);
+
+private:
+ typedef struct
+ {
+ int64_t mObjectID;
+ int64_t mInDirectory;
+ int64_t mSizeInBlocks;
+ int32_t mMarkNumber;
+ int32_t mVersionAgeWithinMark; // 0 == current, 1 latest old version, etc
+ bool mIsFlagDeleted; // false for files flagged "Old"
+ } DelEn;
+
+ struct DelEnCompare
+ {
+ bool operator()(const DelEn &x, const DelEn &y);
+ };
+
+ int mAccountID;
+ std::string mStoreRoot;
+ int mStoreDiscSet;
+ HousekeepingCallback* mpHousekeepingCallback;
+
+ int64_t mDeletionSizeTarget;
+
+ std::set<DelEn, DelEnCompare> mPotentialDeletions;
+ int64_t mPotentialDeletionsTotalSize;
+ int64_t mMaxSizeInPotentialDeletions;
+
+ // List of directories which are empty, and might be good for deleting
+ std::vector<int64_t> mEmptyDirectories;
+
+ // The re-calculated blocks used stats
+ int64_t mBlocksUsed;
+ int64_t mBlocksInOldFiles;
+ int64_t mBlocksInDeletedFiles;
+ int64_t mBlocksInDirectories;
+
+ // Deltas from deletion
+ int64_t mBlocksUsedDelta;
+ int64_t mBlocksInOldFilesDelta;
+ int64_t mBlocksInDeletedFilesDelta;
+ int64_t mBlocksInDirectoriesDelta;
+
+ // Deletion count
+ int64_t mFilesDeleted;
+ int64_t mEmptyDirectoriesDeleted;
+
+ // New reference count list
+ std::vector<uint32_t> mNewRefCounts;
+ bool mSuppressRefCountChangeWarnings;
+
+ // Poll frequency
+ int mCountUntilNextInterprocessMsgCheck;
+};
+
+#endif // HOUSEKEEPSTOREACCOUNT__H
+
diff --git a/bin/bbstored/Makefile.extra b/bin/bbstored/Makefile.extra
new file mode 100644
index 00000000..6562647d
--- /dev/null
+++ b/bin/bbstored/Makefile.extra
@@ -0,0 +1,9 @@
+
+MAKEPROTOCOL = ../../lib/server/makeprotocol.pl
+
+GEN_CMD_SRV = $(MAKEPROTOCOL) Server backupprotocol.txt
+
+# AUTOGEN SEEDING
+autogen_BackupProtocolServer.cpp autogen_BackupProtocolServer.h: $(MAKEPROTOCOL) backupprotocol.txt
+ $(_PERL) $(GEN_CMD_SRV)
+
diff --git a/bin/bbstored/backupprotocol.txt b/bin/bbstored/backupprotocol.txt
new file mode 100644
index 00000000..3eca514a
--- /dev/null
+++ b/bin/bbstored/backupprotocol.txt
@@ -0,0 +1,234 @@
+#
+# backup protocol definition
+#
+
+Name Backup
+IdentString Box-Backup:v=C
+ServerContextClass BackupStoreContext BackupStoreContext.h
+
+ClientType Filename BackupStoreFilenameClear BackupStoreFilenameClear.h
+ServerType Filename BackupStoreFilename BackupStoreFilename.h
+
+ImplementLog Server syslog
+ImplementLog Client syslog
+ImplementLog Client file
+
+LogTypeToText Client Filename \"%s\" VAR.GetClearFilename().c_str()
+
+BEGIN_OBJECTS
+
+# -------------------------------------------------------------------------------------
+# Session commands
+# -------------------------------------------------------------------------------------
+
+Error 0 IsError(Type,SubType) Reply
+ int32 Type
+ int32 SubType
+ CONSTANT ErrorType 1000
+ CONSTANT Err_WrongVersion 1
+ CONSTANT Err_NotInRightProtocolPhase 2
+ CONSTANT Err_BadLogin 3
+ CONSTANT Err_CannotLockStoreForWriting 4
+ CONSTANT Err_SessionReadOnly 5
+ CONSTANT Err_FileDoesNotVerify 6
+ CONSTANT Err_DoesNotExist 7
+ CONSTANT Err_DirectoryAlreadyExists 8
+ CONSTANT Err_CannotDeleteRoot 9
+ CONSTANT Err_TargetNameExists 10
+ CONSTANT Err_StorageLimitExceeded 11
+ CONSTANT Err_DiffFromFileDoesNotExist 12
+ CONSTANT Err_DoesNotExistInDirectory 13
+ CONSTANT Err_PatchConsistencyError 14
+
+Version 1 Command(Version) Reply
+ int32 Version
+
+
+Login 2 Command(LoginConfirmed)
+ int32 ClientID
+ int32 Flags
+ CONSTANT Flags_ReadOnly 1
+
+
+LoginConfirmed 3 Reply
+ int64 ClientStoreMarker
+ int64 BlocksUsed
+ int64 BlocksSoftLimit
+ int64 BlocksHardLimit
+
+
+Finished 4 Command(Finished) Reply EndsConversation
+
+
+# generic success object
+Success 5 Reply
+ int64 ObjectID
+
+
+SetClientStoreMarker 6 Command(Success)
+ int64 ClientStoreMarker
+
+
+# -------------------------------------------------------------------------------------
+# Generic object commands
+# -------------------------------------------------------------------------------------
+
+GetObject 10 Command(Success)
+ int64 ObjectID
+ CONSTANT NoObject 0
+ # reply has stream following, if ObjectID != NoObject
+
+
+MoveObject 11 Command(Success)
+ int64 ObjectID
+ int64 MoveFromDirectory
+ int64 MoveToDirectory
+ int32 Flags
+ Filename NewFilename
+
+ CONSTANT Flags_MoveAllWithSameName 1
+ CONSTANT Flags_AllowMoveOverDeletedObject 2
+
+# consider this an object command as, although it deals with directory entries,
+# it's not specific to either a file or a directory
+
+
+GetObjectName 12 Command(ObjectName)
+ int64 ObjectID
+ int64 ContainingDirectoryID
+ CONSTANT ObjectID_DirectoryOnly 0
+
+ # set ObjectID to ObjectID_DirectoryOnly to only get info on the directory
+
+
+ObjectName 13 Reply
+ int32 NumNameElements
+ int64 ModificationTime
+ int64 AttributesHash
+ int16 Flags
+ # NumNameElements is zero if the object doesn't exist
+ CONSTANT NumNameElements_ObjectDoesntExist 0
+ # a stream of Filename objects follows, if and only if NumNameElements > 0
+
+
+# -------------------------------------------------------------------------------------
+# Directory commands
+# -------------------------------------------------------------------------------------
+
+CreateDirectory 20 Command(Success) StreamWithCommand
+ int64 ContainingDirectoryID
+ int64 AttributesModTime
+ Filename DirectoryName
+ # stream following containing attributes
+
+
+ListDirectory 21 Command(Success)
+ int64 ObjectID
+ int16 FlagsMustBeSet
+ int16 FlagsNotToBeSet
+ bool SendAttributes
+ # make sure these flags are synced with those in BackupStoreDirectory
+ CONSTANT Flags_INCLUDE_EVERYTHING -1
+ CONSTANT Flags_EXCLUDE_NOTHING 0
+ CONSTANT Flags_EXCLUDE_EVERYTHING 15
+ CONSTANT Flags_File 1
+ CONSTANT Flags_Dir 2
+ CONSTANT Flags_Deleted 4
+ CONSTANT Flags_OldVersion 8
+ # make sure this is the same as in BackupStoreConstants.h
+ CONSTANT RootDirectory 1
+
+ # reply has stream following Success object, containing a stored BackupStoreDirectory
+
+
+ChangeDirAttributes 22 Command(Success) StreamWithCommand
+ int64 ObjectID
+ int64 AttributesModTime
+ # stream following containing attributes
+
+
+DeleteDirectory 23 Command(Success)
+ int64 ObjectID
+
+UndeleteDirectory 24 Command(Success)
+ int64 ObjectID
+ # may not have exactly the desired effect if files within in have been deleted before the directory was deleted.
+
+
+# -------------------------------------------------------------------------------------
+# File commands
+# -------------------------------------------------------------------------------------
+
+StoreFile 30 Command(Success) StreamWithCommand
+ int64 DirectoryObjectID
+ int64 ModificationTime
+ int64 AttributesHash
+ int64 DiffFromFileID # 0 if the file is not a diff
+ Filename Filename
+ # then send a stream containing the encoded file
+
+
+GetFile 31 Command(Success)
+ int64 InDirectory
+ int64 ObjectID
+ # error returned if not a file, or does not exist
+ # reply has stream following, containing an encoded file IN STREAM ORDER
+ # (use GetObject to get it in file order)
+
+
+SetReplacementFileAttributes 32 Command(Success) StreamWithCommand
+ int64 InDirectory
+ int64 AttributesHash
+ Filename Filename
+ # stream follows containing attributes
+
+
+DeleteFile 33 Command(Success)
+ int64 InDirectory
+ Filename Filename
+ # will return 0 if the object couldn't be found in the specified directory
+
+
+GetBlockIndexByID 34 Command(Success)
+ int64 ObjectID
+
+ # stream of the block index follows the reply
+ # returns an error if the object didn't exist
+
+
+GetBlockIndexByName 35 Command(Success)
+ int64 InDirectory
+ Filename Filename
+
+ # Success object contains the found ID -- or 0 if the entry wasn't found in the directory
+ # stream of the block index follows the reply if found ID != 0
+
+
+UndeleteFile 36 Command(Success)
+ int64 InDirectory
+ int64 ObjectID
+ # will return 0 if the object couldn't be found in the specified directory
+
+
+# -------------------------------------------------------------------------------------
+# Information commands
+# -------------------------------------------------------------------------------------
+
+GetAccountUsage 40 Command(AccountUsage)
+ # no data members
+
+AccountUsage 41 Reply
+ int64 BlocksUsed
+ int64 BlocksInOldFiles
+ int64 BlocksInDeletedFiles
+ int64 BlocksInDirectories
+ int64 BlocksSoftLimit
+ int64 BlocksHardLimit
+ int32 BlockSize
+
+GetIsAlive 42 Command(IsAlive)
+ # no data members
+
+IsAlive 43 Reply
+ # no data members
+
diff --git a/contrib/mac_osx/org.boxbackup.bbackupd.plist.in b/contrib/mac_osx/org.boxbackup.bbackupd.plist.in
index 3b7b9307..a66f5500 100644
--- a/contrib/mac_osx/org.boxbackup.bbackupd.plist.in
+++ b/contrib/mac_osx/org.boxbackup.bbackupd.plist.in
@@ -4,8 +4,11 @@
<dict>
<key>Label</key>
<string>org.boxbackup.bbackupd</string>
+<<<<<<< HEAD
+=======
<key>OnDemand</key>
<false/>
+>>>>>>> 0.12
<key>RunAtLoad</key>
<true/>
<key>ProgramArguments</key>
diff --git a/contrib/mac_osx/org.boxbackup.bbstored.plist.in b/contrib/mac_osx/org.boxbackup.bbstored.plist.in
index 531ab240..7cd746f3 100644
--- a/contrib/mac_osx/org.boxbackup.bbstored.plist.in
+++ b/contrib/mac_osx/org.boxbackup.bbstored.plist.in
@@ -4,8 +4,11 @@
<dict>
<key>Label</key>
<string>org.boxbackup.bbstored</string>
+<<<<<<< HEAD
+=======
<key>OnDemand</key>
<false/>
+>>>>>>> 0.12
<key>RunAtLoad</key>
<true/>
<key>ProgramArguments</key>
@@ -14,6 +17,10 @@
<string>-F</string>
<string>@prefix@/etc/boxbackup/bbackupd.conf</string>
</array>
+<<<<<<< HEAD
+ </array>
+=======
+>>>>>>> 0.12
<key>LowPriorityIO</key>
<true/>
<key>Nice</key>
diff --git a/contrib/windows/installer/boxbackup.mpi.in b/contrib/windows/installer/boxbackup.mpi.in
index dc68f235..182f8c05 100755
--- a/contrib/windows/installer/boxbackup.mpi.in
+++ b/contrib/windows/installer/boxbackup.mpi.in
@@ -1,5 +1,29 @@
array set info {
AccountNo
+<<<<<<< HEAD
+10005005
+
+AllowLanguageSelection
+No
+
+AppName
+<%BrandName%>
+
+ApplicationID
+E10C6FD9-E524-28BD-B0AB3588F16C
+
+ApplicationURL
+http://www.boxbackup.org/
+
+AutoFileGroups
+No
+
+AutoRefreshFiles
+Yes
+
+BBVersionNo
+@box_version@
+=======
{10005005}
AllowLanguageSelection
@@ -22,6 +46,7 @@ AutoRefreshFiles
BBVersionNo
{@box_version@}
+>>>>>>> 0.12
BrandName
{Box Backup}
@@ -33,7 +58,11 @@ CancelledInstallAction
{Rollback and Stop}
CleanupCancelledInstall
+<<<<<<< HEAD
+Yes
+=======
{Yes}
+>>>>>>> 0.12
CommandLineFailureAction
{Fail (recommended)}
@@ -42,10 +71,17 @@ Company
{Tebuco, Inc. and Ben Summers and Contributors}
CompressionLevel
+<<<<<<< HEAD
+6
+
+CompressionMethod
+zlib
+=======
{6}
CompressionMethod
{zlib}
+>>>>>>> 0.12
ConfigFileName
{<%InstallDir%>\bbackupd.conf}
@@ -54,6 +90,15 @@ ConfigFileTemplate
{<%InstallDir%>\templates\template.conf}
Copyright
+<<<<<<< HEAD
+{2003-2008 Tebuco, Inc. and Ben Summers and Contributors}
+
+CreateDesktopShortcut
+No
+
+CreateQuickLaunchShortcut
+No
+=======
{2003-2011 Tebuco, Inc. and Ben Summers and Contributors}
CreateDesktopShortcut
@@ -61,11 +106,24 @@ CreateDesktopShortcut
CreateQuickLaunchShortcut
{No}
+>>>>>>> 0.12
DefaultDirectoryLocation
{}
DefaultLanguage
+<<<<<<< HEAD
+English
+
+EncryptedKeyFilePassword
+Enter_EncryptedKeys_Password_Here
+
+Ext
+.exe
+
+ExtractSolidArchivesOnStartup
+No
+=======
{English}
DefaultToSystemLanguage
@@ -82,10 +140,21 @@ Ext
ExtractSolidArchivesOnStartup
{No}
+>>>>>>> 0.12
Icon
{}
+<<<<<<< HEAD
+Image
+@build_dir@/docs/html/images/bblogo.png
+
+IncludeDebugging
+Yes
+
+InstallDirSuffix
+<%ShortAppName%>
+=======
IgnoreDirectories
{}
@@ -100,11 +169,48 @@ IncludeDebugging
InstallDirSuffix
{<%ShortAppName%>}
+>>>>>>> 0.12
InstallPassword
{}
InstallVersion
+<<<<<<< HEAD
+@box_version@
+
+Language,de
+No
+
+Language,en
+Yes
+
+Language,es
+No
+
+Language,fr
+No
+
+Language,hu
+Yes
+
+Language,it
+Yes
+
+Language,nl
+Yes
+
+Language,pl
+No
+
+Language,pt_br
+No
+
+Language,ru
+Yes
+
+LaunchApplication
+No
+=======
{0.0.0.0}
Language,ca
@@ -154,6 +260,7 @@ LastIgnoreFiles
LaunchApplication
{No}
+>>>>>>> 0.12
PackageDescription
{<%BrandName%> Backup Service}
@@ -165,18 +272,71 @@ PackageMaintainer
{Tebuco, Inc. and Ben Summers and Contributors}
PackageName
+<<<<<<< HEAD
+<%ShortAppName%>
+=======
{<%ShortAppName%>}
+>>>>>>> 0.12
PackagePackager
{Tebuco, Inc. and Ben Summers and Contributors}
PackageRelease
+<<<<<<< HEAD
+<%PatchVersion%>
+=======
{<%PatchVersion%>}
+>>>>>>> 0.12
PackageSummary
{}
PackageVersion
+<<<<<<< HEAD
+<%MajorVersion%>.<%MinorVersion%>
+
+PreserveFileAttributes
+Yes
+
+PreserveFilePermissions
+Yes
+
+ProjectID
+140B9882-3327-FEA8-13415A62FBB2
+
+ProjectVersion
+1.2.9.0
+
+SaveOnlyToplevelDirs
+No
+
+ScriptExt
+.bat
+
+ServiceExeName
+bbackupd.exe
+
+ServiceName
+<%BrandName%>
+
+ShortAppName
+<%BrandName%>
+
+SkipUnusedFileGroups
+Yes
+
+SystemLanguage
+en_us
+
+Theme
+Modern_Wizard
+
+ThemeDir
+Modern_Wizard
+
+ThemeVersion
+1
+=======
{<%MajorVersion%>.<%MinorVersion%>}
PreserveFileAttributes
@@ -220,12 +380,17 @@ ThemeDir
ThemeVersion
{1}
+>>>>>>> 0.12
UpgradeApplicationID
{}
UserInfoAcctNo
+<<<<<<< HEAD
+<%AccountNo%>
+=======
{<%AccountNo%>}
+>>>>>>> 0.12
UserInfoCompany
{}
@@ -240,6 +405,18 @@ UserInfoPhone
{}
Version
+<<<<<<< HEAD
+@box_version@
+
+ViewReadme
+No
+
+WizardHeight
+365
+
+WizardWidth
+500
+=======
{@box_version@}
ViewReadme
@@ -250,6 +427,7 @@ WizardHeight
WizardWidth
{500}
+>>>>>>> 0.12
}
@@ -299,6 +477,69 @@ test
{Testing Switch Yes No {} {run uninstaller without uninstalling any files}}
}
+<<<<<<< HEAD
+FileGroup ::481451CC-F49C-D389-8645076F595B -setup Install -active Yes -platforms {Windows MacOS-X} -name {Program Files} -parent FileGroups
+File ::B9F58CFC-EE7A-BEE4-62CB-2C10665095A2 -filemethod {Update files with more recent dates} -type dir -directory <%InstallDir%> -name /home/petjal/doc/teb/cli/bu/installer/win/2.2 -location @client_parcel_dir@ -parent 481451CC-F49C-D389-8645076F595B
+File ::CDDED10B-2747-DD07-5F9D-42A7FD7BB7E6 -name LICENSE.txt -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::D6E262BC-8A84-B6DB-794B-8FDC8AECB079 -name mgwz.dll -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::E56A0360-7D7F-D99E-E9A4-3C20BC4C2B99 -name mingwm10.dll -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::47602DF7-8463-AB89-E13F-11983610CAA2 -type dir -name tools -location @build_dir@/contrib/windows/installer/tools -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::F7F61231-C340-5CD5-686B-01F521994B0C -name InstallService.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::68DAE474-165D-81FE-1396-FDD2E6081B41 -name KillBackupProcess.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::2436C940-3332-13AA-7613-8EE67C35CE9B -name ReloadConfig.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::336DDAC3-F3BA-1117-73D4-11DFEF9E98AB -name RemoveService.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::0C15AE46-0FF3-3B7F-FC55-D91EF279DBD3 -name RestartService.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::58D97EDE-58F2-15D7-7113-BEE3047F0782 -name StartService.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::BE7CDB16-D3FE-30FA-2153-7C0509CD5E78 -name StopService.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::73BD5859-FB38-71F8-24BD-BDCF871F9FD3 -name Sync.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::67B3838F-4EF7-2C1C-2E86-78DB8ADD6682 -name ShowUsage.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::2646A97C-C0D9-A29C-E145-C5C371F44938 -name QueryOutputAll.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::2F41E3D2-DA4D-2FCB-B3D5-F04032D17A63 -name QueryOutputCurrent.bat -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::C6430BDD-8A07-B80E-FC0C-426C16EB4187 -name RemoteControl.exe -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::5EADAB59-F559-44CB-A3EE-9A56D4EF17C8 -type dir -name .svn -active 0 -parent 47602DF7-8463-AB89-E13F-11983610CAA2
+File ::31429CC4-525E-4E30-9328-4774AFA9F619 -name entries -active 0 -parent 5EADAB59-F559-44CB-A3EE-9A56D4EF17C8
+File ::A27BEFB6-1421-4030-8F11-F04316BCE57C -name format -active 0 -parent 5EADAB59-F559-44CB-A3EE-9A56D4EF17C8
+File ::C99700CE-1035-498C-9A96-B60835652077 -type dir -name prop-base -active 0 -parent 5EADAB59-F559-44CB-A3EE-9A56D4EF17C8
+File ::6FF9DFDE-4BB7-4319-AC85-BF1E88731C1C -name InstallService.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::6AAE8600-5CFC-4240-A47F-5CFCF4E571C6 -name KillBackupProcess.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::834C33D3-4B53-4B2D-9380-A05420AEE75F -name QueryOutputAll.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::854AD23A-5DDE-44C4-900C-34F5845E6747 -name QueryOutputCurrent.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::9A587DE7-B17C-4CDF-B92C-0D267E30E361 -name ReloadConfig.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::197AAEFA-C62E-4E79-890F-C2E4C8440239 -name RemoteControl.exe.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::912E0F50-53DD-4483-A4F4-CA69944A5959 -name RemoveService.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::BDD695BF-9C7E-4F06-BBCE-EC89536DCF27 -name RestartService.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::61615EE4-BF66-40E7-B89A-E6A50B92AF93 -name ShowUsage.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::A6F7C6B7-9759-4B86-9388-4A42E6F7C5C3 -name StartService.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::45D3E7F5-277B-4E52-81BA-ED6D2BB441D7 -name StopService.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::58966972-8387-4D14-A06E-15AA176633A3 -name Sync.bat.svn-base -active 0 -parent C99700CE-1035-498C-9A96-B60835652077
+File ::2A77AF5B-4761-45B5-A543-6328A7F0F39B -type dir -name props -active 0 -parent 5EADAB59-F559-44CB-A3EE-9A56D4EF17C8
+File ::BF74F2C1-3CE7-4875-9B52-CD0F527E01C7 -type dir -name text-base -active 0 -parent 5EADAB59-F559-44CB-A3EE-9A56D4EF17C8
+File ::D972D6B2-40E5-40B3-BC06-66B8B7F51B04 -name InstallService.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::2F14E4F3-5331-4AC5-93F7-C4748970C7F4 -name KillBackupProcess.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::9F3663B2-8BAA-4EAE-B606-53D5C922E703 -name QueryOutputAll.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::BE9BD4FB-DF44-4F4B-BB55-15285A8566BA -name QueryOutputCurrent.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::3B4E0BF4-7FDD-4903-8D43-76C43F38C6C4 -name ReloadConfig.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::038CEEA0-3F21-48F6-B109-BBE1EF7D3E96 -name RemoteControl.exe.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::0C177E04-DF2D-43AB-8A42-9E7A389AB1D1 -name RemoveService.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::9BE16F40-9D1D-4C84-843D-955A44069040 -name RestartService.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::4E503A3C-EB42-4870-9849-D508A3D9BAB7 -name ShowUsage.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::131B7D8B-1BEB-456C-8F05-386C2EAFBEAE -name StartService.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::D3D0AFC1-CB6C-42D4-8C05-21898505DA40 -name StopService.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::C89F78B2-25A7-432B-9D92-DC2AB636CFB5 -name Sync.bat.svn-base -active 0 -parent BF74F2C1-3CE7-4875-9B52-CD0F527E01C7
+File ::90695C82-0000-4F6A-8FE7-0ABDEAA17CAE -type dir -name tmp -active 0 -parent 5EADAB59-F559-44CB-A3EE-9A56D4EF17C8
+File ::7DFF0EE4-7298-4C8C-A5BC-56BBDD81CFC8 -type dir -name prop-base -active 0 -parent 90695C82-0000-4F6A-8FE7-0ABDEAA17CAE
+File ::4C60E473-119E-4B0B-9B01-56240F24D9D5 -type dir -name props -active 0 -parent 90695C82-0000-4F6A-8FE7-0ABDEAA17CAE
+File ::E1E25ACC-487B-4191-B8CF-9E7C8C88EA09 -type dir -name text-base -active 0 -parent 90695C82-0000-4F6A-8FE7-0ABDEAA17CAE
+File ::E7258732-3D21-4E89-AA41-24AA8B8EBF29 -name all-wcprops -active 0 -parent 5EADAB59-F559-44CB-A3EE-9A56D4EF17C8
+File ::9CEBA2A0-C68B-48BA-944E-2E8EE9A35D97 -name bbackupctl.exe -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::497483A6-7264-4361-86F2-F2703F719908 -name bbackupd-config -active 0 -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::204358FC-610F-47DF-8928-1D0E39921700 -targetfilename templates/original.conf -name bbackupd.conf -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::98C376E2-A6C3-4B6C-BBD4-F70CAC2E6A7B -name bbackupd.exe -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::5C3EAB34-7CD4-4DF3-9DEB-0FC23A6F5812 -name bbackupquery.exe -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::7633DBC3-EACA-4F9B-9A87-AD3AF0EC298E -name installer.iss -active 0 -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::D3CF86E1-CAFF-4342-8730-463F96EACC39 -targetfilename templates/NotifySysAdmin.original.vbs -name NotifySysAdmin.vbs -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+File ::A702625F-29C7-4CA0-A8F8-E50DBF5C541B -name uninstall.exe -active 0 -parent B9F58CFC-EE7A-BEE4-62CB-2C10665095A2
+=======
FileGroup ::481451CC-F49C-D389-8645076F595B -setup Install -active Yes -platforms {Windows} -name Binaries -parent FileGroups
File ::0D5FA1BE-D208-402E-A358-978A57513DCE -name @client_parcel_dir@/bbackupctl.exe -parent 481451CC-F49C-D389-8645076F595B
File ::4BE333C8-23F0-4629-82D6-E655641D4007 -name @client_parcel_dir@/bbackupd.exe -parent 481451CC-F49C-D389-8645076F595B
@@ -316,10 +557,20 @@ File ::A72A7844-0245-40C8-B5AE-D10F8654318E -name @build_dir@/distribution/boxba
File ::47390686-C767-4E91-AE69-4A980C67B304 -name @build_dir@/distribution/boxbackup/DOCUMENTATION.txt -parent 2C456223-3E1E-4D43-B31A-868EAD3241E1
File ::D4EF569E-F14A-41B7-853C-46C652DA51A7 -name @build_dir@/distribution/boxbackup/THANKS.txt -parent 2C456223-3E1E-4D43-B31A-868EAD3241E1
File ::143FE54A-7743-4AA5-9DF9-084ECA4ABFF9 -name @build_dir@/distribution/boxbackup/VERSION.txt -parent 2C456223-3E1E-4D43-B31A-868EAD3241E1
+>>>>>>> 0.12
Component ::4A9C852B-647E-EED5-5482FFBCC2AF -setup Install -active Yes -platforms {Windows MacOS-X} -name {Default Component} -parent Components
SetupType ::8202CECC-54A0-9B6C-D24D111BA52E -setup Install -active Yes -platforms {Windows MacOS-X} -name Typical -parent SetupTypes
InstallComponent AE3BD5B4-35DE-4240-B79914D43E56 -setup Install -type pane -title {Welcome Screen} -component Welcome -active No -parent StandardInstall
+<<<<<<< HEAD
+InstallComponent 2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8 -setup Install -type pane -conditions 4EE35849-FAD7-170B-0E45-FA30636467B1 -title {Install Password} -component InstallPassword -command insert -active No -parent StandardInstall
+Condition 4EE35849-FAD7-170B-0E45-FA30636467B1 -active Yes -parent 2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8 -title {Password Test Condition} -component PasswordTestCondition -TreeObject::id 4EE35849-FAD7-170B-0E45-FA30636467B1
+InstallComponent B3B99E2D-C368-A921-B7BC-A71EBDE3AD4D -setup Install -type action -title {Set Install Password} -component SetInstallPassword -active Yes -parent 2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8
+InstallComponent 1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E -setup Install -type pane -title {User Information} -component UserInformation -active Yes -parent StandardInstall
+InstallComponent 9013E862-8E81-5290-64F9-D8BCD13EC7E5 -setup Install -type pane -title {User Information Phone Email} -component UserInformation -active Yes -parent StandardInstall
+InstallComponent F8FD4BD6-F1DF-3F8D-B857-98310E4B1143 -setup Install -type pane -title {User Information Account No} -component UserInformation -active Yes -parent StandardInstall
+InstallComponent 58E1119F-639E-17C9-5D3898F385AA -setup Install -type pane -conditions 84DA7F05-9FB7-CC36-9EC98F8A6826 -title {Select Destination} -component SelectDestination -command insert -active Yes -parent StandardInstall
+=======
InstallComponent 2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8 -setup Install -type pane -conditions 4EE35849-FAD7-170B-0E45-FA30636467B1 -title {Install Password} -component InstallPassword -active No -parent StandardInstall
Condition 4EE35849-FAD7-170B-0E45-FA30636467B1 -active Yes -parent 2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8 -title {Password Test Condition} -component PasswordTestCondition -TreeObject::id 4EE35849-FAD7-170B-0E45-FA30636467B1
InstallComponent B3B99E2D-C368-A921-B7BC-A71EBDE3AD4D -setup Install -type action -title {Set Install Password} -component SetInstallPassword -active Yes -parent 2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8
@@ -327,12 +578,17 @@ InstallComponent 1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E -setup Install -type pane
InstallComponent 9013E862-8E81-5290-64F9-D8BCD13EC7E5 -setup Install -type pane -title {User Information Phone Email} -component UserInformation -active No -parent StandardInstall
InstallComponent F8FD4BD6-F1DF-3F8D-B857-98310E4B1143 -setup Install -type pane -title {User Information Account No} -component UserInformation -active Yes -parent StandardInstall
InstallComponent 58E1119F-639E-17C9-5D3898F385AA -setup Install -type pane -conditions 84DA7F05-9FB7-CC36-9EC98F8A6826 -title {Select Destination} -component SelectDestination -active Yes -parent StandardInstall
+>>>>>>> 0.12
Condition 84DA7F05-9FB7-CC36-9EC98F8A6826 -active Yes -parent 58E1119F-639E-17C9-5D3898F385AA -title {File Permission Condition} -component FilePermissionCondition -TreeObject::id 84DA7F05-9FB7-CC36-9EC98F8A6826
InstallComponent 0FDBA082-90AB-808C-478A-A13E7C525336 -setup Install -type action -title BackupLocationNumber -component ExecuteScript -active Yes -parent 58E1119F-639E-17C9-5D3898F385AA
InstallComponent 0047FF40-0139-2A59-AAC0-A44D46D6F5CC -setup Install -type action -title BackupLocationName -component ExecuteScript -active No -parent 58E1119F-639E-17C9-5D3898F385AA
InstallComponent 2BB06B72-DE53-2319-B1B8-351CDCBA2008 -setup Install -type action -title AddBackupLocation -component ExecuteScript -active Yes -parent 58E1119F-639E-17C9-5D3898F385AA
InstallComponent B506E7DA-E7C4-4D42-8C03-FD27BA16D078 -setup Install -type pane -title {License Agreement} -component License -active Yes -parent StandardInstall
+<<<<<<< HEAD
+InstallComponent B93D2216-1DDB-484C-A9AC-D6C18ED7DE23 -setup Install -type action -conditions {6D9D1ABC-7146-443F-9EE9-205D5CA6C830 79DAC913-A33D-4ED6-9BAE-B3A2053C0F2C} -title {Modify Widget} -component ModifyWidget -command insert -active Yes -parent B506E7DA-E7C4-4D42-8C03-FD27BA16D078
+=======
InstallComponent B93D2216-1DDB-484C-A9AC-D6C18ED7DE23 -setup Install -type action -conditions {6D9D1ABC-7146-443F-9EE9-205D5CA6C830 79DAC913-A33D-4ED6-9BAE-B3A2053C0F2C} -title {Modify Widget} -component ModifyWidget -active Yes -parent B506E7DA-E7C4-4D42-8C03-FD27BA16D078
+>>>>>>> 0.12
Condition 6D9D1ABC-7146-443F-9EE9-205D5CA6C830 -active Yes -parent B93D2216-1DDB-484C-A9AC-D6C18ED7DE23 -title {String Is Condition} -component StringIsCondition -TreeObject::id 6D9D1ABC-7146-443F-9EE9-205D5CA6C830
Condition 79DAC913-A33D-4ED6-9BAE-B3A2053C0F2C -active Yes -parent B93D2216-1DDB-484C-A9AC-D6C18ED7DE23 -title {String Is Condition} -component StringIsCondition -TreeObject::id 79DAC913-A33D-4ED6-9BAE-B3A2053C0F2C
InstallComponent 37E627F2-E04B-AEF2-D566C017A4D6 -setup Install -type pane -title {Copying Files} -component CopyFiles -active Yes -parent StandardInstall
@@ -349,7 +605,11 @@ InstallComponent 5F2C1F1C-B9F7-1642-59D9-A18318C1D70B -setup Install -type actio
InstallComponent 2EC82FBD-8294-A3E4-7F39-1CBA0582FA64 -setup Install -type action -title {Write Text To File} -component WriteTextToFile -active Yes -parent 37E627F2-E04B-AEF2-D566C017A4D6
InstallComponent 28E76C8B-2605-4739-9FFE-9C2880C17E59 -setup Install -type action -title {Edit config file} -component ExecuteExternalProgram -active No -parent 37E627F2-E04B-AEF2-D566C017A4D6
InstallComponent 52F0A238-57E1-A578-2CE4DA177B32 -setup Install -type action -title {Move Forward} -component MoveForward -active Yes -parent 37E627F2-E04B-AEF2-D566C017A4D6
+<<<<<<< HEAD
+InstallComponent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7 -setup Install -type pane -title SetBackupLocations -component CustomBlankPane2 -command reorder -active Yes -parent StandardInstall
+=======
InstallComponent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7 -setup Install -type pane -title SetBackupLocations -component CustomBlankPane2 -active Yes -parent StandardInstall
+>>>>>>> 0.12
InstallComponent 614C45B2-7515-780C-E444-7F165CF02DD7 -setup Install -type action -title {Execute Script} -component ExecuteScript -active No -parent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
InstallComponent A5B32DA1-B2FE-C1FA-6057-FBC3059EF076 -setup Install -type action -title {Execute Script} -component ExecuteScript -active Yes -parent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
InstallComponent F9E38720-6ABA-8B99-2471-496902E4CBC2 -setup Install -type action -title {Execute Script} -component ExecuteScript -active No -parent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
@@ -363,12 +623,20 @@ InstallComponent 9892B25C-689B-5B8F-F0C9-B14FF6ACC40C -setup Install -type actio
InstallComponent 8419AAAD-5860-F73E-8D11-4D1BDA4D7D37 -setup Install -type action -title AddAnother -component AddWidget -active Yes -parent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
InstallComponent C7762473-273F-E3CA-17E3-65789B14CDB0 -setup Install -type action -title {Write Text To File} -component WriteTextToFile -active Yes -parent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
InstallComponent D7FBBEBB-2186-5674-BA87-BB7151859D4E -setup Install -type action -title BackupLocationNumber -component ExecuteScript -active Yes -parent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
+<<<<<<< HEAD
+InstallComponent 49E80443-62DB-1C10-392D-1091AEA5ED88 -setup Install -type action -conditions EB532611-5F30-3C24-66EB-F3826D9054FD -title {Move to Pane} -component MoveToPane -command insert -active Yes -parent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
+=======
InstallComponent 49E80443-62DB-1C10-392D-1091AEA5ED88 -setup Install -type action -conditions EB532611-5F30-3C24-66EB-F3826D9054FD -title {Move to Pane} -component MoveToPane -active Yes -parent 3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
+>>>>>>> 0.12
Condition EB532611-5F30-3C24-66EB-F3826D9054FD -active Yes -parent 49E80443-62DB-1C10-392D-1091AEA5ED88 -title {String Is Condition} -component StringIsCondition -TreeObject::id EB532611-5F30-3C24-66EB-F3826D9054FD
InstallComponent 9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266 -setup Install -type pane -title {Click Next to Continue} -component CustomBlankPane2 -active Yes -parent StandardInstall
InstallComponent DDBBD8A9-13D7-9509-9202-419E989F60A9 -setup Install -type action -title {Add Widget} -component AddWidget -active No -parent 9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266
InstallComponent 8E095096-F018-A880-429D-A2177A9B70EA -setup Install -type action -title {Add Widget} -component AddWidget -active No -parent 9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266
+<<<<<<< HEAD
+InstallComponent 88A50FD5-480F-19A5-DA74-C915EB0A9765 -setup Install -type action -conditions 5EE78EF7-37CA-D440-3DB5-09136CD566B3 -title {Move to Pane} -component MoveToPane -command insert -active No -parent 9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266
+=======
InstallComponent 88A50FD5-480F-19A5-DA74-C915EB0A9765 -setup Install -type action -conditions 5EE78EF7-37CA-D440-3DB5-09136CD566B3 -title {Move to Pane} -component MoveToPane -active No -parent 9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266
+>>>>>>> 0.12
Condition 5EE78EF7-37CA-D440-3DB5-09136CD566B3 -active Yes -parent 88A50FD5-480F-19A5-DA74-C915EB0A9765 -title {String Is Condition} -component StringIsCondition -TreeObject::id 5EE78EF7-37CA-D440-3DB5-09136CD566B3
InstallComponent 908CE221-5A3D-0A78-24A1-E7C91EBE38D4 -setup Install -type pane -title {Next-Build Config} -component CustomBlankPane2 -active No -parent StandardInstall
InstallComponent DA33B826-E633-A845-4646-76DFA78B907B -setup Install -type pane -title {Custom Blank Pane 2} -component CustomBlankPane2 -active Yes -parent StandardInstall
@@ -383,6 +651,18 @@ InstallComponent 8A761DBD-0640-D98C-9B3AD7672A8F -setup Install -type action -ti
InstallComponent 6E70FB1F-6A43-6C23-3242E965A0D0 -setup Install -type action -title {Execute Action} -component ExecuteAction -active Yes -parent 574198A7-7322-2F5E-02EF185D965C
InstallComponent 8E1A5944-5AF5-5906-16D395E386D8 -setup Install -type action -title {Move Forward} -component MoveForward -active Yes -parent 574198A7-7322-2F5E-02EF185D965C
InstallComponent 1F0926EE-6884-1330-B4A1DB11C1BF -setup Install -type pane -title {Setup Complete} -component SetupComplete -active Yes -parent DefaultInstall
+<<<<<<< HEAD
+InstallComponent 3B6E2E7C-1A26-27F1-D578E383B128 -setup Install -type action -conditions {13BD88FE-CD71-5AC7-E99C10B6CB28 E02368C5-95B5-03A7-3282740037B0} -title {View Readme Checkbutton} -component AddWidget -command insert -active Yes -parent 1F0926EE-6884-1330-B4A1DB11C1BF
+Condition 13BD88FE-CD71-5AC7-E99C10B6CB28 -active Yes -parent 3B6E2E7C-1A26-27F1-D578E383B128 -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 13BD88FE-CD71-5AC7-E99C10B6CB28
+Condition E02368C5-95B5-03A7-3282740037B0 -active Yes -parent 3B6E2E7C-1A26-27F1-D578E383B128 -title {String Is Condition} -component StringIsCondition -TreeObject::id E02368C5-95B5-03A7-3282740037B0
+InstallComponent CFFA27AF-A641-E41C-B4A0E3BB3CBB -setup Install -type action -conditions {592F46AE-8CEE-01F3-0BA7EBDCA4F4 793D8178-0F51-7F07-BC5886586D3C} -title {Launch Application Checkbutton} -component AddWidget -command insert -active Yes -parent 1F0926EE-6884-1330-B4A1DB11C1BF
+Condition 592F46AE-8CEE-01F3-0BA7EBDCA4F4 -active Yes -parent CFFA27AF-A641-E41C-B4A0E3BB3CBB -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 592F46AE-8CEE-01F3-0BA7EBDCA4F4
+Condition 793D8178-0F51-7F07-BC5886586D3C -active Yes -parent CFFA27AF-A641-E41C-B4A0E3BB3CBB -title {String Is Condition} -component StringIsCondition -TreeObject::id 793D8178-0F51-7F07-BC5886586D3C
+InstallComponent 16D53E40-546B-54C3-088B1B5E3BBB -setup Install -type action -conditions {4E643D8A-CA31-018D-57D7053C2CE8 B39C0455-D1B6-7DDC-E2717F83463E} -title {Desktop Shortcut Checkbutton} -component AddWidget -command insert -active Yes -parent 1F0926EE-6884-1330-B4A1DB11C1BF
+Condition 4E643D8A-CA31-018D-57D7053C2CE8 -active Yes -parent 16D53E40-546B-54C3-088B1B5E3BBB -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 4E643D8A-CA31-018D-57D7053C2CE8
+Condition B39C0455-D1B6-7DDC-E2717F83463E -active Yes -parent 16D53E40-546B-54C3-088B1B5E3BBB -title {String Is Condition} -component StringIsCondition -TreeObject::id B39C0455-D1B6-7DDC-E2717F83463E
+InstallComponent 937C3FDD-FB28-98BD-3DAB276E59ED -setup Install -type action -conditions {6B966959-05D9-DB32-8D9C4AD2A3DF 748D673B-DFE6-5F74-329903ACE4DB 3379F80B-36D6-73DC-6FC1D6223A26} -title {Quick Launch Shortcut Checkbutton} -component AddWidget -command insert -active Yes -parent 1F0926EE-6884-1330-B4A1DB11C1BF
+=======
InstallComponent 3B6E2E7C-1A26-27F1-D578E383B128 -setup Install -type action -conditions {13BD88FE-CD71-5AC7-E99C10B6CB28 E02368C5-95B5-03A7-3282740037B0} -title {View Readme Checkbutton} -component AddWidget -active Yes -parent 1F0926EE-6884-1330-B4A1DB11C1BF
Condition 13BD88FE-CD71-5AC7-E99C10B6CB28 -active Yes -parent 3B6E2E7C-1A26-27F1-D578E383B128 -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 13BD88FE-CD71-5AC7-E99C10B6CB28
Condition E02368C5-95B5-03A7-3282740037B0 -active Yes -parent 3B6E2E7C-1A26-27F1-D578E383B128 -title {String Is Condition} -component StringIsCondition -TreeObject::id E02368C5-95B5-03A7-3282740037B0
@@ -393,13 +673,20 @@ InstallComponent 16D53E40-546B-54C3-088B1B5E3BBB -setup Install -type action -co
Condition 4E643D8A-CA31-018D-57D7053C2CE8 -active Yes -parent 16D53E40-546B-54C3-088B1B5E3BBB -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 4E643D8A-CA31-018D-57D7053C2CE8
Condition B39C0455-D1B6-7DDC-E2717F83463E -active Yes -parent 16D53E40-546B-54C3-088B1B5E3BBB -title {String Is Condition} -component StringIsCondition -TreeObject::id B39C0455-D1B6-7DDC-E2717F83463E
InstallComponent 937C3FDD-FB28-98BD-3DAB276E59ED -setup Install -type action -conditions {6B966959-05D9-DB32-8D9C4AD2A3DF 748D673B-DFE6-5F74-329903ACE4DB 3379F80B-36D6-73DC-6FC1D6223A26} -title {Quick Launch Shortcut Checkbutton} -component AddWidget -active Yes -parent 1F0926EE-6884-1330-B4A1DB11C1BF
+>>>>>>> 0.12
Condition 6B966959-05D9-DB32-8D9C4AD2A3DF -active Yes -parent 937C3FDD-FB28-98BD-3DAB276E59ED -title {Platform Condition} -component PlatformCondition -TreeObject::id 6B966959-05D9-DB32-8D9C4AD2A3DF
Condition 748D673B-DFE6-5F74-329903ACE4DB -active Yes -parent 937C3FDD-FB28-98BD-3DAB276E59ED -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 748D673B-DFE6-5F74-329903ACE4DB
Condition 3379F80B-36D6-73DC-6FC1D6223A26 -active Yes -parent 937C3FDD-FB28-98BD-3DAB276E59ED -title {String Is Condition} -component StringIsCondition -TreeObject::id 3379F80B-36D6-73DC-6FC1D6223A26
InstallComponent 3FE82C17-A3E2-4A57-A563-F80818B00B81 -setup Install -type action -title {Console Ask Yes Or No} -component ConsoleAskYesOrNo -active Yes -parent ConsoleInstall
+<<<<<<< HEAD
+InstallComponent 56EE5149-6AA2-4E0C-8841-F66A2EF9276E -setup Install -type action -conditions 241BBFCE-4EB1-432F-94DD-69D444DDB6C0 -title Exit -component Exit -command insert -active Yes -parent ConsoleInstall
+Condition 241BBFCE-4EB1-432F-94DD-69D444DDB6C0 -active Yes -parent 56EE5149-6AA2-4E0C-8841-F66A2EF9276E -title {String Is Condition} -component StringIsCondition -TreeObject::id 241BBFCE-4EB1-432F-94DD-69D444DDB6C0
+InstallComponent 0C12D2D3-AEBC-42FE-A73A-0815EFB10DA5 -setup Install -type action -conditions BC4EA5FD-50BD-4D6E-953F-5E3EDB957360 -title {Console Get User Input} -component ConsoleGetUserInput -command insert -active Yes -parent ConsoleInstall
+=======
InstallComponent 56EE5149-6AA2-4E0C-8841-F66A2EF9276E -setup Install -type action -conditions 241BBFCE-4EB1-432F-94DD-69D444DDB6C0 -title Exit -component Exit -active Yes -parent ConsoleInstall
Condition 241BBFCE-4EB1-432F-94DD-69D444DDB6C0 -active Yes -parent 56EE5149-6AA2-4E0C-8841-F66A2EF9276E -title {String Is Condition} -component StringIsCondition -TreeObject::id 241BBFCE-4EB1-432F-94DD-69D444DDB6C0
InstallComponent 0C12D2D3-AEBC-42FE-A73A-0815EFB10DA5 -setup Install -type action -conditions BC4EA5FD-50BD-4D6E-953F-5E3EDB957360 -title {Console Get User Input} -component ConsoleGetUserInput -active Yes -parent ConsoleInstall
+>>>>>>> 0.12
Condition BC4EA5FD-50BD-4D6E-953F-5E3EDB957360 -active Yes -parent 0C12D2D3-AEBC-42FE-A73A-0815EFB10DA5 -title {File Permission Condition} -component FilePermissionCondition -TreeObject::id BC4EA5FD-50BD-4D6E-953F-5E3EDB957360
InstallComponent B002A311-F8E7-41DE-B039-521391924E5B -setup Install -type action -title {Console Message} -component ConsoleMessage -active Yes -parent ConsoleInstall
InstallComponent D4FC6EB5-DDEE-4E4A-B8E1-D4B588A7928B -setup Install -type action -title {Execute Action} -component ExecuteAction -active Yes -parent ConsoleInstall
@@ -408,16 +695,26 @@ InstallComponent 6B4CB3C2-4799-4C9F-BA8E-1EE47C4606E1 -setup Install -type actio
InstallComponent D8F0AA0F-AD79-C566-15CC508F503B -setup Install -type action -title {Execute Action} -component ExecuteAction -active Yes -parent SilentInstall
InstallComponent 175CBE81-9EBE-1E21-A91479BEEFAE -setup Install -type action -title Exit -component Exit -active Yes -parent SilentInstall
InstallComponent A1DD1DC2-85D7-9BC6-998AC3D4A3A9 -setup Install -type actiongroup -title {Startup Actions} -active Yes -parent ActionGroupsInstall
+<<<<<<< HEAD
+InstallComponent 1F9E8CB8-02C1-0416-1F7445B4147F -setup Install -type action -conditions {3D0D1898-4C65-3E66-F82F56581E87 32F5B0AF-EB83-7A03-D8FAE1ECE473} -title Exit -component Exit -command insert -active Yes -parent A1DD1DC2-85D7-9BC6-998AC3D4A3A9
+=======
InstallComponent 1F9E8CB8-02C1-0416-1F7445B4147F -setup Install -type action -conditions {3D0D1898-4C65-3E66-F82F56581E87 32F5B0AF-EB83-7A03-D8FAE1ECE473} -title Exit -component Exit -active Yes -parent A1DD1DC2-85D7-9BC6-998AC3D4A3A9
+>>>>>>> 0.12
Condition 3D0D1898-4C65-3E66-F82F56581E87 -active Yes -parent 1F9E8CB8-02C1-0416-1F7445B4147F -title {String Is Condition} -component StringIsCondition -TreeObject::id 3D0D1898-4C65-3E66-F82F56581E87
Condition 32F5B0AF-EB83-7A03-D8FAE1ECE473 -active Yes -parent 1F9E8CB8-02C1-0416-1F7445B4147F -title {Ask Yes or No} -component AskYesOrNo -TreeObject::id 32F5B0AF-EB83-7A03-D8FAE1ECE473
InstallComponent 32DC8FB1-A04B-71AA-EC18496D4BD0 -setup Install -type action -title {Create Install Panes} -component CreateInstallPanes -active Yes -parent A1DD1DC2-85D7-9BC6-998AC3D4A3A9
InstallComponent 198905FB-9FAC-23DE-7422D25B8ECA -setup Install -type actiongroup -title {Install Actions} -active Yes -parent ActionGroupsInstall
InstallComponent 4D4A7BF0-7CCE-46E6-BDE5222F82D7 -setup Install -type action -title {Install Selected Files} -component InstallSelectedFiles -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
InstallComponent 53588803-6B41-D9FC-A385906A5106 -setup Install -type action -title {Install Uninstaller} -component InstallUninstaller -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
+<<<<<<< HEAD
+InstallComponent 73EA65C1-3BE3-B190-55C3E99F6269 -setup Install -type action -conditions 4EF787E3-0643-DE46-15E64BAF0816 -title {Windows Uninstall Registry} -component AddWindowsUninstallEntry -command insert -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
+Condition 4EF787E3-0643-DE46-15E64BAF0816 -active Yes -parent 73EA65C1-3BE3-B190-55C3E99F6269 -title {Platform Condition} -component PlatformCondition -TreeObject::id 4EF787E3-0643-DE46-15E64BAF0816
+InstallComponent 39B2B666-78D8-75E6-6EA071594D34 -setup Install -type action -conditions 18C00430-D6B1-151F-307762B3A045 -title {Uninstall Shortcut} -component InstallWindowsShortcut -command insert -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
+=======
InstallComponent 73EA65C1-3BE3-B190-55C3E99F6269 -setup Install -type action -conditions 4EF787E3-0643-DE46-15E64BAF0816 -title {Windows Uninstall Registry} -component AddWindowsUninstallEntry -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
Condition 4EF787E3-0643-DE46-15E64BAF0816 -active Yes -parent 73EA65C1-3BE3-B190-55C3E99F6269 -title {Platform Condition} -component PlatformCondition -TreeObject::id 4EF787E3-0643-DE46-15E64BAF0816
InstallComponent 39B2B666-78D8-75E6-6EA071594D34 -setup Install -type action -conditions 18C00430-D6B1-151F-307762B3A045 -title {Uninstall Shortcut} -component InstallWindowsShortcut -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
+>>>>>>> 0.12
Condition 18C00430-D6B1-151F-307762B3A045 -active Yes -parent 39B2B666-78D8-75E6-6EA071594D34 -title {Platform Condition} -component PlatformCondition -TreeObject::id 18C00430-D6B1-151F-307762B3A045
InstallComponent 6652193C-5D4B-44B6-ABC6-D6E96D89E5DC -setup Install -type action -title {Install Program Folder Shortcut} -component InstallProgramFolderShortcut -active No -parent 198905FB-9FAC-23DE-7422D25B8ECA
InstallComponent 9D101299-B80C-441B-8685-6E3AC61808E8 -setup Install -type action -title {RemoteControl Shortcut} -component InstallProgramFolderShortcut -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
@@ -435,6 +732,20 @@ InstallComponent 9A663209-495B-ED16-09BE-457B61148022 -setup Install -type actio
InstallComponent C0AF7C05-A31A-8376-BCB9-BA8B3A666252 -setup Install -type action -title SafeQueryAll -component InstallProgramFolderShortcut -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
InstallComponent 32B08FB1-99DF-234E-8BAF-333E80AAC9F5 -setup Install -type action -title Usage -component InstallProgramFolderShortcut -active Yes -parent 198905FB-9FAC-23DE-7422D25B8ECA
InstallComponent FEFD090D-C133-BC95-B3564F693CD3 -setup Install -type actiongroup -title {Finish Actions} -active Yes -parent ActionGroupsInstall
+<<<<<<< HEAD
+InstallComponent DECC120D-6904-7F17-45A49184A5A3 -setup Install -type action -conditions {E44CFF46-6302-C518-B9C30D2E43F7 B0AA6839-AAB6-A602-C0E4ECA2E4FF} -title {Install Desktop Shortcut} -component InstallDesktopShortcut -command insert -active No -parent FEFD090D-C133-BC95-B3564F693CD3
+Condition E44CFF46-6302-C518-B9C30D2E43F7 -active Yes -parent DECC120D-6904-7F17-45A49184A5A3 -title {String Is Condition} -component StringIsCondition -TreeObject::id E44CFF46-6302-C518-B9C30D2E43F7
+Condition B0AA6839-AAB6-A602-C0E4ECA2E4FF -active Yes -parent DECC120D-6904-7F17-45A49184A5A3 -title {File Exists Condition} -component FileExistsCondition -TreeObject::id B0AA6839-AAB6-A602-C0E4ECA2E4FF
+InstallComponent 7B770A07-A785-5215-956FA82CF14E -setup Install -type action -conditions {6F94698F-0839-3ABF-0CF2DF05A4C8 738DD098-7E3B-BC89-875CDB93CBE2 8C866252-8760-9B08-FE569C25B60D} -title {Install Quick Launch Shortcut} -component InstallWindowsShortcut -command insert -active No -parent FEFD090D-C133-BC95-B3564F693CD3
+Condition 6F94698F-0839-3ABF-0CF2DF05A4C8 -active Yes -parent 7B770A07-A785-5215-956FA82CF14E -title {String Is Condition} -component StringIsCondition -TreeObject::id 6F94698F-0839-3ABF-0CF2DF05A4C8
+Condition 738DD098-7E3B-BC89-875CDB93CBE2 -active Yes -parent 7B770A07-A785-5215-956FA82CF14E -title {Platform Condition} -component PlatformCondition -TreeObject::id 738DD098-7E3B-BC89-875CDB93CBE2
+Condition 8C866252-8760-9B08-FE569C25B60D -active Yes -parent 7B770A07-A785-5215-956FA82CF14E -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 8C866252-8760-9B08-FE569C25B60D
+InstallComponent C105AAAE-7C16-2C9E-769FE4535B60 -setup Install -type action -conditions {2583A547-11DE-1C27-B6D04B023CC0 A6E1B027-A1B4-5848-4F868D028D00 0357FAE9-FCFD-26D8-6541D810CD61} -title {View Readme Window} -component TextWindow -command insert -active No -parent FEFD090D-C133-BC95-B3564F693CD3
+Condition 2583A547-11DE-1C27-B6D04B023CC0 -active Yes -parent C105AAAE-7C16-2C9E-769FE4535B60 -title {String Is Condition} -component StringIsCondition -TreeObject::id 2583A547-11DE-1C27-B6D04B023CC0
+Condition A6E1B027-A1B4-5848-4F868D028D00 -active Yes -parent C105AAAE-7C16-2C9E-769FE4535B60 -title {String Is Condition} -component StringIsCondition -TreeObject::id A6E1B027-A1B4-5848-4F868D028D00
+Condition 0357FAE9-FCFD-26D8-6541D810CD61 -active Yes -parent C105AAAE-7C16-2C9E-769FE4535B60 -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 0357FAE9-FCFD-26D8-6541D810CD61
+InstallComponent C33D74B2-26FA-16F5-433A10C6A747 -setup Install -type action -conditions {CC4337CC-F3B5-757C-DFCF5D1D365A 795EE61F-6C0D-4A8B-93E02AA3894A 1528F4F0-145C-A48D-A8526DBB6289} -title {Launch Application} -component ExecuteExternalProgram -command insert -active No -parent FEFD090D-C133-BC95-B3564F693CD3
+=======
InstallComponent DECC120D-6904-7F17-45A49184A5A3 -setup Install -type action -conditions {E44CFF46-6302-C518-B9C30D2E43F7 B0AA6839-AAB6-A602-C0E4ECA2E4FF} -title {Install Desktop Shortcut} -component InstallDesktopShortcut -active No -parent FEFD090D-C133-BC95-B3564F693CD3
Condition E44CFF46-6302-C518-B9C30D2E43F7 -active Yes -parent DECC120D-6904-7F17-45A49184A5A3 -title {String Is Condition} -component StringIsCondition -TreeObject::id E44CFF46-6302-C518-B9C30D2E43F7
Condition B0AA6839-AAB6-A602-C0E4ECA2E4FF -active Yes -parent DECC120D-6904-7F17-45A49184A5A3 -title {File Exists Condition} -component FileExistsCondition -TreeObject::id B0AA6839-AAB6-A602-C0E4ECA2E4FF
@@ -447,6 +758,7 @@ Condition 2583A547-11DE-1C27-B6D04B023CC0 -active Yes -parent C105AAAE-7C16-2C9E
Condition A6E1B027-A1B4-5848-4F868D028D00 -active Yes -parent C105AAAE-7C16-2C9E-769FE4535B60 -title {String Is Condition} -component StringIsCondition -TreeObject::id A6E1B027-A1B4-5848-4F868D028D00
Condition 0357FAE9-FCFD-26D8-6541D810CD61 -active Yes -parent C105AAAE-7C16-2C9E-769FE4535B60 -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 0357FAE9-FCFD-26D8-6541D810CD61
InstallComponent C33D74B2-26FA-16F5-433A10C6A747 -setup Install -type action -conditions {CC4337CC-F3B5-757C-DFCF5D1D365A 795EE61F-6C0D-4A8B-93E02AA3894A 1528F4F0-145C-A48D-A8526DBB6289} -title {Launch Application} -component ExecuteExternalProgram -active No -parent FEFD090D-C133-BC95-B3564F693CD3
+>>>>>>> 0.12
Condition CC4337CC-F3B5-757C-DFCF5D1D365A -active Yes -parent C33D74B2-26FA-16F5-433A10C6A747 -title {String Is Condition} -component StringIsCondition -TreeObject::id CC4337CC-F3B5-757C-DFCF5D1D365A
Condition 795EE61F-6C0D-4A8B-93E02AA3894A -active Yes -parent C33D74B2-26FA-16F5-433A10C6A747 -title {String Is Condition} -component StringIsCondition -TreeObject::id 795EE61F-6C0D-4A8B-93E02AA3894A
Condition 1528F4F0-145C-A48D-A8526DBB6289 -active Yes -parent C33D74B2-26FA-16F5-433A10C6A747 -title {File Exists Condition} -component FileExistsCondition -TreeObject::id 1528F4F0-145C-A48D-A8526DBB6289
@@ -457,6 +769,17 @@ InstallComponent 7A983CD8-302C-4942-BE59-525C5B5FA2F2 -setup Uninstall -type act
InstallComponent E4DEA723-FC78-45D7-BAB1-A3E4C4C96EA1 -setup Uninstall -type action -title {Stop Service} -component ExecuteExternalProgram -active Yes -parent 3B8CDC8E-1239-D2E9-DF4CA6B1756D
InstallComponent B4D31D1E-ADB1-DE8F-18EB7294DDA8 -setup Uninstall -type action -title {Remove Service} -component ExecuteExternalProgram -active Yes -parent 3B8CDC8E-1239-D2E9-DF4CA6B1756D
InstallComponent D55BA4AF-E73B-60D1-E26F79175227 -setup Uninstall -type action -title {Execute Action} -component ExecuteAction -active Yes -parent 3B8CDC8E-1239-D2E9-DF4CA6B1756D
+<<<<<<< HEAD
+InstallComponent 69FD7409-5E2A-143B-DABD1C3B1E67 -setup Uninstall -type action -conditions {96A68CAC-9ED7-806C-086B104720FD E161F216-E597-B340-C1A71C476E2C} -title {Uninstall Leftover Files} -component UninstallLeftoverFiles -command insert -active Yes -parent 3B8CDC8E-1239-D2E9-DF4CA6B1756D
+Condition 96A68CAC-9ED7-806C-086B104720FD -active Yes -parent 69FD7409-5E2A-143B-DABD1C3B1E67 -title {String Is Condition} -component StringIsCondition -TreeObject::id 96A68CAC-9ED7-806C-086B104720FD
+Condition E161F216-E597-B340-C1A71C476E2C -active Yes -parent 69FD7409-5E2A-143B-DABD1C3B1E67 -title {Ask Yes or No} -component AskYesOrNo -TreeObject::id E161F216-E597-B340-C1A71C476E2C
+InstallComponent 05060263-E852-87AB-8D0F2954CAA6 -setup Uninstall -type action -title {Move Forward} -component MoveForward -active Yes -parent 3B8CDC8E-1239-D2E9-DF4CA6B1756D
+InstallComponent 41D3E165-C263-5F80-0FEEC0AEE47A -setup Uninstall -type pane -conditions EB2B31A1-C111-3582-0C8A5656692A -title {Uninstall Details} -component UninstallDetails -command insert -active Yes -parent StandardUninstall
+Condition EB2B31A1-C111-3582-0C8A5656692A -active Yes -parent 41D3E165-C263-5F80-0FEEC0AEE47A -title {String Is Condition} -component StringIsCondition -TreeObject::id EB2B31A1-C111-3582-0C8A5656692A
+InstallComponent 3D33AA8C-0037-204B-39A339FD38BD -setup Uninstall -type pane -title {Uninstall Complete} -component UninstallComplete -active Yes -parent StandardUninstall
+InstallComponent 49E59F91-27F7-46D1-A1C1-19865C2392D3 -setup Uninstall -type action -title {Console Ask Yes Or No} -component ConsoleAskYesOrNo -active Yes -parent ConsoleUninstall
+InstallComponent ADA6EB2F-8820-4366-BBEF-ED1335B7F828 -setup Uninstall -type action -conditions 87DE6D78-81E1-495B-A214-B3FF3E7E5614 -title Exit -component Exit -command insert -active Yes -parent ConsoleUninstall
+=======
InstallComponent 69FD7409-5E2A-143B-DABD1C3B1E67 -setup Uninstall -type action -conditions {96A68CAC-9ED7-806C-086B104720FD E161F216-E597-B340-C1A71C476E2C} -title {Uninstall Leftover Files} -component UninstallLeftoverFiles -active Yes -parent 3B8CDC8E-1239-D2E9-DF4CA6B1756D
Condition 96A68CAC-9ED7-806C-086B104720FD -active Yes -parent 69FD7409-5E2A-143B-DABD1C3B1E67 -title {String Is Condition} -component StringIsCondition -TreeObject::id 96A68CAC-9ED7-806C-086B104720FD
Condition E161F216-E597-B340-C1A71C476E2C -active Yes -parent 69FD7409-5E2A-143B-DABD1C3B1E67 -title {Ask Yes or No} -component AskYesOrNo -TreeObject::id E161F216-E597-B340-C1A71C476E2C
@@ -466,6 +789,7 @@ Condition EB2B31A1-C111-3582-0C8A5656692A -active Yes -parent 41D3E165-C263-5F80
InstallComponent 3D33AA8C-0037-204B-39A339FD38BD -setup Uninstall -type pane -title {Uninstall Complete} -component UninstallComplete -active Yes -parent StandardUninstall
InstallComponent 49E59F91-27F7-46D1-A1C1-19865C2392D3 -setup Uninstall -type action -title {Console Ask Yes Or No} -component ConsoleAskYesOrNo -active Yes -parent ConsoleUninstall
InstallComponent ADA6EB2F-8820-4366-BBEF-ED1335B7F828 -setup Uninstall -type action -conditions 87DE6D78-81E1-495B-A214-B3FF3E7E5614 -title Exit -component Exit -active Yes -parent ConsoleUninstall
+>>>>>>> 0.12
Condition 87DE6D78-81E1-495B-A214-B3FF3E7E5614 -active Yes -parent ADA6EB2F-8820-4366-BBEF-ED1335B7F828 -title {String Is Condition} -component StringIsCondition -TreeObject::id 87DE6D78-81E1-495B-A214-B3FF3E7E5614
InstallComponent B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174 -setup Uninstall -type action -title {Console Message} -component ConsoleMessage -active Yes -parent ConsoleUninstall
InstallComponent 3C7130B3-3206-403D-B09E-59D4A758FBAD -setup Uninstall -type action -title {Execute Action} -component ExecuteAction -active Yes -parent ConsoleUninstall
@@ -474,7 +798,11 @@ InstallComponent 7F85263E-CAE2-46BA-AAC0-6B89D20FD2DE -setup Uninstall -type act
InstallComponent 17D8BA8E-5992-AA5C-F5ECB73A3433 -setup Uninstall -type action -title {Execute Action} -component ExecuteAction -active Yes -parent SilentUninstall
InstallComponent D3D73C76-D9D3-07DA-63D4163A44BE -setup Uninstall -type action -title Exit -component Exit -active Yes -parent SilentUninstall
InstallComponent 848844B5-6103-9343-8B731B0BE4E0 -setup Uninstall -type actiongroup -title {Startup Actions} -active Yes -parent ActionGroupsUninstall
+<<<<<<< HEAD
+InstallComponent 97ACF525-C075-8635-E019202A83D8 -setup Uninstall -type action -conditions {DFFF91A9-2CA5-6ABE-8474D814AF88 4ACB0B47-42B3-2B3A-BFE9AA4EC707} -title Exit -component Exit -command insert -active Yes -parent 848844B5-6103-9343-8B731B0BE4E0
+=======
InstallComponent 97ACF525-C075-8635-E019202A83D8 -setup Uninstall -type action -conditions {DFFF91A9-2CA5-6ABE-8474D814AF88 4ACB0B47-42B3-2B3A-BFE9AA4EC707} -title Exit -component Exit -active Yes -parent 848844B5-6103-9343-8B731B0BE4E0
+>>>>>>> 0.12
Condition DFFF91A9-2CA5-6ABE-8474D814AF88 -active Yes -parent 97ACF525-C075-8635-E019202A83D8 -title {String Is Condition} -component StringIsCondition -TreeObject::id DFFF91A9-2CA5-6ABE-8474D814AF88
Condition 4ACB0B47-42B3-2B3A-BFE9AA4EC707 -active Yes -parent 97ACF525-C075-8635-E019202A83D8 -title {Ask Yes or No} -component AskYesOrNo -TreeObject::id 4ACB0B47-42B3-2B3A-BFE9AA4EC707
InstallComponent F4024A3E-9A6D-2726-5E0CFFA93054 -setup Uninstall -type actiongroup -title {Uninstall Actions} -active Yes -parent ActionGroupsUninstall
@@ -484,7 +812,11 @@ InstallComponent 905DA2E9-988C-2F27-BB1F5F274AC9 -setup Uninstall -type actiongr
array set Properties {
0047FF40-0139-2A59-AAC0-A44D46D6F5CC,Active
+<<<<<<< HEAD
+No
+=======
{No}
+>>>>>>> 0.12
0047FF40-0139-2A59-AAC0-A44D46D6F5CC,Comment
{set BackupLocationName "BackupLocation_${BackupLocationNumber}"}
@@ -496,7 +828,11 @@ array set Properties {
{Before Next Pane is Displayed}
0047FF40-0139-2A59-AAC0-A44D46D6F5CC,ResultVirtualText
+<<<<<<< HEAD
+BackupLocationName
+=======
{BackupLocationName}
+>>>>>>> 0.12
0047FF40-0139-2A59-AAC0-A44D46D6F5CC,TclScript
{set BackupLocationName "BackupLocation_${BackupLocationNumber}"}
@@ -505,22 +841,37 @@ array set Properties {
{Before Action is Executed}
0357FAE9-FCFD-26D8-6541D810CD61,Filename
+<<<<<<< HEAD
+<%ProgramReadme%>
+=======
{<%ProgramReadme%>}
+>>>>>>> 0.12
05060263-E852-87AB-8D0F2954CAA6,Conditions
{0 conditions}
0C12D2D3-AEBC-42FE-A73A-0815EFB10DA5,Prompt
+<<<<<<< HEAD
+<%ConsoleSelectDestinationText%>
+
+0C12D2D3-AEBC-42FE-A73A-0815EFB10DA5,VirtualText
+InstallDir
+=======
{<%ConsoleSelectDestinationText%>}
0C12D2D3-AEBC-42FE-A73A-0815EFB10DA5,VirtualText
{InstallDir}
+>>>>>>> 0.12
0D93323D-779D-44A8-1E0614E5285D,Conditions
{0 conditions}
0D93323D-779D-44A8-1E0614E5285D,State
+<<<<<<< HEAD
+disabled
+=======
{disabled}
+>>>>>>> 0.12
0D93323D-779D-44A8-1E0614E5285D,Widget
{Back Button;Next Button}
@@ -532,7 +883,11 @@ array set Properties {
{Before Next Pane is Displayed}
0FDBA082-90AB-808C-478A-A13E7C525336,ResultVirtualText
+<<<<<<< HEAD
+BackupLocationNumber
+=======
{BackupLocationNumber}
+>>>>>>> 0.12
0FDBA082-90AB-808C-478A-A13E7C525336,TclScript
{set BackupLocationNumber 1}
@@ -541,13 +896,21 @@ array set Properties {
{Before Action is Executed}
13BD88FE-CD71-5AC7-E99C10B6CB28,Filename
+<<<<<<< HEAD
+<%ProgramReadme%>
+=======
{<%ProgramReadme%>}
+>>>>>>> 0.12
1528F4F0-145C-A48D-A8526DBB6289,CheckCondition
{Before Action is Executed}
1528F4F0-145C-A48D-A8526DBB6289,Filename
+<<<<<<< HEAD
+<%ProgramExecutable%>
+=======
{<%ProgramExecutable%>}
+>>>>>>> 0.12
1681CF85-A5D2-4D73-A3FC-52B2A6A1847D,Alias
{Stop Backup Windows Process}
@@ -556,12 +919,25 @@ array set Properties {
{0 conditions}
1681CF85-A5D2-4D73-A3FC-52B2A6A1847D,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-killbackupprocess
+=======
{<%ShortAppName%>-program-killbackupprocess}
+>>>>>>> 0.12
1681CF85-A5D2-4D73-A3FC-52B2A6A1847D,ShortcutName
{Stop backup process}
1681CF85-A5D2-4D73-A3FC-52B2A6A1847D,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/KillBackupProcess.bat
+
+1681CF85-A5D2-4D73-A3FC-52B2A6A1847D,WorkingDirectory
+<%InstallDir%>
+
+16D53E40-546B-54C3-088B1B5E3BBB,Background
+white
+=======
{<%InstallDir%>/tools/KillBackupProcess.bat}
1681CF85-A5D2-4D73-A3FC-52B2A6A1847D,WorkingDirectory
@@ -569,11 +945,30 @@ array set Properties {
16D53E40-546B-54C3-088B1B5E3BBB,Background
{white}
+>>>>>>> 0.12
16D53E40-546B-54C3-088B1B5E3BBB,Conditions
{2 conditions}
16D53E40-546B-54C3-088B1B5E3BBB,Text,subst
+<<<<<<< HEAD
+1
+
+16D53E40-546B-54C3-088B1B5E3BBB,Type
+checkbutton
+
+16D53E40-546B-54C3-088B1B5E3BBB,VirtualText
+CreateDesktopShortcut
+
+16D53E40-546B-54C3-088B1B5E3BBB,X
+185
+
+16D53E40-546B-54C3-088B1B5E3BBB,Y
+180
+
+175CBE81-9EBE-1E21-A91479BEEFAE,ExitType
+Finish
+=======
{1}
16D53E40-546B-54C3-088B1B5E3BBB,Type
@@ -590,6 +985,7 @@ array set Properties {
175CBE81-9EBE-1E21-A91479BEEFAE,ExitType
{Finish}
+>>>>>>> 0.12
17D8BA8E-5992-AA5C-F5ECB73A3433,Action
{Uninstall Actions}
@@ -601,7 +997,11 @@ array set Properties {
{Before Action is Executed}
18C00430-D6B1-151F-307762B3A045,Platform
+<<<<<<< HEAD
+Windows
+=======
{Windows}
+>>>>>>> 0.12
198905FB-9FAC-23DE-7422D25B8ECA,Alias
{Install Actions}
@@ -613,13 +1013,21 @@ array set Properties {
{0 conditions}
19ADBDDB-1690-4A57-913E32A026C4,State
+<<<<<<< HEAD
+disabled
+=======
{disabled}
+>>>>>>> 0.12
19ADBDDB-1690-4A57-913E32A026C4,Widget
{NextButton; CancelButton}
1AF5CD58-65C0-49CB-9A9D-994816CF414E,Active
+<<<<<<< HEAD
+No
+=======
{No}
+>>>>>>> 0.12
1AF5CD58-65C0-49CB-9A9D-994816CF414E,Alias
{Upload File Listing}
@@ -631,12 +1039,37 @@ array set Properties {
{0 conditions}
1AF5CD58-65C0-49CB-9A9D-994816CF414E,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-TebucoSafeQuerypload
+=======
{<%ShortAppName%>-program-TebucoSafeQuerypload}
+>>>>>>> 0.12
1AF5CD58-65C0-49CB-9A9D-994816CF414E,ShortcutName
{Upload Filelisting to TebucoSafe for review}
1AF5CD58-65C0-49CB-9A9D-994816CF414E,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/TebucoSafeQueryUpload.bat
+
+1AF5CD58-65C0-49CB-9A9D-994816CF414E,WorkingDirectory
+<%InstallDir%>
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,Active
+Yes
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,BackButton,subst
+1
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,CancelButton,subst
+1
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,Caption,subst
+1
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,CompanyLabel,subst
+0
+=======
{<%InstallDir%>/tools/TebucoSafeQueryUpload.bat}
1AF5CD58-65C0-49CB-9A9D-994816CF414E,WorkingDirectory
@@ -653,11 +1086,30 @@ array set Properties {
1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,CompanyLabel,subst
{0}
+>>>>>>> 0.12
1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,Conditions
{0 conditions}
1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,Message,subst
+<<<<<<< HEAD
+1
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,NextButton,subst
+1
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,Subtitle,subst
+1
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,Title,subst
+1
+
+1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,UserNameLabel,subst
+0
+
+1C14291C-0971-4283-92E9-3808401303F5,Active
+No
+=======
{1}
1BEFB82C-C073-73D4-CFCE-F5DE7A674D9E,NextButton,subst
@@ -674,6 +1126,7 @@ array set Properties {
1C14291C-0971-4283-92E9-3808401303F5,Active
{No}
+>>>>>>> 0.12
1C14291C-0971-4283-92E9-3808401303F5,Comment
{Don't start it yet, need to install keys by hand.}
@@ -685,6 +1138,24 @@ array set Properties {
{net start <%ServiceName%>}
1C14291C-0971-4283-92E9-3808401303F5,WorkingDirectory
+<<<<<<< HEAD
+<%InstallDir%>
+
+1F0926EE-6884-1330-B4A1DB11C1BF,BackButton,subst
+1
+
+1F0926EE-6884-1330-B4A1DB11C1BF,CancelButton,subst
+1
+
+1F0926EE-6884-1330-B4A1DB11C1BF,Caption,subst
+1
+
+1F0926EE-6884-1330-B4A1DB11C1BF,Message,subst
+1
+
+1F0926EE-6884-1330-B4A1DB11C1BF,NextButton,subst
+1
+=======
{<%InstallDir%>}
1F0926EE-6884-1330-B4A1DB11C1BF,BackButton,subst
@@ -701,6 +1172,7 @@ array set Properties {
1F0926EE-6884-1330-B4A1DB11C1BF,NextButton,subst
{1}
+>>>>>>> 0.12
1F9E8CB8-02C1-0416-1F7445B4147F,Comment
{Ask the user if they want to proceed with the install.}
@@ -709,25 +1181,43 @@ array set Properties {
{2 conditions}
20CBDBEA-2217-457B-8D98-D692C4F591E9,Message,subst
+<<<<<<< HEAD
+1
+=======
{1}
+>>>>>>> 0.12
241BBFCE-4EB1-432F-94DD-69D444DDB6C0,CheckCondition
{Before Action is Executed}
241BBFCE-4EB1-432F-94DD-69D444DDB6C0,Operator
+<<<<<<< HEAD
+false
+
+241BBFCE-4EB1-432F-94DD-69D444DDB6C0,String
+<%Answer%>
+=======
{false}
241BBFCE-4EB1-432F-94DD-69D444DDB6C0,String
{<%Answer%>}
+>>>>>>> 0.12
2583A547-11DE-1C27-B6D04B023CC0,CheckCondition
{Before Action is Executed}
2583A547-11DE-1C27-B6D04B023CC0,Operator
+<<<<<<< HEAD
+false
+
+2583A547-11DE-1C27-B6D04B023CC0,String
+<%SilentMode%>
+=======
{false}
2583A547-11DE-1C27-B6D04B023CC0,String
{<%SilentMode%>}
+>>>>>>> 0.12
25AA533E-02FC-47D9-9273-25266B8FA1F9,Alias
{Remove Backup Service}
@@ -739,12 +1229,25 @@ array set Properties {
{0 conditions}
25AA533E-02FC-47D9-9273-25266B8FA1F9,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-removeService
+=======
{<%ShortAppName%>-program-removeService}
+>>>>>>> 0.12
25AA533E-02FC-47D9-9273-25266B8FA1F9,ShortcutName
{Remove Service}
25AA533E-02FC-47D9-9273-25266B8FA1F9,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/RemoveService.bat
+
+25AA533E-02FC-47D9-9273-25266B8FA1F9,WorkingDirectory
+<%InstallDir%>
+
+28E76C8B-2605-4739-9FFE-9C2880C17E59,Active
+No
+=======
{<%InstallDir%>/tools/RemoveService.bat}
25AA533E-02FC-47D9-9273-25266B8FA1F9,WorkingDirectory
@@ -752,6 +1255,7 @@ array set Properties {
28E76C8B-2605-4739-9FFE-9C2880C17E59,Active
{No}
+>>>>>>> 0.12
28E76C8B-2605-4739-9FFE-9C2880C17E59,Conditions
{0 conditions}
@@ -760,6 +1264,18 @@ array set Properties {
{notepad <%ConfigFileName%>}
28E76C8B-2605-4739-9FFE-9C2880C17E59,WorkingDirectory
+<<<<<<< HEAD
+<%InstallDir%>
+
+2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,BackButton,subst
+1
+
+2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,CancelButton,subst
+1
+
+2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,Caption,subst
+1
+=======
{<%InstallDir%>}
2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,BackButton,subst
@@ -770,11 +1286,24 @@ array set Properties {
2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,Caption,subst
{1}
+>>>>>>> 0.12
2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,Conditions
{1 condition}
2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,Message,subst
+<<<<<<< HEAD
+1
+
+2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,NextButton,subst
+1
+
+2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,Subtitle,subst
+1
+
+2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,Title,subst
+1
+=======
{1}
2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,NextButton,subst
@@ -785,6 +1314,7 @@ array set Properties {
2AC89879-6E9D-3D4E-F28E-5985EEBFAAA8,Title,subst
{1}
+>>>>>>> 0.12
2BB06B72-DE53-2319-B1B8-351CDCBA2008,Conditions
{0 conditions}
@@ -793,12 +1323,19 @@ array set Properties {
{Before Next Pane is Displayed}
2BB06B72-DE53-2319-B1B8-351CDCBA2008,ResultVirtualText
+<<<<<<< HEAD
+AddBackupLocation
+=======
{AddBackupLocation}
+>>>>>>> 0.12
2BB06B72-DE53-2319-B1B8-351CDCBA2008,TclScript
{set AddBackupLocation no}
2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message,subst
+<<<<<<< HEAD
+1
+=======
{1}
2C456223-3E1E-4D43-B31A-868EAD3241E1,Destination
@@ -806,11 +1343,27 @@ array set Properties {
2C456223-3E1E-4D43-B31A-868EAD3241E1,Name
{Documents}
+>>>>>>> 0.12
2E2963BD-DDBD-738D-A910-B7F3F04946F9,Conditions
{0 conditions}
2E2963BD-DDBD-738D-A910-B7F3F04946F9,Text,subst
+<<<<<<< HEAD
+1
+
+2E2963BD-DDBD-738D-A910-B7F3F04946F9,Value
+<%AddBackupLocation%>
+
+2E2963BD-DDBD-738D-A910-B7F3F04946F9,X
+400
+
+2E2963BD-DDBD-738D-A910-B7F3F04946F9,Y
+70
+
+2EC82FBD-8294-A3E4-7F39-1CBA0582FA64,AppendNewline
+No
+=======
{1}
2E2963BD-DDBD-738D-A910-B7F3F04946F9,Value
@@ -824,6 +1377,7 @@ array set Properties {
2EC82FBD-8294-A3E4-7F39-1CBA0582FA64,AppendNewline
{No}
+>>>>>>> 0.12
2EC82FBD-8294-A3E4-7F39-1CBA0582FA64,Comment
{.conf doesn't exist yet}
@@ -835,15 +1389,34 @@ array set Properties {
{Append to file}
2EC82FBD-8294-A3E4-7F39-1CBA0582FA64,Files
+<<<<<<< HEAD
+<%ConfigFileTemplate%>
+
+2EC82FBD-8294-A3E4-7F39-1CBA0582FA64,TextToWrite,subst
+1
+=======
{<%ConfigFileTemplate%>}
2EC82FBD-8294-A3E4-7F39-1CBA0582FA64,TextToWrite,subst
{1}
+>>>>>>> 0.12
32B08FB1-99DF-234E-8BAF-333E80AAC9F5,Conditions
{0 conditions}
32B08FB1-99DF-234E-8BAF-333E80AAC9F5,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-Usage
+
+32B08FB1-99DF-234E-8BAF-333E80AAC9F5,ShortcutName
+Usage
+
+32B08FB1-99DF-234E-8BAF-333E80AAC9F5,TargetFileName
+<%InstallDir%>/tools/ShowUsage.bat
+
+32B08FB1-99DF-234E-8BAF-333E80AAC9F5,WorkingDirectory
+<%InstallDir%>
+=======
{<%ShortAppName%>-program-Usage}
32B08FB1-99DF-234E-8BAF-333E80AAC9F5,ShortcutName
@@ -854,6 +1427,7 @@ array set Properties {
32B08FB1-99DF-234E-8BAF-333E80AAC9F5,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
32DC8FB1-A04B-71AA-EC18496D4BD0,Conditions
{0 conditions}
@@ -862,6 +1436,15 @@ array set Properties {
{Before Action is Executed}
32F5B0AF-EB83-7A03-D8FAE1ECE473,Message,subst
+<<<<<<< HEAD
+1
+
+32F5B0AF-EB83-7A03-D8FAE1ECE473,Title,subst
+1
+
+32F5B0AF-EB83-7A03-D8FAE1ECE473,TrueValue
+No
+=======
{1}
32F5B0AF-EB83-7A03-D8FAE1ECE473,Title,subst
@@ -869,11 +1452,21 @@ array set Properties {
32F5B0AF-EB83-7A03-D8FAE1ECE473,TrueValue
{No}
+>>>>>>> 0.12
3379F80B-36D6-73DC-6FC1D6223A26,CheckCondition
{Before Action is Executed}
3379F80B-36D6-73DC-6FC1D6223A26,Operator
+<<<<<<< HEAD
+false
+
+3379F80B-36D6-73DC-6FC1D6223A26,String
+<%InstallStopped%>
+
+362B6D6A-11BC-83CE-AFF6-410D8FBCF54D,Active
+No
+=======
{false}
3379F80B-36D6-73DC-6FC1D6223A26,String
@@ -881,17 +1474,31 @@ array set Properties {
362B6D6A-11BC-83CE-AFF6-410D8FBCF54D,Active
{No}
+>>>>>>> 0.12
362B6D6A-11BC-83CE-AFF6-410D8FBCF54D,Conditions
{0 conditions}
362B6D6A-11BC-83CE-AFF6-410D8FBCF54D,ResultVirtualText
+<<<<<<< HEAD
+BackupLocationExclusions
+=======
{BackupLocationExclusions}
+>>>>>>> 0.12
362B6D6A-11BC-83CE-AFF6-410D8FBCF54D,TclScript
{set BackupLocationExclusions ""}
37E627F2-E04B-AEF2-D566C017A4D6,BackButton,subst
+<<<<<<< HEAD
+1
+
+37E627F2-E04B-AEF2-D566C017A4D6,CancelButton,subst
+1
+
+37E627F2-E04B-AEF2-D566C017A4D6,Caption,subst
+1
+=======
{1}
37E627F2-E04B-AEF2-D566C017A4D6,CancelButton,subst
@@ -899,11 +1506,30 @@ array set Properties {
37E627F2-E04B-AEF2-D566C017A4D6,Caption,subst
{1}
+>>>>>>> 0.12
37E627F2-E04B-AEF2-D566C017A4D6,Conditions
{0 conditions}
37E627F2-E04B-AEF2-D566C017A4D6,FileLabel,subst
+<<<<<<< HEAD
+1
+
+37E627F2-E04B-AEF2-D566C017A4D6,Message,subst
+1
+
+37E627F2-E04B-AEF2-D566C017A4D6,NextButton,subst
+1
+
+37E627F2-E04B-AEF2-D566C017A4D6,ProgressValue,subst
+1
+
+37E627F2-E04B-AEF2-D566C017A4D6,Subtitle,subst
+1
+
+37E627F2-E04B-AEF2-D566C017A4D6,Title,subst
+1
+=======
{1}
37E627F2-E04B-AEF2-D566C017A4D6,Message,subst
@@ -920,6 +1546,7 @@ array set Properties {
37E627F2-E04B-AEF2-D566C017A4D6,Title,subst
{1}
+>>>>>>> 0.12
39270FD8-932E-6132-7EF795ED9B93,Alias
{Finish Actions}
@@ -934,21 +1561,56 @@ array set Properties {
{Uninstall <%BrandName%>}
39B2B666-78D8-75E6-6EA071594D34,TargetFileName
+<<<<<<< HEAD
+<%Uninstaller%>
+
+39B2B666-78D8-75E6-6EA071594D34,WorkingDirectory
+<%InstallDir%>
+=======
{<%Uninstaller%>}
39B2B666-78D8-75E6-6EA071594D34,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
39D7394E-04E9-CA70-0034DB830BFE,Conditions
{0 conditions}
3B6E2E7C-1A26-27F1-D578E383B128,Background
+<<<<<<< HEAD
+white
+=======
{white}
+>>>>>>> 0.12
3B6E2E7C-1A26-27F1-D578E383B128,Conditions
{2 conditions}
3B6E2E7C-1A26-27F1-D578E383B128,Text,subst
+<<<<<<< HEAD
+1
+
+3B6E2E7C-1A26-27F1-D578E383B128,Type
+checkbutton
+
+3B6E2E7C-1A26-27F1-D578E383B128,VirtualText
+ViewReadme
+
+3B6E2E7C-1A26-27F1-D578E383B128,X
+185
+
+3B6E2E7C-1A26-27F1-D578E383B128,Y
+140
+
+3B8CDC8E-1239-D2E9-DF4CA6B1756D,BackButton,subst
+1
+
+3B8CDC8E-1239-D2E9-DF4CA6B1756D,CancelButton,subst
+1
+
+3B8CDC8E-1239-D2E9-DF4CA6B1756D,Caption,subst
+1
+=======
{1}
3B6E2E7C-1A26-27F1-D578E383B128,Type
@@ -971,11 +1633,30 @@ array set Properties {
3B8CDC8E-1239-D2E9-DF4CA6B1756D,Caption,subst
{1}
+>>>>>>> 0.12
3B8CDC8E-1239-D2E9-DF4CA6B1756D,Conditions
{0 conditions}
3B8CDC8E-1239-D2E9-DF4CA6B1756D,FileValue,subst
+<<<<<<< HEAD
+1
+
+3B8CDC8E-1239-D2E9-DF4CA6B1756D,Message,subst
+1
+
+3B8CDC8E-1239-D2E9-DF4CA6B1756D,NextButton,subst
+1
+
+3B8CDC8E-1239-D2E9-DF4CA6B1756D,ProgressValue,subst
+1
+
+3B8CDC8E-1239-D2E9-DF4CA6B1756D,Subtitle,subst
+1
+
+3B8CDC8E-1239-D2E9-DF4CA6B1756D,Title,subst
+1
+=======
{1}
3B8CDC8E-1239-D2E9-DF4CA6B1756D,Message,subst
@@ -992,6 +1673,7 @@ array set Properties {
3B8CDC8E-1239-D2E9-DF4CA6B1756D,Title,subst
{1}
+>>>>>>> 0.12
3C7130B3-3206-403D-B09E-59D4A758FBAD,Action
{Uninstall Actions}
@@ -1000,21 +1682,47 @@ array set Properties {
{0 conditions}
3CFFF099-6122-46DD-9CE4-F5819434AC53,IgnoreErrors
+<<<<<<< HEAD
+Yes
+=======
{Yes}
+>>>>>>> 0.12
3CFFF099-6122-46DD-9CE4-F5819434AC53,ProgramCommandLine
{net stop <%ServiceName%>}
3CFFF099-6122-46DD-9CE4-F5819434AC53,ProgressiveOutputWidget
+<<<<<<< HEAD
+Message
+
+3CFFF099-6122-46DD-9CE4-F5819434AC53,WorkingDirectory
+<%Temp%>
+=======
{Message}
3CFFF099-6122-46DD-9CE4-F5819434AC53,WorkingDirectory
{<%Temp%>}
+>>>>>>> 0.12
3D0D1898-4C65-3E66-F82F56581E87,CheckCondition
{Before Action is Executed}
3D0D1898-4C65-3E66-F82F56581E87,Operator
+<<<<<<< HEAD
+false
+
+3D0D1898-4C65-3E66-F82F56581E87,String
+<%SilentMode%>
+
+3D33AA8C-0037-204B-39A339FD38BD,BackButton,subst
+1
+
+3D33AA8C-0037-204B-39A339FD38BD,CancelButton,subst
+1
+
+3D33AA8C-0037-204B-39A339FD38BD,Caption,subst
+1
+=======
{false}
3D0D1898-4C65-3E66-F82F56581E87,String
@@ -1028,11 +1736,33 @@ array set Properties {
3D33AA8C-0037-204B-39A339FD38BD,Caption,subst
{1}
+>>>>>>> 0.12
3D33AA8C-0037-204B-39A339FD38BD,Conditions
{0 conditions}
3D33AA8C-0037-204B-39A339FD38BD,Message,subst
+<<<<<<< HEAD
+1
+
+3D33AA8C-0037-204B-39A339FD38BD,NextButton,subst
+1
+
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Active
+Yes
+
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Alias
+SetBackupLocations
+
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,BackButton,subst
+1
+
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,CancelButton,subst
+1
+
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Caption,subst
+1
+=======
{1}
3D33AA8C-0037-204B-39A339FD38BD,NextButton,subst
@@ -1052,11 +1782,24 @@ array set Properties {
3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Caption,subst
{1}
+>>>>>>> 0.12
3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Conditions
{0 conditions}
3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Message,subst
+<<<<<<< HEAD
+1
+
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,NextButton,subst
+1
+
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Subtitle,subst
+1
+
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Title,subst
+1
+=======
{1}
3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,NextButton,subst
@@ -1067,20 +1810,40 @@ array set Properties {
3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7,Title,subst
{1}
+>>>>>>> 0.12
3FDB57ED-598D-8A4E-CEF7-D90833305558,Conditions
{0 conditions}
3FDB57ED-598D-8A4E-CEF7-D90833305558,LabelSide
+<<<<<<< HEAD
+left
+
+3FDB57ED-598D-8A4E-CEF7-D90833305558,Text,subst
+1
+=======
{left}
3FDB57ED-598D-8A4E-CEF7-D90833305558,Text,subst
{1}
+>>>>>>> 0.12
3FDB57ED-598D-8A4E-CEF7-D90833305558,Type
{browse entry}
3FDB57ED-598D-8A4E-CEF7-D90833305558,VirtualText
+<<<<<<< HEAD
+BackupLocationPath
+
+3FDB57ED-598D-8A4E-CEF7-D90833305558,Y
+70
+
+3FE82C17-A3E2-4A57-A563-F80818B00B81,Default
+Yes
+
+3FE82C17-A3E2-4A57-A563-F80818B00B81,Prompt
+<%InstallStartupText%>
+=======
{BackupLocationPath}
3FDB57ED-598D-8A4E-CEF7-D90833305558,Y
@@ -1091,6 +1854,7 @@ array set Properties {
3FE82C17-A3E2-4A57-A563-F80818B00B81,Prompt
{<%InstallStartupText%>}
+>>>>>>> 0.12
41CDE776-2667-5CEB-312A-FC4C33A83E7F,Conditions
{0 conditions}
@@ -1099,6 +1863,18 @@ array set Properties {
{*/*.conf;*/*.txt;*/*.pem;*/*.raw;*/*.exe;*/*.bat;*/*.dll}
41CDE776-2667-5CEB-312A-FC4C33A83E7F,RenameFiles
+<<<<<<< HEAD
+Yes
+
+41D3E165-C263-5F80-0FEEC0AEE47A,BackButton,subst
+1
+
+41D3E165-C263-5F80-0FEEC0AEE47A,CancelButton,subst
+1
+
+41D3E165-C263-5F80-0FEEC0AEE47A,Caption,subst
+1
+=======
{Yes}
41D3E165-C263-5F80-0FEEC0AEE47A,BackButton,subst
@@ -1109,11 +1885,33 @@ array set Properties {
41D3E165-C263-5F80-0FEEC0AEE47A,Caption,subst
{1}
+>>>>>>> 0.12
41D3E165-C263-5F80-0FEEC0AEE47A,Conditions
{1 condition}
41D3E165-C263-5F80-0FEEC0AEE47A,Message,subst
+<<<<<<< HEAD
+1
+
+41D3E165-C263-5F80-0FEEC0AEE47A,NextButton,subst
+1
+
+41D3E165-C263-5F80-0FEEC0AEE47A,Subtitle,subst
+1
+
+41D3E165-C263-5F80-0FEEC0AEE47A,Text,subst
+1
+
+41D3E165-C263-5F80-0FEEC0AEE47A,Title,subst
+1
+
+481451CC-F49C-D389-8645076F595B,Destination
+<%InstallDir%>
+
+481451CC-F49C-D389-8645076F595B,FileSize
+15288767
+=======
{1}
41D3E165-C263-5F80-0FEEC0AEE47A,NextButton,subst
@@ -1133,15 +1931,23 @@ array set Properties {
481451CC-F49C-D389-8645076F595B,FileSize
{7893504}
+>>>>>>> 0.12
481451CC-F49C-D389-8645076F595B,Name
{Program Files}
49E59F91-27F7-46D1-A1C1-19865C2392D3,Default
+<<<<<<< HEAD
+Yes
+
+49E59F91-27F7-46D1-A1C1-19865C2392D3,Prompt
+<%UninstallStartupText%>
+=======
{Yes}
49E59F91-27F7-46D1-A1C1-19865C2392D3,Prompt
{<%UninstallStartupText%>}
+>>>>>>> 0.12
49E80443-62DB-1C10-392D-1091AEA5ED88,Conditions
{1 condition}
@@ -1150,6 +1956,18 @@ array set Properties {
{Before Next Pane is Displayed}
49E80443-62DB-1C10-392D-1091AEA5ED88,Pane
+<<<<<<< HEAD
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
+
+4A9C852B-647E-EED5-5482FFBCC2AF,Description,subst
+1
+
+4A9C852B-647E-EED5-5482FFBCC2AF,DisplayName,subst
+1
+
+4A9C852B-647E-EED5-5482FFBCC2AF,FileGroups
+481451CC-F49C-D389-8645076F595B
+=======
{3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7}
4A9C852B-647E-EED5-5482FFBCC2AF,Description,subst
@@ -1160,17 +1978,31 @@ array set Properties {
4A9C852B-647E-EED5-5482FFBCC2AF,FileGroups
{481451CC-F49C-D389-8645076F595B}
+>>>>>>> 0.12
4A9C852B-647E-EED5-5482FFBCC2AF,Name
{Default Component}
4A9C852B-647E-EED5-5482FFBCC2AF,RequiredComponent
+<<<<<<< HEAD
+Yes
+=======
{Yes}
+>>>>>>> 0.12
4ACB0B47-42B3-2B3A-BFE9AA4EC707,CheckCondition
{Before Action is Executed}
4ACB0B47-42B3-2B3A-BFE9AA4EC707,Message,subst
+<<<<<<< HEAD
+1
+
+4ACB0B47-42B3-2B3A-BFE9AA4EC707,Title,subst
+1
+
+4ACB0B47-42B3-2B3A-BFE9AA4EC707,TrueValue
+No
+=======
{1}
4ACB0B47-42B3-2B3A-BFE9AA4EC707,Title,subst
@@ -1178,42 +2010,69 @@ array set Properties {
4ACB0B47-42B3-2B3A-BFE9AA4EC707,TrueValue
{No}
+>>>>>>> 0.12
4D4A7BF0-7CCE-46E6-BDE5222F82D7,Conditions
{0 conditions}
4D4A7BF0-7CCE-46E6-BDE5222F82D7,UpdateFilePercentage
+<<<<<<< HEAD
+Yes
+
+4D4A7BF0-7CCE-46E6-BDE5222F82D7,UpdateFileText
+Yes
+=======
{Yes}
4D4A7BF0-7CCE-46E6-BDE5222F82D7,UpdateFileText
{Yes}
+>>>>>>> 0.12
4E643D8A-CA31-018D-57D7053C2CE8,CheckCondition
{Before Action is Executed}
4E643D8A-CA31-018D-57D7053C2CE8,Filename
+<<<<<<< HEAD
+<%ProgramExecutable%>
+=======
{<%ProgramExecutable%>}
+>>>>>>> 0.12
4EE35849-FAD7-170B-0E45-FA30636467B1,CheckCondition
{Before Next Pane is Displayed}
4EE35849-FAD7-170B-0E45-FA30636467B1,EncryptedPassword
+<<<<<<< HEAD
+<%InstallPasswordEncrypted%>
+=======
{<%InstallPasswordEncrypted%>}
+>>>>>>> 0.12
4EE35849-FAD7-170B-0E45-FA30636467B1,FailureFocus
{Password Entry}
4EE35849-FAD7-170B-0E45-FA30636467B1,FailureMessage
+<<<<<<< HEAD
+<%PasswordIncorrectText%>
+
+4EE35849-FAD7-170B-0E45-FA30636467B1,UnencryptedPassword
+<%InstallPassword%>
+=======
{<%PasswordIncorrectText%>}
4EE35849-FAD7-170B-0E45-FA30636467B1,UnencryptedPassword
{<%InstallPassword%>}
+>>>>>>> 0.12
4EF787E3-0643-DE46-15E64BAF0816,CheckCondition
{Before Action is Executed}
4EF787E3-0643-DE46-15E64BAF0816,Platform
+<<<<<<< HEAD
+Windows
+=======
{Windows}
+>>>>>>> 0.12
52F0A238-57E1-A578-2CE4DA177B32,Conditions
{0 conditions}
@@ -1222,6 +2081,15 @@ array set Properties {
{0 conditions}
574198A7-7322-2F5E-02EF185D965C,BackButton,subst
+<<<<<<< HEAD
+1
+
+574198A7-7322-2F5E-02EF185D965C,CancelButton,subst
+1
+
+574198A7-7322-2F5E-02EF185D965C,Caption,subst
+1
+=======
{1}
574198A7-7322-2F5E-02EF185D965C,CancelButton,subst
@@ -1229,11 +2097,45 @@ array set Properties {
574198A7-7322-2F5E-02EF185D965C,Caption,subst
{1}
+>>>>>>> 0.12
574198A7-7322-2F5E-02EF185D965C,Conditions
{0 conditions}
574198A7-7322-2F5E-02EF185D965C,FileLabel,subst
+<<<<<<< HEAD
+1
+
+574198A7-7322-2F5E-02EF185D965C,Message,subst
+1
+
+574198A7-7322-2F5E-02EF185D965C,NextButton,subst
+1
+
+574198A7-7322-2F5E-02EF185D965C,ProgressValue,subst
+1
+
+574198A7-7322-2F5E-02EF185D965C,Subtitle,subst
+1
+
+574198A7-7322-2F5E-02EF185D965C,Title,subst
+1
+
+58E1119F-639E-17C9-5D3898F385AA,BackButton,subst
+1
+
+58E1119F-639E-17C9-5D3898F385AA,BrowseButton,subst
+1
+
+58E1119F-639E-17C9-5D3898F385AA,BrowseText,subst
+1
+
+58E1119F-639E-17C9-5D3898F385AA,CancelButton,subst
+1
+
+58E1119F-639E-17C9-5D3898F385AA,Caption,subst
+1
+=======
{1}
574198A7-7322-2F5E-02EF185D965C,Message,subst
@@ -1265,10 +2167,27 @@ array set Properties {
58E1119F-639E-17C9-5D3898F385AA,Caption,subst
{1}
+>>>>>>> 0.12
58E1119F-639E-17C9-5D3898F385AA,Conditions
{1 condition}
+<<<<<<< HEAD
+58E1119F-639E-17C9-5D3898F385AA,DestinationLabel,subst
+0
+
+58E1119F-639E-17C9-5D3898F385AA,Message,subst
+1
+
+58E1119F-639E-17C9-5D3898F385AA,NextButton,subst
+1
+
+58E1119F-639E-17C9-5D3898F385AA,Subtitle,subst
+1
+
+58E1119F-639E-17C9-5D3898F385AA,Title,subst
+1
+=======
58E1119F-639E-17C9-5D3898F385AA,Destination,subst
{1}
@@ -1286,12 +2205,17 @@ array set Properties {
58E1119F-639E-17C9-5D3898F385AA,Title,subst
{1}
+>>>>>>> 0.12
592F46AE-8CEE-01F3-0BA7EBDCA4F4,CheckCondition
{Before Action is Executed}
592F46AE-8CEE-01F3-0BA7EBDCA4F4,Filename
+<<<<<<< HEAD
+<%ProgramExecutable%>
+=======
{<%ProgramExecutable%>}
+>>>>>>> 0.12
5CA3EA16-E37C-AABE-E576C4636EB0,Action
{Install Actions}
@@ -1303,7 +2227,11 @@ array set Properties {
{Before Action is Executed}
5EE78EF7-37CA-D440-3DB5-09136CD566B3,String
+<<<<<<< HEAD
+<%AddBackupLocation%>
+=======
{<%AddBackupLocation%>}
+>>>>>>> 0.12
5F2C1F1C-B9F7-1642-59D9-A18318C1D70B,Conditions
{0 conditions}
@@ -1312,7 +2240,11 @@ array set Properties {
{<%ConfigFileTemplate%>;*/*.bat;<%InstallDir%>/*.vbs}
5F2C1F1C-B9F7-1642-59D9-A18318C1D70B,LineFeed
+<<<<<<< HEAD
+Windows
+=======
{Windows}
+>>>>>>> 0.12
5F2C1F1C-B9F7-1642-59D9-A18318C1D70B,StringMap
{"@@CUSTOMERCOMPANY@@" <%UserInfoCompany%>
@@ -1325,19 +2257,31 @@ array set Properties {
"@@INSTALLDIR@@" <%InstallDir%>}
614C45B2-7515-780C-E444-7F165CF02DD7,Active
+<<<<<<< HEAD
+No
+=======
{No}
+>>>>>>> 0.12
614C45B2-7515-780C-E444-7F165CF02DD7,Conditions
{0 conditions}
614C45B2-7515-780C-E444-7F165CF02DD7,ResultVirtualText
+<<<<<<< HEAD
+BackupLocationShortName
+=======
{BackupLocationShortName}
+>>>>>>> 0.12
614C45B2-7515-780C-E444-7F165CF02DD7,TclScript
{set BackupLocationShortName ""}
6652193C-5D4B-44B6-ABC6-D6E96D89E5DC,Active
+<<<<<<< HEAD
+No
+=======
{No}
+>>>>>>> 0.12
6652193C-5D4B-44B6-ABC6-D6E96D89E5DC,Comment
{PJ removed. Is this the one at the top leve?}
@@ -1349,12 +2293,28 @@ array set Properties {
{2 conditions}
6B4CB3C2-4799-4C9F-BA8E-1EE47C4606E1,ExitType
+<<<<<<< HEAD
+Finish
+=======
{Finish}
+>>>>>>> 0.12
6B966959-05D9-DB32-8D9C4AD2A3DF,CheckCondition
{Before Action is Executed}
6B966959-05D9-DB32-8D9C4AD2A3DF,Platform
+<<<<<<< HEAD
+Windows
+
+6C323815-B9AB-FA94-4F5D152EBC51,BackButton,subst
+1
+
+6C323815-B9AB-FA94-4F5D152EBC51,CancelButton,subst
+1
+
+6C323815-B9AB-FA94-4F5D152EBC51,Caption,subst
+1
+=======
{Windows}
6C323815-B9AB-FA94-4F5D152EBC51,BackButton,subst
@@ -1365,15 +2325,23 @@ array set Properties {
6C323815-B9AB-FA94-4F5D152EBC51,Caption,subst
{1}
+>>>>>>> 0.12
6C323815-B9AB-FA94-4F5D152EBC51,Conditions
{0 conditions}
6C323815-B9AB-FA94-4F5D152EBC51,Message,subst
+<<<<<<< HEAD
+1
+
+6C323815-B9AB-FA94-4F5D152EBC51,NextButton,subst
+1
+=======
{1}
6C323815-B9AB-FA94-4F5D152EBC51,NextButton,subst
{1}
+>>>>>>> 0.12
6D9D1ABC-7146-443F-9EE9-205D5CA6C830,CheckCondition
{Before Action is Executed}
@@ -1394,25 +2362,43 @@ array set Properties {
{0 conditions}
6F61CDA8-30C9-454F-82A3-9987E1203079,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-sync
+=======
{<%ShortAppName%>-program-sync}
+>>>>>>> 0.12
6F61CDA8-30C9-454F-82A3-9987E1203079,ShortcutName
{Sync now}
6F61CDA8-30C9-454F-82A3-9987E1203079,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/Sync.bat
+
+6F61CDA8-30C9-454F-82A3-9987E1203079,WorkingDirectory
+<%InstallDir%>
+=======
{<%InstallDir%>/tools/Sync.bat}
6F61CDA8-30C9-454F-82A3-9987E1203079,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
6F94698F-0839-3ABF-0CF2DF05A4C8,CheckCondition
{Before Action is Executed}
6F94698F-0839-3ABF-0CF2DF05A4C8,String
+<<<<<<< HEAD
+<%CreateQuickLaunchShortcut%>
+
+6FEE2889-0338-1D49-60BF-1471F465AB26,AppendNewline
+No
+=======
{<%CreateQuickLaunchShortcut%>}
6FEE2889-0338-1D49-60BF-1471F465AB26,AppendNewline
{No}
+>>>>>>> 0.12
6FEE2889-0338-1D49-60BF-1471F465AB26,Comment
{Closing final BackupLocations bracket}
@@ -1424,6 +2410,15 @@ array set Properties {
{Append to file}
6FEE2889-0338-1D49-60BF-1471F465AB26,Files
+<<<<<<< HEAD
+<%ConfigFileTemplate%>
+
+6FEE2889-0338-1D49-60BF-1471F465AB26,LineFeed
+Windows
+
+6FEE2889-0338-1D49-60BF-1471F465AB26,TextToWrite,subst
+1
+=======
{<%ConfigFileTemplate%>}
6FEE2889-0338-1D49-60BF-1471F465AB26,LineFeed
@@ -1431,21 +2426,33 @@ array set Properties {
6FEE2889-0338-1D49-60BF-1471F465AB26,TextToWrite,subst
{1}
+>>>>>>> 0.12
738DD098-7E3B-BC89-875CDB93CBE2,CheckCondition
{Before Action is Executed}
738DD098-7E3B-BC89-875CDB93CBE2,Platform
+<<<<<<< HEAD
+Windows
+=======
{Windows}
+>>>>>>> 0.12
73DD4D07-B1DC-BA38-2B12-07EB24A7F0C8,Conditions
{0 conditions}
73DD4D07-B1DC-BA38-2B12-07EB24A7F0C8,Destination
+<<<<<<< HEAD
+<%ConfigFileName%>
+
+73DD4D07-B1DC-BA38-2B12-07EB24A7F0C8,Source
+<%ConfigFileTemplate%>
+=======
{<%ConfigFileName%>}
73DD4D07-B1DC-BA38-2B12-07EB24A7F0C8,Source
{<%ConfigFileTemplate%>}
+>>>>>>> 0.12
73EA65C1-3BE3-B190-55C3E99F6269,Conditions
{1 condition}
@@ -1454,31 +2461,53 @@ array set Properties {
{Before Action is Executed}
748D673B-DFE6-5F74-329903ACE4DB,Filename
+<<<<<<< HEAD
+<%ProgramExecutable%>
+=======
{<%ProgramExecutable%>}
+>>>>>>> 0.12
793D8178-0F51-7F07-BC5886586D3C,CheckCondition
{Before Action is Executed}
793D8178-0F51-7F07-BC5886586D3C,Operator
+<<<<<<< HEAD
+false
+
+793D8178-0F51-7F07-BC5886586D3C,String
+<%InstallStopped%>
+=======
{false}
793D8178-0F51-7F07-BC5886586D3C,String
{<%InstallStopped%>}
+>>>>>>> 0.12
795EE61F-6C0D-4A8B-93E02AA3894A,CheckCondition
{Before Action is Executed}
795EE61F-6C0D-4A8B-93E02AA3894A,String
+<<<<<<< HEAD
+<%LaunchApplication%>
+=======
{<%LaunchApplication%>}
+>>>>>>> 0.12
79DAC913-A33D-4ED6-9BAE-B3A2053C0F2C,CheckCondition
{Before Action is Executed}
79DAC913-A33D-4ED6-9BAE-B3A2053C0F2C,Operator
+<<<<<<< HEAD
+false
+
+79DAC913-A33D-4ED6-9BAE-B3A2053C0F2C,String
+<%LicenseAccepted%>
+=======
{false}
79DAC913-A33D-4ED6-9BAE-B3A2053C0F2C,String
{<%LicenseAccepted%>}
+>>>>>>> 0.12
7A983CD8-302C-4942-BE59-525C5B5FA2F2,Conditions
{0 conditions}
@@ -1487,15 +2516,34 @@ array set Properties {
{ServiceControl terminate}
7A983CD8-302C-4942-BE59-525C5B5FA2F2,WorkingDirectory
+<<<<<<< HEAD
+<%InstallDir%>
+
+7B770A07-A785-5215-956FA82CF14E,Active
+No
+=======
{<%InstallDir%>}
7B770A07-A785-5215-956FA82CF14E,Active
{No}
+>>>>>>> 0.12
7B770A07-A785-5215-956FA82CF14E,Conditions
{3 conditions}
7B770A07-A785-5215-956FA82CF14E,ShortcutDirectory
+<<<<<<< HEAD
+<%QUICK_LAUNCH%>
+
+7B770A07-A785-5215-956FA82CF14E,ShortcutName
+<%BrandName%>
+
+7B770A07-A785-5215-956FA82CF14E,TargetFileName
+<%ProgramExecutable%>
+
+7B770A07-A785-5215-956FA82CF14E,WorkingDirectory
+<%InstallDir%>
+=======
{<%QUICK_LAUNCH%>}
7B770A07-A785-5215-956FA82CF14E,ShortcutName
@@ -1506,6 +2554,7 @@ array set Properties {
7B770A07-A785-5215-956FA82CF14E,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
7D8E1902-2BC4-80D8-2C18771E7C22,Conditions
{0 conditions}
@@ -1514,6 +2563,33 @@ array set Properties {
{<%ServiceExeName%> -i -S <%ServiceName%> -c "<%ConfigFileName%>"}
7D8E1902-2BC4-80D8-2C18771E7C22,ProgressiveOutputWidget
+<<<<<<< HEAD
+Message
+
+7D8E1902-2BC4-80D8-2C18771E7C22,ShowProgressiveOutput
+Yes
+
+7D8E1902-2BC4-80D8-2C18771E7C22,WorkingDirectory
+<%InstallDir%>
+
+7F85263E-CAE2-46BA-AAC0-6B89D20FD2DE,ExitType
+Finish
+
+8202CECC-54A0-9B6C-D24D111BA52E,Components
+4A9C852B-647E-EED5-5482FFBCC2AF
+
+8202CECC-54A0-9B6C-D24D111BA52E,Description,subst
+1
+
+8202CECC-54A0-9B6C-D24D111BA52E,DisplayName,subst
+1
+
+8202CECC-54A0-9B6C-D24D111BA52E,Name
+Typical
+
+8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Checked
+No
+=======
{Message}
7D8E1902-2BC4-80D8-2C18771E7C22,ShowProgressiveOutput
@@ -1539,11 +2615,27 @@ array set Properties {
8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Checked
{No}
+>>>>>>> 0.12
8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Conditions
{0 conditions}
8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Text,subst
+<<<<<<< HEAD
+1
+
+8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Type
+checkbutton
+
+8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Value
+Yes
+
+8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,VirtualText
+AddBackupLocation
+
+8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Y
+250
+=======
{1}
8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Type
@@ -1557,6 +2649,7 @@ array set Properties {
8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Y
{250}
+>>>>>>> 0.12
848844B5-6103-9343-8B731B0BE4E0,Alias
{Startup Actions}
@@ -1568,10 +2661,17 @@ array set Properties {
{Before Next Pane is Displayed}
84DA7F05-9FB7-CC36-9EC98F8A6826,FailureMessage
+<<<<<<< HEAD
+<%DirectoryPermissionText%>
+
+84DA7F05-9FB7-CC36-9EC98F8A6826,Filename
+<%InstallDir%>
+=======
{<%DirectoryPermissionText%>}
84DA7F05-9FB7-CC36-9EC98F8A6826,Filename
{<%InstallDir%>}
+>>>>>>> 0.12
84DA7F05-9FB7-CC36-9EC98F8A6826,Permission
{can create}
@@ -1580,6 +2680,21 @@ array set Properties {
{0 conditions}
855DE408-060E-3D35-08B5-1D9AB05C2865,Height
+<<<<<<< HEAD
+100
+
+855DE408-060E-3D35-08B5-1D9AB05C2865,Text,subst
+1
+
+855DE408-060E-3D35-08B5-1D9AB05C2865,Type
+text
+
+855DE408-060E-3D35-08B5-1D9AB05C2865,VirtualText
+BackupLocationExclusions
+
+855DE408-060E-3D35-08B5-1D9AB05C2865,Y
+130
+=======
{100}
855DE408-060E-3D35-08B5-1D9AB05C2865,Text,subst
@@ -1593,11 +2708,21 @@ array set Properties {
855DE408-060E-3D35-08B5-1D9AB05C2865,Y
{130}
+>>>>>>> 0.12
87DE6D78-81E1-495B-A214-B3FF3E7E5614,CheckCondition
{Before Action is Executed}
87DE6D78-81E1-495B-A214-B3FF3E7E5614,Operator
+<<<<<<< HEAD
+false
+
+87DE6D78-81E1-495B-A214-B3FF3E7E5614,String
+<%Answer%>
+
+88A50FD5-480F-19A5-DA74-C915EB0A9765,Active
+No
+=======
{false}
87DE6D78-81E1-495B-A214-B3FF3E7E5614,String
@@ -1605,6 +2730,7 @@ array set Properties {
88A50FD5-480F-19A5-DA74-C915EB0A9765,Active
{No}
+>>>>>>> 0.12
88A50FD5-480F-19A5-DA74-C915EB0A9765,Conditions
{1 condition}
@@ -1613,13 +2739,21 @@ array set Properties {
{After Pane is Finished}
88A50FD5-480F-19A5-DA74-C915EB0A9765,Pane
+<<<<<<< HEAD
+3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7
+=======
{3FD9BFF3-2F6E-E4FC-2FAE-98F2017916A7}
+>>>>>>> 0.12
8A761DBD-0640-D98C-9B3AD7672A8F,Conditions
{0 conditions}
8A761DBD-0640-D98C-9B3AD7672A8F,State
+<<<<<<< HEAD
+disabled
+=======
{disabled}
+>>>>>>> 0.12
8A761DBD-0640-D98C-9B3AD7672A8F,Widget
{Back Button;Next Button}
@@ -1628,15 +2762,31 @@ array set Properties {
{Before Action is Executed}
8C866252-8760-9B08-FE569C25B60D,Filename
+<<<<<<< HEAD
+<%ProgramExecutable%>
+
+8E095096-F018-A880-429D-A2177A9B70EA,Active
+No
+=======
{<%ProgramExecutable%>}
8E095096-F018-A880-429D-A2177A9B70EA,Active
{No}
+>>>>>>> 0.12
8E095096-F018-A880-429D-A2177A9B70EA,Conditions
{0 conditions}
8E095096-F018-A880-429D-A2177A9B70EA,Text,subst
+<<<<<<< HEAD
+1
+
+8E095096-F018-A880-429D-A2177A9B70EA,X
+50
+
+8E095096-F018-A880-429D-A2177A9B70EA,Y
+150
+=======
{1}
8E095096-F018-A880-429D-A2177A9B70EA,X
@@ -1644,10 +2794,27 @@ array set Properties {
8E095096-F018-A880-429D-A2177A9B70EA,Y
{150}
+>>>>>>> 0.12
8E1A5944-5AF5-5906-16D395E386D8,Conditions
{0 conditions}
+<<<<<<< HEAD
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,Active
+Yes
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,BackButton,subst
+1
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,CancelButton,subst
+1
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,Caption,subst
+1
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,CompanyLabel,subst
+1
+=======
9013E862-8E81-5290-64F9-D8BCD13EC7E5,BackButton,subst
{1}
@@ -1659,11 +2826,27 @@ array set Properties {
9013E862-8E81-5290-64F9-D8BCD13EC7E5,CompanyLabel,subst
{1}
+>>>>>>> 0.12
9013E862-8E81-5290-64F9-D8BCD13EC7E5,Conditions
{0 conditions}
9013E862-8E81-5290-64F9-D8BCD13EC7E5,Message,subst
+<<<<<<< HEAD
+1
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,NextButton,subst
+1
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,Subtitle,subst
+1
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,Title,subst
+1
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,UserNameLabel,subst
+1
+=======
{1}
9013E862-8E81-5290-64F9-D8BCD13EC7E5,NextButton,subst
@@ -1677,6 +2860,7 @@ array set Properties {
9013E862-8E81-5290-64F9-D8BCD13EC7E5,UserNameLabel,subst
{1}
+>>>>>>> 0.12
905DA2E9-988C-2F27-BB1F5F274AC9,Alias
{Cancel Actions}
@@ -1685,6 +2869,15 @@ array set Properties {
{0 conditions}
908CE221-5A3D-0A78-24A1-E7C91EBE38D4,BackButton,subst
+<<<<<<< HEAD
+1
+
+908CE221-5A3D-0A78-24A1-E7C91EBE38D4,CancelButton,subst
+1
+
+908CE221-5A3D-0A78-24A1-E7C91EBE38D4,Caption,subst
+1
+=======
{1}
908CE221-5A3D-0A78-24A1-E7C91EBE38D4,CancelButton,subst
@@ -1692,11 +2885,27 @@ array set Properties {
908CE221-5A3D-0A78-24A1-E7C91EBE38D4,Caption,subst
{1}
+>>>>>>> 0.12
908CE221-5A3D-0A78-24A1-E7C91EBE38D4,Conditions
{0 conditions}
908CE221-5A3D-0A78-24A1-E7C91EBE38D4,Message,subst
+<<<<<<< HEAD
+1
+
+908CE221-5A3D-0A78-24A1-E7C91EBE38D4,NextButton,subst
+1
+
+908CE221-5A3D-0A78-24A1-E7C91EBE38D4,Subtitle,subst
+1
+
+908CE221-5A3D-0A78-24A1-E7C91EBE38D4,Title,subst
+1
+
+937C3FDD-FB28-98BD-3DAB276E59ED,Background
+white
+=======
{1}
908CE221-5A3D-0A78-24A1-E7C91EBE38D4,NextButton,subst
@@ -1710,11 +2919,30 @@ array set Properties {
937C3FDD-FB28-98BD-3DAB276E59ED,Background
{white}
+>>>>>>> 0.12
937C3FDD-FB28-98BD-3DAB276E59ED,Conditions
{3 conditions}
937C3FDD-FB28-98BD-3DAB276E59ED,Text,subst
+<<<<<<< HEAD
+1
+
+937C3FDD-FB28-98BD-3DAB276E59ED,Type
+checkbutton
+
+937C3FDD-FB28-98BD-3DAB276E59ED,VirtualText
+CreateQuickLaunchShortcut
+
+937C3FDD-FB28-98BD-3DAB276E59ED,X
+185
+
+937C3FDD-FB28-98BD-3DAB276E59ED,Y
+200
+
+93AA298C-B64E-5683-14D2-7B86F7DEFD2C,Active
+No
+=======
{1}
937C3FDD-FB28-98BD-3DAB276E59ED,Type
@@ -1731,6 +2959,7 @@ array set Properties {
93AA298C-B64E-5683-14D2-7B86F7DEFD2C,Active
{No}
+>>>>>>> 0.12
93AA298C-B64E-5683-14D2-7B86F7DEFD2C,Comment
{set BackupLocationName "BackupLocation_${BackupLocationNumber}"}
@@ -1739,7 +2968,11 @@ array set Properties {
{0 conditions}
93AA298C-B64E-5683-14D2-7B86F7DEFD2C,ResultVirtualText
+<<<<<<< HEAD
+BackupLocationName
+=======
{BackupLocationName}
+>>>>>>> 0.12
93AA298C-B64E-5683-14D2-7B86F7DEFD2C,TclScript
{set BackupLocationName "BackupLocation_${BackupLocationNumber}"}
@@ -1748,24 +2981,48 @@ array set Properties {
{Before Action is Executed}
96A68CAC-9ED7-806C-086B104720FD,String
+<<<<<<< HEAD
+<%ErrorsOccurred%>
+=======
{<%ErrorsOccurred%>}
+>>>>>>> 0.12
97ACF525-C075-8635-E019202A83D8,Comment
{Ask the user if they want to proceed with the uninstall.}
9892B25C-689B-5B8F-F0C9-B14FF6ACC40C,Active
+<<<<<<< HEAD
+No
+=======
{No}
+>>>>>>> 0.12
9892B25C-689B-5B8F-F0C9-B14FF6ACC40C,Conditions
{0 conditions}
9892B25C-689B-5B8F-F0C9-B14FF6ACC40C,ResultVirtualText
+<<<<<<< HEAD
+AddBackupLocation
+=======
{AddBackupLocation}
+>>>>>>> 0.12
9892B25C-689B-5B8F-F0C9-B14FF6ACC40C,TclScript
{set AddBackupLocation no}
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Active
+<<<<<<< HEAD
+Yes
+
+9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,BackButton,subst
+1
+
+9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,CancelButton,subst
+1
+
+9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Caption,subst
+1
+=======
{Yes}
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,BackButton,subst
@@ -1776,11 +3033,24 @@ array set Properties {
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Caption,subst
{1}
+>>>>>>> 0.12
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Conditions
{0 conditions}
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Message,subst
+<<<<<<< HEAD
+1
+
+9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,NextButton,subst
+1
+
+9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Subtitle,subst
+1
+
+9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Title,subst
+1
+=======
{1}
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,NextButton,subst
@@ -1791,21 +3061,33 @@ array set Properties {
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Title,subst
{1}
+>>>>>>> 0.12
9A663209-495B-ED16-09BE-457B61148022,Conditions
{0 conditions}
9A663209-495B-ED16-09BE-457B61148022,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-QueryCurrent
+=======
{<%ShortAppName%>-program-QueryCurrent}
+>>>>>>> 0.12
9A663209-495B-ED16-09BE-457B61148022,ShortcutName
{Query Current Only}
9A663209-495B-ED16-09BE-457B61148022,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/QueryOutputCurrent.bat
+
+9A663209-495B-ED16-09BE-457B61148022,WorkingDirectory
+<%InstallDir%>
+=======
{<%InstallDir%>/tools/QueryOutputCurrent.bat}
9A663209-495B-ED16-09BE-457B61148022,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
9D101299-B80C-441B-8685-6E3AC61808E8,Alias
{Remote Control}
@@ -1817,6 +3099,18 @@ array set Properties {
{0 conditions}
9D101299-B80C-441B-8685-6E3AC61808E8,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-RemoteControl
+
+9D101299-B80C-441B-8685-6E3AC61808E8,ShortcutName
+RemoteControl
+
+9D101299-B80C-441B-8685-6E3AC61808E8,TargetFileName
+<%InstallDir%>/tools/RemoteControl.exe
+
+9D101299-B80C-441B-8685-6E3AC61808E8,WorkingDirectory
+<%InstallDir%>
+=======
{<%ShortAppName%>-program-RemoteControl}
9D101299-B80C-441B-8685-6E3AC61808E8,ShortcutName
@@ -1827,6 +3121,7 @@ array set Properties {
9D101299-B80C-441B-8685-6E3AC61808E8,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
A1DD1DC2-85D7-9BC6-998AC3D4A3A9,Alias
{Startup Actions}
@@ -1838,7 +3133,11 @@ A5B32DA1-B2FE-C1FA-6057-FBC3059EF076,Conditions
{0 conditions}
A5B32DA1-B2FE-C1FA-6057-FBC3059EF076,ResultVirtualText
+<<<<<<< HEAD
+AddBackupLocation
+=======
{AddBackupLocation}
+>>>>>>> 0.12
A5B32DA1-B2FE-C1FA-6057-FBC3059EF076,TclScript
{set AddBackupLocation no }
@@ -1847,12 +3146,28 @@ A6E1B027-A1B4-5848-4F868D028D00,CheckCondition
{Before Action is Executed}
A6E1B027-A1B4-5848-4F868D028D00,String
+<<<<<<< HEAD
+<%ViewReadme%>
+=======
{<%ViewReadme%>}
+>>>>>>> 0.12
ADA6EB2F-8820-4366-BBEF-ED1335B7F828,Conditions
{1 condition}
AE3BD5B4-35DE-4240-B79914D43E56,Active
+<<<<<<< HEAD
+No
+
+AE3BD5B4-35DE-4240-B79914D43E56,BackButton,subst
+1
+
+AE3BD5B4-35DE-4240-B79914D43E56,CancelButton,subst
+1
+
+AE3BD5B4-35DE-4240-B79914D43E56,Caption,subst
+1
+=======
{No}
AE3BD5B4-35DE-4240-B79914D43E56,BackButton,subst
@@ -1863,11 +3178,42 @@ AE3BD5B4-35DE-4240-B79914D43E56,CancelButton,subst
AE3BD5B4-35DE-4240-B79914D43E56,Caption,subst
{1}
+>>>>>>> 0.12
AE3BD5B4-35DE-4240-B79914D43E56,Conditions
{0 conditions}
AE3BD5B4-35DE-4240-B79914D43E56,Message,subst
+<<<<<<< HEAD
+1
+
+AE3BD5B4-35DE-4240-B79914D43E56,NextButton,subst
+1
+
+AIX-ppc,Active
+No
+
+AIX-ppc,DefaultDirectoryPermission
+0755
+
+AIX-ppc,DefaultFilePermission
+0755
+
+AIX-ppc,Executable
+<%AppName%>-<%Version%>-<%Platform%>-Install<%Ext%>
+
+AIX-ppc,FallBackToConsole
+Yes
+
+AIX-ppc,InstallDir
+<%Home%>/<%ShortAppName%>
+
+AIX-ppc,InstallMode
+Standard
+
+AIX-ppc,InstallType
+Typical
+=======
{1}
AE3BD5B4-35DE-4240-B79914D43E56,NextButton,subst
@@ -1899,11 +3245,21 @@ AIX-ppc,InstallMode
AIX-ppc,InstallType
{Typical}
+>>>>>>> 0.12
AIX-ppc,ProgramExecutable
{}
AIX-ppc,ProgramFolderAllUsers
+<<<<<<< HEAD
+No
+
+AIX-ppc,ProgramFolderName
+<%AppName%>
+
+AIX-ppc,ProgramLicense
+<%InstallDir%>/LICENSE.txt
+=======
{No}
AIX-ppc,ProgramFolderName
@@ -1911,11 +3267,27 @@ AIX-ppc,ProgramFolderName
AIX-ppc,ProgramLicense
{<%InstallDir%>/LICENSE.txt}
+>>>>>>> 0.12
AIX-ppc,ProgramName
{}
AIX-ppc,ProgramReadme
+<<<<<<< HEAD
+<%InstallDir%>/README.txt
+
+AIX-ppc,PromptForRoot
+Yes
+
+AIX-ppc,RequireRoot
+No
+
+AIX-ppc,RootInstallDir
+/usr/local/<%ShortAppName%>
+
+B002A311-F8E7-41DE-B039-521391924E5B,Message,subst
+1
+=======
{<%InstallDir%>/README.txt}
AIX-ppc,PromptForRoot
@@ -1929,6 +3301,7 @@ AIX-ppc,RootInstallDir
B002A311-F8E7-41DE-B039-521391924E5B,Message,subst
{1}
+>>>>>>> 0.12
B01CBBB2-6A78-CA53-9ED9-C3C4CFC9239E,Alias
{Stop Backup Service}
@@ -1940,31 +3313,53 @@ B01CBBB2-6A78-CA53-9ED9-C3C4CFC9239E,Conditions
{0 conditions}
B01CBBB2-6A78-CA53-9ED9-C3C4CFC9239E,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-stopservice
+=======
{<%ShortAppName%>-program-stopservice}
+>>>>>>> 0.12
B01CBBB2-6A78-CA53-9ED9-C3C4CFC9239E,ShortcutName
{Stop Service}
B01CBBB2-6A78-CA53-9ED9-C3C4CFC9239E,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/StopService.bat
+
+B01CBBB2-6A78-CA53-9ED9-C3C4CFC9239E,WorkingDirectory
+<%InstallDir%>
+=======
{<%InstallDir%>/tools/StopService.bat}
B01CBBB2-6A78-CA53-9ED9-C3C4CFC9239E,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
B0AA6839-AAB6-A602-C0E4ECA2E4FF,CheckCondition
{Before Action is Executed}
B0AA6839-AAB6-A602-C0E4ECA2E4FF,Filename
+<<<<<<< HEAD
+<%ProgramExecutable%>
+=======
{<%ProgramExecutable%>}
+>>>>>>> 0.12
B39C0455-D1B6-7DDC-E2717F83463E,CheckCondition
{Before Action is Executed}
B39C0455-D1B6-7DDC-E2717F83463E,Operator
+<<<<<<< HEAD
+false
+
+B39C0455-D1B6-7DDC-E2717F83463E,String
+<%InstallStopped%>
+=======
{false}
B39C0455-D1B6-7DDC-E2717F83463E,String
{<%InstallStopped%>}
+>>>>>>> 0.12
B3B99E2D-C368-A921-B7BC-A71EBDE3AD4D,Conditions
{0 conditions}
@@ -1973,7 +3368,11 @@ B3B99E2D-C368-A921-B7BC-A71EBDE3AD4D,ExecuteAction
{Before Next Pane is Displayed}
B3B99E2D-C368-A921-B7BC-A71EBDE3AD4D,Password
+<<<<<<< HEAD
+<%InstallPassword%>
+=======
{<%InstallPassword%>}
+>>>>>>> 0.12
B4D31D1E-ADB1-DE8F-18EB7294DDA8,Conditions
{0 conditions}
@@ -1982,6 +3381,27 @@ B4D31D1E-ADB1-DE8F-18EB7294DDA8,ProgramCommandLine
{<%ServiceExeName%> -r -S <%ServiceName%>}
B4D31D1E-ADB1-DE8F-18EB7294DDA8,WorkingDirectory
+<<<<<<< HEAD
+<%InstallDir%>
+
+B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message,subst
+1
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,AcceptRadiobutton,subst
+0
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Active
+Yes
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,BackButton,subst
+1
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,CancelButton,subst
+1
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Caption,subst
+1
+=======
{<%InstallDir%>}
B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message,subst
@@ -2001,11 +3421,30 @@ B506E7DA-E7C4-4D42-8C03-FD27BA16D078,CancelButton,subst
B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Caption,subst
{1}
+>>>>>>> 0.12
B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Conditions
{0 conditions}
B506E7DA-E7C4-4D42-8C03-FD27BA16D078,DeclineRadiobutton,subst
+<<<<<<< HEAD
+0
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Message,subst
+1
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,NextButton,subst
+1
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Subtitle,subst
+1
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Text,subst
+1
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Title,subst
+1
+=======
{0}
B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Message,subst
@@ -2022,6 +3461,7 @@ B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Text,subst
B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Title,subst
{1}
+>>>>>>> 0.12
B5DFEC63-92A9-4686-909E-0CE78A7069D6,Alias
{Restart Backup Service}
@@ -2033,7 +3473,11 @@ B5DFEC63-92A9-4686-909E-0CE78A7069D6,Conditions
{0 conditions}
B5DFEC63-92A9-4686-909E-0CE78A7069D6,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-restartservice
+=======
{<%ShortAppName%>-program-restartservice}
+>>>>>>> 0.12
B5DFEC63-92A9-4686-909E-0CE78A7069D6,ShortcutName
{Restart Service}
@@ -2042,12 +3486,31 @@ B5DFEC63-92A9-4686-909E-0CE78A7069D6,TargetFileName
{<%InstallDir%>\tools\RestartService.bat}
B5DFEC63-92A9-4686-909E-0CE78A7069D6,WorkingDirectory
+<<<<<<< HEAD
+<%InstallDir%>
+=======
{<%InstallDir%>}
+>>>>>>> 0.12
B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,Conditions
{0 conditions}
B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,LabelSide
+<<<<<<< HEAD
+left
+
+B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,Text,subst
+1
+
+B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,Type
+entry
+
+B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,VirtualText
+BackupLocationShortName
+
+B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,Y
+100
+=======
{left}
B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,Text,subst
@@ -2061,24 +3524,39 @@ B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,VirtualText
B927A5AF-4DFE-82A3-DCA8-35FA4D91EC5A,Y
{100}
+>>>>>>> 0.12
B93D2216-1DDB-484C-A9AC-D6C18ED7DE23,Conditions
{2 conditions}
B93D2216-1DDB-484C-A9AC-D6C18ED7DE23,State
+<<<<<<< HEAD
+disabled
+
+B93D2216-1DDB-484C-A9AC-D6C18ED7DE23,Widget
+NextButton
+=======
{disabled}
B93D2216-1DDB-484C-A9AC-D6C18ED7DE23,Widget
{NextButton}
+>>>>>>> 0.12
BC4EA5FD-50BD-4D6E-953F-5E3EDB957360,CheckCondition
{Before Next Action is Executed}
BC4EA5FD-50BD-4D6E-953F-5E3EDB957360,FailureMessage
+<<<<<<< HEAD
+<%DirectoryPermissionText%>
+
+BC4EA5FD-50BD-4D6E-953F-5E3EDB957360,Filename
+<%InstallDir%>
+=======
{<%DirectoryPermissionText%>}
BC4EA5FD-50BD-4D6E-953F-5E3EDB957360,Filename
{<%InstallDir%>}
+>>>>>>> 0.12
BC4EA5FD-50BD-4D6E-953F-5E3EDB957360,Permission
{can create}
@@ -2093,27 +3571,57 @@ C0452595-F3EB-43AD-BCA2-661437584636,Conditions
{0 conditions}
C0452595-F3EB-43AD-BCA2-661437584636,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-editconfig
+=======
{<%ShortAppName%>-program-editconfig}
+>>>>>>> 0.12
C0452595-F3EB-43AD-BCA2-661437584636,ShortcutName
{Edit Config File}
C0452595-F3EB-43AD-BCA2-661437584636,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/EditConfig.bat
+
+C0452595-F3EB-43AD-BCA2-661437584636,WorkingDirectory
+<%InstallDir%>
+=======
{<%InstallDir%>/tools/EditConfig.bat}
C0452595-F3EB-43AD-BCA2-661437584636,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
C0AF7C05-A31A-8376-BCB9-BA8B3A666252,Conditions
{0 conditions}
C0AF7C05-A31A-8376-BCB9-BA8B3A666252,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-QueryAll
+=======
{<%ShortAppName%>-program-QueryAll}
+>>>>>>> 0.12
C0AF7C05-A31A-8376-BCB9-BA8B3A666252,ShortcutName
{Query All}
C0AF7C05-A31A-8376-BCB9-BA8B3A666252,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/QueryOutputAll.bat
+
+C0AF7C05-A31A-8376-BCB9-BA8B3A666252,WorkingDirectory
+<%InstallDir%>
+
+C105AAAE-7C16-2C9E-769FE4535B60,Active
+No
+
+C105AAAE-7C16-2C9E-769FE4535B60,Caption,subst
+1
+
+C105AAAE-7C16-2C9E-769FE4535B60,CloseButton,subst
+1
+=======
{<%InstallDir%>/tools/QueryOutputAll.bat}
C0AF7C05-A31A-8376-BCB9-BA8B3A666252,WorkingDirectory
@@ -2127,11 +3635,24 @@ C105AAAE-7C16-2C9E-769FE4535B60,Caption,subst
C105AAAE-7C16-2C9E-769FE4535B60,CloseButton,subst
{1}
+>>>>>>> 0.12
C105AAAE-7C16-2C9E-769FE4535B60,Conditions
{3 conditions}
C105AAAE-7C16-2C9E-769FE4535B60,Message,subst
+<<<<<<< HEAD
+1
+
+C105AAAE-7C16-2C9E-769FE4535B60,TextFile
+<%ProgramReadme%>
+
+C105AAAE-7C16-2C9E-769FE4535B60,Title,subst
+1
+
+C33D74B2-26FA-16F5-433A10C6A747,Active
+No
+=======
{1}
C105AAAE-7C16-2C9E-769FE4535B60,TextFile
@@ -2142,11 +3663,21 @@ C105AAAE-7C16-2C9E-769FE4535B60,Title,subst
C33D74B2-26FA-16F5-433A10C6A747,Active
{No}
+>>>>>>> 0.12
C33D74B2-26FA-16F5-433A10C6A747,Conditions
{3 conditions}
C33D74B2-26FA-16F5-433A10C6A747,ProgramCommandLine
+<<<<<<< HEAD
+<%ProgramExecutable%>
+
+C33D74B2-26FA-16F5-433A10C6A747,WaitForProgram
+No
+
+C33D74B2-26FA-16F5-433A10C6A747,WorkingDirectory
+<%InstallDir%>
+=======
{<%ProgramExecutable%>}
C33D74B2-26FA-16F5-433A10C6A747,WaitForProgram
@@ -2154,6 +3685,7 @@ C33D74B2-26FA-16F5-433A10C6A747,WaitForProgram
C33D74B2-26FA-16F5-433A10C6A747,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
C7762473-273F-E3CA-17E3-65789B14CDB0,Conditions
{0 conditions}
@@ -2165,19 +3697,33 @@ C7762473-273F-E3CA-17E3-65789B14CDB0,FileOpenAction
{Append to file}
C7762473-273F-E3CA-17E3-65789B14CDB0,Files
+<<<<<<< HEAD
+<%ConfigFileTemplate%>
+
+C7762473-273F-E3CA-17E3-65789B14CDB0,TextToWrite,subst
+1
+=======
{<%ConfigFileTemplate%>}
C7762473-273F-E3CA-17E3-65789B14CDB0,TextToWrite,subst
{1}
+>>>>>>> 0.12
CC4337CC-F3B5-757C-DFCF5D1D365A,CheckCondition
{Before Action is Executed}
CC4337CC-F3B5-757C-DFCF5D1D365A,Operator
+<<<<<<< HEAD
+false
+
+CC4337CC-F3B5-757C-DFCF5D1D365A,String
+<%SilentMode%>
+=======
{false}
CC4337CC-F3B5-757C-DFCF5D1D365A,String
{<%SilentMode%>}
+>>>>>>> 0.12
CDD84DE3-C970-458F-9162-1A3CE0AA716B,Alias
{Start Backup Service}
@@ -2189,7 +3735,11 @@ CDD84DE3-C970-458F-9162-1A3CE0AA716B,Conditions
{0 conditions}
CDD84DE3-C970-458F-9162-1A3CE0AA716B,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-startservice
+=======
{<%ShortAppName%>-program-startservice}
+>>>>>>> 0.12
CDD84DE3-C970-458F-9162-1A3CE0AA716B,ShortcutName
{Start Service}
@@ -2198,15 +3748,37 @@ CDD84DE3-C970-458F-9162-1A3CE0AA716B,TargetFileName
{<%InstallDir%>\tools\StartService.bat}
CDD84DE3-C970-458F-9162-1A3CE0AA716B,WorkingDirectory
+<<<<<<< HEAD
+<%InstallDir%>
+
+CFFA27AF-A641-E41C-B4A0E3BB3CBB,Background
+white
+=======
{<%InstallDir%>}
CFFA27AF-A641-E41C-B4A0E3BB3CBB,Background
{white}
+>>>>>>> 0.12
CFFA27AF-A641-E41C-B4A0E3BB3CBB,Conditions
{2 conditions}
CFFA27AF-A641-E41C-B4A0E3BB3CBB,Text,subst
+<<<<<<< HEAD
+1
+
+CFFA27AF-A641-E41C-B4A0E3BB3CBB,Type
+checkbutton
+
+CFFA27AF-A641-E41C-B4A0E3BB3CBB,VirtualText
+LaunchApplication
+
+CFFA27AF-A641-E41C-B4A0E3BB3CBB,X
+185
+
+CFFA27AF-A641-E41C-B4A0E3BB3CBB,Y
+160
+=======
{1}
CFFA27AF-A641-E41C-B4A0E3BB3CBB,Type
@@ -2220,6 +3792,7 @@ CFFA27AF-A641-E41C-B4A0E3BB3CBB,X
CFFA27AF-A641-E41C-B4A0E3BB3CBB,Y
{160}
+>>>>>>> 0.12
D23DD94C-E517-7F34-FD59-802CB18AB887,Comment
{Need to do before starting anything else.}
@@ -2231,13 +3804,21 @@ D23DD94C-E517-7F34-FD59-802CB18AB887,Files
{*/*.conf;*/*.txt;*/*.bat}
D23DD94C-E517-7F34-FD59-802CB18AB887,LineFeed
+<<<<<<< HEAD
+Windows
+=======
{Windows}
+>>>>>>> 0.12
D3D73C76-D9D3-07DA-63D4163A44BE,Conditions
{0 conditions}
D3D73C76-D9D3-07DA-63D4163A44BE,ExitType
+<<<<<<< HEAD
+Finish
+=======
{Finish}
+>>>>>>> 0.12
D4FC6EB5-DDEE-4E4A-B8E1-D4B588A7928B,Action
{Install Actions}
@@ -2252,7 +3833,11 @@ D7FBBEBB-2186-5674-BA87-BB7151859D4E,Conditions
{0 conditions}
D7FBBEBB-2186-5674-BA87-BB7151859D4E,ResultVirtualText
+<<<<<<< HEAD
+BackupLocationNumber
+=======
{BackupLocationNumber}
+>>>>>>> 0.12
D7FBBEBB-2186-5674-BA87-BB7151859D4E,TclScript
{incr BackupLocationNumber}
@@ -2264,16 +3849,27 @@ D8B8A9BF-5F2E-4236-A63E-5A8C5FFA8968,Conditions
{0 conditions}
D8B8A9BF-5F2E-4236-A63E-5A8C5FFA8968,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-reloadconfig
+=======
{<%ShortAppName%>-program-reloadconfig}
+>>>>>>> 0.12
D8B8A9BF-5F2E-4236-A63E-5A8C5FFA8968,ShortcutName
{Reload configuration file}
D8B8A9BF-5F2E-4236-A63E-5A8C5FFA8968,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/ReloadConfig.bat
+
+D8B8A9BF-5F2E-4236-A63E-5A8C5FFA8968,WorkingDirectory
+<%InstallDir%>
+=======
{<%InstallDir%>/tools/ReloadConfig.bat}
D8B8A9BF-5F2E-4236-A63E-5A8C5FFA8968,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
D8F0AA0F-AD79-C566-15CC508F503B,Action
{Install Actions}
@@ -2285,6 +3881,24 @@ D9F88AC1-3D2D-F6DB-871E-3A0E016770B1,Conditions
{0 conditions}
D9F88AC1-3D2D-F6DB-871E-3A0E016770B1,Destination
+<<<<<<< HEAD
+<%ConfigFileTemplate%>
+
+D9F88AC1-3D2D-F6DB-871E-3A0E016770B1,Source
+<%InstallDir%>/templates/original.conf
+
+DA33B826-E633-A845-4646-76DFA78B907B,Active
+Yes
+
+DA33B826-E633-A845-4646-76DFA78B907B,BackButton,subst
+1
+
+DA33B826-E633-A845-4646-76DFA78B907B,CancelButton,subst
+1
+
+DA33B826-E633-A845-4646-76DFA78B907B,Caption,subst
+1
+=======
{<%ConfigFileTemplate%>}
D9F88AC1-3D2D-F6DB-871E-3A0E016770B1,Source
@@ -2301,11 +3915,30 @@ DA33B826-E633-A845-4646-76DFA78B907B,CancelButton,subst
DA33B826-E633-A845-4646-76DFA78B907B,Caption,subst
{1}
+>>>>>>> 0.12
DA33B826-E633-A845-4646-76DFA78B907B,Conditions
{0 conditions}
DA33B826-E633-A845-4646-76DFA78B907B,Message,subst
+<<<<<<< HEAD
+1
+
+DA33B826-E633-A845-4646-76DFA78B907B,NextButton,subst
+1
+
+DA33B826-E633-A845-4646-76DFA78B907B,Subtitle,subst
+1
+
+DA33B826-E633-A845-4646-76DFA78B907B,Title,subst
+1
+
+DDBBD8A9-13D7-9509-9202-419E989F60A9,Active
+No
+
+DDBBD8A9-13D7-9509-9202-419E989F60A9,Checked
+No
+=======
{1}
DA33B826-E633-A845-4646-76DFA78B907B,NextButton,subst
@@ -2322,11 +3955,27 @@ DDBBD8A9-13D7-9509-9202-419E989F60A9,Active
DDBBD8A9-13D7-9509-9202-419E989F60A9,Checked
{No}
+>>>>>>> 0.12
DDBBD8A9-13D7-9509-9202-419E989F60A9,Conditions
{0 conditions}
DDBBD8A9-13D7-9509-9202-419E989F60A9,Text,subst
+<<<<<<< HEAD
+1
+
+DDBBD8A9-13D7-9509-9202-419E989F60A9,Type
+checkbutton
+
+DDBBD8A9-13D7-9509-9202-419E989F60A9,VirtualText
+AddBackupLocation
+
+DDBBD8A9-13D7-9509-9202-419E989F60A9,X
+50
+
+DDBBD8A9-13D7-9509-9202-419E989F60A9,Y
+200
+=======
{1}
DDBBD8A9-13D7-9509-9202-419E989F60A9,Type
@@ -2340,6 +3989,7 @@ DDBBD8A9-13D7-9509-9202-419E989F60A9,X
DDBBD8A9-13D7-9509-9202-419E989F60A9,Y
{200}
+>>>>>>> 0.12
DE800F1C-CB1A-E1CE-AEB8-B0A6DB4818E7,Alias
{Install Backup Service}
@@ -2351,12 +4001,25 @@ DE800F1C-CB1A-E1CE-AEB8-B0A6DB4818E7,Conditions
{0 conditions}
DE800F1C-CB1A-E1CE-AEB8-B0A6DB4818E7,FileName
+<<<<<<< HEAD
+<%ShortAppName%>-program-installService
+=======
{<%ShortAppName%>-program-installService}
+>>>>>>> 0.12
DE800F1C-CB1A-E1CE-AEB8-B0A6DB4818E7,ShortcutName
{Install Service}
DE800F1C-CB1A-E1CE-AEB8-B0A6DB4818E7,TargetFileName
+<<<<<<< HEAD
+<%InstallDir%>/tools/InstallService.bat
+
+DE800F1C-CB1A-E1CE-AEB8-B0A6DB4818E7,WorkingDirectory
+<%InstallDir%>
+
+DECC120D-6904-7F17-45A49184A5A3,Active
+No
+=======
{<%InstallDir%>/tools/InstallService.bat}
DE800F1C-CB1A-E1CE-AEB8-B0A6DB4818E7,WorkingDirectory
@@ -2364,11 +4027,21 @@ DE800F1C-CB1A-E1CE-AEB8-B0A6DB4818E7,WorkingDirectory
DECC120D-6904-7F17-45A49184A5A3,Active
{No}
+>>>>>>> 0.12
DECC120D-6904-7F17-45A49184A5A3,Conditions
{2 conditions}
DECC120D-6904-7F17-45A49184A5A3,ShortcutName
+<<<<<<< HEAD
+<%AppName%>
+
+DECC120D-6904-7F17-45A49184A5A3,TargetFileName
+<%ProgramExecutable%>
+
+DECC120D-6904-7F17-45A49184A5A3,WorkingDirectory
+<%InstallDir%>
+=======
{<%AppName%>}
DECC120D-6904-7F17-45A49184A5A3,TargetFileName
@@ -2376,33 +4049,55 @@ DECC120D-6904-7F17-45A49184A5A3,TargetFileName
DECC120D-6904-7F17-45A49184A5A3,WorkingDirectory
{<%InstallDir%>}
+>>>>>>> 0.12
DFFF91A9-2CA5-6ABE-8474D814AF88,CheckCondition
{Before Action is Executed}
DFFF91A9-2CA5-6ABE-8474D814AF88,Operator
+<<<<<<< HEAD
+false
+
+DFFF91A9-2CA5-6ABE-8474D814AF88,String
+<%SilentMode%>
+=======
{false}
DFFF91A9-2CA5-6ABE-8474D814AF88,String
{<%SilentMode%>}
+>>>>>>> 0.12
E02368C5-95B5-03A7-3282740037B0,CheckCondition
{Before Action is Executed}
E02368C5-95B5-03A7-3282740037B0,Operator
+<<<<<<< HEAD
+false
+
+E02368C5-95B5-03A7-3282740037B0,String
+<%InstallStopped%>
+=======
{false}
E02368C5-95B5-03A7-3282740037B0,String
{<%InstallStopped%>}
+>>>>>>> 0.12
E161F216-E597-B340-C1A71C476E2C,CheckCondition
{Before Action is Executed}
E161F216-E597-B340-C1A71C476E2C,Message,subst
+<<<<<<< HEAD
+1
+
+E161F216-E597-B340-C1A71C476E2C,Title,subst
+1
+=======
{1}
E161F216-E597-B340-C1A71C476E2C,Title,subst
{1}
+>>>>>>> 0.12
E23AC50D-7CFB-800E-A99C6F4068F8,Alias
{Cancel Actions}
@@ -2414,7 +4109,11 @@ E44CFF46-6302-C518-B9C30D2E43F7,CheckCondition
{Before Action is Executed}
E44CFF46-6302-C518-B9C30D2E43F7,String
+<<<<<<< HEAD
+<%CreateDesktopShortcut%>
+=======
{<%CreateDesktopShortcut%>}
+>>>>>>> 0.12
E4DEA723-FC78-45D7-BAB1-A3E4C4C96EA1,Conditions
{0 conditions}
@@ -2432,13 +4131,21 @@ E56ADFF4-C15E-AEDB-A599-C468AF72C4BB,Source
{<%InstallDir%>\templates\NotifySysAdmin.template.vbs}
EB2B31A1-C111-3582-0C8A5656692A,String
+<<<<<<< HEAD
+<%ErrorsOccurred%>
+=======
{<%ErrorsOccurred%>}
+>>>>>>> 0.12
EB532611-5F30-3C24-66EB-F3826D9054FD,CheckCondition
{Before Action is Executed}
EB532611-5F30-3C24-66EB-F3826D9054FD,String
+<<<<<<< HEAD
+<%AddBackupLocation%>
+=======
{<%AddBackupLocation%>}
+>>>>>>> 0.12
F4024A3E-9A6D-2726-5E0CFFA93054,Alias
{Uninstall Actions}
@@ -2447,7 +4154,11 @@ F4024A3E-9A6D-2726-5E0CFFA93054,Conditions
{0 conditions}
F5F21749-8B3A-49C6-9138-9C4D6D703D26,Active
+<<<<<<< HEAD
+No
+=======
{No}
+>>>>>>> 0.12
F5F21749-8B3A-49C6-9138-9C4D6D703D26,Conditions
{0 conditions}
@@ -2456,6 +4167,30 @@ F5F21749-8B3A-49C6-9138-9C4D6D703D26,ProgramCommandLine
{cmd /k tools/7za.exe encrypted_keys.exe -p<%InstallPassword%>}
F5F21749-8B3A-49C6-9138-9C4D6D703D26,ProgressiveOutputWidget
+<<<<<<< HEAD
+Message
+
+F5F21749-8B3A-49C6-9138-9C4D6D703D26,ShowProgressiveOutput
+Yes
+
+F5F21749-8B3A-49C6-9138-9C4D6D703D26,WorkingDirectory
+<%InstallDir%>
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,Active
+Yes
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,BackButton,subst
+1
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,CancelButton,subst
+1
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,Caption,subst
+1
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,CompanyLabel,subst
+0
+=======
{Message}
F5F21749-8B3A-49C6-9138-9C4D6D703D26,ShowProgressiveOutput
@@ -2478,11 +4213,30 @@ F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,Caption,subst
F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,CompanyLabel,subst
{0}
+>>>>>>> 0.12
F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,Conditions
{0 conditions}
F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,Message,subst
+<<<<<<< HEAD
+1
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,NextButton,subst
+1
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,Subtitle,subst
+1
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,Title,subst
+1
+
+F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,UserNameLabel,subst
+1
+
+F9E38720-6ABA-8B99-2471-496902E4CBC2,Active
+No
+=======
{1}
F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,NextButton,subst
@@ -2499,39 +4253,63 @@ F8FD4BD6-F1DF-3F8D-B857-98310E4B1143,UserNameLabel,subst
F9E38720-6ABA-8B99-2471-496902E4CBC2,Active
{No}
+>>>>>>> 0.12
F9E38720-6ABA-8B99-2471-496902E4CBC2,Conditions
{0 conditions}
F9E38720-6ABA-8B99-2471-496902E4CBC2,ResultVirtualText
+<<<<<<< HEAD
+BackupLocationPath
+=======
{BackupLocationPath}
+>>>>>>> 0.12
F9E38720-6ABA-8B99-2471-496902E4CBC2,TclScript
{set BackupLocationPath "" }
FB697A88-2842-468E-9776-85E84B009340,Active
+<<<<<<< HEAD
+No
+=======
{No}
+>>>>>>> 0.12
FB697A88-2842-468E-9776-85E84B009340,Conditions
{0 conditions}
FB697A88-2842-468E-9776-85E84B009340,IgnoreErrors
+<<<<<<< HEAD
+Yes
+=======
{Yes}
+>>>>>>> 0.12
FB697A88-2842-468E-9776-85E84B009340,ProgramCommandLine
{"<%InstallDir%>\<%ServiceExeName%> -r -S <%ServiceName%>}
FB697A88-2842-468E-9776-85E84B009340,WorkingDirectory
+<<<<<<< HEAD
+<%Temp%>
+
+FDF68FD6-BEA8-4A74-867D-5139F4D9E793,Active
+No
+=======
{<%Temp%>}
FDF68FD6-BEA8-4A74-867D-5139F4D9E793,Active
{No}
+>>>>>>> 0.12
FDF68FD6-BEA8-4A74-867D-5139F4D9E793,Conditions
{0 conditions}
FDF68FD6-BEA8-4A74-867D-5139F4D9E793,WaitTime
+<<<<<<< HEAD
+2000
+=======
{2000}
+>>>>>>> 0.12
FEFD090D-C133-BC95-B3564F693CD3,Alias
{Finish Actions}
@@ -2540,6 +4318,30 @@ FEFD090D-C133-BC95-B3564F693CD3,Conditions
{0 conditions}
FreeBSD-4-x86,Active
+<<<<<<< HEAD
+No
+
+FreeBSD-4-x86,DefaultDirectoryPermission
+0755
+
+FreeBSD-4-x86,DefaultFilePermission
+0755
+
+FreeBSD-4-x86,Executable
+<%AppName%>-<%Version%>-<%Platform%>-Install<%Ext%>
+
+FreeBSD-4-x86,FallBackToConsole
+Yes
+
+FreeBSD-4-x86,InstallDir
+<%Home%>/<%ShortAppName%>
+
+FreeBSD-4-x86,InstallMode
+Standard
+
+FreeBSD-4-x86,InstallType
+Typical
+=======
{No}
FreeBSD-4-x86,BuildSeparateArchives
@@ -2565,11 +4367,21 @@ FreeBSD-4-x86,InstallMode
FreeBSD-4-x86,InstallType
{Typical}
+>>>>>>> 0.12
FreeBSD-4-x86,ProgramExecutable
{}
FreeBSD-4-x86,ProgramFolderAllUsers
+<<<<<<< HEAD
+No
+
+FreeBSD-4-x86,ProgramFolderName
+<%AppName%>
+
+FreeBSD-4-x86,ProgramLicense
+<%InstallDir%>/LICENSE.txt
+=======
{No}
FreeBSD-4-x86,ProgramFolderName
@@ -2577,11 +4389,99 @@ FreeBSD-4-x86,ProgramFolderName
FreeBSD-4-x86,ProgramLicense
{<%InstallDir%>/LICENSE.txt}
+>>>>>>> 0.12
FreeBSD-4-x86,ProgramName
{}
FreeBSD-4-x86,ProgramReadme
+<<<<<<< HEAD
+<%InstallDir%>/README.txt
+
+FreeBSD-4-x86,PromptForRoot
+Yes
+
+FreeBSD-4-x86,RequireRoot
+No
+
+FreeBSD-4-x86,RootInstallDir
+/usr/local/<%ShortAppName%>
+
+FreeBSD-x86,Active
+No
+
+FreeBSD-x86,DefaultDirectoryPermission
+0755
+
+FreeBSD-x86,DefaultFilePermission
+0755
+
+FreeBSD-x86,Executable
+<%AppName%>-<%Version%>-<%Platform%>-Install<%Ext%>
+
+FreeBSD-x86,FallBackToConsole
+Yes
+
+FreeBSD-x86,InstallDir
+<%Home%>/<%ShortAppName%>
+
+FreeBSD-x86,InstallMode
+Standard
+
+FreeBSD-x86,InstallType
+Typical
+
+FreeBSD-x86,ProgramExecutable
+{}
+
+FreeBSD-x86,ProgramFolderAllUsers
+No
+
+FreeBSD-x86,ProgramFolderName
+<%AppName%>
+
+FreeBSD-x86,ProgramLicense
+<%InstallDir%>/LICENSE.txt
+
+FreeBSD-x86,ProgramName
+{}
+
+FreeBSD-x86,ProgramReadme
+<%InstallDir%>/README.txt
+
+FreeBSD-x86,PromptForRoot
+Yes
+
+FreeBSD-x86,RequireRoot
+No
+
+FreeBSD-x86,RootInstallDir
+/usr/local/<%ShortAppName%>
+
+HPUX-hppa,Active
+No
+
+HPUX-hppa,DefaultDirectoryPermission
+0755
+
+HPUX-hppa,DefaultFilePermission
+0755
+
+HPUX-hppa,Executable
+<%AppName%>-<%Version%>-<%Platform%>-Install<%Ext%>
+
+HPUX-hppa,FallBackToConsole
+Yes
+
+HPUX-hppa,InstallDir
+<%Home%>/<%ShortAppName%>
+
+HPUX-hppa,InstallMode
+Standard
+
+HPUX-hppa,InstallType
+Typical
+=======
{<%InstallDir%>/README.txt}
FreeBSD-4-x86,PromptForRoot
@@ -2781,11 +4681,21 @@ HPUX-hppa,InstallMode
HPUX-hppa,InstallType
{Typical}
+>>>>>>> 0.12
HPUX-hppa,ProgramExecutable
{}
HPUX-hppa,ProgramFolderAllUsers
+<<<<<<< HEAD
+No
+
+HPUX-hppa,ProgramFolderName
+<%AppName%>
+
+HPUX-hppa,ProgramLicense
+<%InstallDir%>/LICENSE.txt
+=======
{No}
HPUX-hppa,ProgramFolderName
@@ -2793,11 +4703,63 @@ HPUX-hppa,ProgramFolderName
HPUX-hppa,ProgramLicense
{<%InstallDir%>/LICENSE.txt}
+>>>>>>> 0.12
HPUX-hppa,ProgramName
{}
HPUX-hppa,ProgramReadme
+<<<<<<< HEAD
+<%InstallDir%>/README.txt
+
+HPUX-hppa,PromptForRoot
+Yes
+
+HPUX-hppa,RequireRoot
+No
+
+HPUX-hppa,RootInstallDir
+/usr/local/<%ShortAppName%>
+
+Linux-x86,Active
+No
+
+Linux-x86,BuildType
+dynamic
+
+Linux-x86,DefaultDirectoryPermission
+00755
+
+Linux-x86,DefaultFilePermission
+00755
+
+Linux-x86,Executable
+<%AppName%>-<%Version%>-<%Platform%>-Install<%Ext%>
+
+Linux-x86,FallBackToConsole
+Yes
+
+Linux-x86,InstallDir
+<%Home%>/<%ShortAppName%>
+
+Linux-x86,InstallMode
+Standard
+
+Linux-x86,InstallType
+Typical
+
+Linux-x86,ProgramExecutable
+<%InstallDir%>/TebucoSafe
+
+Linux-x86,ProgramFolderAllUsers
+No
+
+Linux-x86,ProgramFolderName
+<%AppName%>
+
+Linux-x86,ProgramLicense
+<%InstallDir%>/LICENSE.txt
+=======
{<%InstallDir%>/README.txt}
HPUX-hppa,PromptForRoot
@@ -2850,11 +4812,48 @@ Linux-x86,ProgramFolderName
Linux-x86,ProgramLicense
{<%InstallDir%>/LICENSE.txt}
+>>>>>>> 0.12
Linux-x86,ProgramName
{}
Linux-x86,ProgramReadme
+<<<<<<< HEAD
+<%InstallDir%>/README.txt
+
+Linux-x86,PromptForRoot
+Yes
+
+Linux-x86,RequireRoot
+No
+
+Linux-x86,RootInstallDir
+/usr/local/<%ShortAppName%>
+
+Solaris-sparc,Active
+No
+
+Solaris-sparc,DefaultDirectoryPermission
+0755
+
+Solaris-sparc,DefaultFilePermission
+0755
+
+Solaris-sparc,Executable
+<%AppName%>-<%Version%>-<%Platform%>-Install<%Ext%>
+
+Solaris-sparc,FallBackToConsole
+Yes
+
+Solaris-sparc,InstallDir
+<%Home%>/<%ShortAppName%>
+
+Solaris-sparc,InstallMode
+Standard
+
+Solaris-sparc,InstallType
+Typical
+=======
{<%InstallDir%>/README.txt}
Linux-x86,PromptForRoot
@@ -2946,11 +4945,21 @@ Solaris-sparc,InstallMode
Solaris-sparc,InstallType
{Typical}
+>>>>>>> 0.12
Solaris-sparc,ProgramExecutable
{}
Solaris-sparc,ProgramFolderAllUsers
+<<<<<<< HEAD
+No
+
+Solaris-sparc,ProgramFolderName
+<%AppName%>
+
+Solaris-sparc,ProgramLicense
+<%InstallDir%>/LICENSE.txt
+=======
{No}
Solaris-sparc,ProgramFolderName
@@ -2958,11 +4967,54 @@ Solaris-sparc,ProgramFolderName
Solaris-sparc,ProgramLicense
{<%InstallDir%>/LICENSE.txt}
+>>>>>>> 0.12
Solaris-sparc,ProgramName
{}
Solaris-sparc,ProgramReadme
+<<<<<<< HEAD
+<%InstallDir%>/README.txt
+
+Solaris-sparc,PromptForRoot
+Yes
+
+Solaris-sparc,RequireRoot
+No
+
+Solaris-sparc,RootInstallDir
+/usr/local/<%ShortAppName%>
+
+TarArchive,Active
+No
+
+TarArchive,CompressionLevel
+6
+
+TarArchive,DefaultDirectoryPermission
+0755
+
+TarArchive,DefaultFilePermission
+0755
+
+TarArchive,Executable
+<%AppName%>-<%Version%>-<%Platform%>-Install<%Ext%>
+
+TarArchive,FallBackToConsole
+Yes
+
+TarArchive,InstallDir
+<%Home%>/<%ShortAppName%>
+
+TarArchive,InstallMode
+Standard
+
+TarArchive,InstallType
+Typical
+
+TarArchive,OutputFileName
+<%ShortAppName%>-<%Version%>.tar.gz
+=======
{<%InstallDir%>/README.txt}
Solaris-sparc,PromptForRoot
@@ -3060,11 +5112,21 @@ TarArchive,InstallType
TarArchive,OutputFileName
{<%ShortAppName%>-<%Version%>.tar.gz}
+>>>>>>> 0.12
TarArchive,ProgramExecutable
{}
TarArchive,ProgramFolderAllUsers
+<<<<<<< HEAD
+No
+
+TarArchive,ProgramFolderName
+<%AppName%>
+
+TarArchive,ProgramLicense
+<%InstallDir%>/LICENSE.txt
+=======
{No}
TarArchive,ProgramFolderName
@@ -3072,11 +5134,24 @@ TarArchive,ProgramFolderName
TarArchive,ProgramLicense
{<%InstallDir%>/LICENSE.txt}
+>>>>>>> 0.12
TarArchive,ProgramName
{}
TarArchive,ProgramReadme
+<<<<<<< HEAD
+<%InstallDir%>/README.txt
+
+TarArchive,PromptForRoot
+Yes
+
+TarArchive,RequireRoot
+No
+
+TarArchive,RootInstallDir
+/usr/local/<%ShortAppName%>
+=======
{<%InstallDir%>/README.txt}
TarArchive,PromptForRoot
@@ -3087,20 +5162,31 @@ TarArchive,RequireRoot
TarArchive,RootInstallDir
{/usr/local/<%ShortAppName%>}
+>>>>>>> 0.12
TarArchive,VirtualTextMap
{<%InstallDir%> <%ShortAppName%>}
Windows,Active
+<<<<<<< HEAD
+Yes
+=======
{Yes}
Windows,BuildSeparateArchives
{No}
+>>>>>>> 0.12
Windows,BuildType
{}
Windows,Executable
+<<<<<<< HEAD
+installer.exe
+
+Windows,IncludeTWAPI
+No
+=======
{installer.exe}
Windows,FileDescription
@@ -3108,11 +5194,18 @@ Windows,FileDescription
Windows,IncludeTWAPI
{No}
+>>>>>>> 0.12
Windows,InstallDir
{C:\Program Files\<%BrandName%>}
Windows,InstallMode
+<<<<<<< HEAD
+Standard
+
+Windows,InstallType
+Typical
+=======
{Standard}
Windows,InstallType
@@ -3120,15 +5213,23 @@ Windows,InstallType
Windows,LastRequireAdministrator
{Yes}
+>>>>>>> 0.12
Windows,ProgramExecutable
{}
Windows,ProgramFolderAllUsers
+<<<<<<< HEAD
+No
+
+Windows,ProgramFolderName
+<%BrandName%>
+=======
{No}
Windows,ProgramFolderName
{<%BrandName%>}
+>>>>>>> 0.12
Windows,ProgramLicense
{<%InstallDir%>\LICENSE.txt}
@@ -3139,16 +5240,49 @@ Windows,ProgramName
Windows,ProgramReadme
{}
+<<<<<<< HEAD
+=======
Windows,RequireAdministrator
{Yes}
Windows,UseUncompressedBinaries
{No}
+>>>>>>> 0.12
Windows,WindowsIcon
{}
ZipArchive,Active
+<<<<<<< HEAD
+No
+
+ZipArchive,CompressionLevel
+6
+
+ZipArchive,DefaultDirectoryPermission
+0755
+
+ZipArchive,DefaultFilePermission
+0755
+
+ZipArchive,Executable
+<%AppName%>-<%Version%>-<%Platform%>-Install<%Ext%>
+
+ZipArchive,FallBackToConsole
+Yes
+
+ZipArchive,InstallDir
+<%Home%>/<%ShortAppName%>
+
+ZipArchive,InstallMode
+Standard
+
+ZipArchive,InstallType
+Typical
+
+ZipArchive,OutputFileName
+<%ShortAppName%>-<%Version%>.zip
+=======
{No}
ZipArchive,BuildSeparateArchives
@@ -3180,11 +5314,21 @@ ZipArchive,InstallType
ZipArchive,OutputFileName
{<%ShortAppName%>-<%Version%>.zip}
+>>>>>>> 0.12
ZipArchive,ProgramExecutable
{}
ZipArchive,ProgramFolderAllUsers
+<<<<<<< HEAD
+No
+
+ZipArchive,ProgramFolderName
+<%AppName%>
+
+ZipArchive,ProgramLicense
+<%InstallDir%>/LICENSE.txt
+=======
{No}
ZipArchive,ProgramFolderName
@@ -3192,11 +5336,24 @@ ZipArchive,ProgramFolderName
ZipArchive,ProgramLicense
{<%InstallDir%>/LICENSE.txt}
+>>>>>>> 0.12
ZipArchive,ProgramName
{}
ZipArchive,ProgramReadme
+<<<<<<< HEAD
+<%InstallDir%>/README.txt
+
+ZipArchive,PromptForRoot
+Yes
+
+ZipArchive,RequireRoot
+No
+
+ZipArchive,RootInstallDir
+/usr/local/<%ShortAppName%>
+=======
{<%InstallDir%>/README.txt}
ZipArchive,PromptForRoot
@@ -3207,6 +5364,7 @@ ZipArchive,RequireRoot
ZipArchive,RootInstallDir
{/usr/local/<%ShortAppName%>}
+>>>>>>> 0.12
ZipArchive,VirtualTextMap
{<%InstallDir%> <%ShortAppName%>}
@@ -3215,6 +5373,18 @@ ZipArchive,VirtualTextMap
::msgcat::mcmset de {
20CBDBEA-2217-457B-8D98-D692C4F591E9,Message
+<<<<<<< HEAD
+<%UninstallCompleteText%>
+
+2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
+<%InstallationCompleteText%>
+
+B002A311-F8E7-41DE-B039-521391924E5B,Message
+<%InstallingApplicationText%>
+
+B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
+<%UninstallingApplicationText%>
+=======
{<%UninstallCompleteText%>}
2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
@@ -3225,10 +5395,20 @@ B002A311-F8E7-41DE-B039-521391924E5B,Message
B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
{<%UninstallingApplicationText%>}
+>>>>>>> 0.12
}
::msgcat::mcmset en {
16D53E40-546B-54C3-088B1B5E3BBB,Text
+<<<<<<< HEAD
+<%CreateDesktopShortcutText%>
+
+20CBDBEA-2217-457B-8D98-D692C4F591E9,Message
+<%UninstallCompleteText%>
+
+2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
+<%InstallationCompleteText%>
+=======
{<%CreateDesktopShortcutText%>}
20CBDBEA-2217-457B-8D98-D692C4F591E9,Message
@@ -3236,6 +5416,7 @@ B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
{<%InstallationCompleteText%>}
+>>>>>>> 0.12
2E2963BD-DDBD-738D-A910-B7F3F04946F9,Text
{No:<%BackupLocationNumber%> }
@@ -3244,6 +5425,18 @@ B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
BackupLocations\n\{\n
32F5B0AF-EB83-7A03-D8FAE1ECE473,Message
+<<<<<<< HEAD
+<%InstallStartupText%>
+
+32F5B0AF-EB83-7A03-D8FAE1ECE473,Title
+<%InstallApplicationText%>
+
+36FF8915-8148-0F1F-27D7239CBFA1,Text
+<%ViewReadmeText%>
+
+3B6E2E7C-1A26-27F1-D578E383B128,Text
+<%ViewReadmeText%>
+=======
{<%InstallStartupText%>}
32F5B0AF-EB83-7A03-D8FAE1ECE473,Title
@@ -3254,6 +5447,7 @@ BackupLocations\n\{\n
3B6E2E7C-1A26-27F1-D578E383B128,Text
{<%ViewReadmeText%>}
+>>>>>>> 0.12
3D33AA8C-0037-204B-39A339FD38BD,Message
{<%BrandName%> has been removed from your system. Thank you for using the <%BrandName%> Backup Service. If you need further assistance, please contact us at http://<%BrandName%>.com or support@<%BrandName%>.com.}
@@ -3274,6 +5468,15 @@ BackupLocations\n\{\n
{Backup Directory}
4A9C852B-647E-EED5-5482FFBCC2AF,Description
+<<<<<<< HEAD
+<%ProgramFilesDescription%>
+
+4ACB0B47-42B3-2B3A-BFE9AA4EC707,Message
+<%UninstallStartupText%>
+
+4ACB0B47-42B3-2B3A-BFE9AA4EC707,Title
+<%UninstallApplicationText%>
+=======
{<%ProgramFilesDescription%>}
4ACB0B47-42B3-2B3A-BFE9AA4EC707,Message
@@ -3281,6 +5484,7 @@ BackupLocations\n\{\n
4ACB0B47-42B3-2B3A-BFE9AA4EC707,Title
{<%UninstallApplicationText%>}
+>>>>>>> 0.12
58E1119F-639E-17C9-5D3898F385AA,Caption
{Setup will install <%ShortAppName%> in the following folder.
@@ -3329,13 +5533,21 @@ You will be presented with the current configuration file so that you may make a
\}\n
8202CECC-54A0-9B6C-D24D111BA52E,Description
+<<<<<<< HEAD
+<%TypicalInstallDescription%>
+=======
{<%TypicalInstallDescription%>}
+>>>>>>> 0.12
8419AAAD-5860-F73E-8D11-4D1BDA4D7D37,Text
{Add another backup location?}
855DE408-060E-3D35-08B5-1D9AB05C2865,Text
+<<<<<<< HEAD
+Exclusions
+=======
{Exclusions}
+>>>>>>> 0.12
8E095096-F018-A880-429D-A2177A9B70EA,Text
{AddAnother: <%AddBackupLocation%>}
@@ -3344,6 +5556,15 @@ You will be presented with the current configuration file so that you may make a
{Please enter your phone number and email address.}
9013E862-8E81-5290-64F9-D8BCD13EC7E5,CompanyLabel
+<<<<<<< HEAD
+Email:
+
+9013E862-8E81-5290-64F9-D8BCD13EC7E5,UserNameLabel
+Phone:
+
+937C3FDD-FB28-98BD-3DAB276E59ED,Text
+<%CreateQuickLaunchShortcutText%>
+=======
{Email:}
9013E862-8E81-5290-64F9-D8BCD13EC7E5,UserNameLabel
@@ -3351,6 +5572,7 @@ You will be presented with the current configuration file so that you may make a
937C3FDD-FB28-98BD-3DAB276E59ED,Text
{<%CreateQuickLaunchShortcutText%>}
+>>>>>>> 0.12
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Caption
{Click Next to continue...}
@@ -3362,16 +5584,27 @@ You will be presented with the current configuration file so that you may make a
{}
9A23D3ED-4D9D-9C57-C2A7-71DE0FFF0266,Title
+<<<<<<< HEAD
+Continue
+=======
{Continue}
+>>>>>>> 0.12
9BAB328D-414B-D351-CA8D-824DF94B9DCA,Text
{Add another backup location after this one?}
A18C2977-1409-C1FB-892415711F72,Text
+<<<<<<< HEAD
+<%LaunchApplicationText%>
+
+AAF2142A-9FC9-4664-DFF2-13B9EB7BA0E1,CompanyLabel
+Company:
+=======
{<%LaunchApplicationText%>}
AAF2142A-9FC9-4664-DFF2-13B9EB7BA0E1,CompanyLabel
{Company:}
+>>>>>>> 0.12
AE3BD5B4-35DE-4240-B79914D43E56,Caption
{Welcome to the Installation Wizard for <%BrandName%> Backup Service!}
@@ -3389,6 +5622,34 @@ Click Next to continue or Cancel to exit Setup.
}
B002A311-F8E7-41DE-B039-521391924E5B,Message
+<<<<<<< HEAD
+<%InstallingApplicationText%>
+
+B4404713-AF4F-4F4B-670F3115517F,Description
+<%CustomInstallDescription%>
+
+B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
+<%UninstallingApplicationText%>
+
+B506E7DA-E7C4-4D42-8C03-FD27BA16D078,Text
+{Box Backup, http://www.fluffy.co.uk/boxbackup
+Copyright (c) 2003-2007 Ben Summers and contributors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. All use of this software and associated advertising materials must display the following acknowledgement:
+ This product includes software developed by Ben Summers and contributors.
+
+4. The names of the Authors may not be used to endorse or promote products derived from this software without specific prior written permission.
+
+[Where legally impermissible the Authors do not disclaim liability for direct physical injury or death caused solely by defects in the software unless it is modified by a third party.]
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE}
+=======
{<%InstallingApplicationText%>}
B4404713-AF4F-4F4B-670F3115517F,Description
@@ -3475,6 +5736,7 @@ distribution
The dual license text may be found in the file
LICENSE-DUAL.txt, or online at:
[https://www.boxbackup.org/svn/box/trunk/LICENSE-DUAL.txt]}
+>>>>>>> 0.12
B57F8C91-2439-CFD3-7EB5-57D4EA48D3C6,Caption
{<%BrandName%> will backup the following folder.
@@ -3500,19 +5762,31 @@ B9B85EF1-1D76-4BF5-ABB9-092A8DB35851,Caption
{Please enter the agreed-upon password for your encrypted key file...}
B9B85EF1-1D76-4BF5-ABB9-092A8DB35851,CompanyLabel
+<<<<<<< HEAD
+Password:
+=======
{Password:}
+>>>>>>> 0.12
B9B85EF1-1D76-4BF5-ABB9-092A8DB35851,Subtitle
{Please enter your encrypted key file password.}
C105AAAE-7C16-2C9E-769FE4535B60,Caption
+<<<<<<< HEAD
+<%ApplicationReadmeText%>
+=======
{<%ApplicationReadmeText%>}
+>>>>>>> 0.12
C105AAAE-7C16-2C9E-769FE4535B60,Message
{}
C105AAAE-7C16-2C9E-769FE4535B60,Title
+<<<<<<< HEAD
+<%ApplicationReadmeText%>
+=======
{<%ApplicationReadmeText%>}
+>>>>>>> 0.12
C7762473-273F-E3CA-17E3-65789B14CDB0,TextToWrite
{<%BackupLocationShortName%>
@@ -3538,10 +5812,17 @@ CB058DBA-C3B7-2F48-D985-BE2F7107A76D,Title
{Choose Backup Location}
CFFA27AF-A641-E41C-B4A0E3BB3CBB,Text
+<<<<<<< HEAD
+<%LaunchApplicationText%>
+
+D4625CA6-9864-D8EF-F252D7B7DC87,Text
+<%CreateDesktopShortcutText%>
+=======
{<%LaunchApplicationText%>}
D4625CA6-9864-D8EF-F252D7B7DC87,Text
{<%CreateDesktopShortcutText%>}
+>>>>>>> 0.12
D47BE952-79F2-844E-D2E5-8F22044E7A9D,Text
{Account Number:}
@@ -3556,7 +5837,11 @@ DA33B826-E633-A845-4646-76DFA78B907B,Subtitle
{}
DA33B826-E633-A845-4646-76DFA78B907B,Title
+<<<<<<< HEAD
+Continue
+=======
{Continue}
+>>>>>>> 0.12
DDBBD8A9-13D7-9509-9202-419E989F60A9,Text
{Add another Backup Location?}
@@ -3565,7 +5850,11 @@ E0CADC4E-08A6-E429-3B49-BB8CFB7B097F,Text
{Simple name for this Backup Location (short, no spaces or special characters)}
E161F216-E597-B340-C1A71C476E2C,Message
+<<<<<<< HEAD
+<%UninstallLeftoverText%>
+=======
{<%UninstallLeftoverText%>}
+>>>>>>> 0.12
E161F216-E597-B340-C1A71C476E2C,Title
{Uninstall <%BrandName%>}
@@ -3592,7 +5881,11 @@ F98784B1-1965-0F42-6BB0542AE1A9,Message
{Click Next to install the TebucoSafe Backup Service as an operating system service on your computer (see services.msc), and start up that service. }
FC678E76-6823-2E55-204CA01C35EF,Text
+<<<<<<< HEAD
+<%CreateQuickLaunchShortcutText%>
+=======
{<%CreateQuickLaunchShortcutText%>}
+>>>>>>> 0.12
FF4F6EEA-F4CC-428E-AF33-EB0E88E2147E,Text
{
@@ -3636,6 +5929,18 @@ POSSIBILITY OF SUCH DAMAGE.
}
::msgcat::mcmset es {
20CBDBEA-2217-457B-8D98-D692C4F591E9,Message
+<<<<<<< HEAD
+<%UninstallCompleteText%>
+
+2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
+<%InstallationCompleteText%>
+
+B002A311-F8E7-41DE-B039-521391924E5B,Message
+<%InstallingApplicationText%>
+
+B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
+<%UninstallingApplicationText%>
+=======
{<%UninstallCompleteText%>}
2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
@@ -3646,10 +5951,23 @@ B002A311-F8E7-41DE-B039-521391924E5B,Message
B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
{<%UninstallingApplicationText%>}
+>>>>>>> 0.12
}
::msgcat::mcmset fr {
20CBDBEA-2217-457B-8D98-D692C4F591E9,Message
+<<<<<<< HEAD
+<%UninstallCompleteText%>
+
+2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
+<%InstallationCompleteText%>
+
+B002A311-F8E7-41DE-B039-521391924E5B,Message
+<%InstallingApplicationText%>
+
+B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
+<%UninstallingApplicationText%>
+=======
{<%UninstallCompleteText%>}
2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
@@ -3660,10 +5978,23 @@ B002A311-F8E7-41DE-B039-521391924E5B,Message
B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
{<%UninstallingApplicationText%>}
+>>>>>>> 0.12
}
::msgcat::mcmset pl {
20CBDBEA-2217-457B-8D98-D692C4F591E9,Message
+<<<<<<< HEAD
+<%UninstallCompleteText%>
+
+2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
+<%InstallationCompleteText%>
+
+B002A311-F8E7-41DE-B039-521391924E5B,Message
+<%InstallingApplicationText%>
+
+B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
+<%UninstallingApplicationText%>
+=======
{<%UninstallCompleteText%>}
2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
@@ -3674,10 +6005,23 @@ B002A311-F8E7-41DE-B039-521391924E5B,Message
B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
{<%UninstallingApplicationText%>}
+>>>>>>> 0.12
}
::msgcat::mcmset pt_br {
20CBDBEA-2217-457B-8D98-D692C4F591E9,Message
+<<<<<<< HEAD
+<%UninstallCompleteText%>
+
+2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
+<%InstallationCompleteText%>
+
+B002A311-F8E7-41DE-B039-521391924E5B,Message
+<%InstallingApplicationText%>
+
+B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
+<%UninstallingApplicationText%>
+=======
{<%UninstallCompleteText%>}
2BF07B5A-9B06-4C1E-810D-5B5E9303D2C6,Message
@@ -3688,6 +6032,7 @@ B002A311-F8E7-41DE-B039-521391924E5B,Message
B4ED4636-22D8-41DC-9E3D-BD1E1CAD2174,Message
{<%UninstallingApplicationText%>}
+>>>>>>> 0.12
}
diff --git a/contrib/windows/installer/tools/RemoteControl.exe b/contrib/windows/installer/tools/RemoteControl.exe
new file mode 100755
index 00000000..f7667421
--- /dev/null
+++ b/contrib/windows/installer/tools/RemoteControl.exe
Binary files differ
diff --git a/debian/NEWS b/debian/NEWS
new file mode 100644
index 00000000..2c3e7c25
--- /dev/null
+++ b/debian/NEWS
@@ -0,0 +1,24 @@
+boxbackup (0.11~rc2+r2072-1) unstable; urgency=low
+
+ * The upstream parts of this file have been renamed to a new file called
+ NEWS.upstream to make the process of updating it easier.
+
+ -- Reinhard Tartler <siretart@tauware.de> Wed, 01 Apr 2009 10:24:51 +0200
+
+boxbackup (0.10-1) unstable; urgency=low
+
+ * This Package has been initially prepared and mantained by Jérôme
+ Schell since 2004 in a private repository. I like the software, and
+ decided to take it over in order to have it in Debian. Please note
+ that I'm actively looking for co-maintainers, so do not hesitate to
+ get a copy of my bzr branch and share your commits with me.
+
+ The only major change has been to drop the boxbackup-utils package. It
+ contained only one single command to manage certificates. It has been
+ moved to the boxbackup-server package.
+
+ The complete debconf integration has been written by Jérôme. It works
+ for me quite well. If it doesn't for you, please file a bug and CC
+ Jérôme to that bugreport. Thanks.
+
+ -- Reinhard Tartler <siretart@tauware.de> Wed, 25 Apr 2007 18:06:04 +0200
diff --git a/debian/NEWS.upstream b/debian/NEWS.upstream
new file mode 100644
index 00000000..2ae473dd
--- /dev/null
+++ b/debian/NEWS.upstream
@@ -0,0 +1,124 @@
+The following notes have been copied from the boxbackup trac wiki at
+http://www.boxbackup.org/trac/wiki/011?format=txt
+
+== Changes in This Release ==
+
+ * Fixed some bugs with backing up, restoring and comparing [#2 files over 2GB] in compressed size.
+ * Added new logging infrastructure, allows more control over whether messages are sent to the console or system logs, and at what level of detail.
+ * Changed keepalive and diff timers to run in real time, not CPU time.
+ * Enable KeepAlive time by default on new installations, set to 120 seconds.
+ * Added bbackupctl commands for improved scripting of syncs.
+ * Fixed a bug with restoring symlinks to directories outside of the backed-up location (thanks to Hans-Joachim Baader)
+ * Ported unit tests for Windows.
+ * Added full unit tests for keep-alives and diff timer on most platforms.
+ * Fixed a number of bugs in the Windows port.
+ * Added option to send Extended Logs to a file instead of to system logs.
+ * Added option to log all file access, for debugging when a file is not backed up or causes the backup to fail mysteriously.
+ * Improved error messages to identify the causes of some errors which were difficult to track down before.
+ * Added bbackupd option to set the length of time before unused locations are deleted.
+ * Changed default location of bbackupd.conf on Windows to the same directory as bbackupd.exe.
+ * Fixed a bug where bbstoreaccounts could modify an account while it was locked by a running backup.
+ * Improved command-line option handling.
+ * Added command-line help (-h option) to bbackupd and bbstored.
+ * Add a new -F option for daemons, which runs in the foreground but still accepts multiple connections, which is what SINGLEPROCESS used to do.
+ * Fixed compare of timestamps on filesystems which cannot set them more accurately than 1 second.
+ * Added new backup-start and backup-finish events to the NotifyScript, which can be used to implement more advanced functionality such as snapshotting databases.
+ * Added a new sample !NotifySysAdmin script for Windows, written by James O'Gorman in VBscript.
+ * Added support for multiple Box Backup (bbackupd) services on Windows, with different service names and named pipe names, to implement redundancy.
+ * Fixed bbackupd mysteriously failing to back up if one of the location paths did not exist.
+ * Fixed entering of international characters into bbackupquery on Windows (instructions) and Unixes with editline.
+ * Improve Makefiles by reducing verbosity during build, so that any errors and warnings can be seen more easily.
+ * Added saving of the list of unused root directory entries to the !StoreObjectInfoFile, so that they will persist across restarts of bbackup (thanks to Gary Niemcewicz).
+ * Updated built-in documentation (program manuals, installation guide and administrator's guide).
+ * Improved build targets (thanks to James O'Gorman).
+ * On Unix platforms, all commands have moved from bin to sbin.
+
+== Source Code ==
+
+The source code for all platforms can be downloaded
+[http://www.boxbackup.org/svn/box/packages/boxbackup-0.11rc2.tgz here], although for Windows Native builds please read the [wiki:Installation#Windows Windows installation] notes.
+
+== Upgrading ==
+
+Upgrade all clients and servers to [wiki:010 0.10] first.
+
+Remove any Windows services before upgrading (with `bbackupd -r`) and reinstall after upgrading (with `bbackupd -i`).
+
+New logging options (LogAllFileAccess, ExtendedLogging and [wiki:ManualPages command-line options]) are useful but not required. To use LogAllFileAccess you need to start the daemon with the `-V` option as well.
+
+The protocol is the same, so it shouldn't require the store server to be updated at the same time as the clients, or even fix the order of updating them. We would recommend that you upgrade the store server first, and then the clients one at a time.
+
+You might want to either regenerate their configs, or look at the difference between a fresh config and their current one, to enable some useful options like KeepAliveTime (which is enabled by default in new installations) and to think about enabling StoreObjectInfoFile.
+
+Most syslog messages have changed their format, so any scripts which parse syslog will have to be updated.
+
+Anyone using SINGLEPROCESS in anger (e.g. to run bbstored as a managed service under daemontools or similar) should shoot themselves quietly in the foot and prepare to change it to '''-F''' after the upgrade. (this was never a documented option, and now behaves a little differently).
+
+If you have problems with large files (over 2GB compressed) not being backed up, restored or compared, you will need to delete them from the store server to fix them properly. You can do this before or after upgrading, but if they are uploaded again by the 0.10 client then the problem will not be solved.
+
+You will probably get this error message every backup run:
+
+{{{
+BACKUP PROBLEM on host your.client.host (unknown)
+}}}
+
+To fix this, edit the !NotifyScript (usually `/etc/box/bbackupd/NotifyScript.sh`), find the line that starts with the word `else`, and add these three lines immediately before it:
+
+{{{
+elif [ "$1" = backup-start -o "$1" = backup-finish -o "$1" = backup-ok ]; then
+ # do nothing by default
+ true
+}}}
+
+== Known Issues ==
+
+[[TicketQuery(status!=closed)]]
+
+== Credits ==
+
+ * '''Martin Ebourne''' reviewed code from Windows port for merge;
+
+ * '''Pierre-Henri Lavigne''' created and started maintaining fink packages for MacOS X;
+
+ * '''Stuart Hickinbottom''', '''Mark''', '''Nestor Arocha Rodriguez''' and '''James Stark''' contributed code;
+
+ * '''Pete Jalajas''' contributed the Windows installer
+
+ * '''Charles Lecklider''' reviewed code from Windows port for merge;
+
+ * '''Kenny Millington''' provided the bbreporter.py Python script;
+
+ * '''Gary Niemcewicz''' tested and fixed support for Microsoft Visual Studio as a compiler;
+
+ * '''James O'Gorman''' hosts our website, wrote a lot of documentation, bought us a real SSL certificate and fixed autoconf problems;
+
+ * '''Ben Summers''' contributed ideas and reviewed code from Windows port for merge;
+
+ * '''Reinhard Tartler''' created and started maintaining Debian packages;
+
+ * '''Per Thomsen''' wrote the Docbook documentation;
+
+ * '''Chris Wilson''' implemented most of the new features, tested Solaris, FreeBSD and MacOS X and helped out on the mailing list;
+
+ * Testing and bug reports (in alphabetical order)
+ * Tom Albers
+ * Tobias Balle-Petersen
+ * Damien B
+ * Dave Bamford
+ * Torsten Boob
+ * Matt Brown (who also lent us a MacOS X laptop for testing)
+ * Eric Cronin
+ * Johann Glaser
+ * Alex Harper
+ * Guno Heitman
+ * Stuart Hickinbottom
+ * Richard Hurt
+ * Pete Jalajas
+ * David Kaufman
+ * kiru
+ * Paul MacKenzie
+ * Mitja Muzenic
+ * Tuukka Pasanen
+ * Phil Shelley
+
+ * Please let us know if we've missed you out!
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
index 00000000..63d47a10
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,125 @@
+Quick setup guide for boxbackup system
+--------------------------------------
+
+NOTE: The debian package should handle most of the configuration
+for you via debconf.
+
+However this is a quick guide if you prefer to do this by
+yourself.
+
+If you want to use debconf to configure Boxbackup, do NOT follow
+those explanations. Jump directly to the section on Managing certificates
+
+Boxbackup-server configuration
+------------------------------
+
+You need to create the server configuration files contained in
+/etc/boxbackup.
+
+For this you must first use the raidfile-config script.
+
+raidfile-config /etc/boxbackup 2048 /raid/0.0 /raid/0.1 /raid/0.2
+
+where:
+- /etc/boxbackup is the location of the configuration files (don't
+ change that as several scripts use that by default)
+- 2048 is the block size of the RAID system, this should be set to
+ the block size of the underlying filesystem
+- the three following path names are the location of the 3 RAID partitions
+ used by boxbackup to store the backup. They should be on 3 different
+ physical drive. You can disable the use of userland RAID by specifying
+ only one path name.
+
+You should now have a file /etc/boxbackup/raidfile.conf that you can
+customize to add another set of disc.
+
+Now run the bbstored-config script:
+
+bbstored-config /etc/boxbackup serverhostname bbstored
+
+where:
+- /etc/boxbackup is the location of the configuration files (don't
+ change that as several scripts use that by default).
+- serverhostname is the fqdn name of the server you are installing on,
+ this is used to determine on wich interface the daemon will listen on.
+- bbstored is the user the server will run under, this user is automatically
+ created by the Debian package.
+
+Now you have to manage your certificate. See below for this.
+
+To manage the client accounts use the bbstoreaccounts utility.
+To add an account:
+bbstoreaccounts create ACCOUNT_NUMBER DISC_SET SOFT_QUOTA HARD_QUOTA
+
+where:
+- ACCOUNT_NUMBER is the account number to create, a 8 digits hexadecimal number.
+- DISC_SET is a disc set number defined in /etc/boxbackup/raidfile.conf where the
+ files for that account will go into.
+- SOFT_QUOTA is the soft storage quota size, the client will avoid to upload files
+ when reaching that limit
+- HARD_QUOTA is the hard storage quota size, the server will not store files when
+ reaching that limit.
+
+An exemple of invocation:
+bbstoreaccounts create 1EF235CA 0 1024M 1250M
+(suffixes M, G and B are accepted for quota size meaning respectively Megabytes,
+Gigabytes and Blocks)
+
+Boxbackup-client configuration
+------------------------------
+
+You need to create the client configuration files contained in
+/etc/boxbackup.
+
+For this you must use the bbackupd-config script.
+
+bbackupd-config /etc/boxbackup lazy ACCOUNT_NUMBER SERVER_NAME /var/lib/bbackupd BACKUP_DIR [[BACKUP_DIR]...]
+
+where:
+- /etc/boxbackup is the location of the configuration files (don't
+ change that as several scripts use that by default).
+- lazy: backup mode, could be lazy (continuous scan of filesystem) or
+ snapshot (backup launch by a cron script, see /etc/cron.d/boxbackup-client)
+- ACCOUT_NUMBER: your account number provided by the backup server administrator
+- SERVER_NAME is the fqdn name of the server you will connect to.
+- /var/lib/bbackupd: location of working directory (don't change)
+- BACKUP_DIR: a list of directories to backup (they must not contain another
+ mounted filesystem)
+
+
+Managing certificates
+---------------------
+
+For this you need to use the bbstored-certs script contained in the
+boxbackup-server package.
+
+To initialise your CA (creates a "ca" directory with private key and certificate in it) launch:
+bbstored-certs ca init
+
+To sign a server certificate:
+bbstored-certs ca sign-server server-csr.pem
+
+To sign a client certificate:
+bbstored-certs ca sign clientaccount-csr.pem
+
+You will find a more detailled documentation on the boxbackup Web site:
+http://www.boxbackup.org
+
+
+"Upstream" tarball
+------------------
+
+Althogh upstream indeed publishes tarballs, the debian package is no
+longer based on these tarballs. The reason for this is that the
+procedure for creating these tarballs makes package maintenance and
+interaction with upstream unnecessary hard.
+
+Moreover, there seem to be different types of tarballs. Official ones
+used for a release and "unofficial" ones that are created for snapshot
+releases, causing further confusion.
+
+Since upstream releases rather seldomly, but we want to distribute
+pre-releases and integrate patches from the upstream svn, the package
+ships a script in the source that is used to create the orig.tar.gz.
+
+ -- Reinhard Tartler <siretart@tauware.de>, Wed, 1 Apr 2009 16:24:42 +0200
diff --git a/debian/boxbackup-client.config b/debian/boxbackup-client.config
new file mode 100644
index 00000000..a2ed866d
--- /dev/null
+++ b/debian/boxbackup-client.config
@@ -0,0 +1,117 @@
+#!/bin/bash -e
+
+# Source debconf library
+. /usr/share/debconf/confmodule
+
+# This conf script is capable of backing up
+#db_version 2.0
+#db_capb backup
+
+#db_metaget debconf/priority value
+#CONFPRIO=$RET
+
+# Handle with debconf or not?
+db_input medium boxbackup-client/debconf || true
+db_go
+db_get boxbackup-client/debconf
+if [ "$RET" = "false" ]; then
+ exit 0
+fi
+
+# Backup mode
+db_get boxbackup-client/backupMode
+OLDMODE=$RET
+
+db_input medium boxbackup-client/backupMode || true
+db_go
+
+
+# accountNumber
+ANOK=0
+while [ $ANOK = 0 ]; do
+ db_input critical boxbackup-client/accountNumber || true
+ db_go
+
+ db_get boxbackup-client/accountNumber
+
+ if [ -z `echo $RET | sed 's/[[:xdigit:]]//g'` ]; then
+ ANOK=1
+ fi
+
+ if [ $ANOK = 0 ]; then
+ db_input critical boxbackup-client/incorrectAccountNumber || true
+ db_go
+ fi
+done
+
+# backupServer
+db_input critical boxbackup-client/backupServer || true
+db_go
+
+# backupDirs
+DIRSOK=0
+while [ $DIRSOK = 0 ]; do
+ db_input critical boxbackup-client/backupDirs || true
+ db_go
+
+ db_get boxbackup-client/backupDirs
+
+ if [ ! -z "$RET" ]; then
+ DIRSOK=1
+ for dir in $RET; do
+ if [ ! -z `echo $dir | sed 's/^[[:space:]]*\/[[:alnum:]\.\_-]*\/*\([[:alnum:]\.\_-]*\/*\)*[[:space:]]*$//g'` ]; then
+ DIRSOK=0;
+ fi
+ done
+ fi
+
+ if [ $DIRSOK = 0 ]; then
+ db_input critical boxbackup-client/incorrectDirectories || true
+ db_go
+ fi
+done
+
+# UpdateStoreInterval MinimumFileAge MaxUploadWait
+#db_get boxbackup-client/backupMode
+
+# This is a way to get back to the default values when switching the backup mode
+#if [ ! -z $OLDMODE ]; then
+# if [ $OLDMODE != $RET ]; then
+# db_set boxbackup-client/UpdateStoreInterval "3600"
+# db_set boxbackup-client/MinimumFileAge "21600"
+# db_set boxbackup-client/MaxUploadWait "86400"
+# fi
+#fi
+
+db_get boxbackup-client/backupMode
+if [ "$RET" = "lazy" ]; then
+ for param in UpdateStoreInterval MinimumFileAge MaxUploadWait; do
+ NUMOK=0
+ while [ $NUMOK = 0 ]; do
+ db_input medium boxbackup-client/$param || true
+ db_go
+
+ db_get boxbackup-client/$param
+
+ if [ -z `echo $RET | sed 's/[[:digit:]]//g'` ]; then
+ NUMOK=1
+ fi
+
+ if [ $NUMOK = 0 ]; then
+ db_input critical boxbackup-client/IncorrectNumber || true
+ db_go
+ fi
+ done
+ done
+fi
+
+
+# NotifyMail
+db_input medium boxbackup-client/notifyMail || true
+db_go
+
+# x509 and private key
+db_input medium boxbackup-client/generateCertificate || true
+db_go
+
+exit 0
diff --git a/debian/boxbackup-client.cron.d b/debian/boxbackup-client.cron.d
new file mode 100644
index 00000000..486e4be3
--- /dev/null
+++ b/debian/boxbackup-client.cron.d
@@ -0,0 +1,2 @@
+# Launch the boxbackup client/server synchronization when in snapshot mode
+#0 0 * * * root /usr/sbin/bbackupctl -q sync
diff --git a/debian/boxbackup-client.dirs b/debian/boxbackup-client.dirs
new file mode 100644
index 00000000..96e786f8
--- /dev/null
+++ b/debian/boxbackup-client.dirs
@@ -0,0 +1,5 @@
+usr/sbin
+var/lib/bbackupd
+etc/boxbackup
+etc/boxbackup/bbackupd
+
diff --git a/debian/boxbackup-client.docs b/debian/boxbackup-client.docs
new file mode 100644
index 00000000..ccd1de71
--- /dev/null
+++ b/debian/boxbackup-client.docs
@@ -0,0 +1,3 @@
+BUGS.txt
+distribution/boxbackup/LINUX.txt
+distribution/boxbackup/THANKS.txt
diff --git a/debian/boxbackup-client.init b/debian/boxbackup-client.init
new file mode 100644
index 00000000..e6ceced7
--- /dev/null
+++ b/debian/boxbackup-client.init
@@ -0,0 +1,69 @@
+#! /bin/sh
+#
+### BEGIN INIT INFO
+# Provides: boxbackup-client
+# Required-Start: $syslog $remote_fs $network
+# Required-Stop: $syslog $remote_fs $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: boxbackup client
+# Description: Init script to start and stop the boxbackup client
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/bbackupd
+NAME=bbackupd
+DESC=boxbackup-client
+CONF=/etc/boxbackup/bbackupd.conf
+
+test -f $DAEMON || exit 0
+
+test -f $CONF || exit 0
+
+PIDFILE=`grep 'PidFile' $CONF | sed 's/[[:space:]]*PidFile[[:space:]]*=[[:space:]]*\(\/[A-Za-z0-9/]*\)/\1/'`
+CERTFILE=`grep 'CertificateFile' $CONF | sed 's/[[:space:]]*CertificateFile[[:space:]]*=[[:space:]]*\(\/[A-Za-z0-9/]*\)/\1/'`
+ACCNUM=`grep 'AccountNumber' $CONF | sed 's/[[:space:]]*AccountNumber[[:space:]]*=[[:space:]]*\([A-Za-z0-9/]*\)/\1/'`
+
+[ -z $PIDFILE ] && PIDFILE="/var/run/bbackupd.pid"
+
+# Don't start if certificate file or account number are not present
+[ ! -e $CERTFILE -o -z $ACCNUM ] && exit 0
+
+set -e
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC: "
+ start-stop-daemon --start --quiet --pidfile $PIDFILE \
+ --exec $DAEMON -- $CONF
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ start-stop-daemon --oknodo --retry 5 --stop --quiet --pidfile $PIDFILE \
+ --exec $DAEMON
+ echo "$NAME."
+ ;;
+ reload|force-reload)
+ echo "Reloading $DESC configuration files."
+ start-stop-daemon --stop --signal 1 --quiet --pidfile \
+ $PIDFILE --exec $DAEMON -- $CONF
+ ;;
+ restart)
+ echo -n "Restarting $DESC: "
+ start-stop-daemon --oknodo --retry 5 --stop --quiet --pidfile \
+ $PIDFILE --exec $DAEMON
+ sleep 1
+ start-stop-daemon --start --quiet --pidfile \
+ $PIDFILE --exec $DAEMON -- $CONF
+ echo "$NAME."
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
+ #echo "Usage: $N {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/debian/boxbackup-client.install b/debian/boxbackup-client.install
new file mode 100644
index 00000000..5dbf00bf
--- /dev/null
+++ b/debian/boxbackup-client.install
@@ -0,0 +1,4 @@
+parcels/boxbackup-*-backup-client-*-gnu*/bbackupctl /usr/sbin/
+parcels/boxbackup-*-backup-client-*-gnu*/bbackupd /usr/sbin/
+parcels/boxbackup-*-backup-client-*-gnu*/bbackupd-config /usr/sbin/
+parcels/boxbackup-*-backup-client-*-gnu*/bbackupquery /usr/sbin/
diff --git a/debian/boxbackup-client.manpages b/debian/boxbackup-client.manpages
new file mode 100644
index 00000000..562b2f7e
--- /dev/null
+++ b/debian/boxbackup-client.manpages
@@ -0,0 +1,6 @@
+docs/man/bbackupd.8.gz
+docs/man/bbackupd.conf.5.gz
+docs/man/bbackupd-config.8.gz
+docs/man/bbackupctl.8.gz
+docs/man/bbackupquery.8.gz
+
diff --git a/debian/boxbackup-client.postinst b/debian/boxbackup-client.postinst
new file mode 100644
index 00000000..aa58f3b8
--- /dev/null
+++ b/debian/boxbackup-client.postinst
@@ -0,0 +1,349 @@
+#! /bin/bash
+# postinst script for boxbackup-client
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+#
+# quoting from the policy:
+# Any necessary prompting should almost always be confined to the
+# post-installation script, and should be protected with a conditional
+# so that unnecessary prompting doesn't happen if a package's
+# installation fails and the `postinst' is called with `abort-upgrade',
+# `abort-remove' or `abort-deconfigure'.
+
+#loading debconf module
+. /usr/share/debconf/confmodule
+
+CONFDIR=/etc/boxbackup
+DEBCONFBB=$CONFDIR/bbackupd.debconf
+BBCONF=$CONFDIR/bbackupd.conf
+BBKEY=$CONFDIR/bbackupd/boxbackup-client-encrypt-key.raw
+BBPRIVKEY=$CONFDIR/bbackupd/boxbackup-client-priv-key.pem
+BBCERTREQ=$CONFDIR/bbackupd/boxbackup-client-cert-req.pem
+BBCERT=$CONFDIR/bbackupd/boxbackup-client-cert.pem
+BBCACERT=$CONFDIR/bbackupd/boxbackup-server-ca-cert.pem
+DEBCONFNOTIFY=$CONFDIR/bbackupd/notifyadmin.debconf
+NOTIFYSCRIPT=$CONFDIR/bbackupd/notifyadmin
+
+case "$1" in
+ configure)
+ db_get boxbackup-client/debconf
+ if [ "$RET" = "true" ]; then
+ # Generate configuration files
+ # backupd.conf
+ echo "#To reconfigure boxbackup-client run #dpkg-reconfigure boxbackup-client" >> $DEBCONFBB
+
+ db_get boxbackup-client/backupServer
+ echo "StoreHostname = $RET" >> $DEBCONFBB
+
+ db_get boxbackup-client/accountNumber
+ ACCOUNT=$RET
+ echo "AccountNumber = 0x$ACCOUNT" >> $DEBCONFBB
+ echo "KeysFile = $BBKEY" >> $DEBCONFBB
+ echo "" >> $DEBCONFBB
+ echo "CertificateFile = $BBCERT" >> $DEBCONFBB
+ echo "PrivateKeyFile = $BBPRIVKEY" >> $DEBCONFBB
+ echo "TrustedCAsFile = $BBCACERT" >> $DEBCONFBB
+ echo "" >> $DEBCONFBB
+ echo "DataDirectory = /var/lib/bbackupd" >> $DEBCONFBB
+
+ cat >>$DEBCONFBB <<__EOF
+
+# This script is run whenever bbackupd encounters a problem which requires
+# the system administrator to assist:
+# 1) The store is full, and no more data can be uploaded.
+# 2) Some files or directories were not readable.
+# The default script emails the system administrator.
+NotifyScript = $NOTIFYSCRIPT
+
+__EOF
+
+ db_get boxbackup-client/backupMode
+ if [ "$RET" = "lazy" ]; then
+ db_get boxbackup-client/UpdateStoreInterval
+ UPDATE=$RET
+ [ -z "$UPDATE" ] && UPDATE="3600"
+
+ db_get boxbackup-client/MinimumFileAge
+ FILEAGE=$RET
+ [ -z "$FILEAGE" ] && FILEAGE="21600"
+
+ db_get boxbackup-client/MaxUploadWait
+ UPWAIT=$RET
+ [ -z "$UPWAIT" ] && UPWAIT="86400"
+
+ AUTO=yes
+ else
+ AUTO=no
+ UPDATE=0
+ FILEAGE=0
+ UPWAIT=0
+ fi
+
+ cat >>$DEBCONFBB <<__EOF
+# Backup mode specification
+# With snapshot mode, you will need to run bbackupctl to instruct the daemon to upload files.
+# Set to no for snapshot mode and yes for lazy mode
+AutomaticBackup = $AUTO
+
+# A scan of the local discs will be made once an hour (approximately).
+# To avoid cycles of load on the server, this time is randomly adjusted by a small
+# percentage as the daemon runs.
+# Defaults: 3600 for lazy mode - 0 for snapshot mode
+UpdateStoreInterval = $UPDATE
+
+# A file must have been modified at least 6 hours ago before it will be uploaded.
+# Defaults: 21600 for lazy mode - 0 for snapshot mode
+MinimumFileAge = $FILEAGE
+
+# If a file is modified repeated, it won't be uploaded immediately in case it's modified again.
+# However, it should be uploaded eventually. This is how long we should wait after first noticing
+# a change. (1 day)
+# Defaults: 86400 for lazy mode - 0 for snapshot mode
+MaxUploadWait = $UPWAIT
+
+# Files above this size (in bytes) are tracked, and if they are renamed they will simply be
+# renamed on the server, rather than being uploaded again. (64k - 1)
+FileTrackingSizeThreshold = 65535
+
+# The daemon does "changes only" uploads for files above this size (in bytes).
+# Files less than it are uploaded whole without this extra processing.
+DiffingUploadSizeThreshold = 8192
+
+# The limit on how much time is spent diffing files. Most files shouldn't take very long,
+# but if you have really big files you can use this to limit the time spent diffing them.
+# * Reduce if you are having problems with processor usage.
+# * Increase if you have large files, and think the upload of changes is too large and want
+# to spend more time searching for unchanged blocks.
+MaximumDiffingTime = 20
+
+# Uncomment this line to see exactly what the daemon is going when it's connected to the server.
+# ExtendedLogging = yes
+
+# Use this to temporarily stop bbackupd from syncronising or connecting to the store.
+# This specifies a program or script script which is run just before each sync, and ideally
+# the full path to the interpreter. It will be run as the same user bbackupd is running as,
+# usually root.
+# The script prints either "now" or a number to STDOUT (and a terminating newline, no quotes).
+# If the result was "now", then the sync will happen. If it's a number, then the script will
+# be asked again in that number of seconds.
+# For example, you could use this on a laptop to only backup when on a specific network.
+
+# SyncAllowScript = /path/to/intepreter/or/exe script-name parameters etc
+
+# Where the command socket is created in the filesystem.
+CommandSocket = /var/run/bbackupd.sock
+
+Server
+{
+ PidFile = /var/run/bbackupd.pid
+}
+
+#
+# BackupLocations specifies which locations on disc should be backed up. Each
+# directory is in the format
+#
+# name
+# {
+# Path = /path/of/directory
+# (optional exclude directives)
+# }
+#
+# 'name' is derived from the Path by the config script, but should merely be
+# unique.
+#
+# The exclude directives are of the form
+#
+# [Exclude|AlwaysInclude][File|Dir][|sRegex] = regex or full pathname
+#
+# (The regex suffix is shown as 'sRegex' to make File or Dir plural)
+#
+# For example:
+#
+# ExcludeDir = /home/guest-user
+# ExcludeFilesRegex = \.(mp3|MP3)$
+# AlwaysIncludeFile = /home/username/veryimportant.mp3
+#
+# This excludes the directory /home/guest-user from the backup along with all mp3
+# files, except one MP3 file in particular.
+#
+# In general, Exclude excludes a file or directory, unless the directory is
+# explicitly mentioned in a AlwaysInclude directive.
+#
+# If a directive ends in Regex, then it is a regular expression rather than a
+# explicit full pathname. See
+#
+# man 7 re_format
+#
+# for the regex syntax on your platform.
+#
+
+BackupLocations
+{
+__EOF
+
+ db_get boxbackup-client/backupDirs
+
+ for dir in $RET; do
+ NAME=`echo $dir | sed 's/\//-/g' | sed 's/^-//'`
+
+ # TODO : exclude encrypt key file from the backup
+
+ echo " $NAME" >> $DEBCONFBB
+ echo " {" >> $DEBCONFBB
+ echo " Path = $dir" >> $DEBCONFBB
+ echo " }" >> $DEBCONFBB
+ done
+
+ echo "}" >> $DEBCONFBB
+
+ # Encryption key
+ if [ ! -e $BBKEY ]; then
+ if ! openssl rand -out $BBKEY 1024 >&2; then
+ echo "Can't generate encryption key. Check why." >&2
+ fi
+ fi
+
+ chmod 600 $BBKEY || true
+
+ # SSL stuff
+ if [ ! -z "$ACCOUNT" ]; then
+ if [ ! -e $BBPRIVKEY -a ! -e $BBCERT ]; then
+ db_get boxbackup-client/generateCertificate
+
+ if [ "$RET" = "true" ]; then
+ if ! openssl genrsa -out $BBPRIVKEY 2048 >&2; then
+ echo "Private key generation failed! Check why." >&2
+ else
+ chmod 600 $BBPRIVKEY || true
+ fi
+
+
+ if ! openssl req -new -key $BBPRIVKEY -sha1 -out $BBCERTREQ >&2 <<__EOF
+.
+.
+.
+.
+.
+BACKUP-$ACCOUNT
+.
+.
+.
+__EOF
+ then
+ echo "Certificate request generation failed ! Check why." >&2
+ fi
+ fi
+ fi
+ fi
+
+ # Generate notify script
+ CLIENTNAME=`hostname --fqdn`
+
+ db_get boxbackup-client/notifyMail
+ MAILTO=$RET
+
+ cat >>$DEBCONFNOTIFY <<__EOF
+#!/bin/sh
+#To reconfigure boxbackup-client run #dpkg-reconfigure boxbackup-client
+SUBJECT="BACKUP PROBLEM on host $CLIENTNAME"
+SENDTO="$MAILTO"
+
+if [ \$1 = store-full ]
+then
+sendmail \$SENDTO <<EOM
+Subject: \$SUBJECT (store full)
+To: \$SENDTO
+
+
+The store account for $CLIENTNAME is full.
+
+=============================
+FILES ARE NOT BEING BACKED UP
+=============================
+
+Please adjust the limits on account $account_num on server $server.
+
+EOM
+elif [ \$1 = read-error ]
+then
+sendmail \$SENDTO <<EOM
+Subject: \$SUBJECT (read errors)
+To: \$SENDTO
+
+
+Errors occured reading some files or directories for backup on $CLIENTNAME.
+
+===================================
+THESE FILES ARE NOT BEING BACKED UP
+===================================
+
+Check the logs on $CLIENTNAME for the files and directories which caused
+these errors, and take appropraite action.
+
+Other files are being backed up.
+
+EOM
+else
+sendmail \$SENDTO <<EOM
+Subject: \$SUBJECT (unknown)
+To: \$SENDTO
+
+
+The backup daemon on $CLIENTNAME reported an unknown error.
+
+==========================
+FILES MAY NOT BE BACKED UP
+==========================
+
+Please check the logs on $CLIENTNAME.
+
+EOM
+fi
+__EOF
+
+ if [ -x "`which ucf`" ]; then
+ ucf --three-way --debconf-ok $DEBCONFBB $BBCONF
+ fi
+ rm -f $DEBCONFBB
+ chmod 644 $BBCONF || true
+ chown root:root $BBCONF || true
+
+ if [ -x "`which ucf`" ]; then
+ ucf --three-way --debconf-ok $DEBCONFNOTIFY $NOTIFYSCRIPT
+ fi
+ rm -f $DEBCONFNOTIFY
+ chmod 755 $NOTIFYSCRIPT || true
+ chown root:root $NOTIFYSCRIPT || true
+ fi
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+db_stop
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/boxbackup-client.postrm b/debian/boxbackup-client.postrm
new file mode 100644
index 00000000..5272f93e
--- /dev/null
+++ b/debian/boxbackup-client.postrm
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+
+if [ "$1" = "purge" ]; then
+ for i in /etc/boxbackup/bbackupd.conf /etc/boxbackup/bbackupd/notifyadmin; do
+ if [ -e $i ]; then
+ rm -f $i
+ fi
+ if which ucf >/dev/null; then
+ ucf -p $i
+ fi
+ done
+fi
+
+#DEBHELPER#
diff --git a/debian/boxbackup-client.templates b/debian/boxbackup-client.templates
new file mode 100644
index 00000000..cf0d41c8
--- /dev/null
+++ b/debian/boxbackup-client.templates
@@ -0,0 +1,137 @@
+# These templates have been reviewed by the debian-l10n-english
+# team
+#
+# If modifications/additions/rewording are needed, please ask
+# for an advice to debian-l10n-english@lists.debian.org
+#
+# Even minor modifications require translation updates and such
+# changes should be coordinated with translators and reviewers.
+
+Template: boxbackup-client/debconf
+Type: boolean
+Default: false
+_Description: Should the BoxBackup client be configured automatically?
+ The package configuration scripts can create the configuration files
+ for the BoxBackup client.
+ .
+ You should choose this option if you are not familiar with BoxBackup's
+ configuration options.
+ .
+ Please read the /usr/share/doc/boxbackup-client/README.Debian for details
+ about the configuration of the BoxBackup client.
+
+Template: boxbackup-client/backupMode
+Type: select
+Choices: lazy, snapshot
+#flag:comment:3
+# Translators, please keep reference to 'lazy' and 'snapshot' as
+# these options are written as is in the software documentation
+_Description: Run mode for the BoxBackup client:
+ The BoxBackup client supports two modes of backup:
+ .
+ In the 'lazy' mode, the backup daemon will regularly scan the file system
+ searching for modified files. It will then upload the files older than a
+ specified age to the backup server.
+ .
+ In the 'snapshot' mode the backup will be explicitly run at regular intervals.
+ A cron file (/etc/cron.d/boxbackup-client) is provided with the
+ package and should be adapted to suit your needs.
+
+Template: boxbackup-client/accountNumber
+Type: string
+_Description: Account number for this node on the backup server:
+ The administrator of the BoxBackup server should have assigned this client
+ a hexadecimal account number.
+ .
+ If no account number has been assigned yet, leave this field blank and
+ configure it later by running 'dpkg-reconfigure boxbackup-client' as root.
+
+Template: boxbackup-client/incorrectAccountNumber
+Type: error
+_Description: Invalid account number
+ The account number must be a hexadecimal number (such as 1F04 or 4500).
+
+Template: boxbackup-client/backupServer
+Type: string
+_Description: Fully qualified domain name of the backup server:
+ Please enter the fully qualified domain name of the BoxBackup server which
+ your client will use.
+ .
+ The client will connect to the server on TCP port 2201.
+
+Template: boxbackup-client/backupDirs
+Type: string
+_Description: List of directories to backup:
+ Please give a space-separated list of directories to be backed up onto
+ the remote server.
+ .
+ Those directories should not contain mounted file systems at any level
+ in their subdirectories.
+
+Template: boxbackup-client/incorrectDirectories
+Type: error
+_Description: Invalid path name
+ The path names to the directories must be absolute path names, separated
+ by spaces.
+ .
+ For example: /home/myaccount /etc/
+
+Template: boxbackup-client/UpdateStoreInterval
+Type: string
+Default: 3600
+_Description: Interval (in seconds) between directory scans:
+ BoxBackup regularly scans the selected directories, looking for modified
+ files.
+ .
+ Please choose the scan interval in seconds.
+
+Template: boxbackup-client/MinimumFileAge
+Type: string
+Default: 21600
+_Description: Minimum time to wait (in seconds) before uploading a file:
+ A file will be uploaded to the server only after a certain time after its
+ last modification.
+ .
+ Low interval values will trigger frequent uploads to the server and more
+ revisions being created with older revisions being removed earlier.
+
+Template: boxbackup-client/MaxUploadWait
+Type: string
+Default: 86400
+_Description: Maximum time to wait (in seconds) before uploading a file:
+ Frequently modified files are likely to never get uploaded if they
+ never reach the minimum wait time.
+ .
+ Please enter the maximum time to reach before the upload of a modified
+ file to the server is enforced.
+
+Template: boxbackup-client/IncorrectNumber
+Type: error
+_Description: Invalid time entered
+ Please enter an integer value greater null.
+
+Template: boxbackup-client/notifyMail
+Type: string
+Default: root
+_Description: Recipient for alert notifications:
+ The BoxBackup client sends alert notifications when a problem occurs
+ during the backup.
+ .
+ Please enter either a local user name (for example 'root') or an email
+ address (for example 'admin@example.org').
+
+Template: boxbackup-client/generateCertificate
+Type: boolean
+Default: true
+_Description: Generate the client private key and X.509 certificate request?
+ The BoxBackup client needs an RSA private key and the corresponding X.509
+ certificate to authenticate itself with the server.
+ .
+ Both can be generated automatically. You will need to send the
+ certificate request to the BoxBackup server administrator who will
+ sign it and send it back to you along with the server's Certification
+ Authority certificate.
+ .
+ These files should be copied into BoxBackup's configuration
+ directory. The file names to use are given in the
+ /etc/boxbackup/bbackupd.conf file.
diff --git a/debian/boxbackup-server.config b/debian/boxbackup-server.config
new file mode 100644
index 00000000..8f5d321c
--- /dev/null
+++ b/debian/boxbackup-server.config
@@ -0,0 +1,110 @@
+#!/bin/bash -e
+
+# Source debconf library
+. /usr/share/debconf/confmodule
+
+# This conf script is capable of backing up
+#db_version 2.0
+#db_capb backup
+
+#db_metaget debconf/priority value
+#CONFPRIO=$RET
+
+# Handle with debconf or not?
+db_input medium boxbackup-server/debconf || true
+db_go
+db_get boxbackup-server/debconf
+if [ "$RET" = "false" ]; then
+ exit 0
+fi
+
+# RAID directories
+db_get boxbackup-server/raidDirectories
+OLDRAIDDIR=$RET
+RAIDOK=0
+while [ $RAIDOK = 0 ]; do
+ db_input critical boxbackup-server/raidDirectories || true
+ db_go
+
+ db_get boxbackup-server/raidDirectories
+
+ DIR1=`echo "$RET" | awk '{ print $1 }'`
+ DIR2=`echo "$RET" | awk '{ print $2 }'`
+ DIR3=`echo "$RET" | awk '{ print $3 }'`
+
+ if [ -n $DIR1 ]; then
+ if [ -z "$DIR2" -o -z "$DIR3" ]; then
+ DIR2=$DIR1
+ DIR3=$DIR1
+ fi
+
+ PATHOK=1
+ for i in $DIR1 $DIR2 $DIR3; do
+ if [ `echo $i | awk '{ if (/^\/[A-Za-z0-9\.\-_]+\/?([A-Za-z0-9\.\-_]+\/?)*$/) { print 1 } else { print 0 } }'` = 0 ]; then
+ PATHOK=0
+ fi
+ done
+
+ if [ $PATHOK = 1 ]; then
+ RAIDOK=1;
+ fi
+ fi
+
+ if [ $RAIDOK = 0 ]; then
+ db_input critical boxbackup-server/incorrectDirectories || true
+ db_go
+ fi
+done
+
+# RAID block size
+# Try to figure out the block size of the first partition given
+db_get boxbackup-server/raidDirectories
+if [ "$OLDRAIDDIR" != "$RET" ]; then # Directories have been changed so we can try to guess the block size
+ TMPDIR=`echo $DIR1 | sed 's/\/$//'`
+
+ while [ "$TMPDIR" != "" ]; do
+ DEV=`df -P | grep "$TMPDIR$" | awk '{ print $1 }'`
+
+ if [ -z "$DEV" ]; then
+ TMPDIR=`echo $TMPDIR | sed 's/\/[^\/]*$//'`
+ else
+ TMPDIR=""
+ fi
+ done
+
+ if [ "$DEV" != "" ]; then
+ if [ -x /sbin/tune2fs ]; then
+ BS=`tune2fs -l $DEV 2>/dev/null | grep 'Block size' | awk '{print $3 }'`
+
+ if [ $? = 0 -a $BS != "" ]; then
+ db_set boxbackup-server/raidBlockSize "$BS"
+ fi
+ fi
+ fi
+fi
+
+BSOK=0
+while [ $BSOK = 0 ]; do
+ db_input critical boxbackup-server/raidBlockSize || true
+ db_go
+
+ db_get boxbackup-server/raidBlockSize
+
+ if [ `echo $RET | awk '{ if (/^[0-9]+$/) { print 1 } else { print 0 } }'` = 1 ]; then
+ if [ `echo $RET | awk '{ bs=sqrt($1); if (bs ~ /^[0-9]+$/) { print 1 } else { print 0 } }'` = 1 ]; then
+ BSOK=1
+ fi
+ fi
+
+ if [ $BSOK = 0 ]; then
+ db_input critical boxbackup-server/incorrectBlocksize || true
+ db_go
+ fi
+done
+
+# x509 and private key
+db_input medium boxbackup-server/generateCertificate || true
+db_go
+
+exit 0
+
diff --git a/debian/boxbackup-server.dirs b/debian/boxbackup-server.dirs
new file mode 100644
index 00000000..a6c52ea6
--- /dev/null
+++ b/debian/boxbackup-server.dirs
@@ -0,0 +1,6 @@
+usr/sbin
+etc/boxbackup
+etc/boxbackup/bbstored
+etc/logcheck/ignore.d.workstation
+etc/logcheck/ignore.d.server
+
diff --git a/debian/boxbackup-server.docs b/debian/boxbackup-server.docs
new file mode 100644
index 00000000..ccd1de71
--- /dev/null
+++ b/debian/boxbackup-server.docs
@@ -0,0 +1,3 @@
+BUGS.txt
+distribution/boxbackup/LINUX.txt
+distribution/boxbackup/THANKS.txt
diff --git a/debian/boxbackup-server.init b/debian/boxbackup-server.init
new file mode 100644
index 00000000..11529b4d
--- /dev/null
+++ b/debian/boxbackup-server.init
@@ -0,0 +1,80 @@
+#! /bin/sh
+#
+### BEGIN INIT INFO
+# Provides: boxbackup-server
+# Required-Start: $syslog $remote_fs $network
+# Required-Stop: $syslog $remote_fs $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: boxbackup server
+# Description: Init script to start and stop the boxbackup server
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/bbstored
+NAME=bbstored
+DESC=boxbackup-server
+CONF=/etc/boxbackup/bbstored.conf
+
+test -f $DAEMON || exit 0
+
+test -f $CONF || exit 0
+
+PIDFILE=`grep 'PidFile' $CONF | sed 's/[[:space:]]*PidFile[[:space:]]*=[[:space:]]*\(\/[A-Za-z0-9/]*\)/\1/'`
+CERTFILE=`grep 'CertificateFile' $CONF | sed 's/[[:space:]]*CertificateFile[[:space:]]*=[[:space:]]*\(\/[A-Za-z0-9/]*\)/\1/'`
+
+[ -z $PIDFILE ] && PIDFILE="/var/run/bbstored.pid"
+
+# Don't start if certificate file is not present
+[ ! -e $CERTFILE ] && exit 0
+
+set -e
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC: "
+ start-stop-daemon --start --quiet --pidfile $PIDFILE \
+ --exec $DAEMON -- $CONF
+ echo "$NAME."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: "
+ start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
+ --exec $DAEMON
+ echo "$NAME."
+ ;;
+ #reload)
+ #
+ # If the daemon can reload its config files on the fly
+ # for example by sending it SIGHUP, do it here.
+ #
+ # If the daemon responds to changes in its config file
+ # directly anyway, make this a do-nothing entry.
+ #
+ # echo "Reloading $DESC configuration files."
+ # start-stop-daemon --stop --signal 1 --quiet --pidfile \
+ # /var/run/$NAME.pid --exec $DAEMON
+ #;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented, move the "force-reload"
+ # option to the "reload" entry above. If not, "force-reload" is
+ # just the same as "restart".
+ #
+ echo -n "Restarting $DESC: "
+ start-stop-daemon --oknodo --stop --quiet --pidfile \
+ $PIDFILE --exec $DAEMON
+ sleep 1
+ start-stop-daemon --start --quiet --pidfile \
+ $PIDFILE --exec $DAEMON -- $CONF
+ echo "$NAME."
+ ;;
+ *)
+ N=/etc/init.d/$NAME
+ # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $N {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/debian/boxbackup-server.install b/debian/boxbackup-server.install
new file mode 100644
index 00000000..24809064
--- /dev/null
+++ b/debian/boxbackup-server.install
@@ -0,0 +1,8 @@
+
+debian/tmp/etc/logcheck/ignore.d.server/boxbackup-server /etc/logcheck/ignore.d.server
+debian/tmp/etc/logcheck/ignore.d.workstation/boxbackup-server /etc/logcheck/ignore.d.workstation
+parcels/boxbackup-*-backup-server-*-gnu*/bbstoreaccounts /usr/sbin/
+parcels/boxbackup-*-backup-server-*-gnu*/bbstored /usr/sbin/
+parcels/boxbackup-*-backup-server-*-gnu*/bbstored-certs /usr/bin/
+parcels/boxbackup-*-backup-server-*-gnu*/bbstored-config /usr/sbin/
+parcels/boxbackup-*-backup-server-*-gnu*/raidfile-config /usr/sbin/
diff --git a/debian/boxbackup-server.logcheck.ignore b/debian/boxbackup-server.logcheck.ignore
new file mode 100644
index 00000000..c19b43db
--- /dev/null
+++ b/debian/boxbackup-server.logcheck.ignore
@@ -0,0 +1,10 @@
+bbstored/hk\[.*\]: Starting housekeeping
+bbstored/hk\[.*\]: Finished housekeeping
+bbstored/hk\[.*\]: Housekeeping process started
+bbstored\[.*\]: Starting daemon
+bbstored\[.*\]: Terminating daemon
+bbstored\[.*\]: Incoming connection from.*port.*\(handling in child.*\)
+bbstored\[.*\]: Certificate CN:
+bbstored\[.*\]: Login: Client ID
+bbstored\[.*\]: Session finished
+
diff --git a/debian/boxbackup-server.manpages b/debian/boxbackup-server.manpages
new file mode 100644
index 00000000..09a62b31
--- /dev/null
+++ b/debian/boxbackup-server.manpages
@@ -0,0 +1,7 @@
+docs/man/bbstoreaccounts.8.gz
+docs/man/bbstored-certs.8.gz
+docs/man/bbstored.conf.5.gz
+docs/man/bbstored-config.8.gz
+docs/man/bbstored.8.gz
+docs/man/raidfile-config.8.gz
+docs/man/raidfile.conf.5.gz
diff --git a/debian/boxbackup-server.postinst b/debian/boxbackup-server.postinst
new file mode 100644
index 00000000..1b19de97
--- /dev/null
+++ b/debian/boxbackup-server.postinst
@@ -0,0 +1,212 @@
+#! /bin/sh
+# postinst script for boxbackup-server
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+#
+# quoting from the policy:
+# Any necessary prompting should almost always be confined to the
+# post-installation script, and should be protected with a conditional
+# so that unnecessary prompting doesn't happen if a package's
+# installation fails and the `postinst' is called with `abort-upgrade',
+# `abort-remove' or `abort-deconfigure'.
+
+#loading debconf module
+. /usr/share/debconf/confmodule
+
+CONFDIR=/etc/boxbackup
+DEBCONFRAID=$CONFDIR/raidfile.debconf
+DEBCONFBB=$CONFDIR/bbstored.debconf
+RAIDCONF=$CONFDIR/raidfile.conf
+BBCONF=$CONFDIR/bbstored.conf
+BBACCOUNTS=$CONFDIR/bbstored/boxbackup-server-accounts.txt
+BBUSER=bbstored
+BBPRIVKEY=$CONFDIR/bbstored/boxbackup-server-key.pem
+BBCERTREQ=$CONFDIR/bbstored/boxbackup-server-cert-req.pem
+BBCERT=$CONFDIR/bbstored/boxbackup-server-cert.pem
+BBCACERT=$CONFDIR/bbstored/boxbackup-client-ca-cert.pem
+
+case "$1" in
+ configure)
+
+ # Set up the bbstored user
+ if [ -z "`getent passwd $BBUSER`" ]; then
+ echo "Creating $BBUSER user." >&2
+ adduser --system --no-create-home \
+ --disabled-password --disabled-login \
+ --shell /bin/false --group --home /var $BBUSER
+ else
+ echo "User $BBUSER already exists." >&2
+ fi
+
+ db_get boxbackup-server/debconf
+ if [ "$RET" = "true" ]; then
+ # Generate configuration files
+ # raidfile.conf
+ echo "#To reconfigure boxbackup-server run #dpkg-reconfigure boxbackup-server" >> $DEBCONFRAID
+
+ echo "disc0" >> $DEBCONFRAID
+ echo "{" >> $DEBCONFRAID
+ echo " SetNumber = 0" >> $DEBCONFRAID
+
+ db_get boxbackup-server/raidBlockSize
+ echo " BlockSize = $RET" >> $DEBCONFRAID
+
+ db_get boxbackup-server/raidDirectories
+
+ DIR1=`echo "$RET" | awk '{ print $1 }'`
+ DIR2=`echo "$RET" | awk '{ print $2 }'`
+ DIR3=`echo "$RET" | awk '{ print $3 }'`
+
+ if [ -n $DIR1 ]; then
+ if [ -z "$DIR2" -o -z "$DIR3" ]; then
+ DIR2=$DIR1
+ DIR3=$DIR1
+ fi
+ fi
+
+ echo " Dir0 = $DIR1" >> $DEBCONFRAID
+ echo " Dir1 = $DIR2" >> $DEBCONFRAID
+ echo " Dir2 = $DIR3" >> $DEBCONFRAID
+
+ echo "}" >> $DEBCONFRAID
+
+ # Handle backup directories creation/permissions
+ for dir in "$DIR1" "$DIR2" "$DIR3"; do
+ if [ -d "$dir/backup" ]; then
+ # need stat package on Woody
+ #if (`stat -c %U $dir/backup` != $BBUSER); then
+ if [ `ls -ld $dir/backup | awk '{ print $3 }'` != "$BBUSER" ]; then
+ echo "Incorrect owner of backup directory. Changing it to $BBUSER..." >&2
+ chown $BBUSER:$BBUSER $dir/backup
+ fi
+
+ #if [ `stat -c %a $dir/backup` != "700" ]; then
+ if [ `ls -ld $dir/backup | awk '{ print $1 }'` != "drwx------" ]; then
+ chmod 700 $dir/backup
+ fi
+ else
+ echo "Creating $dir/backup directory..." >&2
+ mkdir -p $dir/backup
+ chown $BBUSER:$BBUSER $dir/backup
+ chmod 700 $dir/backup
+ fi
+ done
+
+ if ! dpkg-statoverride --list $CONFDIR/bbstored > /dev/null; then
+ dpkg-statoverride --update --add $BBUSER $BBUSER 700 $CONFDIR/bbstored
+ fi
+
+ # Accounts file
+ if [ ! -e $BBACCOUNTS ]; then
+ touch $BBACCOUNTS
+ fi
+
+ #if [ `stat -c %U $BBACCOUNTS` != $BBUSER ]; then
+ if [ `ls -ld $BBACCOUNTS | awk '{ print $3 }'` != "$BBUSER" ]; then
+ chown $BBUSER:$BBUSER $BBACCOUNTS
+ fi
+
+ #if [ `stat -c %a $BBACCOUNTS` != "600" ]; then
+ if [ `ls -ld $BBACCOUNTS | awk '{ print $1 }'` != "drw-------" ]; then
+ chmod 600 $BBACCOUNTS
+ fi
+
+ SERVNAME=`hostname --fqdn`
+
+ # SSL stuff
+ if [ ! -e $BBPRIVKEY -a ! -e $BBCERT ]; then
+ db_get boxbackup-server/generateCertificate
+
+ if [ "$RET" = "true" ]; then
+ if ! openssl genrsa -out $BBPRIVKEY 2048 >&2; then
+ echo "Private key generation failed! Check why." >&2
+ else
+ chown $BBUSER: $BBPRIVKEY
+ chmod 600 $BBPRIVKEY || true
+ fi
+
+ if ! openssl req -new -key $BBPRIVKEY -sha1 -out $BBCERTREQ >&2 <<EOF
+.
+.
+.
+.
+.
+$SERVNAME
+.
+.
+.
+EOF
+ then
+ echo "Certificate request generation failed ! Check why." >&2
+ fi
+ fi
+ fi
+
+ # Generate bbstored.conf
+ echo "#To reconfigure boxbackup-server run #dpkg-reconfigure boxbackup-server" >> $DEBCONFBB
+ echo "RaidFileConf = $RAIDCONF" >> $DEBCONFBB
+ echo "AccountDatabase = $BBACCOUNTS" >> $DEBCONFBB
+ echo >> $DEBCONFBB
+ echo "# Uncomment this line to see exactly what commands are being received from clients." >> $DEBCONFBB
+ echo "# ExtendedLogging = yes" >> $DEBCONFBB
+ echo >> $DEBCONFBB
+ echo "# scan all accounts for files which need deleting every 15 minutes." >> $DEBCONFBB
+ echo "TimeBetweenHousekeeping = 900" >> $DEBCONFBB
+ echo >> $DEBCONFBB
+ echo "Server" >> $DEBCONFBB
+ echo "{" >> $DEBCONFBB
+ echo " PidFile = /var/run/bbstored.pid" >> $DEBCONFBB
+ echo " User = bbstored" >> $DEBCONFBB
+ echo " ListenAddresses = inet:$SERVNAME" >> $DEBCONFBB
+ echo " CertificateFile = $BBCERT" >> $DEBCONFBB
+ echo " PrivateKeyFile = $BBPRIVKEY" >> $DEBCONFBB
+ echo " TrustedCAsFile = $BBCACERT" >> $DEBCONFBB
+ echo "}" >> $DEBCONFBB
+
+ if [ -x "`which ucf`" ]; then
+ ucf --three-way --debconf-ok $DEBCONFRAID $RAIDCONF
+ fi
+ rm -f $DEBCONFRAID
+ chmod 644 $RAIDCONF || true
+ chown root:root $RAIDCONF || true
+
+ if [ -x "`which ucf`" ]; then
+ ucf --three-way --debconf-ok $DEBCONFBB $BBCONF
+ fi
+ rm -f $DEBCONFBB
+ chmod 644 $BBCONF || true
+ chown root:root $BBCONF || true
+ fi
+ db_stop
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+ db_stop
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ db_stop
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/boxbackup-server.postrm b/debian/boxbackup-server.postrm
new file mode 100644
index 00000000..7e6ac797
--- /dev/null
+++ b/debian/boxbackup-server.postrm
@@ -0,0 +1,22 @@
+#! /bin/sh
+set -e
+
+if [ "$1" = "purge" ]; then
+ for i in /etc/boxbackup/raidfile.conf /etc/boxbackup/bbstored.conf; do
+ if [ -e $i ]; then
+ rm -f $i
+ fi
+ if which ucf >/dev/null; then
+ ucf -p $i
+ fi
+ done
+
+ dpkg-statoverride --remove /etc/boxbackup/bbstored || true
+
+ if which deluser >/dev/null; then
+ getent passwd bbstored >/dev/null && deluser bbstored
+ getent group bbstored >/dev/null && delgroup bbstored
+ fi
+fi
+
+#DEBHELPER#
diff --git a/debian/boxbackup-server.templates b/debian/boxbackup-server.templates
new file mode 100644
index 00000000..3c6016e2
--- /dev/null
+++ b/debian/boxbackup-server.templates
@@ -0,0 +1,77 @@
+# These templates have been reviewed by the debian-l10n-english
+# team
+#
+# If modifications/additions/rewording are needed, please ask
+# for an advice to debian-l10n-english@lists.debian.org
+#
+# Even minor modifications require translation updates and such
+# changes should be coordinated with translators and reviewers.
+
+Template: boxbackup-server/debconf
+Type: boolean
+Default: false
+_Description: Should BoxBackup be configured automatically?
+ The package configuration scripts can create the configuration files
+ for the BoxBackup server.
+ .
+ You should choose this option if you are not familiar with BoxBackup's
+ configuration options. The configuration can be done manually with the
+ 'raidfile-config' and 'bbstored-config' scripts.
+ .
+ The server will not start if it is not configured. In all cases,
+ reading the /usr/share/doc/boxbackup-server/README.Debian is
+ recommended.
+
+Template: boxbackup-server/raidDirectories
+Type: string
+_Description: Location of the RAID directories:
+ Please choose the location for the three RAID file directories.
+ .
+ To enable RAID, the directory names should be a space-separated list of
+ three partitions, each on different physical hard drives (for example:
+ '/raid/0.0 /raid/0.1 /raid/0.2').
+ .
+ If you don't want to enable RAID, just specify the path to one directory
+ where the backups will be stored (for example, /usr/local/lib/boxbackup).
+ .
+ These directories will be created if they do not exist.
+
+Template: boxbackup-server/incorrectDirectories
+Type: error
+_Description: Invalid path names
+ The path names to the directories must be absolute path names,
+ separated by spaces.
+ .
+ For example: /raid/0.0 /raid/0.1 /raid/0.2
+
+Template: boxbackup-server/raidBlockSize
+Type: string
+Default: 4096
+_Description: Block size for the userland RAID system:
+ BoxBackup uses userland RAID techniques.
+ .
+ Please choose the block size to use for the storage.
+ For maximum efficiency, you should choose the block size of the underlying
+ file system (which can be displayed for ext2 filesystems with the 'tune2fs -l'
+ command).
+ .
+ This value should be set even if you don't plan to use RAID.
+
+Template: boxbackup-server/generateCertificate
+Type: boolean
+Default: true
+_Description: Generate a server private key and X.509 certificate request?
+ The BoxBackup server needs an RSA private key and the corresponding X.509
+ certificate to perform client-server authentication and communication
+ encryption.
+ .
+ Both can be generated automatically. You will need to sign the
+ certificate with your root CA (see the boxbackup-server package) and
+ put this signed certificate and the root CA certificate in the
+ configuration folder.
+
+Template: boxbackup-server/incorrectBlocksize
+Type: error
+_Description: Invalid block size
+ The block size must be a power of two (e.g. 1024 or 4096).
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 00000000..573f969f
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,338 @@
+boxbackup (0.11.1~r2837-5) experimental; urgency=medium
+
+ * Honor test failures during build (Closes: #744266)
+
+ -- Reinhard Tartler <siretart@tauware.de> Sun, 11 Jun 2017 20:59:40 -0400
+
+boxbackup (0.11.1~r2837-4) unstable; urgency=medium
+
+ * QA upload.
+ * Check for ucf and deluser availability before calling them during postrm
+ purge. (Closes: #688373, #667535)
+ * Add Italian (it) debconf translations by Beatrice Torracca.
+ (Closes: #658724)
+ * Add Dutch (nl) debconf translations by Frans Spiesschaert.
+ (Closes: #766532)
+ * Build with dh_autotools-dev_*.
+ * Switch to source format 3.0 (quilt).
+
+ -- Andreas Beckmann <anbe@debian.org> Sun, 22 Jan 2017 03:29:52 +0100
+
+boxbackup (0.11.1~r2837-3) unstable; urgency=medium
+
+ * QA upload.
+ * Build with openssl 1.0. Thanks to Adrian Bunk. (Closes: #828253)
+ * Bump Standards-Version to 3.9.8.
+
+ -- Chris Lamb <lamby@debian.org> Sat, 12 Nov 2016 14:15:06 +0000
+
+boxbackup (0.11.1~r2837-2) unstable; urgency=medium
+
+ * Ensure that LWP/UserAgent.pm is available (Closes: #816517)
+ * Orphaning package, cf. #817078
+
+ -- Reinhard Tartler <siretart@tauware.de> Mon, 07 Mar 2016 20:19:45 -0500
+
+boxbackup (0.11.1~r2837-1) unstable; urgency=low
+
+ * New upstream release.
+ - Bug fix: "Handling of "get" command broken due to bug in
+ temp file name creation.", thanks to Matto Marjanovic
+ (Closes: #606559).
+ * Bug fix: "[INTL:pt_BR] Brazilian Portuguese debconf templates
+ translation", thanks to Adriano Rafael Gomes (Closes: #610416).
+ * Bug fix: "[INTL:da] Fix Danish translation of the debconf templates
+ BoxBackup", thanks to Joe Dalton (Closes: #619303).
+ * Bug fix: "Documentation errors regarding bbstored-certs", thanks to
+ Clint Adams (Closes: #601882).
+ * Build in verbose mode.
+ * Bump standards version to 3.9.2, no changes needed.
+ * Normalize fields in debian/control with wrap-and-sort(1).
+ * implement build-arch and build-indep targets
+
+ -- Reinhard Tartler <siretart@tauware.de> Fri, 28 Oct 2011 01:53:48 +0200
+
+boxbackup (0.11~rc8~r2714-1) unstable; urgency=low
+
+ * New upstream release.
+ * New Upstream fixes Bug: "boxbackup-client complains about
+ /home/*/.gvfs", thanks for reporting to Sune Mølgaard.
+ Closes: #593401, LP: #496334
+ * Enhancement: "Please use newer bdb", thanks to Clint Adams
+ Closes: #548475
+ * bin/bbstored/bbstored-certs: reduce root CA expiration date to avoid
+ Y2k38 overflow. Thanks to Clint Adams <schizo@debian.org> for
+ reporting it. Closes: #601506, LP: #641112
+ * By default, do not manage boxbackup-client configuration via debconf
+ * Allow dpkg-reconfigure to work even when the debconf level is set to
+ 'high'.
+ * Various debconf severity fixes in boxbackup-*.conf
+
+ -- Reinhard Tartler <siretart@tauware.de> Tue, 09 Nov 2010 18:14:58 +0100
+
+boxbackup (0.11~rc3~r2502-4) unstable; urgency=low
+
+ * use more globs in install paths to avoid failures on kFreeBSD
+ * Bump standards version, no changes needed
+
+ -- Reinhard Tartler <siretart@tauware.de> Wed, 13 Oct 2010 20:51:39 +0200
+
+boxbackup (0.11~rc3~r2502-3) unstable; urgency=low
+
+ * Update Vitnamese debconf translations. Closes: #598581
+
+ -- Reinhard Tartler <siretart@tauware.de> Tue, 12 Oct 2010 10:50:37 +0200
+
+boxbackup (0.11~rc3~r2502-2.1ubuntu1) maverick; urgency=low
+
+ * fix install paths for armel (LP: #616461)
+
+ -- David Sugar <david.sugar@canonical.com> Mon, 16 Aug 2010 23:49:22 +0200
+
+boxbackup (0.11~rc3~r2502-2.1) unstable; urgency=low
+
+ * Non-maintainer upload.
+ * No longer hardcode path to tune2fs in config script
+ * Fix pending l10n issues. Debconf translations:
+ - Spanish (Omar Campagne). Closes: #537589
+ - Japanese (Hideki Yamane (Debian-JP)). Closes: #558074
+ - Danish (Joe Hansen). Closes: #582174
+
+ -- Christian Perrier <bubulle@debian.org> Mon, 24 May 2010 09:33:23 +0200
+
+boxbackup (0.11~rc3~r2502-2) unstable; urgency=low
+
+ * Bug fix: "tries to contact a server build-time", thanks to
+ Riku Voipio for reporting. Fix based on a patch contributed
+ by peter green, thanks as well! (Closes: #525277).
+ * Bug fix: "missing #include", thanks to Martin Michlmayr
+ (Closes: #526152, LP: #371809)
+
+ -- Reinhard Tartler <siretart@tauware.de> Tue, 05 May 2009 07:42:40 +0200
+
+boxbackup (0.11~rc3~r2502-1) unstable; urgency=low
+
+ * New upstream release, built from svn revision 2502.
+ - silently ignores sockets and named pipes (Closes: #479145)
+ - syslog facility is now configurable (Closes: #521283)
+
+ -- Reinhard Tartler <siretart@tauware.de> Thu, 02 Apr 2009 13:58:17 +0200
+
+boxbackup (0.11~rc2+r2072-1) unstable; urgency=low
+
+ * New upstream release. (Closes: #503942)
+ * no longer use the upstream tarballs, but create them with the script
+ debian/get-orig-source.sh to create the orig.tar.gz. See README.Debian
+ for a rationale of this step.
+ * Therefore, run autoconf on the buildds.
+ * always use config.sub/config.guess from the autotools-dev package
+ * Fake a "VERSION.txt" instead of letting the build system try to figure
+ out the svn version by itself (which would fail)
+ * no longer include patches to the upstream source inline. This doesn't
+ work out too well with bzr. Port all patches to quilt instead.
+ * factor out distribution independent cleaning rules to a new shell script
+ called debian/clean.sh.
+ * make debian/NEWS actually parsable by dpkg-parsechangelog. This should
+ make apt-parsechangelog work.
+ * Update debian specific documentation to new URL: http://boxbackup.org
+ * Don't install the files DOCUMENTATION.txt and CONTACT.txt. Both contain
+ just (outdated) contact addresses and URLs. (Closes: #503659)
+ * add translation for swedish debconf messages. Translation provided by
+ Martin Bagge <brother@bsnet.se>. (Closes: #513776)
+ * adjust configure.ac to only AC_SUBST single variables instead of 3 in
+ a row. Fixes FTBFS on sid, found at http://bugs.gentoo.org/205558
+
+ -- Reinhard Tartler <siretart@tauware.de> Tue, 31 Mar 2009 15:58:23 +0200
+
+boxbackup (0.11~rc2-6) unstable; urgency=low
+
+ * Fix shell scripting in the debconf interaction code of the package's
+ postinst script. This should prevent problems like LP: #222999
+
+ -- Reinhard Tartler <siretart@tauware.de> Wed, 11 Feb 2009 08:55:05 +0100
+
+boxbackup (0.11~rc2-5) unstable; urgency=low
+
+ * Bugfix: "Please build-depend on docbook-xml". Thanks to Luca Falavigna
+ <dktrkranz@ubuntu.com> for reporting. Closes: #507973
+ * Add missing #includes in lib/common/Logging.cpp and
+ lib/common/DebugMemLeakFinder.cpp. Also use malloc, free, etc from the
+ namespace std:: instead of the global namespace in several other files
+ Closes: #505696, #512510
+
+ -- Reinhard Tartler <siretart@tauware.de> Thu, 22 Jan 2009 08:26:24 +0100
+
+boxbackup (0.11~rc2-4) unstable; urgency=low
+
+ * add a note to documentation about adjusted syslog facility.
+ * build and install the administrator guide and the installation guide.
+ * By default do not configure boxbackup. Most users of this package need
+ to know what the postinst/configure scripts are doing anyway, and this
+ avoids piuparts to fail here. Closes: #502742, #502461
+
+ -- Reinhard Tartler <siretart@tauware.de> Thu, 23 Oct 2008 20:25:10 +0200
+
+boxbackup (0.11~rc2-3.1) unstable; urgency=low
+
+ * Non-maintainer upload to fix pending l10n issues.
+ * Debconf translations:
+ - German. Closes: #477719
+ - French. Closes: #478557
+ - Portuguese. Closes: #483869
+ - Czech. Closes: #483981
+ - Galician. Closes: #483857
+ - Finnish. Closes: #484353
+ - Basque. Closes: #484563
+ - Russian. Closes: #484829
+
+ -- Christian Perrier <bubulle@debian.org> Tue, 20 May 2008 07:54:18 +0200
+
+boxbackup (0.11~rc2-3) unstable; urgency=low
+
+ * fix another miss '#include <string.h>' to fix compilation with g++-4.3.
+
+ -- Reinhard Tartler <siretart@tauware.de> Wed, 23 Apr 2008 13:10:17 +0200
+
+boxbackup (0.11~rc2-2) unstable; urgency=low
+
+ * merge forgotten changes from the unstable Branch. (sorry to the
+ translators for the confusion).
+ * The previous upload forgot to change some references to the default
+ configuration directory from /etc/box -> /etc/boxbackup. Now rectified.
+ * add an '#include <string.h>' in ./lib/common/Logging.cpp. Should fix
+ build failiures on mips, powerpc and sparc.
+
+ -- Reinhard Tartler <siretart@tauware.de> Mon, 21 Apr 2008 13:41:18 +0200
+
+boxbackup (0.11~rc2-1) unstable; urgency=low
+
+ * new upstream release.
+ * update watch file.
+ * bump standards version to 3.7.3 (No changes needed)
+ * update frensh debconf template translations. Thanks to
+ Christian Perrier (Closes: #476090)
+
+ -- Reinhard Tartler <siretart@tauware.de> Sun, 20 Apr 2008 14:01:27 +0200
+
+boxbackup (0.11~rc1-1) experimental; urgency=low
+
+ * New upstream release.
+ - should fix builds on kFreeBSD architectures: (Closes: #440156).
+ - build against libbd4.6 instead of libdb4.3. (Closes: #442640).
+ - the config file template has been updated to be more specific for
+ the AlwaysIncludeFile Option (Closes: #435860).
+ * remove all generated files in clean target of debian/rules. Allows
+ package to build twice in a row (Closes: #442515).
+ * Install file ExceptionCodes.txt to documentation directories. The file
+ contains a list of Error codes found in logfiles.
+ * Simplify debian/rules by removing code to build arch-independent
+ packages. There are none.
+
+ -- Reinhard Tartler <siretart@tauware.de> Sun, 20 Jan 2008 19:09:59 +0100
+
+boxbackup (0.10+really0.10-2) unstable; urgency=medium
+
+ * raise urgency because of RC bug!
+ * use rather 'nocheck' instead of 'notest'. Thanks to Michael Banck
+ <mbanck@debian.org> for notifying me about this.
+ * Ack NMUs. Thanks Amaya for handling these! (Closes: #470060, #467628).
+ * Merge Ubuntu changes, fixing installations without tty. (Closes: #474587).
+ * build against libdb4.6 (Closes: #442640)
+ * don't ignores errors on clean. Thanks lintian.
+ * update Standards Version to 3.7.3, no changes needed.
+ * clarify debconf question "boxbackup-client/IncorrectNumber" (Closes: #467635).
+ * clarify debconf question "boxbackup-server/raidBlockSize" (Closes: #467636).
+
+ -- Reinhard Tartler <siretart@tauware.de> Sun, 13 Apr 2008 11:38:01 +0200
+
+boxbackup (0.10+really0.10-1.2) unstable; urgency=low
+
+ * Non-maintainer upload.
+ * Fix FTBFS introduced by my previous NMU. Apply patch from Cyril Brulebois
+ (Closes: #454862).
+ * Added debian debconf translation by Kai Wasserbäch (Closes: #467628).
+
+ -- Amaya Rodrigo Sastre <amaya@debian.org> Sat, 05 Apr 2008 12:37:16 +0200
+
+boxbackup (0.10+really0.10-1.1) unstable; urgency=low
+
+ * Non-maintainer upload.
+ * iFix LSB header in init.d script (Closes: #470060).
+
+ -- Amaya Rodrigo Sastre <amaya@debian.org> Mon, 31 Mar 2008 18:43:40 +0200
+
+boxbackup (0.10+really0.10-1ubuntu3) hardy; urgency=low
+
+ * Don't redirect ucf calls. This was forgotten in the previous upload,
+ but should have been there.
+
+ -- Tollef Fog Heen <tfheen@ubuntu.com> Thu, 06 Mar 2008 07:17:35 +0100
+
+boxbackup (0.10+really0.10-1ubuntu2) hardy; urgency=low
+
+ * Fix up postinst so we don't call db_stop too early, and use
+ --debconf-ok to ucf. (No versioned dependency since even oldstable
+ has a new enough ucf.) Use db_stop near the end to make sure we don't
+ hang after starting the daemon though.
+
+ -- Tollef Fog Heen <tfheen@ubuntu.com> Wed, 05 Mar 2008 22:33:57 +0100
+
+boxbackup (0.10+really0.10-1ubuntu1) hardy; urgency=low
+
+ * Rebuild for libdb4.3 -> libdb4.6 migration.
+ * Set MOTU to maintainer.
+
+ -- Chuck Short <zulcss@ubuntu.com> Mon, 03 Mar 2008 12:37:35 -0500
+
+boxbackup (0.10+really0.10-1) unstable; urgency=low
+
+ * revert new upstream accidentally slipped into unstable.
+ * big apologies that I now need to upload this package earlier than
+ promised to the boxbackup translators :(
+ * add watchfile
+ * Bug fix: "boxbackup-server recommends boxbackup-utils (unavailable)",
+ thanks to Pelayo Gonzalez (Closes: #424992).
+ * Apply new debconf templates and debian/control review. Thanks to
+ Christan Perrier! (Closes: #429396)
+ * Bug fix: "boxbackup: French debconf templates translation", thanks to
+ Vincent Bernat (Closes: #430856).
+ * Bug fix: "[l10n] Czech translation of boxbackup debconf messages",
+ thanks to Miroslav Kure (Closes: #431463).
+ * Bug fix: "boxbackup: [INTL:vi] Vietnamese debconf templates
+ translation", thanks to Clytie Siddall (Closes: #430535).
+ * Bug fix: "depends on non-essential package ucf in postrm", thanks to
+ Michael Ablassmeier (Closes: #431518).
+ * Bug fix: "depends on non-essential package ucf in postrm", thanks to
+ Michael Ablassmeier (Closes: #431519).
+ * run testsuite on build, use 'notest' in $DEB_BUILD_OPTIONS to disable
+
+ -- Reinhard Tartler <siretart@tauware.de> Tue, 03 Jul 2007 12:30:49 +0200
+
+boxbackup (0.10-1) unstable; urgency=low
+
+ * upload to debian (Closes: #416605)
+ * Cleanups in debian/rules
+ * Apply patch from svn, commit #626, in order to fix FTBFS
+ see http://bbdev.fluffy.co.uk/trac/changeset/626
+ * Drop the boxbackup-utils package, since it only shipped one single
+ script, which is generally used for CA maintenance, so move it to the
+ to the boxbackup-server package
+ * Bump standards version to 3.7.2
+ * add missing manpages
+ * add README.Debian
+ * use debhelper 5
+ * cleanup the versioned dependencies in debian/control
+
+ [ Jérôme Schell ]
+
+ * New upstream version
+ * Add LSB headers in init script
+
+ -- Reinhard Tartler <siretart@tauware.de> Mon, 18 Jun 2007 15:35:55 +0100
+
+boxbackup (0.09-3) unstable; urgency=low
+
+ * Added man pages for bbackupd, bbackupd-config, bbackupctl, bbackupquery
+ * Improve lintian compatibility of the packages
+
+ -- Jérôme Schell <jerome@myreseau.org> Mon, 10 Oct 2005 14:16:20 +0200
diff --git a/debian/clean b/debian/clean
new file mode 100644
index 00000000..0f10520d
--- /dev/null
+++ b/debian/clean
@@ -0,0 +1,146 @@
+# generated using bzr status
+ExceptionCodes.txt
+Makefile
+aclocal.m4
+configure
+runtest.pl
+test-backupdiff.log
+test-backupstore.log
+test-backupstorefix.log
+test-backupstorepatch.log
+test-basicserver.log
+test-bbackupd.log
+test-common.log
+test-compress.log
+test-crypto.log
+test-httpserver.log
+test-raidfile.log
+bin/bbackupctl/Makefile
+bin/bbackupd/Makefile
+bin/bbackupd/autogen_ClientException.cpp
+bin/bbackupd/autogen_ClientException.h
+bin/bbackupd/bbackupd-config
+bin/bbackupobjdump/Makefile
+bin/bbackupquery/Makefile
+bin/bbackupquery/autogen_Documentation.cpp
+bin/bbackupquery/makedocumentation.pl
+bin/bbstoreaccounts/Makefile
+bin/bbstored/Makefile
+bin/bbstored/autogen_BackupProtocolServer.cpp
+bin/bbstored/autogen_BackupProtocolServer.h
+bin/bbstored/bbstored-certs
+bin/bbstored/bbstored-config
+bin/s3simulator/Makefile
+contrib/debian/bbackupd
+contrib/debian/bbstored
+contrib/mac_osx/org.boxbackup.bbackupd.plist
+contrib/mac_osx/org.boxbackup.bbstored.plist
+contrib/redhat/bbackupd
+contrib/redhat/bbstored
+contrib/solaris/bbackupd-manifest.xml
+contrib/solaris/bbackupd-smf-method
+contrib/solaris/bbstored-manifest.xml
+contrib/solaris/bbstored-smf-method
+contrib/suse/bbackupd
+contrib/suse/bbstored
+contrib/windows/installer/boxbackup.mpi
+docs/docbook/ExceptionCodes.xml
+docs/docbook/adminguide.pdf
+docs/docbook/instguide.pdf
+infrastructure/BoxPlatform.pm
+infrastructure/makebuildenv.pl
+infrastructure/makedistribution.pl
+infrastructure/makeparcels.pl
+lib/backupclient/Makefile
+lib/backupclient/autogen_BackupProtocolClient.cpp
+lib/backupclient/autogen_BackupProtocolClient.h
+lib/backupclient/autogen_BackupStoreException.cpp
+lib/backupclient/autogen_BackupStoreException.h
+lib/backupstore/Makefile
+lib/common/BoxConfig.h
+lib/common/BoxConfig.h.in
+lib/common/BoxPortsAndFiles.h
+lib/common/Makefile
+lib/common/autogen_CommonException.cpp
+lib/common/autogen_CommonException.h
+lib/common/autogen_ConversionException.cpp
+lib/common/autogen_ConversionException.h
+lib/common/makeexception.pl
+lib/compress/Makefile
+lib/compress/autogen_CompressException.cpp
+lib/compress/autogen_CompressException.h
+lib/crypto/Makefile
+lib/crypto/autogen_CipherException.cpp
+lib/crypto/autogen_CipherException.h
+lib/httpserver/Makefile
+lib/httpserver/autogen_HTTPException.cpp
+lib/httpserver/autogen_HTTPException.h
+lib/intercept/Makefile
+lib/raidfile/Makefile
+lib/raidfile/autogen_RaidFileException.cpp
+lib/raidfile/autogen_RaidFileException.h
+lib/raidfile/raidfile-config
+lib/server/Makefile
+lib/server/autogen_ConnectionException.cpp
+lib/server/autogen_ConnectionException.h
+lib/server/autogen_ServerException.cpp
+lib/server/autogen_ServerException.h
+lib/server/makeprotocol.pl
+lib/win32/Makefile
+test/backupdiff/Makefile
+test/backupdiff/_main.cpp
+test/backupdiff/_t
+test/backupdiff/_t-gdb
+test/backupstore/Makefile
+test/backupstore/_main.cpp
+test/backupstore/_t
+test/backupstore/_t-gdb
+test/backupstorefix/Makefile
+test/backupstorefix/_main.cpp
+test/backupstorefix/_t
+test/backupstorefix/_t-gdb
+test/backupstorefix/testfiles/testbackupstorefix.pl
+test/backupstorepatch/Makefile
+test/backupstorepatch/_main.cpp
+test/backupstorepatch/_t
+test/backupstorepatch/_t-gdb
+test/basicserver/Makefile
+test/basicserver/_main.cpp
+test/basicserver/_t
+test/basicserver/_t-gdb
+test/basicserver/autogen_TestProtocolClient.cpp
+test/basicserver/autogen_TestProtocolClient.h
+test/basicserver/autogen_TestProtocolServer.cpp
+test/basicserver/autogen_TestProtocolServer.h
+test/bbackupd/Makefile
+test/bbackupd/_main.cpp
+test/bbackupd/_t
+test/bbackupd/_t-gdb
+test/bbackupd/testfiles/bbackupd-exclude.conf
+test/bbackupd/testfiles/bbackupd-snapshot.conf
+test/bbackupd/testfiles/bbackupd-symlink.conf
+test/bbackupd/testfiles/bbackupd.conf
+test/bbackupd/testfiles/extcheck1.pl
+test/bbackupd/testfiles/extcheck2.pl
+test/bbackupd/testfiles/notifyscript.pl
+test/bbackupd/testfiles/syncallowscript.pl
+test/common/Makefile
+test/common/_main.cpp
+test/common/_t
+test/common/_t-gdb
+test/compress/Makefile
+test/compress/_main.cpp
+test/compress/_t
+test/compress/_t-gdb
+test/crypto/Makefile
+test/crypto/_main.cpp
+test/crypto/_t
+test/crypto/_t-gdb
+test/httpserver/Makefile
+test/httpserver/_main.cpp
+test/httpserver/_t
+test/httpserver/_t-gdb
+test/raidfile/Makefile
+test/raidfile/_main.cpp
+test/raidfile/_t
+test/raidfile/_t-gdb
diff --git a/debian/clean.sh b/debian/clean.sh
new file mode 100644
index 00000000..90a30513
--- /dev/null
+++ b/debian/clean.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+rm -rf debug/
+rm -rf local/
+rm -rf parcels/
+rm -rf release/
+rm -rf docs/htmlguide/
+rm -rf docs/man/
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 00000000..7f8f011e
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/debian/control b/debian/control
new file mode 100644
index 00000000..5cbdba67
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,57 @@
+Source: boxbackup
+Section: utils
+Priority: optional
+Maintainer: Debian QA Group <packages@qa.debian.org>
+Build-Depends:
+ autoconf,
+ automake,
+ autotools-dev,
+ debhelper (>> 7.0.0),
+ docbook-utils,
+ docbook-xml,
+ docbook-xsl,
+ libdb-dev (>= 4.7),
+ libedit-dev,
+ libssl1.0-dev,
+ libtest-lwp-useragent-perl,
+ xsltproc,
+ zlib1g-dev
+Standards-Version: 3.9.8
+Homepage: http://boxbackup.org
+Vcs-Git: git://anonscm.debian.org/collab-maint/boxbackup.git
+Vcs-Browser: https://anonscm.debian.org/git/collab-maint/boxbackup.git
+
+Package: boxbackup-server
+Architecture: any
+Depends:
+ adduser,
+ debconf | debconf-2.0,
+ gawk,
+ openssl,
+ perl,
+ ucf,
+ ${misc:Depends},
+ ${shlibs:Depends}
+Description: server for the BoxBackup remote backup system
+ BoxBackup is an automatic on-line backup system.
+ The server waits for connections from remote clients,
+ authenticates them via X.509 certificates and stores the
+ encrypted data on hard drives with optional RAID techniques.
+ It also supports versions historization and per-user quotas.
+
+Package: boxbackup-client
+Architecture: any
+Depends:
+ debconf | debconf-2.0,
+ openssl,
+ perl,
+ ucf,
+ ${misc:Depends},
+ ${shlibs:Depends}
+Description: client for the BoxBackup remote backup system
+ BoxBackup is an automatic on-line backup system.
+ The client watches for changes on the local file system,
+ connects to a BoxBackup server and sends the changes via a
+ secure channel. All data is encrypted before being sent to
+ the server. A command-line tool is provided for restoration
+ of backups including deleted files and old versions.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 00000000..ffb3eead
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,48 @@
+This package was debianized by Jérôme Schell <jerome@myreseau.org> on
+Tue, 1 Jun 2004 07:51:24 +0000.
+
+It was downloaded from http://boxbackup.org
+
+Upstream Author: Ben Summers <ben@fluffy.co.uk>
+
+Copyright:
+
+Copyright (c) 2003, 2004
+ Ben Summers. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All use of this software and associated advertising materials must
+ display the following acknowledgement:
+ This product includes software developed by Ben Summers.
+4. The names of the Authors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+[Where legally impermissible the Authors do not disclaim liability for
+direct physical injury or death caused solely by defects in the software
+unless it is modified by a third party.]
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+Commentary
+
+This license is based on a standard BSD license. Some minor changes in wording have been made to fit in with English law.
+
+© Ben Summers, 2003, 2004
diff --git a/debian/get-orig-source.sh b/debian/get-orig-source.sh
new file mode 100644
index 00000000..d56ab929
--- /dev/null
+++ b/debian/get-orig-source.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# Script to create a 'pristine' tarball for the debian boxbackup source
+# package. Copyright (C) 2009, Reinhard Tartler
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+set -eu
+
+usage() {
+ cat >&2 <<EOF
+usage: $0 [-dh]
+ -h : display help
+ -r : svn revision
+ -o : output tarball name
+EOF
+}
+
+debug () {
+ $DEBUG && echo "DEBUG: $*" >&2
+}
+
+error () {
+ echo "$1" >&2
+ exit 1;
+}
+
+set +e
+PARAMS=`getopt hr: "$@"`
+if test $? -ne 0; then usage; exit 1; fi;
+set -e
+
+eval set -- "$PARAMS"
+
+DEBUG=false
+SVNREVISION=
+
+while test $# -gt 0
+do
+ case $1 in
+ -h) usage; exit 1 ;;
+ -r) SVNREVISION=$2; shift ;;
+ --) shift ; break ;;
+ *) echo "Internal error!" ; exit 1 ;;
+ esac
+ shift
+done
+
+# sanity checks now
+dh_testdir
+
+if [ -z $SVNREVISION ]; then
+ error "you need to specify an svn revision."
+fi
+
+PACKAGENAME=boxbackup
+baseurl="https://www.boxbackup.org/svn/box/RELEASE/0.11.1"
+TARBALL=../${PACKAGENAME}_0.11.1~r${SVNREVISION}.orig.tar.gz
+
+TMPDIR=`mktemp -d`
+trap 'rm -rf ${TMPDIR}' EXIT
+
+
+svn export -r${SVNREVISION} \
+ --ignore-externals \
+ ${baseurl} \
+ ${TMPDIR}/${PACKAGENAME}
+
+svn info -r${SVNREVISION} \
+ ${baseurl} \
+ | awk '/^Revision/ {print $2}' \
+ > ${TMPDIR}/${PACKAGENAME}/.svnrevision
+
+tar czf ${TARBALL} -C ${TMPDIR} ${PACKAGENAME}
diff --git a/debian/patches/03-adjust-syslog-facility.diff b/debian/patches/03-adjust-syslog-facility.diff
new file mode 100644
index 00000000..e3033573
--- /dev/null
+++ b/debian/patches/03-adjust-syslog-facility.diff
@@ -0,0 +1,50 @@
+change default syslog facility from LOG_LOCAL6 to LOG_DAEMON
+
+--- a/bin/bbstored/BackupStoreDaemon.cpp
++++ b/bin/bbstored/BackupStoreDaemon.cpp
+@@ -203,7 +203,7 @@ void BackupStoreDaemon::Run()
+ SetProcessTitle("housekeeping, idle");
+ whichSocket = 1;
+ // Change the log name
+- ::openlog("bbstored/hk", LOG_PID, LOG_LOCAL6);
++ ::openlog("bbstored/hk", LOG_PID, LOG_DAEMON);
+ // Log that housekeeping started
+ BOX_INFO("Housekeeping process started");
+ // Ignore term and hup
+--- a/lib/common/Logging.cpp
++++ b/lib/common/Logging.cpp
+@@ -401,7 +401,7 @@ bool Syslog::Log(Log::Level level, const
+ return true;
+ }
+
+-Syslog::Syslog() : mFacility(LOG_LOCAL6)
++Syslog::Syslog() : mFacility(LOG_DAEMON)
+ {
+ ::openlog("Box Backup", LOG_PID, mFacility);
+ }
+@@ -439,8 +439,8 @@ int Syslog::GetNamedFacility(const std::
+ #undef CASE_RETURN
+
+ BOX_ERROR("Unknown log facility '" << rFacility << "', "
+- "using default LOCAL6");
+- return LOG_LOCAL6;
++ "using default DAEMON");
++ return LOG_DAEMON;
+ }
+
+ bool FileLogger::Log(Log::Level Level, const std::string& rFile,
+--- a/docs/docbook/adminguide.xml
++++ b/docs/docbook/adminguide.xml
+@@ -286,6 +286,12 @@ local5.info /var
+ <para><emphasis role="bold">Note:</emphasis> Separators must be tabs,
+ otherwise these entries will be ignored.</para>
+
++ <para><emphasis role="bold">Note2:</emphasis> The packaged
++ debian and ubuntu versions of boxbackup do not log to local6,
++ but to the more standard 'daemon' facility. This means you
++ should not have anything to do to your syslog configuration,
++ since it is configured to be logged by default.</para>
++
+ <programlisting>touch /var/log/box
+ touch /var/log/raidfile</programlisting>
+
diff --git a/debian/patches/05-dont_use_net_for_docs.diff b/debian/patches/05-dont_use_net_for_docs.diff
new file mode 100644
index 00000000..71cb6c25
--- /dev/null
+++ b/debian/patches/05-dont_use_net_for_docs.diff
@@ -0,0 +1,12 @@
+=== modified file 'docs/Makefile'
+--- a/docs/Makefile
++++ b/docs/Makefile
+@@ -10,7 +10,7 @@
+
+ all: docs
+
+-DBPROC_COMMAND = xsltproc
++DBPROC_COMMAND = xsltproc --nonet
+ MKDIR_COMMAND = mkdir
+ CP_COMMAND = cp
+ PERL_COMMAND = perl
diff --git a/debian/patches/06-gcc_4.4_fixes.diff b/debian/patches/06-gcc_4.4_fixes.diff
new file mode 100644
index 00000000..46ec64cf
--- /dev/null
+++ b/debian/patches/06-gcc_4.4_fixes.diff
@@ -0,0 +1,17 @@
+references:
+
+http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=526152
+https://bugs.launchpad.net/bugs/371809
+
+Impact: FTBFS with gcc 4.4
+
+=== modified file 'lib/server/ServerControl.cpp'
+--- a/lib/server/ServerControl.cpp
++++ b/lib/server/ServerControl.cpp
+@@ -1,5 +1,6 @@
+ #include "Box.h"
+
++#include <stdio.h>
+ #include <errno.h>
+ #include <stdio.h>
+
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 00000000..ab768cfb
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,3 @@
+03-adjust-syslog-facility.diff
+05-dont_use_net_for_docs.diff
+06-gcc_4.4_fixes.diff
diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in
new file mode 100644
index 00000000..6cd99807
--- /dev/null
+++ b/debian/po/POTFILES.in
@@ -0,0 +1,2 @@
+[type: gettext/rfc822deb] boxbackup-client.templates
+[type: gettext/rfc822deb] boxbackup-server.templates
diff --git a/debian/po/cs.po b/debian/po/cs.po
new file mode 100644
index 00000000..195059dd
--- /dev/null
+++ b/debian/po/cs.po
@@ -0,0 +1,512 @@
+# Czech translation of boxbackup debconf messages.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the boxbackup package.
+# Miroslav Kure <kurem@debian.cz>, 2007,2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2008-06-01 11:36+0200\n"
+"Last-Translator: Miroslav Kure <kurem@debian.cz>\n"
+"Language-Team: Czech <debian-l10n-czech@lists.debian.org>\n"
+"Language: cs\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Má se klient BoxBackupu nastavit automaticky?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Konfigurační skript balíku může vytvořit konfigurační soubory pro klienta "
+"BoxBackupu."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Pokud zrovna nekamarádíte s konfiguračními volbami BoxBackupu, měli byste "
+"tuto možnost povolit."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Podrobnosti o nastavení klienta BoxBackupu naleznete v souboru /usr/share/"
+"doc/boxbackup-client/README.Debian."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Režim spouštění klienta BoxBackupu:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "Klient BoxBackupu podporuje dva režimy zálohování:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"V „líném“ režimu bude zálohovací daemon pravidelně prohledávat souborový "
+"systém a hledat změněné soubory. Poté nahraje soubory starší než zadaný věk "
+"na zálohovací server."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"Ve „snímkovém“ režimu se bude zálohování spouštět v pravidelných "
+"intervalech. S balíkem se dodává cronový soubor /etc/cron.d/boxbackup-"
+"client, který byste měli upravit dle svých potřeb."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Číslo účtu tohoto uzlu na zálohovacím serveru:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"Správce serveru BoxBackup by měl tomuto klientovi přidělit hexadecimální "
+"číslo účtu."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Pokud tomuto klientovi ještě nebylo přiděleno číslo účtu, ponechte pole "
+"prázdné a nastavte jej později spuštěním „dpkg-reconfigure boxbackup-client“ "
+"pod uživatelem root."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Neplatné číslo účtu"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr "Číslo účtu musí být hexadecimální číslo (např. 1F04 nebo 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Plně kvalifikované jméno zálohovacího serveru:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Zadejte prosím plně kvalifikované doménové jméno BoxBackup serveru, který má "
+"tento klient používat."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Klient se připojí k serveru na TCP portu 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Seznam adresářů pro zálohování:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Zadejte prosím mezerami oddělený seznam adresářů, které se mají zálohovat na "
+"vzdálený server."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Tyto adresáře by v žádné úrovni podadresářů neměly obsahovat připojené "
+"souborové systémy."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Neplatná cesta"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr "Cesty k souborům musí být absolutní a oddělené mezerami."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Například: /home/mujucet /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Interval (v sekundách) mezi prohledáváním adresářů:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup pravidelně prohledává vybrané adresáře a hledá změněné soubory."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Zadejte prosím interval mezi prohledáváními."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Minimální doba čekání (v sekundách) před nahráním souboru:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Soubor se zazálohuje na server pouze po uplynutí určitého času od jeho "
+"poslední změny."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Nízké hodnoty způsobí častější nahrávání na server, vytváření více revizí a "
+"rychlejší rušení starých revizí."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Maximální doba čekání (v sekundách) před nahráním souboru:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Často upravované soubory nejspíš nikdy nedosáhnou minimální hranice před "
+"nahráním souboru a tedy nebudou zálohovány."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Zadejte prosím maximální čas, po kterém je nahrání změněného souboru na "
+"server vynuceno."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Zadán neplatný čas"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Zadejte prosím neprázdnou celočíselnou hodnotu větší než nula."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Příjemce výstražných upozornění:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"Jestliže se během zálohy vyskytne problém, klient BoxBackupu posílá "
+"výstražné upozornění."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Zadejte prosím jméno lokálního uživatele (například „root“) nebo poštovní "
+"adresu (například „spravce@priklad.cz“)."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Vytvořit privátní klíč klienta a požadavek na certifikát X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"Klient BoxBackupu vyžaduje privátní RSA klíč a odpovídající certifikát "
+"X.509, aby se mohl autentizovat vůči serveru."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Oba se mohou vytvořit automaticky. Požadavek na certifikát budete muset "
+"poslat správci BoxBackup serveru, který požadavek podepíše a pošle zpět "
+"současně s certifikátem certifikační autority serveru."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Tyto soubory by měly být nakopírovány do konfiguračního adresáře BoxBackupu. "
+"Očekávaná jména souborů jsou zadána v souboru /etc/boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Má se BoxBackup nastavit automaticky?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Konfigurační skripty balíku mohou vytvořit konfigurační soubory BoxBackup "
+"serveru."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Pokud zrovna nekamarádíte s konfiguračními volbami BoxBackupu, měli byste "
+"tuto možnost povolit. Konfiguraci můžete provést i ručně pomocí skriptů "
+"„raidfile-config“ a „bbstored-config“."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Dokud jej nenakonfigurujete, server se odmítne spustit. Každopádně je "
+"doporučeno přečíst si /usr/share/doc/boxbackup-client/README.Debian."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Umístění RAID adresářů:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Vyberte prosím umístění tří adresářů se souborovými RAIDy."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Pro povolení RAIDu zadejte mezerami oddělený seznam tří oblastí, kde každá "
+"by měla ležet na jiném fyzickém disku (například: „/raid/0.0 /raid/0.1 /"
+"raid/0.2“)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Nechcete-li povolit RAID, zadejte cestu k jedinému adresáři, do kterého se "
+"budou ukládat zálohy (například /usr/local/lib/boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Pokud neexistují, budou tyto adresáře vytvořeny."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Neplatné cesty"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Například: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Velikost bloku RAIDu v uživatelském prostoru:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup využívá techniky RAIDu v uživatelském prostoru."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Zadejte prosím velikost bloku, která se má použít pro úložiště. Pro "
+"maximální efektivitu byste měli zvolit stejnou velikost bloku, jakou má "
+"souborový systém, na kterém je úložiště postaveno (pro souborové systémy "
+"ext2 to zjistíte zjistíte například příkazem „tune2fs -l“)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr ""
+"Tuto hodnotu byste měli nastavit i v případě, že neplánujete použití RAIDu."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "Vytvořit privátní klíč serveru a požadavek na certifikát X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"BoxBackup server vyžaduje privátní RSA klíč a odpovídající certifikát X.509, "
+"aby mohl provádět autentizaci mezi klientem a serverem a aby mohl šifrovat "
+"komunikaci."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Oba se mohou vytvořit automaticky. Certifikát budete muset podepsat svou "
+"kořenovou certifikační autoritou (viz balík boxbackup-server) a podepsaný "
+"jej umístit společně s kořenovým certifikátem certifikační autority do "
+"složky s konfigurací."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Neplatná velikost bloku"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "Velikost bloku musí být mocninou dvou (např. 1024 nebo 4096)."
diff --git a/debian/po/da.po b/debian/po/da.po
new file mode 100644
index 00000000..d9ca9924
--- /dev/null
+++ b/debian/po/da.po
@@ -0,0 +1,515 @@
+# Danish translation BoxBackup.
+# Copyright (C) 2010 BoxBackup & Joe Hansen.
+# This file is distributed under the same license as the BoxBackup package.
+# Joe Hansen <joedalton2@yahoo.dk>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: BoxBackup\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2010-05-18 17:30+01:00\n"
+"Last-Translator: Joe Hansen <joedalton2@yahoo.dk>\n"
+"Language-Team: Danish <debian-l10n-danish@lists.debian.org> \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Skal klienten til BoxBackup konfigureres manuelt?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Pakkekonfigurationsskripterne kan oprette konfigurationsfiler for klienten "
+"til BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Du skal vælge denne indstilling, hvis du ikke kender til BoxBackups "
+"konfigurationsindstillinger."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Læs venligst /usr/share/doc/boxbackup-client/README.Debian for detaljer om "
+"konfigurationen til BoxBackup-klienten."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Kørselstilstand for klienten til BoxBackup:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr ""
+"Klienten til BoxBackup understøtter to tilstande til sikkerhedskopiering:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"I tilstanden 'lazy' vil dæmonen til sikkerhedskopiering med passende "
+"mellemrum skanne filsystemet på jagt efter ændrede filer. Den vil så "
+"overføre filer ældre end en angivet alder til sikkerhedskopiserveren."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"I tilstanden 'snapshot' vil sikkerhedskopien blive kørt med faste "
+"intervaller. Et cronjob (/etc/cron.d/boxbackup-client) tilbydes sammen med "
+"pakken og skal tilpasses til dine behov."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Kontonummer for denne knude på sikkerhedskopiserveren:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"Administratoren på BoxBackup-serveren skal have tildelt denne klient et "
+"heksadecimalt kontonummer."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Hvis intet kontonummer er blevet tildelt endnu, så efterlad dette felt tomt "
+"og konfigurer det senere ved at køre 'dpkg-reconfigure boxbackup-client' som "
+"administrator (root)."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Ugyldigt kontonummer"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+"Kontonummeret skal være et heksadecimalt nummer (såsom 1F04 eller 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Fuldt kvalificeret domænenavn på sikkerhedskopiserveren:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Indtast venligt det fuldt kvalificeret domænenavn på den BoxBackup-server "
+"som din klient vil bruge."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Klienten vil forbinde til serveren på TCP port 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Liste af mapper der skal sikkerhedskopieres:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Angiv venligst en mellemrumsadskilt liste af mapper der skal "
+"sikkerhedskopieres til den eksterne server."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"De mapper må ikke indeholde monterede filsystemer på noget niveau i deres "
+"undermapper."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Ugyldigt stinavn"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Stinavnene til mapperne skal være absolutte stinavne, adskilt af mellemrum."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "For eksempel. /home/myaccount /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Interval (i sekunder) mellem mappeskanninger:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup skanner med faste intervaller de udvalgte mapper, på jagt efter "
+"ændrede filer."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Vælg venligst skanningsinterval i sekunder."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Minimum ventetid (i sekunder) før overførsel af en fil:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"En fil vil først blive overført til serveren efter et bestemt tidsinterval "
+"efter sidste ændring."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Lave intervalværdier vil udløse ofte overførsler til serveren og flere "
+"revisioner oprettes, hvilket medfører at gamle revisioner vil blive fjernet "
+"tidligere."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Maksimal ventetid (i sekunder) før overførsel af en fil:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Ofte ændrede filer vil højst sandsynlig aldrig blive overført, hvis de "
+"aldrig når den mindste ventetid."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Indtast venligst den maksimale tid før en ændret fil bliver overført til "
+"serveren."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Ugyldig tid indtastede"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Indtast venligst en heltalsværdi større end nul."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Modtager til alarmbeskeder:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"Klienten til BoxBackup sender alarmbeskeder, når et problem opstår under "
+"sikkerhedskopieringen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Indtast venligst enten et lokalt brugernavn (for eksempel 'root') eller en e-"
+"post-adresse (for eksempel 'admin@eksempl.org')."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Opret klientens private nøgle og X-509-certifikatanmodning?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"Klienten til BoxBackup kræver en RSA-privatnøgle og det tilsvarende X.509-"
+"certificat for at kunne dokumentere sig selv i forhold til serveren."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Begge kan oprettes automatisk. Du vil skulle sende certifikatanmodningen til "
+"BoxBackups serveradministrator som vil underskrive den og sende den tilbage "
+"til dig sammen med serverens Certification Authority-certifikat."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Disse filer skal kopiers ind i BoxBackups konfigurationsmappe. Filnavnene "
+"der skal bruges er oplyst i filen /etc/boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Skal BoxBackup automatisk konfigureres?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Skriptene for pakkekonfigurationen kan oprette konfigurationsfilerne for "
+"BoxBackup-serveren."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Du skal vælge denne indstilling hvis du ikke kender til BoxBackups "
+"konfigurationsindstillinger. Denne konfiguration kan foretages manuelt med "
+"skripterne 'raidfile-config' og 'bbstored-config'."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Serveren vil ikke starte hvis den ikke er konfigureret. Uanset hvad så "
+"anbefales det at læse /usr/share/doc/boxbackup-server/README.Debian."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Placering af RAID-mapperne:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Vælg venligst placeringen af de tre RAID-filmapper."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"For at aktivere RAID, skal mappenavnene være en mellemrumsadskilt liste af "
+"tre partitioner, hver på forskellige fysiske harddiske (for eksempel: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Hvis du ikke ønsker at aktivere RAID, så specificer bare stien til en mappe "
+"hvor sikkerhedskopierne vil blive gemt (for eksempel, /usr/local/lib/"
+"boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Disse mapper vil blive oprettet, hvis de ikke findes."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Ugyldige stinavne"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "For eksempel: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Blokstørrelse for userland-RAID-systemet:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup bruger userland-RAID-teknikker."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Vælg venligst blokstørrelse til brug for lageret. For maksimal effektivitet, "
+"skal du vælge blokstørrelsen på det underlæggende filsystem (som kan ses for "
+"ext2-filsystemer med kommandoen 'tune2fs -l')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Denne værdi skal angives, selv om du ikke planlægger at bruge RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "Opret en serverprivatnøgle og X.509-certifikatforespørgsel?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"BoxBackup-serveren kræver en RSA-privatnøgle og den tilsvarende X.509-"
+"certificat for at udføre klient-server bekræftelse og kryptering af "
+"kommunikation."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Begge kan oprettes automatisk. Du vil skulle underskrive certifikatet med "
+"din root CA (se pakken boxbackup-server) og placer dette underskrevne "
+"certificat og root CA-certifikatet i konfigurationsmappen."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Ugyldig blokstørrelse"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "Blokstørrelsen skal kunne opløses i 2 (for eksempel 1024 eller 4096)."
diff --git a/debian/po/de.po b/debian/po/de.po
new file mode 100644
index 00000000..20eca289
--- /dev/null
+++ b/debian/po/de.po
@@ -0,0 +1,526 @@
+# Translation of the boxbackup debconf template.
+# Copyright (C) 2008 Kai Wasserbäch <debian@carbon-project.org>
+# This file is distributed under the same license as boxbackup package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup 0.10+really0.10-1\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2008-02-13 22:06+0100\n"
+"Last-Translator: Kai Wasserbäch <debian@carbon-project.org>\n"
+"Language-Team: German <debian-l10n-german@lists.debian.org>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Soll der BoxBackup-Client automatisch konfiguriert werden?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Die Paket-Konfigurations-Skripte können die Konfigurationsdateien für den "
+"BoxBackup-Client erstellen."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Sie sollten diese Option wählen, falls Sie nicht mit den "
+"Konfigurationsoptionen von BoxBackup vertraut sind."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Bitte lesen Sie für detaillierte Informationen zur Konfiguration des "
+"BoxBackup-Clients die Datei /usr/share/doc/boxbackup-client/README.Debian."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Betriebsmodus für den BoxBackup-Client:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "Der BoxBackup-Client unterstützt zwei Backup-Modi:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"Im »lazy«-Modus prüft der Sicherungsdienst das Dateisystem regelmäßig, um "
+"veränderte Dateien zu finden. Dateien, die ein zuvor festgelegtes Alter "
+"überschritten haben, werden auf den Sicherungsserver überspielt."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"Im »snapshot«-Modus wird die Sicherung in zuvor festgelegten Abständen "
+"durchgeführt. Eine Cron-Datei (/etc/cron.d/backup-client) wird mit diesem "
+"Paket ausgeliefert und sollte an die eigenen Anforderungen angepasst werden."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Kontennummer für diesen Knoten auf dem Sicherungsserver:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"Der Administrator des BoxBackup-Servers sollte diesem Client eine "
+"hexadezimale Kontennummer zugewiesen haben."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Falls bislang noch keine Kontennummer zugewiesen wurde, lassen Sie dieses "
+"Feld frei und konfigurieren Sie die Option später durch Ausführen des "
+"Befehls »dpkg-reconfigure boxbackup-client« als root."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Ungültige Kontennummer"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+"Die Kontennummer muss hexadezimal sein (wie zum Beispiel 1F04 oder 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Vollständiger Domainname des Sicherungsservers:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Bitte geben Sie den durch Ihren Client zu verwendenden vollständigen "
+"Domainnamen des BoxBackup-Servers an."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Der Client wird sich mit dem Server auf dem TCP-Port 2201 verbinden."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Liste der zu sichernden Verzeichnisse:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Bitte geben Sie die auf den entfernten Server zu sichernden Verzeichnisse "
+"als durch Leerzeichen getrennte Liste ein."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Diese Verzeichnisse sollten in keinem Unterverzeichnis ein eingebundenes "
+"Dateisystem enthalten."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Ungültige Pfadangabe"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Die Pfade zu den Verzeichnissen müssen absolut sein und durch Leerzeichen "
+"getrennt angegeben werden."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Zum Beispiel: /home/meinkonto /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Intervall (in Sekunden) zwischen Verzeichnisüberprüfungen:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup überprüft die ausgewählten Verzeichnisse von Zeit zu Zeit auf "
+"modifizierte Dateien."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Bitte wählen Sie das Überprüfungsintervall in Sekunden."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Mindestwartezeit (in Sekunden) vor dem Hochladen einer Datei:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Eine Datei wird erst eine bestimmte Zeit nach der letzten Modifikation auf "
+"den Server übertragen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Kleine Intervalle resultieren in häufigeren Uploads auf den Server. Dabei "
+"werden mehr Revisionen angelegt und alte früher gelöscht."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Maximale Wartezeit (in Sekunden) bevor eine Datei hochgeladen wird:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Häufig modifizierte Dateien werden wahrscheinlich nie auf den Server "
+"übertragen, falls sie die minimale Wartezeit nicht erreichen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Bitte geben sie die Zeit ein, die maximal erreicht werden darf, bevor das "
+"Hochladen einer Datei erzwungen wird."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Ungültige Zeit eingegeben"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Bitte geben Sie einen ganzzahligen Wert größer Null ein."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Empfänger für Alarmmeldungen:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"Der BoxBackup-Client versendet Alarmmeldungen, wenn während des Sicherns ein "
+"Problem auftritt."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Bitte geben Sie entweder einen lokalen Benutzernamen (zum Beispiel »root«) "
+"oder eine E-Mail-Adresse (zum Beispiel »admin@example.org«) ein."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr ""
+"Soll der private Schlüssel für den Client und der X.509-Zertifikat-Anfrage "
+"erzeugt werden?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"Der BoxBackup-Client benötigt einen privaten RSA-Schlüssel und das "
+"zugehörige X.509-Zertifikat, um sich gegenüber dem Server authentifizieren "
+"zu können."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Beides kann automatisch erzeugt werden. Sie müssen die Zertifikatanfrage an "
+"den Administrator des BoxBackup-Servers senden, der dieses dann signieren "
+"und Ihnen zusammen mit dem Certification-Authority-Zertifikat des Servers "
+"zurücksenden wird."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Diese Dateien sollten in das Konfigurationsverzeichnis von BoxBackup kopiert "
+"werden. Die zu verwendenden Dateinamen werden in /etc/boxbackup/bbacupd.conf "
+"angegeben."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Soll BoxBackup automatisch konfiguriert werden?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Die im Paket enthaltenen Konfigurationskripte können die Konfiguration für "
+"den BoxBackup-Server erzeugen."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Sie sollten diese Option wählen, falls Sie nicht mit den "
+"Konfigurationsoptionen von BoxBackup vertraut sind. Die Konfiguration kann "
+"mit Hilfe der Skripte »raidfile-config« und »bbstored-config« manuell "
+"vorgenommen werden."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Der Server wird nicht starten, falls er nicht konfiguriert wurde. In jedem "
+"Fall wird empfohlen, /usr/share/doc/boxbackup-server/README.Debian zu lesen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Ort der RAID-Verzeichnisse:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Bitte wählen Sie den Ort für die drei RAID-Datei-Verzeichnisse aus."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Um die RAID-Funktion zu aktivieren, sollte eine durch Leerzeichen getrennte "
+"Liste dreier Partitionen eingegeben werden. Jede dieser Partitionen sollten "
+"auf einem anderen physischen Laufwerk sein (zum Beispiel »/raid/0.0 /"
+"raid/0.1 /raid/0.2«)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Falls Sie die RAID-Funktion nicht aktivieren wollen, geben Sie einfach einen "
+"Pfad zu einem Verzeichnis an, in dem die Sicherungskopien gespeichert werden "
+"sollen (zum Beispiel /usr/local/lib/boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Diese Verzeichnisse werden angelegt, sollten sie nicht existieren."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Ungültige Pfadnamen"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Zum Beispiel: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Blockgröße für das im Benutzerbereich angesiedelte RAID-System:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup verwendet RAID-Techniken für den Benutzerbereich."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Bitte wählen Sie die zu verwendende Blockgröße zur Speicherung. Um maximale "
+"Effizienz zu erreichen, sollten Sie die Blockgröße des darunterliegenden "
+"Dateisystems wählen. Diese kann für Ext-Dateisysteme mit dem Befehl »tune2fs "
+"-l« angezeigt werden."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr ""
+"Dieser Wert sollte auch dann angegeben werden, falls Sie kein RAID verwenden "
+"wollen."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr ""
+"Soll ein privater Server-Schlüssel und eine X.509-Zertifikatanfrage erzeugt "
+"werden?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"Der BoxBackup-Server benötigt einen privaten RSA-Schlüssel und ein "
+"zugehöriges X.509-Zertifikat, um die Client-Server-Authentifizierung "
+"durchführen zu können und die Kommunikation zu verschlüsseln."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Beides kann automatisch erzeugt werden. Sie müssen das Zertifikat mit Ihrem "
+"Wurzel-CA-Zertifikat signieren (siehe das Paket »boxbackup-server«) und das "
+"signierte Zertifikat sowie das Wurzel-CA-Zertifikat in Ihrem "
+"Konfigurationsordner ablegen."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Ungültige Blockgröße."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "Die Blockgröße muss eine Potenz von Zwei sein (z.B. 1024 oder 4096)."
diff --git a/debian/po/es.po b/debian/po/es.po
new file mode 100644
index 00000000..cf7bb72e
--- /dev/null
+++ b/debian/po/es.po
@@ -0,0 +1,549 @@
+# boxbackup po-debconf translation to Spanish
+# Copyright (C) 2009 Software in the Public Interest
+# This file is distributed under the same license as the boxbackup package.
+#
+# Changes:
+# - Initial translation
+# Omar Campagne <ocampagne@gmail.com>, 2009
+#
+# - Updates
+# TRADUCTOR <CORREO>, AÑO
+#
+# Traductores, si no conocen el formato PO, merece la pena leer la
+# de gettext, especialmente las secciones dedicadas a este
+# formato, por ejemplo ejecutando:
+# info -n '(gettext)PO Files'
+# info -n '(gettext)Header Entry'
+#
+# Equipo de traducción al español, por favor, lean antes de traducir
+# los siguientes documentos:
+#
+# - El proyecto de traducción de Debian al español
+# http://www.debian.org/intl/spanish/
+# especialmente las notas de traducción en
+# http://www.debian.org/intl/spanish/notas
+#
+# - La guía de traducción de po's de debconf:
+# /usr/share/doc/po-debconf/README-trans
+# o http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.11\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2009-07-16 18:15+0200\n"
+"Last-Translator: Omar Campagne <ocampagne@gmail.com>\n"
+"Language-Team: Debian l10n Spanish <debian-l10n-spanish@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "¿Desea que el cliente de BoxBackup se configure automáticamente?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"El paquete de scripts de configuración puede generar los archivos de "
+"configuración para el cliente de BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Debería escoger esta opción si no está familiarizado con las opciones de "
+"configuración de BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Lea el archivo «/usr/share/doc/boxbackup-client/README.Debian» para más "
+"detalles acerca de la configuración del cliente de BoxBackup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Modo de ejecución para el cliente de BoxBackup:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "El cliente de BoxBackup ofrece dos modos de copia de seguridad:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"En modo «lazy» (vago), el demonio de copia de seguridad examinará con "
+"regularidad el sistema de archivos en busca de archivos modificados. "
+"Finalizado esto, subirá los archivos de una antigüedad específica al "
+"servidor de copias de seguridad."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"En modo «snapshot» (captura de imagen), la copia de seguridad se generará a "
+"intervalos regulares. Un archivo cron (/etc/cron.d/boxbackup-client) se "
+"incluye en el paquete, el cual puede modificar para satisfacer sus "
+"necesidades."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Número de cuenta de este nodo en el servidor de copia de seguridad:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"El administrador del servidor de BoxBackup debería haber asignado a este "
+"cliente un número de cuenta hexadecimal."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Si no ha asignado aún ningún número de cuenta, deje este campo en blanco y "
+"configúrelo más tarde ejecutando «dpkg-reconfigure boxbackup-client» como "
+"administrador."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Número de cuenta no válido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+"El número de cuenta debe ser un número hexadecimal (p. ej., «1F04» o «4500»)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Nombre de dominio completo del servidor de copias de seguridad:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Introduzca el nombre de dominio completo del servidor de BoxBackup que el "
+"cliente usará."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "El cliente se conectará al servidor a través del puerto TCP 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Lista de directorios de los cuales crear una copia de seguridad:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Introduzca una lista de directorios, separados por un espacio, de los cuales "
+"crear una copia de seguridad en el servidor remoto."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Esos directorios no pueden contener sistemas de archivos montados en ningún "
+"nivel de sus subdirectorios."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Nombre de ruta no válido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Los nombres de ruta de los directorios deben ser nombres de ruta absolutos, "
+"separados por espacios."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Por ejemplo: «/home/tucuenta /etc/»"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Intervalo de tiempo (en segundos) entre exploraciones de directorios:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"Boxbackup explora los directorios seleccionados con regularidad en busca de "
+"archivos modificados."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Seleccione el intervalo entre cada exploración en segundos."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Tiempo mínimo de espera (en segundos) antes de subir un archivo:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Un archivo se sube al servidor sólo después de un tiempo especifico desde su "
+"última modificación."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Un valor bajo de intervalo propicia subidas de archivos más regulares al "
+"servidor, generando más revisiones y haciendo que las revisiones más "
+"antiguas se eliminen antes."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Tiempo máximo de espera (en segundos) antes de subir un archivo:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Puede que los archivos modificados con frecuencia no se suban si nunca "
+"alcanzan el tiempo mínimo de espera."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Introduzca el tiempo máximo de espera antes de forzar la subida de un "
+"archivo modificado."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Tiempo introducido no válido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Introduzca un valor entero mayor que 0."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Destinatario de las notificaciones de alerta:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"El cliente de BoxBackup envía notificaciones de alerta cuando ocurre un "
+"problema durante la creación de la copia de seguridad."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Introduzca un nombre de usuario local (por ejemplo, «root») o una dirección "
+"de correo electrónico (por ejemplo, «admin@example.org»)."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr ""
+"¿Desea generar la clave privada del cliente y la petición de certificado "
+"X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"El cliente de BoxBackup necesita una clave privada RSA y su correspondiente "
+"certificado X.509 para autenticarse con el servidor."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Ambos pueden ser generados automáticamente. Necesitará enviar la petición de "
+"certificado al administrador del servidor de BoxBackup, el cual lo firmará y "
+"reenviará a usted junto con el certificado de la «CA» (Autoridad de "
+"Certificación) del servidor."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Estos archivos se deberían copiar en el directorio de configuración de "
+"BoxBackup. Los nombres de archivo empleados se encuentran en el archivo «/"
+"etc/boxbackup/bbackupd.conf»."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "¿Desea que BoxBackup se configure automáticamente?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Los scripts de configuración del paquete pueden generar los archivos de "
+"configuración del servidor de BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Debería escoger esta opción si no está familiarizado con las opciones de "
+"configuración de BoxBackup. Puede configurarlo manualmente, o mediante los "
+"scripts «raidfile-config» y «bbstored-config»."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"El servidor no se iniciará si no está configurado. En cualquier caso, se "
+"recomienda leer «/usr/share/doc/boxbackup-server/README.Debian»."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Ubicación de los directorios RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Escoja la ubicación de los tres directorios RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Para habilitar RAID, los nombres de directorio deberían conformar una lista "
+"de tres particiones, separando cada elemento del mismo con un espacio, y "
+"cada uno de ellos en diferentes discos duros físicos (por ejemplo: «/"
+"raid/0.0 /raid/0.1 /raid/0.2»)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Si no desea habilitar RAID, especifique sólo la ruta a un directorio donde "
+"poder guardar las copias de seguridad (p. ej., «/usr/local/lib/boxbackup»)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "En caso de no existir, se crearán estos directorios."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Nombres de ruta no válidos"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Por ejemplo: «/raid/0.0 /raid/0.1 /raid/0.2»"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Tamaño de bloque para el sistema «userland» de RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup utiliza técnicas «userland» de RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Escoja el tamaño de bloque empleado para el almacenamiento. Para obtener la "
+"máxima eficiencia, debería escoger el tamaño de bloque del sistema de "
+"archivos subyacente (el cual se muestra en los sistemas de archivos ext2 "
+"ejecutando la orden «tune2fs -l»)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Debe definir este valor aunque no tenga planeado utilizar RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr ""
+"¿Desea generar una clave privada de servidor y la petición de certificado "
+"X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"El servidor «BoxBackup» requiere una clave privada RSA y el correspondiente "
+"certificado X.509 para la autenticación cliente-servidor y el cifrado de "
+"comunicaciones."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Ambos pueden ser generados automáticamente. Necesitará firmar el certificado "
+"con su «CA» raíz (vea el paquete «boxbackup-server») y poner este "
+"certificado firmado y el certificado de la «CA» raíz en el directorio de "
+"configuración."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Tamaño de bloque no válido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "El tamaño del bloque ha de ser potencia de dos (p. ej., 1024 o 4096)."
diff --git a/debian/po/eu.po b/debian/po/eu.po
new file mode 100644
index 00000000..ff3d71b8
--- /dev/null
+++ b/debian/po/eu.po
@@ -0,0 +1,527 @@
+# translation of boxbackup debconf to Basque
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# xabier bilbao <xabidu@gmail.com>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup-eu\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2008-06-03 02:21+0200\n"
+"Last-Translator: xabier bilbao <xabidu@gmail.com>\n"
+"Language-Team: basque <debian-l10n-basque@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "BoxBackup bezeroa automatikoki konfiguratu behar al da?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Paketearen konfigurazio script-ek BoxBackup bezeroarentzako konfigurazio-"
+"fitxategiak sor ditzakete."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Aukera hau hautatu beharko zenuke ez baldin badituzu Boxbackup-en "
+"konfigurazio-aukerak ondo ezagutzen."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"BoxBackup bezeroaren konfigurazioaz xehetasun gehiago jakiteko, irakur "
+"ezazu /usr/share/doc/boxbackup-client/README.Debian."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "BoxBackup bezeroaren exekuzio-modua:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "BoxBackup bezeroak bi modutara egin dezake babeskopia:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"'Lazy' (sinplifikatu) moduan, babeskopia-deabruak fitxategi-sistema aldiro "
+"arakatuko du aldatutako fitxategien bila. Data jakin bat baino zaharragoak "
+"diren fitxategiak babeskopien zerbitzarira igoko ditu."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"'Snapshot' (argazki) moduan, babeskopia aldiro exekutatuko da. Cron "
+"fitxategi bat (/etc/cron.d/boxbackup-client) dakar paketeak, norberaren "
+"beharren arabera egokitu behar dena."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Nodo honentzako kontu-zenbakia babeskopien zerbitzarian:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"Bezero honek kontu-zenbaki hamaseitar bat izan behar luke BoxBackup "
+"zerbitzariaren administratzaileak ezarririk."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Oraindik ez bazaio kontu-zenbakirik ezarri, utzi bete gabe arlo hau eta "
+"konfigura ezazu geroago, 'dpkg-reconfigure boxbackup-client' root gisa "
+"exekutatuz."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Kontu-zenbaki baliogabea"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+"Zenbaki hamaseitarra izan behar da kontu-zenbakia (1F04 edo 4500 erakoa)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Babeskopia-zerbitzariaren guztiz kualifikaturiko domeinu-izena (FQDN):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Sar ezazu hemen zure bezeroak erabiliko duen BoxBackup zerbitzariaren guztiz "
+"kualifikaturiko domeinu-izena."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Bezeroa TCP 2201 atakan konektatuko da zerbitzarira."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Babeskopian gordetzeko direktorioen zerrenda:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Zerrenda itzazu, tarte soilez banatuta, urruneko zerbitzarian babeskopian "
+"gordetzeko direktorioak."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Direktorio horiek ez lukete eduki behar muntatutako fitxategi-sistemarik "
+"haien azpidirektorioetako edozein mailatan."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Bide-izen baliogabea"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Direktorioetarako bide-izen absolutuak idatzi behar dira, tartez banaturik."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Adibidez: /home/nirekontua /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Denbora-tartea (segundotan) direktorioen arakatzeen artean:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup-ek aldiro arakatzen ditu aukeratu diren direktorioak, aldatutako "
+"fitxategien bila."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Zehaztu ezazu arakatzea zenbatero egin behar den."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr ""
+"Fitxategi bat igo aurretik itxaron beharreko gutxieneko denbora (segundotan):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Denbora jakin bat itxarongo du programak fitxategi bakoitza, aldaketak jaso "
+"ondoren, zerbitzarira igo aurretik."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Arakatzeetarako denbora tarte txikiak ezarriz gero, sarri igoko dira "
+"fitxategiak zerbitzarira, eta sarri berrituko dira babeskopiak, ondorioz "
+"kopia zaharrak lehenago ezabatuz."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr ""
+"Fitxategi bakoitza igo aurretik itxaron beharreko gehienezko denbora "
+"(segundotan):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Sarri aldatzen diren fitxategiak zerbitzarira inoiz ere igo gabe geldi "
+"daitezke, ez badute gutxieneko denbora irauten aldatu gabe."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Sar ezazu itxaron beharreko gehienezko denbora aldatutako fitxategi bakoitza "
+"zerbitzarira igo aurretik."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Denbora baliogabea sartu duzu"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Sar ezazu balio oso bat, zero baino handiagoa."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Alerta abisuen hartzailea:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"BoxBackup bezeroak alerta abisuak bidaltzen ditu babeskopia egitean arazoren "
+"bat gertatzen denean."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Sar ezazu erabiltzaile-izen lokal bat (adibidez, 'root') edo eposta helbide "
+"bat (adibidez, 'admin@adibidea.org')."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr ""
+"Bezeroarentzako gako pribatua eta X.509 ziurtagiriaren eskaera sortzea nahi "
+"duzu?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"BoxBackup bezeroak RSA gako pribatua eta hari dagokion X.509 ziurtagiria "
+"behar ditu bere burua zerbitzarian egiaztatzeko."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Biak automatikoki sor daitezke. Ziurtagiri-eskaera BoxBackup zerbitzariko "
+"administratzaileari bidali beharko diozu. Hark izenpetuko du eta atzera zuri "
+"bidaliko dizu zerbitzariko Ziurtagiri Emailearen (CA) ziurtagiriarekin "
+"batera."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Fitxategi horiek BoxBackup-en konfigurazio direktoriora kopiatu behar dira. "
+"Fitxategiei eman beharreko izenak /etc/boxbackup/bbackupd.conf fixategian "
+"aurkituko dituzu."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "BoxBackup automatikoki konfiguratu?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Paketearen konfigurazio script-ek BoxBackup zerbitzarirako konfigurazio-"
+"fitxategiak sor ditzakete."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Hauta ezazu bide hau ez badituzu BoxBackup-en konfigurazio aukerak ondo "
+"ezagutzen. Konfigurazioa eskuz egin daiteke 'raidfile-config' eta 'bbstored-"
+"config' script-en bidez."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Zerbitzaria ez da abiatuko konfiguraturik ez badago. Zure kasua edozein dela "
+"ere, gomendagarria da /usr/share/doc/boxbackup-server/README.Debian "
+"irakurtzea."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "RAID direktorioen kokalekua:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Aukera ezazu hiru RAID fitxategi-direktorioen kokalekua."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"RAID kudeaketa gaitzeko, hiru partizioren zerrenda gisa eman behar dira "
+"direktorio-izenak, tarte hutsez banaturik, eta direktorio bakoitza disko "
+"gogor fisiko batean kokaturik (adibidez: '/raid/0.0 /raid/0.1 /raid/0.2')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"RAID kudeaketa gaitu nahi ez baduzu, nahikoa duzu direktorio baterako bidea "
+"ematea, babeskopiak bertan gorde daitezen (adibidez, /usr/local/lib/"
+"boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Direktorio hauek sortu egingo dira aurretik ez badaude."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Bide-izen baliogabeak"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Adibidez: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Userland (erabiltzaile-eremuko) RAID sistemarako bloke-tamaina:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "Boxbackup-ek userland (erabiltzaile-eremuko) RAID sistema darabil."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Aukera ezazu biltegiratzerako erabiliko den bloke-tamaina. Eraginkortasun "
+"handiena lortzeko, aukera ezazu azpiko fitxategi-sistemak duen bloke-tamaina "
+"bera (hura zein den ikusteko 'tune2fs -l' komandoa erabil daiteke ext2 "
+"fitxategi-sistemen kasuan)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Balio hau ezarri beharra dago, RAID erabiltzeko asmoa ez baduzu ere."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr ""
+"Zerbitzarirako gako pribatua eta X.509 ziurtagiriaren eskaera sortzea nahi "
+"duzu?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"BoxBackup bezeroak RSA gako pribatua eta hari dagokion X.509 ziurtagiria "
+"behar ditu bezero/zerbitzari egiaztapena eta komunikazio-enkriptazioa "
+"gauzatzeko."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Automatikoki sor daitezke biak. Horretarako, ziurtagiria sinatu beharko dizu "
+"zure Ziurtagiri Emaile (CA) nagusiak (ikus boxbackup-server paketea) eta "
+"sinaturiko ziurtagiria, root (erro) CAren ziurtagiriarekin batera, "
+"konfigurazio-karpetan kokatu beharko duzu."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Bloke-tamaina baliogabea"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "Bloke-tamainak biren berredura izan behar du (adb. 1024 edo 4096)."
diff --git a/debian/po/fi.po b/debian/po/fi.po
new file mode 100644
index 00000000..da150ff4
--- /dev/null
+++ b/debian/po/fi.po
@@ -0,0 +1,504 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2008-06-03 23:20+0200\n"
+"Last-Translator: Esko Arajärvi <edu@iki.fi>\n"
+"Language-Team: Finnish <debian-l10n-finnish@lists.debian.org>\n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Finnish\n"
+"X-Poedit-Country: FINLAND\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Tulisiko BoxBackup-asiakkaan asetukset tehdä automaattisesti?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"BoxBackup-asiakkaan asetustiedostot voidaan luoda paketin "
+"asetuskomentosarjoilla."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr "Valitse tämä, jos BoxBackupin asetusvalitsimet eivät ole tuttuja."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Lisätietoja BoxBackup-asiakkaan asetuksista löytyy tiedostosta /usr/share/"
+"doc/boxbackup-client/README.Debian."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "BoxBackup-asiakkaan ajotapa:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "BoxBackup-asiakas tukee kahdenlaisia varmuuskopioita:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"Laiska tapa (”lazy”) tarkoittaa, että taustaohjelma säännöllisesti etsii "
+"tiedostojärjestelmästä muuttuneita tiedostoja. Tämän jälkeen tiettyä ikää "
+"vanhemmat tiedostot kopioidaan varmuuskopiopalvelimelle."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"Levykuvatapa (”snapshot”) tarkoittaa, että varmuuskopio otetaan säännöllisin "
+"aikavälein. Paketissa on mukana cron-tiedosto (/etc/cron.d/boxbackup-"
+"client), joka tulisi mukauttaa tarpeisiin."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Tämän solmun tilinumero varmuuskopiopalvelimella:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"BoxBackup-palvelimen ylläpitäjän olisi tullut antaa tälle asiakkaalle "
+"heksadesimaalinen tilinumero."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Jos tilinumeroa ei ole vielä annettu, jätä kenttä tyhjäksi ja aseta se "
+"myöhemmin ajamalla pääkäyttäjänä komento ”dpkg-reconfigure boxbackup-client”."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Virheellinen tilinumero"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr "Tilinumeron tulee olla heksadesimaaliluku (kuten 1F04 tai 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Varmuuskopiopalvelimen täydellinen verkkonimi:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr "Anna asiakkaan käyttämän BoxBackup-palvelimen täydellinen verkkonimi."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Asiakas ottaa yhteyden palvelimen TCP-porttiin 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Hakemistot, joista otetaan varmuuskopiot:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Anna välilyönnein eroteltu lista hakemistoista, joista tehdään varmuuskopiot "
+"etäpalvelimelle."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Näiden hakemistojen ei tulisi sisältää liitettyjä tiedostojärjestelmiä "
+"millään alihakemistojen tasolla."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Virheellinen polku"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Hakemistojen polkujen tulee olla täydellisiä ja ne tulee erottaa toisistaan "
+"välilyönnein."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Esimerkiksi: /home/omahakemisto /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Hakemistojen skannausten välinen aika (sekunteina):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup säännöllisesti skannaa valitut hakemistot etsien muutettuja "
+"tiedostoja."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Anna skannausten aikaväli sekunteina."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Vähimmäisodotusaika (sekunteina) ennen tiedoston kopioimista:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Tiedosto kopioidaan palvelimelle vasta, kun sen viimeisimmästä muokkauksesta "
+"on kulunut tietty aika."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Lyhyt aika-arvo aiheuttaa tiheitä kopiointeja palvelimelle, jolloin luodaan "
+"useampia versioita ja vanhemmat versiot poistetaan aiemmin."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Enimmäisodotusaika (sekunteina) ennen tiedoston kopioimista:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Usein muokattuja tiedostoja ei kopioida koskaan talteen, jos muokkausten "
+"välissä ei ole vähimmäisodotusaikaa."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Anna enimmäisaika, jonka jälkeen muokattu tiedosto kopioidaan pakolla "
+"palvelimelle."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Virheellinen aika annettu"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Anna nollaa suurempi kokonaisluku."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Varoitusviestien vastaanottaja:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"BoxBackup-asiakas lähettää varoitusviestejä, kun varmuuskopioiden otossa "
+"ilmenee ongelmia."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Anna joko paikallinen käyttäjätunnus (esimerkiksi ”root”) tai "
+"sähköpostiosoite (esimerkiksi ”admin@example.org”)."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Luodaanko salattu asiakasavain ja X.509-varmennepyyntö?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"BoxBackup-asiakas tarvitsee salatun RSA-avaimen ja sitä vastaavan X.509-"
+"varmenteen tunnistautuakseen palvelimelle."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Molemmat voidaan luoda automaattisesti. Varmennepyyntö tulee lähettää "
+"BoxBackup-palvelimen ylläpitäjälle, joka allekirjoittaa sen ja lähettää sen "
+"takaisin palvelimen varmentaja-varmenteen kanssa."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Nämä tiedostot tulisi kopioida BoxBackupin asetustiedostoon. Käytettävät "
+"tiedostonimet on annettu tiedostossa /etc/boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Tulisiko BoxBackupin asetukset tehdä automaattisesti?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"BoxBackup-palvelimen asetustiedostot voidaan luoda paketin "
+"asetuskomentosarjoilla."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Valitse tämä, jos BoxBackupin asetusvalitsimet eivät ole tuttuja. Asetukset "
+"voidaan tehdä käsin komentosarjoilla ”raidfile-config” ja ”bbstored-config”."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Palvelin ei käynnisty ennen kuin sen asetukset on tehty. On joka tapauksessa "
+"suositeltavaa lukea tiedosto /usr/share/doc/boxbackup-server/README.Debian."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "RAID-hakemistojen sijainti:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Anna kolmen RAID-tiedostohakemiston sijainnit."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"RAIDin ottaminen käyttöön vaatii, että annetut hakemistot ovat kolmen, eri "
+"fyysisillä kovalevyillä sijaitsevan osion välilyönnein eroteltu lista. "
+"(esimerkiksi: ”/raid/0.0 /raid/0.1 /raid/0.2”)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Jos RAIDia ei haluta käyttää, anna vain yhden hakemiston polku (esimerkiksi: "
+"”/usr/local/lib/boxbackup”). Varmuuskopiot tallennetaan tänne."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Nämä hakemistot luodaan, jos niitä ei vielä ole olemassa."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Virheellisiä polkuja"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Esimerkiksi: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Userland RAID -järjestelmien lohkokoko:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup käyttää userland RAID -tekniikoita."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Valitse varastossa käytettävä lohkokoko. Paras tehokkuus saadaan, jos "
+"lohkokoko on sama kuin alla olevassa tiedostojärjestelmässä (joka saadaan "
+"ext2-tiedostojärjestelmässä näkyviin komennolla ”tune2fs -l”)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Tämä arvo tulisi asettaa, vaikka RAIDia ei aiottaisi käyttää."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "Luodaanko salainen palvelinavain ja X.509-varmennepyyntö?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"BoxBackup-palvelin tarvitsee salaisen RSA-avaimen ja sitä vastaavan X.509-"
+"varmenteen asiakkaiden ja palvelimen väliseen tunnistautumiseen ja "
+"viestinnän salaamiseen."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Molemmat voidaan luoda automaattisesti. Varmenne tulee allekirjoittaa "
+"juurivarmenteella (”root CA”, katso pakettia boxbackup-server). "
+"Allekirjoitettu varmenne ja juurivarmenne tulee laittaa ohjelman "
+"asetustiedostoon."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Virheellinen lohkokoko"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "Lohkokoon tulee olla kahden potenssi (esim. 1024 tai 4096)."
diff --git a/debian/po/fr.po b/debian/po/fr.po
new file mode 100644
index 00000000..6294c5aa
--- /dev/null
+++ b/debian/po/fr.po
@@ -0,0 +1,526 @@
+# Copyright (C) 2007, Vincent Bernat <bernat@luffy.cx>
+# This file is distributed under the same license as the boxbackup package.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup_0.10-1\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2007-06-26 07:42+0200\n"
+"Last-Translator: Vincent Bernat <bernat@luffy.cx>\n"
+"Language-Team: French <debian-l10n-french@lists.debian.org>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Faut-il automatiquement configurer le client BoxBackup ?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Les scripts de configuration de ce paquet peuvent créer les fichiers de "
+"configuration pour le client BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Vous devriez utiliser cette option si les options de configuration de "
+"BoxBackup ne vous sont pas familières."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Veuillez consulter le fichier /usr/share/doc/boxbackup-client/README.Debian "
+"pour obtenir des détails sur la configuration du client BoxBackup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Mode d'exécution pour le client BoxBackup :"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "Le client BoxBackup gère deux modes de sauvegarde :"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"Avec le mode simplifié (« lazy »), le démon de sauvegarde recherchera "
+"régulièrement les fichiers modifiés sur le système. Il enverra les fichiers "
+"plus anciens qu'un âge donné au serveur de sauvegarde."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"Avec le mode instantané (« snapshot »), la sauvegarde sera lancée "
+"explicitement à intervalles réguliers. Le fichier /etc/cron.d/boxbackup-"
+"client pour le démon cron est fourni avec le paquet et devra être adapté à "
+"vos besoins."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Numéro de compte pour ce nœud sur le serveur de sauvegarde :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"L'administrateur de BoxBackup doit assigner à ce client un numéro de compte "
+"en hexadécimal."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Si aucun numéro de compte n'est encore assigné, laissez ce champ vide et "
+"remplissez le plus tard en lançant la commande « dpkg-reconfigure boxbackup-"
+"client » en tant qu'utilisateur root."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Numéro de compte invalide"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+"Le numéro de compte doit être un nombre en hexadécimal (comme 1F04 ou 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Nom d'hôte complet (FQDN) du serveur de sauvegarde :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Veuillez indiquer le nom d'hôte complet (FQDN) du serveur BoxBackup que "
+"votre client doit utiliser."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Le client se connectera sur le port TCP 2201 du serveur."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Liste des répertoires à sauvegarder :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Veuillez indiquer une liste de répertoires, séparés par des espaces, à "
+"sauvegarder sur le serveur distant."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Ces répertoires ne doivent pas contenir de systèmes de fichiers montés dans "
+"l'un de leurs sous-répertoires, quelle que soit la profondeur."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Chemin invalide"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Ces répertoires doivent être indiqués sous forme de chemins absolus et "
+"séparés par des espaces."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Exemple : /home/myaccount /etc/."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Intervalle (en secondes) entre deux parcours du répertoire :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup parcourt régulièrement les répertoires sélectionnés à la recherche "
+"de fichiers modifiés."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Veuillez choisir l'intervalle entre deux parcours en secondes."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Temps minimum à attendre (en secondes) avant d'envoyer un fichier :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Un fichier est envoyé au serveur uniquement après un certain temps après sa "
+"date de dernière modification."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Un intervalle faible provoquera des envois fréquents vers le serveur et des "
+"versions successives en grand nombre. Les versions plus anciennes seront "
+"également supprimées plus tôt."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Délai maximum (en secondes) avant d'envoyer un fichier :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Des fichiers fréquemment modifiés risquent de ne jamais être envoyés si le "
+"temps minimal avant envoi n'est jamais atteint."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Veuillez indiquer le délai maximum à attendre avant de forcer l'envoi d'un "
+"fichier vers le serveur."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Délai non valable"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Veuillez indiquer un entier strictement positif."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Destinataire des notifications d'alertes :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"Le client BoxBackup envoie des notifications d'alertes quand un problème "
+"survient lors d'une sauvegarde."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Vous pouvez soit indiquer un identifiant local (par exemple « root ») ou une "
+"adresse de courrier électronique (par exemple « admin@example.org »)."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr ""
+"Faut-il créer la clef privée et la demande de certificat X.509 du client ?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"Le client BoxBackup a besoin d'une clef privée RSA et d'un certificat X.509 "
+"correspondant pour s'authentifier auprès du serveur."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Tous deux peuvent être créés automatiquement. Vous devrez envoyer la demande "
+"de certificat à l'administrateur du serveur BoxBackup qui la signera et vous "
+"la renverra accompagnée du certificat de l'autorité de certification (CA) du "
+"serveur."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Ces fichiers doivent être copiés dans le répertoire de configuration de "
+"BoxBackup. Les noms de fichier à utiliser sont indiqués dans le fichier /etc/"
+"boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Faut-il automatiquement configurer BoxBackup ?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Les scripts de configuration de ce paquet peuvent créer les fichiers de "
+"configuration pour le serveur BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Vous devriez utiliser cette option si les options de configuration de "
+"BoxBackup ne vous sont pas familières. Vous pouvez aussi configurer le "
+"serveur vous-même à l'aide des scripts « raidfile-config » et « bbstored-"
+"config »."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Le serveur ne démarrera pas s'il n'est pas configuré. Dans tous les cas, la "
+"lecture de /usr/share/doc/boxbackup-server/README.Debian est recommandée."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Emplacement des répertoires RAID :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Veuillez choisir l'emplacement des trois répertoires RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Pour activer la gestion RAID, veuillez indiquer, séparés par des espaces, "
+"les noms de trois partitions situées sur des disques physiques différents "
+"(par exemple : « /raid/0.0 /raid/0.1 /raid/0.2 »)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Si vous ne voulez pas activer la gestion du RAID, indiquez seulement le "
+"chemin d'un répertoire où les sauvegardes seront stockées (par exemple, /usr/"
+"local/lib/boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Ces répertoires seront créés s'ils n'existent pas."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Chemins non valables"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Par exemple : /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Taille des blocs pour le système RAID en espace utilisateur :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup utilise un système de RAID en espace utilisateur."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Veuillez choisir une taille de blocs pour le stockage. Pour une efficacité "
+"maximale, vous devriez choisir la même taille de blocs que le système de "
+"fichiers sous-jacent (que vous pouvez obtenir, pour les systèmes de fichiers "
+"ext2 et ext3, avec la commande « tune2fs -l »)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr ""
+"Cette valeur est nécessaire même si vous ne comptez pas utiliser le RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr ""
+"Faut-il créer une clef privée et une demande de certificat X.509 pour le "
+"serveur ?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"Le serveur BoxBackup a besoin d'une clef privée RSA et du certificat X.509 "
+"correspondant pour l'authentification et le chiffrement entre le client et "
+"le serveur."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Ces deux éléments peuvent être créés automatiquement. Vous aurez besoin de "
+"faire signer le certificat par votre autorité de certification principale "
+"(voir le paquet boxbackup-server) et de placer le certificat signé "
+"accompagné du certificat du CA racine dans le répertoire de configuration."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Taille de blocs non valable"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr ""
+"La taille d'un bloc doit être une puissance de deux (par exemple 1024 ou "
+"4096)."
diff --git a/debian/po/gl.po b/debian/po/gl.po
new file mode 100644
index 00000000..d981e9a6
--- /dev/null
+++ b/debian/po/gl.po
@@ -0,0 +1,516 @@
+# Galician translation of boxbackup's debconf templates
+# This file is distributed under the same license as the boxbackup package.
+# Jacobo Tarrio <jtarrio@debian.org>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2008-05-31 18:06+0100\n"
+"Last-Translator: Jacobo Tarrio <jtarrio@debian.org>\n"
+"Language-Team: Galician <proxecto@trasno.net>\n"
+"Language: gl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "¿Quere configurar o cliente BoxBackup de xeito automático?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Os scripts de configuración do paquete poden crear os ficheiros de "
+"configuración do cliente BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Debería escoller esta opción se non está afeito ás opcións de configuración "
+"de BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Consulte o ficheiro /usr/share/doc/boxbackup-client/README.Debian para máis "
+"información sobre a configuración do cliente BoxBackup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Modo de execución do cliente BoxBackup:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "O cliente BoxBackup soporta dous modos de copia de seguridade:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"No modo \"preguiceiro\" (\"lazy\"), o servizo de copias de seguridade ha "
+"explorar periodicamente o sistema de ficheiros á busca de ficheiros "
+"modificados. Despois ha copiar ao servidor os ficheiros máis vellos dunha "
+"determinada idade."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"No modo \"imaxe\" (\"snapshot\"), a copia de seguridade hase facer a "
+"intervalos regulares. Fornécese un ficheiro cron (/etc/cron.d/boxbackup-"
+"client) co paquete, que se debe adaptar ás súas necesidades."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Número de conta para este nodo no servidor de copias de seguridade:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"O administrador do servidor BoxBackup debeulle asignar a este cliente un "
+"número de conta hexadecimal."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Se non se asignou aínda ningún número de conta, deixe este campo baleiro e "
+"configúreo máis adiante executando \"dpkg-reconfigure boxbackup-client\" "
+"coma administrador."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Número de conta non válido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr "O número de conta debe ser un número hexadecimal (coma 1F04 ou 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Nome de dominio completo do servidor de copias de seguridade:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Introduza o nome de dominio completo do servidor BoxBackup que ha empregar o "
+"cliente."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "O cliente hase conectar ao servidor no porto TCP 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Lista de directorios a copiar:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Introduza unha lista de nomes de directorios a copiar no servidor remoto, "
+"separados por espazos."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Eses directorios non deberían conter sistemas de ficheiros montados en "
+"ningún nivel dos seus subdirectorios."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Ruta non válida"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"As rutas dos directorios deben ser rutas absolutas, separadas por espazos."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Por exemplo: /home/conta /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Intervalo (en segundos) entre as exploracións dos directorios:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup explora periodicamente os directorios seleccionados, á busca de "
+"ficheiros modificados."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Escolla o intervalo de exploración en segundos."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Tempo mínimo a agardar (en segundos) antes de copiar un ficheiro:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Só se ha copiar un ficheiro ao servidor despois de que pase un certo tempo "
+"trala súa última modificación."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Unha periodicidade curta de máis ha causar actualizacións frecuentes no "
+"servidor e a creación de máis revisións, o que ha facer que se eliminen "
+"antes as revisións antigas."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Tempo máximo a agardar (en segundos) antes de copiar un ficheiro:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"É posible que os ficheiros que se modifican con frecuencia non se copien "
+"nunca se nunca chegan ao tempo de espera mínimo."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Introduza o tempo máximo a agardar antes de forzar a copia dun ficheiro "
+"modificado ao servidor."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Introduciuse un tempo non válido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Introduza un número enteiro maior que cero."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Destinatario para os avisos das alertas:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"O cliente BoxBackup envía alertas cando hai un problema durante a copia de "
+"seguridade."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Introduza un nome de usuario local (por exemplo, \"root\") ou un enderezo de "
+"email (por exemplo, \"admin@exemplo.org\")."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "¿Xerar a clave privada e a solicitude de certificado X.509 do cliente?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"O cliente BoxBackup precisa dunha clave privada RSA e o certificado X.509 "
+"correspondente para se autenticar co servidor."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Pódense xerar os dous automaticamente. Ha ter que enviar a solicitude de "
+"certificado ao administrador do servidor BoxBackup, que a ha asinar e lla ha "
+"enviar de volta co certificado de Autoridade Certificadora do servidor."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Debe copiar eses ficheiros ao directorio de configuración de BoxBackup. Os "
+"nomes de ficheiro a empregar figuran no ficheiro /etc/boxbackup/bbackupd."
+"conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "¿Quere configurar BoxBackup de xeito automático?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Os scripts de configuración do paquete poden crear os ficheiros de "
+"configuración do servidor BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Debería escoller esta opción se non está afeito ás opcións de configuración "
+"de BoxBackup. Pódese facer a configuración cos scripts \"raidfile-config\" e "
+"\"bbstored-config\"."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Non se ha iniciar o servidor se non está configurado. En tódolos casos, "
+"recoméndase ler o ficheiro /usr/share/doc/boxbackup-server/README.Debian."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Ubicación dos directorios RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Indique a ubicación dos tres directorios de ficheiros RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Para activar o RAID, os nomes dos directorios deben ser unha lista con tres "
+"particións separadas por espazos, cada unha delas nun disco duro físico "
+"diferente (por exemplo, \"/raid/0.0 /raid/0.1 /raid/0.2\")."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Se non quere activar o RAID, indique a ruta a un só directorio no que "
+"armacenar as copias de seguridade (por exemplo, /usr/local/lib/boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Hanse crear eses directorios se non existen."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Rutas non válidas"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Por exemplo: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Tamaño de bloque para o sistema de RAID de nivel de usuario:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup emprega técnicas de RAID de nivel de usuario."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Escolla o tamaño de bloque a empregar para o armacenamento. Para alcanzar a "
+"máxima eficiencia, debería escoller o tamaño de bloque do sistema de "
+"ficheiros (que se pode ver, para os sistemas de ficheiros ext2, coa orde "
+"\"tune2fs -l\")."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Debería configurar este valor incluso se non quere empregar RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr ""
+"¿Xerar a clave privada e a solicitude de certificado X.509 do servidor?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"O servidor BoxBackup precisa dunha clave privada RSA e o certificado X.509 "
+"correspondente para realizar a autenticación do cliente e o cifrado das "
+"comunicacións."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Pódense xerar os dous automaticamente. Ha ter que asinar o certificado coa "
+"CA raíz (vexa o paquete boxbackup-server) e poñer este certificado asinado e "
+"o certificado da CA raíz no directorio de configuración."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Tamaño de bloque non válido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr ""
+"O tamaño de bloque debe ser unha potencia de 2 (por exemplo, 1024 ou 4096)."
diff --git a/debian/po/it.po b/debian/po/it.po
new file mode 100644
index 00000000..564d3ccb
--- /dev/null
+++ b/debian/po/it.po
@@ -0,0 +1,525 @@
+# Italian translation of boxbackup debconf messages.
+# Copyright (C) 2012
+# This file is distributed under the same license as the boxbackup package.
+# Beatrice Torracca <beatricet@libero.it>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup 0.11.1~r2837-1\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2012-01-30 15:51+0100\n"
+"Last-Translator: Beatrice Torracca <beatricet@libero.it>\n"
+"Language-Team: Italiano <debian-l10n-Italian@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1)\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Configurare automaticamente il client BoxBackup?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Gli script di configurazione del pacchetto possono creare i file di "
+"configurazione per il client BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Scegliere questa opzione se non si ha familiarità con le opzioni di "
+"configurazione di BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Per dettagli sulla configurazione del client BoxBackup, leggere /usr/share/"
+"doc/boxbackup-client/README.Debian."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Modalità di esecuzione del client BoxBackup:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "Il client BoxBackup gestisce due modalità di backup:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"Nella modalità \"pigra\" (\"lazy\"), il demone di backup scansiona a "
+"intervalli regolari il file system alla ricerca di file modificati. Carica "
+"quindi i file più vecchi di una data specificata sul server di backup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"Nella modalità \"istantanea\" (\"snapshot\") il backup viene eseguito "
+"esplicitamente ad intervalli regolari. Con il pacchetto viene fornito un "
+"file cron (/etc/cron.d/boxbackup-client) che deve essere adattato alle "
+"proprie necessità."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Numero di account per questo nodo sul server di backup:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"L'amministratore del server BoxBackup dovrebbe aver assegnato un numero di "
+"account esadecimale a questo client."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Se non è ancora stato assegnato alcun numero di account, lasciare questo "
+"campo in bianco e configurarlo in seguito eseguendo \"dpkg-reconfigure "
+"boxbackup-client\" come utente root."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Numero di account non valido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+"Il numero di account deve essere un numero esadecimale (come 1F04 o 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Nome di dominio pienamente qualificato del server di backup:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Inserire il nome di dominio pienamente qualificato del server BoxBackup che "
+"verrà usato dal client."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Il client si connetterà al server sulla porta TCP 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Lista di directory di cui fare il backup:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Inserire una lista, separata da spazi, di directory di cui fare il backup "
+"sul server remoto."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Queste directory non devono contenere file system montati in nessun livello "
+"delle loro sottodirectory."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Nome di percorso non valido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"I nomi di percorso delle directory devono essere nomi di percorso assoluti, "
+"separati da spazi."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Ad esempio: /home/mioaccount /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Intervallo (in secondi) tra le scansioni delle directory:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup scansiona a intervalli regolari le directory selezionate alla "
+"ricerca dei file modificati."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Scegliere l'intervallo di scansione in secondi."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Tempo minimo di attesa (in secondi) prima di caricare un file:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Un file viene caricato sul server solo dopo che è trascorso un certo tempo "
+"dalla sua ultima modifica."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Valori di intervallo bassi fanno scattare caricamenti frequenti sul server, "
+"creano più revisioni e fanno sì che le revisioni più vecchie vengano rimosse "
+"prima."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Tempo massimo di attesa (in secondi) prima di caricare un file:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"È possibile che i file modificati di frequente non vengano mai caricati se "
+"non raggiungono mai il tempo minimo di attesa."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Inserire il tempo massimo da raggiungere prima di forzare il caricamento di "
+"un file modificato sul server."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Tempo inserito non valido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Inserire un valore intero maggiore di zero."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Destinatario delle notifiche di avvertimento:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"Il client BoxBackup invia notifiche di avvertimento quando si verifica un "
+"problema durante il backup."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Inserire un nome di utente locale (ad esempio \"root\") oppure un indirizzo "
+"di posta elettronica (ad esempio \"admin@example.com\")."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr ""
+"Generare la richiesta di chiave privata e di certificato X.509 del client?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"Il client BoxBackup necessita di una chiave RSA privata e del certificato "
+"X.509 corrispondente per autenticarsi sul server."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Entrambi possono essere generati automaticamente. È necessario inviare la "
+"richiesta di certificato all'amministratore del server BoxBackup che la "
+"firmerà e invierà indietro insieme al certificato Certification Authority "
+"del server."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Questi file devono essere copiati nella directory di configurazione di "
+"BoxBackup. I nomi di file da usare sono indicati nel file /etc/boxbackup/"
+"bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Configurare BoxBackup automaticamente?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Gli script di configurazione possono creare i file di configurazione per il "
+"server BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Scegliere questa opzione se non si ha familiarità con le opzioni di "
+"configurazione di BoxBackup. La configurazione può essere fatta in modo "
+"manuale con gli script \"raidfile-config\" e \"bbstored-config\"."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Il server non si avvia se non è configurato. In ogni caso è raccomandata la "
+"lettura di /usr/share/doc/boxbackup-server/README.Debian."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Posizione delle directory RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Scegliere la posizione per le tre directory dei file RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Per abilitare RAID, i nomi di directory devono essere una lista separata da "
+"spazi di tre partizioni, ciascuna su un'unità fisica differente (ad esempio: "
+"\"/raid/0.0 /raid/0.1 /raid/0.2\")."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Se non si desidera abilitare RAID, specificare semplicemente il percorso di "
+"una directory in cui verranno memorizzati i backup (ad esempio, /usr/local/"
+"lib/boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Se non esistono, queste directory verranno create."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Nomi di percorso non validi"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Ad esempio: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Dimensione dei blocchi per il sistema RAID in spazio utente:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup usa tecniche RAID in spazio utente."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Scegliere la dimensione dei blocchi da usare per la memorizzazione. Per una "
+"massima efficienza, scegliere la dimensione dei blocchi del file system "
+"sottostante (che, per i file system ext2, può essere visualizzata con il "
+"comando \"tune2fs -l\")."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr ""
+"Questo valore andrebbe impostato anche se non si ha intenzione di usare RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr ""
+"Generare una richiesta di chiave privata e certificato X.509 per il server?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"Il server BoxBackup necessita di una chiave RSA privata e del certificato "
+"X.509 corrispondente per effettuare l'autenticazione client-server e la "
+"cifratura delle comunicazioni."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Entrambi possono essere generati automaticamente. È necessario firmare il "
+"certificato con la CA di root (vedere il pacchetto boxbackup-server) e "
+"mettere il certificato firmato e il certificato CA di root nella directory "
+"di configurazione."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Dimensione dei blocchi non valida"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr ""
+"La dimensione dei blocchi deve essere una potenza del due (es., 1024 o 4096)."
diff --git a/debian/po/ja.po b/debian/po/ja.po
new file mode 100644
index 00000000..872b8d47
--- /dev/null
+++ b/debian/po/ja.po
@@ -0,0 +1,509 @@
+# Copyright (C) 2009 Reinhard Tartler <siretart@tauware.de>
+# This file is distributed under the same license as boxbackup package.
+# Hideki Yamane (Debian-JP) <henrich@debian.or.jp>, 2009.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup 0.11~rc3~r2502-2\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2009-11-10 14:26+0900\n"
+"Last-Translator: Hideki Yamane (Debian-JP) <henrich@debian.or.jp>\n"
+"Language-Team: Japanese <debian-japanese@lists.debian.org>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "BoxBackup クライアントを自動的に設定しますか?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"パッケージの設定スクリプトは BoxBackup クライアント用の設定ファイルを作成でき"
+"ます。"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"あなたが BoxBackup の設定オプションに詳しくない場合は、このオプションを選んで"
+"ください。"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"BoxBackup クライアントの設定の詳細については /usr/share/doc/boxbackup-client/"
+"README.Debian を参照してください。"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "BoxBackup クライアントの動作モード:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "BoxBackup クライアントは 2 つのバックアップモードをサポートしています:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"'lazy' モードでは、バックアップのデーモンは変更されたファイルを探すため、定期"
+"的にファイルシステムをスキャンします。そして、指定された期間よりも古いファイ"
+"ルをバックアップサーバへアップロードします。"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"'snapshot' モードは、バックアップは明確に定期的な間隔で動作します。パッケージ"
+"で cron ファイル (/etc/cron.d/boxbackup-client) が用意され、このファイルが用"
+"途に合うはずです。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "バックアップサーバ上でのこのノードのアカウント番号:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"BoxBackup サーバの管理者は、このクライアントを 16 進数のアカウント番号で割り"
+"当てる必要があります。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"アカウント番号がまだ割り当てられていない場合は、この欄を空白のままにして後ほ"
+"ど root ユーザにて 'dpkg-reconfigure boxbackup-client' を実行して設定をしてく"
+"ださい。"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "アカウント番号が正しくありません"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr "アカウント番号は (1F04 や 4500 などの) 16 進数である必要があります。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "バックアップサーバの完全修飾ドメイン名 (FQDN):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"クライアントが利用する BoxBackup サーバの完全修飾ドメイン名 (FQDN) を入力して"
+"ください。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "クライアントはサーバの TCP ポート 2201 に接続します。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "バックアップするディレクトリの一覧:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"リモートのサーバにバックアップされる、空白で区切ったディレクトリの一覧を指定"
+"してください。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"このディレクトリには、サブディレクトリ以下にマウント済みのファイルシステムを"
+"含んではいけません。"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "パス名 (path) が正しくありません"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"ディレクトリへのパス名は絶対パスで、空白で区切られている必要があります。"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "例: /home/myaccount /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "ディレクトリをスキャンする間隔 (秒数):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup は変更されたファイルを探すため、一定間隔で指定されたディレクトリを"
+"スキャンします。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "スキャンの間隔を秒数で指定してください。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "ファイルをアップロードするまでの最小待ち時間 (秒数):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"最後に変更されてから一定時間が経過しないとファイルはアップロードされません。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"短い間隔にすると、サーバへ頻繁にアップロードすることになり、作成されるリビ"
+"ジョンが多くなって、古いリビジョンが早く削除されます。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "ファイルをアップロードするまでの最大待ち時間 (秒数):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"頻繁に変更されるファイルが最小待ち時間にも達しない場合、このファイルは全く"
+"アップロードされないでしょう。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"変更されたファイルがサーバへ強制的にアップロードされるまでの最大時間を入力し"
+"てください。"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "入力された時間が正しくありません"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "自然数を入力してください。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "警告通知の受信者:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"BoxBackup クライアントは、バックアップ中に問題が起きた際に警告の通知を送信し"
+"ます。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"ローカルユーザの名前 (例えば 'root') かメールアドレス (例 'admin@example."
+"org') を入力してください。"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "クライアント秘密鍵と X.509 証明書のリクエストを生成しますか?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"BoxBackup クライアントは、サーバに認証を受ける際に RSA 秘密鍵と対応する "
+"X.509 証明書を必要とします。"
+
+# FIXME: もっとわかりやすい表現
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"双方とも自動的に生成できます。証明書リクエストを BoxBackup サーバの管理者に送"
+"信する必要があります。BoxBackup サーバの管理者は、サーバの認証局の認証に基づ"
+"いて証明書リクエストに署名して返信します。"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"このファイルは BoxBackup の設定ディレクトリにコピーされる必要があります。ファ"
+"イル名は /etc/boxbackup/bbackupd.conf ファイルで指定します。"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "BoxBackup を自動的に設定しますか?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"パッケージの設定スクリプトで BoxBackup サーバの設定ファイルを生成できます。"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"BoxBackup の設定オプションに詳しくない場合はこのオプションを選んでください。"
+"設定は、手動の場合は 'raidfile-config' や'bbstored-config' スクリプトで設定で"
+"きます。"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"サーバは設定されていないと起動しません。どのような場合でも、/usr/share/doc/"
+"boxbackup-server/README.Debian を一読いただくのをお勧めします。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "RAID ディレクトリの位置:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "RAID ファイルが置かれる 3 つのディレクトリを指定してください。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"RAID を有効にするには、ディレクトリ名は 3 つのパーティションのリストを空白で"
+"区切ったもので、それぞれが別の物理ドライブ上にある必要があります (例: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"RAID を有効にしたくない場合は、バックアップが保存される単一ディレクトリへのパ"
+"ス (path) を指定してください (例えば、/usr/local/lib/boxbackup)。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "このディレクトリが存在しない場合、作成されます。"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "パス名が正しくありません"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "例: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "ユーザランド RAID システムのブロックサイズ:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup はユーザランドの RAID 機能を使います。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"ストレージに使うブロックサイズを選んでください。効率を最大限にするには、ファ"
+"イルシステムのブロックサイズに合わせて選ぶ必要があります (ext2 ファイルシステ"
+"ムは 'tune2fs -l' コマンドで表示できます)。"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "RAID を使う予定が無いとしても、この値は設定する必要があります。"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "サーバ秘密鍵と X.509 証明書リクエストを生成しますか?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"BoxBackup サーバは、クライアントとサーバ間の認証と通信暗号化を行うために RSA "
+"秘密鍵と対応する X.509 証明書を必要とします。"
+
+# FIXME もっとわかりやすい表現
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"双方とも自動的に生成ができます。ルート認証局 (root CA) での証明書への署名 "
+"(boxbackup-server パッケージを参照) して、署名した証明書と CA 証明書を設定"
+"フォルダに配置する必要があります。"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "ブロックサイズが正しくありません"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "ブロックサイズは 2 の乗数である必要があります (例: 1024、4096)。"
diff --git a/debian/po/nl.po b/debian/po/nl.po
new file mode 100644
index 00000000..0ef91ab4
--- /dev/null
+++ b/debian/po/nl.po
@@ -0,0 +1,528 @@
+# Dutch translation of boxbackup debconf templates.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the boxbackup package.
+# Frans Spiesschaert <Frans.Spiesschaert@yucom.be>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2014-10-10 15:14+0200\n"
+"Last-Translator: Frans Spiesschaert <Frans.Spiesschaert@yucom.be>\n"
+"Language-Team: Debian Dutch l10n Team <debian-l10n-dutch@lists.debian.org>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Moet de BoxBackup-client automatisch ingesteld worden?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"De configuratiescripts van het pakket kunnen de configuratiebestanden voor "
+"de BoxBackup-client aanmaken."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"U zou deze optie moeten kiezen indien u niet vertrouwd bent met de "
+"configuratieopties van BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Gelieve het bestand /usr/share/doc/boxbackup-client/README.Debian te "
+"raadplegen voor details over het configureren van de BoxBackup-client."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Modus voor het uitvoeren van de BoxBackup-client:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "De BoxBackup-client ondersteunt twee back-upmodussen:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"In de 'luie' modus zal de back-upachtergronddienst regelmatig het "
+"bestandssysteem overlopen op zoek naar gewijzigde bestanden. Daarna zal het "
+"bestanden ouder dan een ingestelde ouderdom naar de server uploaden."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"In de 'momentopname'-modus zal expliciet een back-up gemaakt worden met "
+"vastgelegde intervallen. Met het pakket wordt een cron-bestand (/etc/cron.d/"
+"boxbackup-client) meegeleverd dat volgens uw behoeften aangepast zou moeten "
+"worden."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Accountnummer voor deze machine op de back-upserver:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"De beheerder van de BoxBackup-server zou deze client een hexadecimaal "
+"accountnummer moeten gegeven hebben."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Indien nog geen accountnummer toegekend werd, laat u dit veld leeg en "
+"configureert u het later door als systeembeheerder het commando 'dpkg-"
+"reconfigure boxbackup-client' uit te voeren."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Ongeldig accountnummer"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+"Het accountnummer moet een hexadecimaal getal zijn (zoals 1F04 of 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr ""
+"Volledige domeinnaam (fully qualified domain name) van de back-upserver:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Voer de volledige domeinnaam in van de BoxBackup-server waarvan uw client "
+"gebruik zal maken."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "De client zal met de server contact maken op de TCP-poort 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Lijst van mappen waarvoor een back-up gemaakt moet worden:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Geef een met komma's gescheiden lijst op van mappen waarvoor een reservekopie "
+"moet gemaakt worden op de externe server."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Deze mappen zouden op geen enkel niveau in de onderliggende mappen "
+"aangekoppelde bestandssystemen mogen bevatten."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Ongeldig pad"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"De namen van de mappen moeten het absolute pad er naartoe bevatten en ze "
+"moeten met spaties van elkaar gescheiden worden."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Bijvoorbeeld: /home/mijn_account /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Interval (in seconden) tussen het doorlopen van de mappen:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"Met tussenpozen doorloopt BoxBackup de opgegeven mappen op zoek naar "
+"gewijzigde bestanden."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Gelieve het doorloopinterval te kiezen, uitgedrukt in seconden."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Minimale wachttijd (in seconden) voor het uploaden van een bestand:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Slechts een bepaalde tijd na de laatste wijziging aan een bestand wordt het "
+"naar de server geüpload."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Lage inervalwaarden zullen frequente uploads naar de server en het aanmaken "
+"van meer revisies tot gevolg hebben en meteen ook het vroeger wissen van "
+"oudere revisies."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Maximale wachttijd (in seconden) vooraleer een bestand geüpload wordt:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"De kans bestaat dat bestanden die frequent bijgewerkt worden nooit geüpload "
+"raken omdat ze nooit de minimale wachttijd halen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Gelieve aan te geven hoelang maximaal gewacht mag worden vooraleer het "
+"uploaden van een gewijzigd bestand naar de server afgedwongen wordt."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "De opgegeven tijd is ongeldig"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Gelieve een geheel getal in te geven groter dan nul."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Ontvanger van waarschuwingen:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"De BoxBackup-client stuurt een waarschuwing wanneer er zich een probleem "
+"voordoet tijdens de back-up."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Geef ofwel de naam van een lokale gebruiker op (bijvoorbeeld 'root') of een "
+"e-mailadres (bijvoorbeeld 'admin@voorbeeld.org')."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Een geheime sleutel en een verzoek om een X.509-certificaat aanmaken?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"De BoxBackup-client heeft een geheime RSA-sleutel en een overeenkomstig "
+"X.509-certificaat nodig om zich bij de server te authenticeren."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Beide kunnen automatisch aangemaakt worden. U zult het verzoek om een "
+"certificaat moeten sturen naar de beheerder van de BoxBackup-server, die het "
+"zal ondertekenen en naar u terugsturen samen met het certificaat van de "
+"Certificatie-Autoriteit van de server."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Deze bestanden moeten gekopieerd worden naar de map die de configuratie van "
+"BoxBackup bevat. De te gebruiken bestandsnamen staan vermeld in het bestand /"
+"etc/boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Moet BoxBackup automatisch ingesteld worden?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"De configuratiescripts van het pakket kunnen de configuratiebestanden voor "
+"de BoxBackup-server aanmaken."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"U zou deze optie moeten kiezen indien u niet vertrouwd bent met de "
+"configuratieopties voor BoxBackup. De configuratie kan manueel gebeuren met "
+"behulp van de scripts 'raidfile-config' and 'bbstored-config'."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"De server zal niet opstarten als hij niet geconfigureerd is. Hoe dan ook "
+"wordt aanbevolen om /usr/share/doc/boxbackup-server/README.Debian te "
+"raadplegen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Plaats van de RAID-mappen:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Gelieve de plaats op te geven van de drie RAID bestandsmappen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Om RAID te gebruiken moeten de namen van de mappen ingegeven worden als een "
+"door komma's gescheiden lijst van drie partities, die zich elk op een andere "
+"fysieke harde schijf bevinden (bijvoorbeeld: '/raid/0.0 /raid/0.1 /"
+"raid/0.2')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Indien u RAID niet wilt gebruiken, geeft u enkel het pad op naar een map "
+"waarin de reservekopieën bewaard zullen worden (bijvoorbeeld /usr/local/lib/"
+"boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Deze mappen zullen aangemaakt worden als ze nog niet bestaan."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Ongeldige padnamen"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Bijvoorbeeld: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Blok-grootte voor het RAID-systeem in gebruikersmodus:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup maakt gebruik van RAID-technieken in gebruikersmodus."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Gelieve de blok-grootte voor de opslag te kiezen. Voor maximale efficiëntie, "
+"zou u de blok-grootte van het onderliggende bestandssysteem moeten kiezen "
+"(voor het ext2-bestandssysteem kunt u dat te zien krijgen met het commando "
+"'tune2fs -l')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr ""
+"Deze waarde moet ook ingesteld worden als u niet zinnens bent RAID te "
+"gebruiken."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr ""
+"Een geheime sleutel en een verzoek om een X.509-certificaat aanmaken voor de "
+"server?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"De BoxBackup-server heeft een geheime RSA-sleutel en een overeenkomstig "
+"X.509-certificaat nodig voor de client-server-authenticatie en de "
+"versleuteling van de communicatie."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Beide kunnen automatisch aangemaakt worden. U zult het certificaat moeten "
+"ondertekenen met uw systeembeheerders-CA (zie het boxbackup-serverpakket) en "
+"dit ondertekend certificaat samen met het CA-certificaat van de "
+"systeembeheerder in de configuratiemap plaatsen."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Ongeldige blok-grootte"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "De blok-grootte moet een macht van twee zijn (bijv. 1024 of 4096)."
diff --git a/debian/po/pt.po b/debian/po/pt.po
new file mode 100644
index 00000000..2bcb0a08
--- /dev/null
+++ b/debian/po/pt.po
@@ -0,0 +1,519 @@
+# pt translation of boxbackup.
+# Copyright (C) 2008 THE BOXBACKUP'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the boxbackup package.
+# Bruno Queirós <bqueiros@gmail.com>, 2008.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2008-05-31 20:05+0100\n"
+"Last-Translator: Bruno Queirós <brunoqueiros@portugalmail.com>\n"
+"Language-Team: Portuguese <traduz@debianpt.org>\n"
+"Language: pt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "O cliente BoxBackup deve ser configurado automaticamente?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Os scripts de configuração do pacote podem criar os ficheiros de "
+"configuração para o cliente do BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Deve escolher esta opção se não está familiarizado com as opções de "
+"configuração do BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Por favor leia /usr/share/doc/boxbackup-client/README.Debian para detalhes "
+"acerca da configuração do cliente BoxBackup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Modo de execução para o cliente BoxBackup:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "O cliente BoxBackup suporta dois modos de backup:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"No modo 'lazy', o deamon de backup irá pesquisar regularmente o sistema de "
+"ficheiros à procura de ficheiros modificados. De seguida envia os ficheiros "
+"que sejam mais antigos que uma data especificada para o servidor de backup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"No modo 'snapshot' o backup será executado explicitamente em intervalos "
+"regulares. Um ficheiro cron (/etc/cron.d/boxbackup-client) é fornecido "
+"juntamente com o pacote e deve ser adaptado às suas necessidades."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Número de conta para este nó no servidor de backups:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"O administrador do servidor BoxBackup deve ter atribuído a este cliente um "
+"número de conta em hexadecimal."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Se ainda não foi atribuído nenhum número de conta, deixe este campo em "
+"branco e configure-o mais tarde executando 'dpkg-reconfigure boxbackup-"
+"client' como root."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Número de conta inválido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr "O número de conta deve ser um número hexadecimal (como 1F04 ou 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Nome completo do domínio do servidor de backups:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Por favor introduza o nome completo do domínio do sevidor BoxBackup que o "
+"seu cliente irá utilizar."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "O cliente irá ligar-se o servidor por TCP na porta 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Lista dos directórios para backup:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Por favor forneça uma lista de directórios separados por um espaço para "
+"serem copiados para o servidor remoto."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Esses directórios não devem conter sistemas de ficheiros montados em nenhum "
+"nível dos seus subdirectórios."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Nome de localização inválido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Os nomes das localizações têm que ser nomes de localização absolutos, "
+"separados por espaços."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Por exemplo: /home/minhaconta /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Intervalo (em segundos) entre pesquisas de directórios:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"O BoxBackup pesquisa regularmente os directórios seleccionados, à procura de "
+"ficheiros modificados."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Por favor escolha o intervalo de pesquisa em segundos."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Tempo mínimo de espera (em segundos) antes de carregar um ficheiro:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Um ficheiro será carregado para o servidor apenas após ter passado um certo "
+"tempo depois da sua última modificação."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Baixos valores de intervalo irão activar carregamentos frequentes para o "
+"servidor e serão criadas mais revisões e as revisões mais antigas são "
+"removidas mais cedo."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Tempo máximo de espera (em segundos) antes de carregar um ficheiro:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Ficheiros que são frequentemente modificados raramente são carregados se "
+"eles não atingirem o mínimo tempo de espera."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Por favor introduza o tempo máximo a atingir antes que o carregamento de um "
+"ficheiro modificado para o servidor seja forçado."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Introduzido tempo inválido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Por favor introduza um valor inteiro não nulo."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Destinatário para as notificações de alerta:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"O cliente BoxBackup envia notificações de alerta quando ocorre um problema "
+"durante o backup."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Por favor introduza ou um nome de utilizador local (por exemplo 'root') ou "
+"um endereço de email (por exemplo 'admin@example.org')."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Gerar uma chave privada do cliente e o pedido de certificado X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"O cliente BoxBackup precisa de uma chave privada RSA e o correspondente "
+"certificado X.509 para se autenticar com o servidor."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Ambos podem ser gerados automaticamente. Você precisa de enviar o pedido de "
+"certificado para o administrador do servidor BoxBackup que o irá assinar e "
+"enviá-lo de volta para si juntamente com o certificado 'Certification "
+"Authority' (CA) do servidor."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Estes ficheiros devem ser copiados para o directório de configuração do "
+"BoxBackup. Os nomes de ficheiros a utilizar são dados no ficheiro /etc/"
+"boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "O BoxBackup deve ser configurado automaticamente?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Os scripts de configuração do pacote podem criar os ficheiros de "
+"configuração para o servidor BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Deve escolher esta opção se não estiveir familiarizado com as opções de "
+"configuração do BoxBackup. A configuração pode ser feita manualmente com os "
+"scripts 'raidfile-config' e 'bbstored-config'."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"O servidor não irá funcionar se não estiver configurado. Em todos os casos, "
+"érecomendado ler o /usr/share/doc/boxbackup-server/README.Debian."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Localização dos directórios RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr ""
+"Por favor escolha a localização dos três directórios de ficheiros RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Para activar o RAID, os nomes dos directórios devem ser uma lista separada "
+"por um espaço de três particções, cada uma em discos rígidos diferentes (por "
+"exemplo: '/raid/0.0 /raid/0.1 /raid/0.2')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Se não deseja activar o RAID, simplesmente especifique uma localização para "
+"um directório onde os backups serão armazenados ( por exemplo, /usr/local/"
+"lib/boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Estes directórios devem ser criados caso não existam."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Nomes de localização inválidos"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Por exemplo: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Tamanho do bloco para a userland do sistema RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup usa técnicas userland RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Por favor escolha o tamanho do bloco para utilizar no armazenamento. Para "
+"uma eficiência máxima, deverá escolher o tamanho do bloco do sistema de "
+"ficheiros que utiliza (o qual pode ser visualizado com o comando 'tune2fs -"
+"l')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Este valor deve ser introduzido mesmo que não tencione usar RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "Gerar uma chave privada do servidor e o pedido de certificado X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"O servidor BoxBackup precisa de uma chave privada RSA e o correspondente "
+"certificado X.509 para executar autenticações cliente-servidor e encriptação "
+"de comunicação."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Ambos podem ser gerados automaticamente. Precisará de assinar o certificado "
+"com o seu root CA (veja o pacote boxbackup-server) e ponha este certificado "
+"assinado e o certificado root CA na pasta de configuração."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Tamanho de bloco inválido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "O tamanho do bloco deve ser uma potência de 2 (e.g. 1024 ou 4096)."
diff --git a/debian/po/pt_BR.po b/debian/po/pt_BR.po
new file mode 100644
index 00000000..1a57bb70
--- /dev/null
+++ b/debian/po/pt_BR.po
@@ -0,0 +1,522 @@
+# Debconf translations for boxbackup.
+# Copyright (C) 2010 THE boxbackup'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the boxbackup package.
+# Bruno Gurgel <bruno.gurgel@gmail.com>, 2010.
+# Adriano Rafael Gomes <adrianorg@gmail.com>, 2010, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup 0.11~rc8~r2714-1\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2008-04-21 12:53+0200\n"
+"PO-Revision-Date: 2011-01-18 09:59-0200\n"
+"Last-Translator: Adriano Rafael Gomes <adrianorg@gmail.com>\n"
+"Language-Team: Brazilian Portuguese <debian-l10n-portuguese@lists.debian."
+"org>\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"pt_BR utf-8\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "O cliente BoxBackup deve ser configurado automaticamente?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Os scripts de configuração do pacote podem criar os arquivos de configuração "
+"para o cliente BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Você deve escolher essa opção se você não estiver familiarizado com as "
+"opções de configuração do BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Por favor, leia /usr/share/doc/boxbackup-client/README.Debian para detalhes "
+"sobre a configuração do cliente BoxBackup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Modo de execução para o cliente BoxBackup:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "O cliente BoxBackup suporta dois modos de backup:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"No modo 'lazy', o daemon do backup verificará regularmente o sistema de "
+"arquivos procurando por arquivos modificados. Ele então fará o carregamento "
+"(\"upload\") dos arquivos mais velhos que uma idade especificada para o "
+"servidor de backup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"No modo 'snapshot', o backup será explicitamente executado em intervalos "
+"regulares. Um arquivo do cron (/etc/cron.d/boxbackup-client) é fornecido com "
+"o pacote e deve ser adaptado para atender as suas necessidades."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Número da conta para esse nó no servidor de backup:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"O administrador do servidor BoxBackup deve ter designado a esse cliente um "
+"número de conta hexadecimal."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Se nenhum número de conta foi designado ainda, deixe esse campo em branco e "
+"configure-o depois executando 'dpkg-reconfigure boxbackup-client' como root."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Número de conta inválido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr "O número de conta deve ser um número hexadecimal (como 1F04 ou 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Nome de domínio totalmente qualificado do servidor de backup:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Por favor, informe o nome de domínio totalmente qualificado do servidor "
+"BoxBackup que seu cliente usará."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "O cliente conectará no servidor na porta 2201 TCP."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Lista de diretórios para fazer backup:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Por favor, informe uma lista separada por espaços de diretórios para fazer "
+"backup no servidor remoto."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Esses diretórios não devem conter sistemas de arquivos montados em nenhum "
+"nível em seus subdiretórios."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Nome de caminho inválido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Os nomes de caminho para os diretórios precisam ser nomes de caminho "
+"absolutos, separados por espaços."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Por exemplo: /home/minhaconta /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Intervalo (em segundos) entre as verificações dos diretórios:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"O BoxBackup regularmente verifica os diretórios selecionados, procurando por "
+"arquivos modificados."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Por favor, escolha o intervalo de verificação em segundos."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Tempo mínimo de espera (em segundos) antes de carregar um arquivo:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Um arquivo será carregado para o servidor somente depois de um certo tempo "
+"após sua última modificação."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Valores baixos de intervalo desencadearão carregamentos frequentes para o "
+"servidor e mais revisões serão criadas, com as antigas revisões sendo "
+"removidas mais cedo."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Tempo máximo para esperar (em segundos) antes de carregar um arquivo:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Arquivos frequentemente modificados são suscetíveis a nunca serem carregados "
+"caso nunca atinjam o tempo mínimo de espera."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Por favor, informe o tempo máximo para atingir antes que o carregamento para "
+"o servidor de um arquivo modificado seja forçado."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Tempo inválido informado"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Por favor, informe um valor inteiro maior que zero."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Destinatário para as notificações de alerta:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"O cliente BoxBackup envia notificações de alerta quando ocorre um problema "
+"durante o backup."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Por favor, informe um nome de usuário local (por exemplo 'root') ou um "
+"endereço de e-mail (por exemplo 'admin@exemple.org')."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Gerar a chave privada do cliente e a requisição do certificado X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"O cliente BoxBackup precisa de uma chave privada RSA e o certificado X.509 "
+"correspondente para se autenticar com o servidor."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Ambos podem ser gerados automaticamente. Você precisará enviar a requisição "
+"do certificado para o administrador do servidor BoxBackup que irá assiná-lo "
+"e enviá-lo de volta para você, juntamente com o certificado da Autoridade "
+"Certificadora do servidor."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Esses arquivos devem ser copiados dentro do diretório de configuração do "
+"BoxBackup. Os nomes de arquivo a serem usados são dados no arquivo /etc/"
+"boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "O BoxBackup deve ser configurado automaticamente?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Os scripts de configuração do pacote podem criar os arquivos de configuração "
+"para o servidor BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Você deve escolher essa opção se você não estiver familiarizado com as "
+"opções de configuração do BoxBackup. A configuração pode ser feita "
+"manualmente com os scripts 'raidfile-config' e 'bbstored-config'."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"O servidor não inicializará se não for configurado. Em todos os casos, ler /"
+"usr/share/doc/boxbackup-server/README.Debian é recomendado."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Localização dos diretórios RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr ""
+"Por favor, escolha a localização para os três diretórios de arquivos RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Para habilitar o RAID, os nomes dos diretórios devem ser uma lista separada "
+"por espaços de três partições, cada uma em diferentes discos físicos (por "
+"exemplo: '/raid/0.0 /raid/0.1 /raid/0.2')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Se você não deseja habilitar o RAID, apenas especifique o caminho para um "
+"diretório onde os backups serão armazenados (por exemplo, /usr/local/lib/"
+"boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Esses diretórios serão criados se não existirem."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Nomes de caminho inválidos"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Por exemplo: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr ""
+"Tamanho do bloco para o sistema de RAID em espaço de usuário (\"userland\"):"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup usa técnicas de RAID em espaço de usuário."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Por favor, escolha o tamanho do bloco a ser usado para o armazenamento. Para "
+"eficiência máxima, você deve escolher o tamanho de bloco do sistema de "
+"arquivos subjacente (que pode ser mostrado para sistemas de arquivo ext2 com "
+"o comando 'tune2fs -l')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Esse valor deve ser definido mesmo se você não planeja usar RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "Gerar uma chave privada do servidor e o pedido do certificado X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"O servidor BoxBackup precisa de uma chave privada RSA e do certificado X.509 "
+"correspondente para realizar a autenticação cliente-servidor e a "
+"criptografia da comunicação."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Ambos podem ser gerados automaticamente. Você terá que assinar o certificado "
+"com a sua CA raiz (veja o pacote boxbackup-server) e colocar este certificado "
+"assinado e o certificado da CA raiz na pasta de configuração."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Tamanho de bloco inválido"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "O tamanho do bloco deve ser uma potência de dois (ex. 1024 ou 4096)."
diff --git a/debian/po/ru.po b/debian/po/ru.po
new file mode 100644
index 00000000..f0468989
--- /dev/null
+++ b/debian/po/ru.po
@@ -0,0 +1,519 @@
+# translation of ru.po to Russian
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Yuri Kozlov <kozlov.y@gmail.com>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup new\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2008-06-06 21:51+0400\n"
+"Last-Translator: Yuri Kozlov <kozlov.y@gmail.com>\n"
+"Language-Team: Russian <debian-l10n-russian@lists.debian.org>\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Настроить клиента BoxBackup автоматически?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Сценарии настройки пакета могут создать файлы настройки клиента BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Вы должны ответить утвердительно, если не знакомы параметрами настройки "
+"BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Подробное описание по настройке клиента BoxBackup дано в файле /usr/share/"
+"doc/boxbackup-client/README.Debian."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Режим запуска клиента BoxBackup:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "Клиент BoxBackup поддерживает два режима резервного копирования:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"В режиме 'lazy' служба резервного копирования регулярно сканирует файловую "
+"систему, ища изменившиеся файлы. Затем она закачивает файлы на сервер, если "
+"они новее, чем на сервере (срок можно настроить)."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"В режиме 'snapshot' резервное копирование выполняется через одинаковые "
+"интервалы. В пакете есть файл задания cron (/etc/cron.d/boxbackup-client), "
+"который должен быть изменён под ваши нужды."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Учётный номер этого узла на сервере резервного копирования:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"Администратор сервера BoxBackup должен назначить этому клиенту "
+"шестнадцатеричный учётный номер."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Если учётный номер ещё не назначен, оставьте это поле пустым, и настройте "
+"его позже, запустив команду 'dpkg-reconfigure boxbackup-client' с правами "
+"суперпользователя."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Неверный учётный номер"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+"Учётный номер должен указываться в виде шестнадцатеричного числа (например, "
+"1F04 или 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Полностью определённое доменное имя сервера резервного копирования:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Введите полностью определённое доменное имя сервера BoxBackup, который будет "
+"использовать клиент."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Клиент будет подключаться к серверу по TCP-порту 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Список каталогов для резервного копирования:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Задайте через пробел список каталогов, для которых будет выполняться "
+"резервное копирование на удалённый сервер."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Эти каталоги не должны содержать смонтированных файловых систем в своих "
+"подкаталогах."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Неверный путь"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Пути к каталогам должны указываться в виде абсолютных путей и разделяться "
+"пробелами."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Пример: /home/myaccount /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Интервал (в секундах) между сканированиями:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup регулярно сканирует указанные каталоги, ища изменившиеся файлы."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Введите промежуток между сканированиями в секундах."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Минимальное время ожидания (в секундах) перед закачкой файла:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Файл будет закачан на сервер только по прошествии определённого времени с "
+"момента его последнего изменения."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Короткий интервал приводит к частым закачкам на сервер и созданию большого "
+"числа версий и скорому удалению предыдущих версий."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Максимальное время ожидания (в секундах) перед закачкой файла:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Часто изменяемые файлы, скорее всего, никогда не будут закачаны, так как для "
+"них никогда не наступит конец минимального интервала ожидания."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Введите максимальный интервал, после которого изменённый файл должен быть "
+"принудительно закачан на сервер."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Указано неправильное время"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Введите целое число больше нуля."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Получатель уведомлений о сбоях:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"Клиент BoxBackup посылает уведомления о сбоях, если возникает проблема при "
+"выполнении резервного копирования."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Введите имя локального пользователя (например, 'root') или адрес электронной "
+"почты (например, 'admin@example.org')."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Генерировать клиентский секретный ключ и запрос сертификата X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"Для аутентификации клиента BoxBackup на сервере требуется секретный ключ RSA "
+"и соответствующий сертификат X.509."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Они могут быть сгенерированы автоматически. Вам нужно отправить запрос "
+"сертификата администратору сервера BoxBackup, который его подпишет и "
+"отправит вам обратно вместе сертификатом сервера от удостоверяющего центра."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Эти файлы нужно скопировать в каталог настройки BoxBackup. Имена файлов "
+"задаются в файле /etc/boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Настроить BoxBackup автоматически?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Сценарии настройки пакета могут создать файлы настройки сервера BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Вы должны ответить утвердительно, если не знакомы параметрами настройки "
+"BoxBackup. Настройка может быть выполнена вручную с помощью сценариев "
+"'raidfile-config' и 'bbstored-config'."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Сервер не запустится без настройки. В любом случае, прочитайте файл /usr/"
+"share/doc/boxbackup-server/README.Debian."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Расположение каталогов RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Введите расположение для трёх каталогов RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Чтобы включить RAID, нужно указать имена каталогов трёх разделов через "
+"пробел, каждый на отдельном физическом жёстком диске (например: '/raid/0.0 /"
+"raid/0.1 /raid/0.2')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Если вы не хотите использовать RAID, просто укажите путь к одному каталогу, "
+"где будут сохраняться резервные копии (например, /usr/local/lib/boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Если каталоги не существуют, то они будут созданы."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Неверные имена каталогов"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Например: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Размер блока пользовательской системы RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr ""
+"В BoxBackup используются технологии RAID, работающие в пользовательском "
+"окружении."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Введите размер блока хранилища. Для максимальной эффективности, вам нужно "
+"указать размер блока файловой системы, на которой расположено хранилище (его "
+"можно узнать, например, для файловой системы ext2, с помощью команды "
+"'tune2fs -l')."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr ""
+"Это значение должно быть задано, даже если вы не планируете использовать "
+"RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "Генерировать секретный ключ сервера и запрос сертификата X.509?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"Для аутентификации клиентов и шифрования передачи серверу BoxBackup "
+"требуется секретный ключ RSA и соответствующий сертификат X.509."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Они могут быть сгенерированы автоматически. Вам нужно подписать сертификат в "
+"корневом CA (смотрите пакет boxbackup-server) и положить этот подписанный "
+"сертификат и корневой сертификат CA в каталог с настройками."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Неверный размер блока"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr ""
+"Размер блока должен быть кратен степени двойки (например, 1024 или 4096)."
diff --git a/debian/po/sv.po b/debian/po/sv.po
new file mode 100644
index 00000000..3d797880
--- /dev/null
+++ b/debian/po/sv.po
@@ -0,0 +1,515 @@
+# translation of boxbackup.po to swedish
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the boxbackup package.
+#
+# Martin Bagge <brother@bsnet.se>, 2009.
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2009-02-01 04:14+0100\n"
+"Last-Translator: Martin Bagge <brother@bsnet.se>\n"
+"Language-Team: swedish <debian-l10n-swedish@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Ska inställningarna för BoxBackup-klienten skapas automatiskt?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Paketet kan automatiskt skapa inställningsfiler för Boxbackup-klienten."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Du bör välja detta alternativ om du inte är bekant med BoxBackups "
+"inställningar sedan tidiare."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Läs även i /usr/share/doc/boxbackup-client/README.Debian för närmare "
+"information om inställningsalternativen för BoxBackup-klienten."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Körläge för BoxBackup-klienten:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "BoxBackup-klienten har stöd för två olika lägen för säkerhetskopior:"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"I \"lazy\"-mode söker tjänsten för säkerhetskopiering regelbundet av "
+"dilsystemet för uppdaterade filer. Den kommer sedan att kopiera filer äldre "
+"än ett visst tröskelvärde till servern med säkerhetskopia."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"I läget \"snapshot\" kommer säkerhetskopiorna att utföras enligt ett "
+"rullande schema. Ett cronjobb kommer att installeras (/etc/cron.d/baxbackup-"
+"client) med hjälp av paketet och kan ändras för att passa dina behov."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Kontonummer för den här noden på servern för säkerhetskopior:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"Administratören för BoxBackup-servern ska ha givit denna klient ett "
+"hexadecimalt-kontonummer."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Om inget kontonummer har tilldelats ännu kan du lämna fältet blankt och "
+"ställa in det senare genom att köra \"dpkg-reconfigure boxbackup-client\" "
+"som root."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Ogiltigt kontonummer"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr "Kontonummret måste vara ett hexadecimaltnummer (ex. 1F04 eller 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Komplett domännamn för servern med säkerhetskopior:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Ange det kompletta domännamnet för BoxBackup-servern som din klient ska "
+"använda."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Klienten kommer att ansluta till servern på TCP-port 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Lista med kataloger som ska säkerhetskopieras:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Ange en lista separerad av mellanslag med kataloger som ska "
+"säkerhetskopieras till fjärrservern."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Dessa kataloger får inte innehålla några monterade filsystem i någon nivå i "
+"deras underkataloger."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Ogiltig sökväg"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Sökvägarna till katalogerna måste vara absoluta separerade med mellanslag."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Exempelvis: /home/myaccount/etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Interval (i sekunder) mellan katalogsökningar:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"BoxBackup söker regelbundet av valda kataloger och letar efter uppdaterade "
+"filer."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Ange avsökningsintervallet i sekunder."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr ""
+"Minimal tid att vänta (i sekunder) innan en fil fkopieras till servern:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"En fil kommer att kopieras till servern så länge minst ett visst "
+"tidsintervall har förflutit sedan förra förändringen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Ett lågt intervall kommer att innebära frekventare kopieringar till servern "
+"och fler revisioner kommer att skapas och därmed kommer äldre revisioner att "
+"tas bort snabbare."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Maximal tid att vänta (i sekunder) innan en fil kopieras till servern:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Frekvent modifierade filer kan undgå att kopieras om de aldrig kommer upp i "
+"den minsta väntetiden."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Ange maximal tid som måste förflyta efter att en fil har modifierats innan "
+"en fil kopieras till servern."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Ogiltig tid angiven"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Ange ett heltal större än noll."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Mottagare som ska få varningsmeddelanden:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"BoxBackup-klienten skickar varningsmeddelanden när ett problem uppstår under "
+"säkerhetskopieringen."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Ange antingen ett lokalt användarnamn (exempelvis \"root\") eller en e-post-"
+"adress (exempelvis \"admin@example.org\")."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Skapa klientens privata nyckel och X.509-certifikatförfrågan?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"BoxBackup-klienten behöver en privat RSA-nyckel och dess motsvarande X.509-"
+"certifikat för att kunna identifiera sig mot servern."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Båda kan skapas automatiskt. Du måste flytta certifikatförfrågningen till "
+"administratören av BoxBackupservern som kommer att signera den och skicka "
+"tillbaka den till dig tillsammans med servern certifikatutfärdar-certifikat."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Dessa filer ska kopieras till BoxBackups inställningskatalog. Filnamnen för "
+"filerna anges i filen /etc/boxbackup/bbackupd.conf."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "Ska inställningar för BoxBackup skapas automatiskt?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Paketets inställningsskript kan skapa inställningsfilerna för Boxbackup-"
+"servern."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Du ska anta detta alternativ om du inte känner till BoxBackups "
+"inställningsalternativ sedan tidigare. Inställningarna kan göras manuellt "
+"med skripten \"raidfile-config\" och \"bbstored-config\"."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Servern kommer inte att starta om inställningarna inte är kompletta. Du bör "
+"läsa igenom /usr/share/doc/boxbackup-server/README.Debian."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Plats för RAID-kataloger:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Ange platsen för de tre RAID-katalogerna."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"För att aktivera RAID måste katalognamnen vara en mellanslagsseparerad lista "
+"med tre partitioner, varje partition på en egen fysisk enhet (ex. \"/"
+"raid/0.0 /raid/0.1 /raid/0.2\")."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Om du inte vill aktivera RAID anger du bara en sökväg till en ensam katalog "
+"som säkerhetskopiorna ska lagras i (exempelvis /usr/local/lib/boxbackup)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Dessa kataloger kommer att skapas om de inte existerar."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Ogiltigt namn på sökväg"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Exempelvis: /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Blockstorleken för userland-RAID-system:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup använder userland-RAID-teknologi."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Välj den blockstorlek som ska användas för lagringen. För maximal "
+"effektivitet ska du välja samma blockstorlek som det underliggande "
+"filsystemet använder (storleken kan visas med kommandot \"tune2fs -l\" för "
+"ext2)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Detta värde ska anges även om du inte tänker använda RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "Skapa en privat servernyckel och X.509 certifikatförfrågan?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"BoxBackup-servern behöver en privat RSA-nyckel och ett tillhörande X.509-"
+"certifikat för att kunna utföra klient-server-identifiering och "
+"kommunikationskryptering."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Båda kan skapas automatiskt. Certifikatet måste signeras med ditt "
+"huvudcertifikat från certifikatutfärdaren (se även paketet boxbackup-server) "
+"sedan placeras både det signerade certifikatet och huvudcertifikatet från "
+"certifikatutfärdaren i inställningskatalogen."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Felaktig storlek på block"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "Blockstorleken måste vara binärkompatibel (ex. 1024 eller 4096)."
diff --git a/debian/po/templates.pot b/debian/po/templates.pot
new file mode 100644
index 00000000..b897dfbf
--- /dev/null
+++ b/debian/po/templates.pot
@@ -0,0 +1,446 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr ""
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr ""
diff --git a/debian/po/vi.po b/debian/po/vi.po
new file mode 100644
index 00000000..d1412967
--- /dev/null
+++ b/debian/po/vi.po
@@ -0,0 +1,514 @@
+# Vietnamese translation for BoxBackup.
+# Copyright © 2010 Free Software Foundation, Inc.
+# Clytie Siddall <clytie@riverland.net.au>, 2007-2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: boxbackup 0.11~rc3~r2502-2.1\n"
+"Report-Msgid-Bugs-To: boxbackup@packages.debian.org\n"
+"POT-Creation-Date: 2011-10-28 01:51+0200\n"
+"PO-Revision-Date: 2010-09-30 18:14+0930\n"
+"Last-Translator: Clytie Siddall <clytie@riverland.net.au>\n"
+"Language-Team: Vietnamese <vi-VN@googlegroups.com>\n"
+"Language: vi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: LocFactoryEditor 1.8\n"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid "Should the BoxBackup client be configured automatically?"
+msgstr "Ứng dụng khách BoxBackup có nên được tự động cấu hình không?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup client."
+msgstr ""
+"Các văn lệnh cấu hình gói có khả năng tạo những tập tin cấu hình cho ứng "
+"dụng khách BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options."
+msgstr ""
+"Có nên bật tùy chọn này nếu bạn chưa quen với các tùy chọn cấu hình của "
+"BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:2001
+msgid ""
+"Please read the /usr/share/doc/boxbackup-client/README.Debian for details "
+"about the configuration of the BoxBackup client."
+msgstr ""
+"Xem tài liệu Đọc Đi « /usr/share/doc/boxbackup-client/README.Debian » để tìm "
+"chi tiết về cấu hình của ứng dụng khách BoxBackup."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "Run mode for the BoxBackup client:"
+msgstr "Chế độ chạy ứng dụng khách BoxBackup:"
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid "The BoxBackup client supports two modes of backup:"
+msgstr "Ứng dụng khách BoxBackup hỗ trợ hai chế độ sao lưu :"
+
+#. Type: select
+#. Description
+#. Translators, please keep reference to 'lazy' and 'snapshot' as
+#. these options are written as is in the software documentation
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'lazy' mode, the backup daemon will regularly scan the file system "
+"searching for modified files. It will then upload the files older than a "
+"specified age to the backup server."
+msgstr ""
+"Trong chế độ « làm biếng », trình nền sao lưu sẽ quét đều đặn hệ thống tập "
+"tin tìm tập tin bị sửa đổi. Tìm được thì cũng tải lên máy phục vụ sao lưu "
+"tập tin nào « cũ » hơn một thời gian nào đó."
+
+#. Type: select
+#. Description
+#: ../boxbackup-client.templates:3001
+msgid ""
+"In the 'snapshot' mode the backup will be explicitly run at regular "
+"intervals. A cron file (/etc/cron.d/boxbackup-client) is provided with the "
+"package and should be adapted to suit your needs."
+msgstr ""
+"Trong chế độ « chụp hiện trạng », việc sao lưu sẽ được chạy dứt khoát theo "
+"mỗi khoảng đều đặn. Một tập tin định kỳ cron (/etc/cron.d/boxbackup-client) "
+"có sẵn với gói này và nên được sửa đổi để thích hợp với yêu cầu của bạn."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid "Account number for this node on the backup server:"
+msgstr "Số thứ tự tài khoản cho nút này trên máy phục vụ sao lưu :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"The administrator of the BoxBackup server should have assigned this client a "
+"hexadecimal account number."
+msgstr ""
+"Quản trị của máy phục vụ BoxBackup nên đã gán cho ứng dụng khách này một số "
+"thứ tự tài khoản kiểu thập lục."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:4001
+msgid ""
+"If no account number has been assigned yet, leave this field blank and "
+"configure it later by running 'dpkg-reconfigure boxbackup-client' as root."
+msgstr ""
+"Chưa gán số thứ tự tài khoản thì bạn bỏ trống trường này và cấu hình về sau "
+"bằng cách chạy câu lệnh « dpkg-reconfigure boxbackup-client » với quyền "
+"người chủ."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "Invalid account number"
+msgstr "Số thứ tự tài khoản sai"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:5001
+msgid "The account number must be a hexadecimal number (such as 1F04 or 4500)."
+msgstr "Số thứ tự tài khoản phải là một con số thập lục (v.d. 1F04 hay 4500)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "Fully qualified domain name of the backup server:"
+msgstr "Tên miền có khả năng đầy đủ của máy phục vụ sao lưu :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid ""
+"Please enter the fully qualified domain name of the BoxBackup server which "
+"your client will use."
+msgstr ""
+"Hãy gõ tên miền có khả năng đầy đủ (FQDN) của máy phục vụ Boxbackup cho ứng "
+"dụng khách sử dụng."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:6001
+msgid "The client will connect to the server on TCP port 2201."
+msgstr "Ứng dụng khách sẽ kết nối tới máy phục vụ trên cổng TCP 2201."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid "List of directories to backup:"
+msgstr "Danh sách các thư mục cần sao lưu :"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Please give a space-separated list of directories to be backed up onto the "
+"remote server."
+msgstr ""
+"Hãy đưa ra một danh sách định giới bằng dấu cách chứa những thư mục cần sao "
+"lưu vào máy phục vụ từ xa."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:7001
+msgid ""
+"Those directories should not contain mounted file systems at any level in "
+"their subdirectories."
+msgstr ""
+"Những thư mục này không nên chứa hệ thống tập tin đã lắp ở cấp nào trong các "
+"thư mục phụ."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "Invalid path name"
+msgstr "Tên đường dẫn sai"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001 ../boxbackup-server.templates:4001
+msgid ""
+"The path names to the directories must be absolute path names, separated by "
+"spaces."
+msgstr ""
+"Mỗi tên đường dẫn tới thư mục phải là một tên đường dẫn tuyệt đối, định giới "
+"bằng dấu cách."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:8001
+msgid "For example: /home/myaccount /etc/"
+msgstr "Thí dụ : /home/tài_khoản_mình /etc/"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Interval (in seconds) between directory scans:"
+msgstr "Khoảng (theo giây) giữa hai lần quét thư mục:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid ""
+"BoxBackup regularly scans the selected directories, looking for modified "
+"files."
+msgstr ""
+"Trình BoxBackup quét đều đặn các thư mục đã chọn, tìm tập tin bị sửa đổi."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:9001
+msgid "Please choose the scan interval in seconds."
+msgstr "Hãy chọn khoảng quét theo giây."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid "Minimum time to wait (in seconds) before uploading a file:"
+msgstr "Thời gian tối thiểu (theo giây) cần đợi trước khi tải lên tập tin:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"A file will be uploaded to the server only after a certain time after its "
+"last modification."
+msgstr ""
+"Mỗi tập tin sẽ được tải lên máy phục vụ chỉ sau khi đợi một khoảng thời gian "
+"nào đó sau lần cuối cùng bị sửa đổi."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:10001
+msgid ""
+"Low interval values will trigger frequent uploads to the server and more "
+"revisions being created with older revisions being removed earlier."
+msgstr ""
+"Giá trị khoảng thấp sẽ gây ra nhiều việc tải lên máy phục vụ hơn thì nhiều "
+"bản sửa đổi được tạo hơn, và các bản sửa đổi cũ bị gỡ bỏ trước."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid "Maximum time to wait (in seconds) before uploading a file:"
+msgstr "Thời gian tối đa (theo giây) cần đợi trước khi tải lên tập tin:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Frequently modified files are likely to never get uploaded if they never "
+"reach the minimum wait time."
+msgstr ""
+"Tập tin thường bị sửa đổi thì sẽ không được tải lên nếu chưa tới thời gian "
+"đợi tối thiểu."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:11001
+msgid ""
+"Please enter the maximum time to reach before the upload of a modified file "
+"to the server is enforced."
+msgstr ""
+"Hãy gõ khoảng thời gian tối đa cần tới trước khi ép buộc việc tải lên máy "
+"phục vụ tập tin bị sửa đổi."
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Invalid time entered"
+msgstr "Sai nhập thời gian"
+
+#. Type: error
+#. Description
+#: ../boxbackup-client.templates:12001
+msgid "Please enter an integer value greater null."
+msgstr "Hãy gõ một giá trị số nguyên dương (>0)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid "Recipient for alert notifications:"
+msgstr "Người nhận thông báo cảnh giác:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"The BoxBackup client sends alert notifications when a problem occurs during "
+"the backup."
+msgstr ""
+"Ứng dụng khách BoxBackup gửi thông báo cảnh giác khi gặp vấn đề trong khi "
+"sao lưu."
+
+#. Type: string
+#. Description
+#: ../boxbackup-client.templates:13001
+msgid ""
+"Please enter either a local user name (for example 'root') or an email "
+"address (for example 'admin@example.org')."
+msgstr ""
+"Hãy gõ hoặc một tên người dùng cục bộ (v.d. « root »), hoặc một địa chỉ thư "
+"điện tử (v.d. « admin@thí_dụ.org »)."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid "Generate the client private key and X.509 certificate request?"
+msgstr "Tạo ra khoá riêng ứng dụng khách và yêu cầu chứng nhận X.509 ?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"The BoxBackup client needs an RSA private key and the corresponding X.509 "
+"certificate to authenticate itself with the server."
+msgstr ""
+"Ứng dụng khách BoxBackup yêu cầu một khoá riêng kiểu RSA, và chứng nhận "
+"X.509 tương ứng, để tự xác thực với máy phục vụ."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"Both can be generated automatically. You will need to send the certificate "
+"request to the BoxBackup server administrator who will sign it and send it "
+"back to you along with the server's Certification Authority certificate."
+msgstr ""
+"Cả hai có thể được tự động tạo ra. Bạn cần phải gửi yêu cầu chứng nhận cho "
+"quản trị máy phục vụ BoxBackup ký và trả lại cùng với chứng nhận CA (nhà cầm "
+"quyền cấp chứng nhận) của máy phục vụ."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-client.templates:14001
+msgid ""
+"These files should be copied into BoxBackup's configuration directory. The "
+"file names to use are given in the /etc/boxbackup/bbackupd.conf file."
+msgstr ""
+"Những tập tin này nên được sao chép vào thư mục cấu hình của BoxBackup. Các "
+"tên tập tin cần dùng được đưa ra trong tập tin cấu hình « /etc/boxbackup/"
+"bbackupd.conf file »."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid "Should BoxBackup be configured automatically?"
+msgstr "BoxBackup có nên được tự động cấu hình không?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The package configuration scripts can create the configuration files for the "
+"BoxBackup server."
+msgstr ""
+"Các văn lệnh cấu hình gói có khả năng tạo những tập tin cấu hình cho trình "
+"phục vụ BoxBackup."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"You should choose this option if you are not familiar with BoxBackup's "
+"configuration options. The configuration can be done manually with the "
+"'raidfile-config' and 'bbstored-config' scripts."
+msgstr ""
+"Có nên bật tùy chọn này nếu bạn chưa quen với các tùy chọn cấu hình của "
+"BoxBackup. Bạn cũng có thể tự cấu hình dùng văn lệnh « raidfile-config » va "
+"« bbstored-config »."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:2001
+msgid ""
+"The server will not start if it is not configured. In all cases, reading "
+"the /usr/share/doc/boxbackup-server/README.Debian is recommended."
+msgstr ""
+"Chưa cấu hình thì trình phục vụ không khởi chạy. Trong mọi trường hợp, "
+"khuyên bạn đọc tài liệu Đọc Đi « /usr/share/doc/boxbackup-server/README."
+"Debian »."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Location of the RAID directories:"
+msgstr "Vị trí của thư mục RAID:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "Please choose the location for the three RAID file directories."
+msgstr "Hãy chọn vị trí cho ba thư mục tập tin RAID."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"To enable RAID, the directory names should be a space-separated list of "
+"three partitions, each on different physical hard drives (for example: '/"
+"raid/0.0 /raid/0.1 /raid/0.2')."
+msgstr ""
+"Để hiệu lực chức năng RAID, những tên thư mục nên làm một danh sách định "
+"giới bằng dấu cách chứa ba phân vùng, mỗi điều trên một ổ đĩa cứng vật lý "
+"riêng (v.d. « /raid/0.0 /raid/0.1 /raid/0.2 »)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid ""
+"If you don't want to enable RAID, just specify the path to one directory "
+"where the backups will be stored (for example, /usr/local/lib/boxbackup)."
+msgstr ""
+"Không muốn hiệu lực RAID thì chỉ cần xác định đường dẫn tới một thư mục "
+"trong đó có thể cất giữ các bản sao lưu (v.d. « /usr/local/lib/boxbackup »)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:3001
+msgid "These directories will be created if they do not exist."
+msgstr "Chưa tồn tại thì tự động tạo những thư mục này."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "Invalid path names"
+msgstr "Tên đường dẫn sai"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:4001
+msgid "For example: /raid/0.0 /raid/0.1 /raid/0.2"
+msgstr "Thí dụ : /raid/0.0 /raid/0.1 /raid/0.2"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "Block size for the userland RAID system:"
+msgstr "Kích cỡ khối cho hệ thống RAID vùng người dùng:"
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "BoxBackup uses userland RAID techniques."
+msgstr "BoxBackup sử dụng kỹ thuật RAID kiểu vùng người dùng."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid ""
+"Please choose the block size to use for the storage. For maximum efficiency, "
+"you should choose the block size of the underlying file system (which can be "
+"displayed for ext2 filesystems with the 'tune2fs -l' command)."
+msgstr ""
+"Hãy chọn kích cỡ khối cần dùng cho sức chứa. Để hữu hiệu nhất, bạn nên chọn "
+"kích cỡ khối của hệ thống tập tin bên dưới (trên hệ thống tập tin ext2 có "
+"thể hiển thị nó dùng câu lệnh « tune2fs -l »)."
+
+#. Type: string
+#. Description
+#: ../boxbackup-server.templates:5001
+msgid "This value should be set even if you don't plan to use RAID."
+msgstr "Giá trị này nên được lập thậm chí nếu bạn không định sử dụng RAID."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid "Generate a server private key and X.509 certificate request?"
+msgstr "Tạo ra một khoá riêng máy phục vụ và yêu cầu chứng nhận X.509 ?"
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"The BoxBackup server needs an RSA private key and the corresponding X.509 "
+"certificate to perform client-server authentication and communication "
+"encryption."
+msgstr ""
+"Trình phục vụ BoxBackup yêu cầu một khoá riêng kiểu RSA, và chứng nhận X.509 "
+"tương ứng, để thực hiện tiến trình xác thực giữa ứng dụng khách và trình "
+"phục vụ, và để mật mã hoá giao thông."
+
+#. Type: boolean
+#. Description
+#: ../boxbackup-server.templates:6001
+msgid ""
+"Both can be generated automatically. You will need to sign the certificate "
+"with your root CA (see the boxbackup-server package) and put this signed "
+"certificate and the root CA certificate in the configuration folder."
+msgstr ""
+"Cả hai có thể được tự động tạo ra. Bạn cần phải ký chứng nhận dùng CA gốc "
+"(xem gói tiện ích « boxbackup-server »), và để vào thư mục cấu hình chứng "
+"nhận đã ký và chứng nhận CA gốc."
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "Invalid block size"
+msgstr "Sai lập kích cỡ khối"
+
+#. Type: error
+#. Description
+#: ../boxbackup-server.templates:7001
+msgid "The block size must be a power of two (e.g. 1024 or 4096)."
+msgstr "Kích cỡ khối phải là hai lũy thừa (v.d. 1024 hay 4096)."
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 00000000..525f257d
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,102 @@
+#!/usr/bin/make -f
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+TMP:=$(CURDIR)/debian/tmp
+
+ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -g
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+endif
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ dh_autotools-dev_updateconfig
+ echo "0.11rc8+`cat .svnrevision`" > VERSION.txt
+ echo "boxbackup" >> VERSION.txt
+ sh -x ./bootstrap
+ ./configure $(DEB_EXTRA_CONFIG_FLAGS) LDFLAGS="-Wl,--as-needed"
+ touch configure-stamp
+
+build-stamp: configure-stamp
+ dh_testdir
+ $(MAKE) V=1
+ifeq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS)))
+ ./runtest.pl ALL
+endif
+ touch build-stamp
+
+docs/docbook/instguide.pdf:
+ $(MAKE) -C docs instguide
+ cd docs/docbook && docbook2pdf instguide.xml
+
+docs/docbook/adminguide.pdf: configure-stamp
+ $(MAKE) -C docs adminguide
+ cd docs/docbook && docbook2pdf adminguide.xml
+
+docs: docs/docbook/instguide.pdf docs/docbook/adminguide.pdf
+ $(MAKE) -C docs manpages
+
+build-arch: build-stamp
+build-indep: docs
+
+build: build-arch build-indep
+
+clean:
+ dh_testdir
+ dh_testroot
+ dh_clean build-stamp configure-stamp
+ echo "USE_SVN_VERSION" > VERSION.txt
+ echo "boxbackup" >> VERSION.txt
+ [ ! -f Makefile ] || make clean
+ sh debian/clean.sh
+ dh_autotools-dev_restoreconfig
+ dh_clean config.log config.status
+
+install: DH_OPTIONS=
+install: build
+ dh_testdir
+ dh_testroot
+ dh_prep
+ dh_installdirs
+
+ mkdir -p $(TMP)/etc/logcheck/ignore.d.workstation
+ mkdir -p $(TMP)/etc/logcheck/ignore.d.server
+ install -m 644 debian/boxbackup-server.logcheck.ignore $(TMP)/etc/logcheck/ignore.d.workstation/boxbackup-server
+ install -m 644 debian/boxbackup-server.logcheck.ignore $(TMP)/etc/logcheck/ignore.d.server/boxbackup-server
+
+ dh_install
+
+binary-indep:
+# no architecture independant packages are being built
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir -a
+ dh_testroot -a
+ dh_installdebconf -a
+ dh_installdocs -a -A ExceptionCodes.txt docs/docbook/instguide.pdf docs/docbook/adminguide.pdf
+ dh_installinit -a
+ dh_installcron -a
+ dh_installman
+ dh_installchangelogs -a
+ dh_strip -a
+ dh_compress -a
+ dh_fixperms -a
+ dh_installdeb -a
+ dh_shlibdeps -a
+ dh_gencontrol -a
+ dh_md5sums -a
+ dh_builddeb -a
+
+binary: binary-arch
+.PHONY: build build-arch build-indep clean binary-indep binary-arch binary install docs
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 00000000..163aaf8d
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 00000000..5ec27736
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,4 @@
+version=3
+# release candidates are not on sf
+# http://sf.net/boxbackup/ boxbackup-(.*)\.tgz
+http://boxbackup.org/svn/box/packages/ boxbackup-(.*)\.tgz
diff --git a/distribution/boxbackup/DISTRIBUTION-MANIFEST.txt b/distribution/boxbackup/DISTRIBUTION-MANIFEST.txt
index 70a3a7bc..2fca9572 100644
--- a/distribution/boxbackup/DISTRIBUTION-MANIFEST.txt
+++ b/distribution/boxbackup/DISTRIBUTION-MANIFEST.txt
@@ -1,5 +1,8 @@
LICENSE-GPL.txt
+<<<<<<< HEAD
+=======
qdbm
+>>>>>>> 0.12
LICENSE DUAL
lib/intercept
@@ -28,6 +31,11 @@ test/backupstorepatch
test/bbackupd
test/bbackupd/testfiles
test/backupdiff
+<<<<<<< HEAD
+test/httpserver/testfiles
+test/httpserver/testfiles/photos
+=======
+>>>>>>> 0.12
docs/Makefile
docs/tools
diff --git a/distribution/boxbackup/VERSION.txt b/distribution/boxbackup/VERSION.txt
index 0188cacd..feeac86a 100644
--- a/distribution/boxbackup/VERSION.txt
+++ b/distribution/boxbackup/VERSION.txt
@@ -1,2 +1,6 @@
+<<<<<<< HEAD
+0.11.1
+=======
0.12
+>>>>>>> 0.12
boxbackup
diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in
index b2b2ce43..f3c71308 100644
--- a/infrastructure/BoxPlatform.pm.in
+++ b/infrastructure/BoxPlatform.pm.in
@@ -24,6 +24,13 @@ BEGIN
# Cygwin Builds usually something like CYGWIN_NT-5.0, CYGWIN_NT-5.1
# Box Backup tried on Win2000,XP only :)
$build_os = 'CYGWIN' if $build_os =~ m/CYGWIN/;
+<<<<<<< HEAD
+
+ $make_command = ($build_os eq 'Darwin') ? 'bsdmake' : ($build_os eq 'SunOS') ? 'gmake' : 'make';
+
+ $bsd_make = ($build_os ne 'Linux' && $build_os ne 'CYGWIN' &&
+ $build_os ne "SunOS" && $build_os ne 'GNU/kFreeBSD');
+=======
$build_os = 'MINGW32' if $build_os =~ m/MINGW32/;
if ($build_os eq 'Darwin') {
@@ -35,6 +42,7 @@ BEGIN
$bsd_make = ($build_os ne 'Linux' && $build_os ne 'CYGWIN' &&
$build_os ne "MINGW32" && $build_os ne "SunOS"
&& $build_os ne 'GNU/kFreeBSD' && $xcode_ver < 4);
+>>>>>>> 0.12
# blank extra flags by default
$platform_compile_line_extra = '';
@@ -88,6 +96,19 @@ BEGIN
# where to put the files
$install_into_dir = '@sbindir_expanded@';
+<<<<<<< HEAD
+ # if it's Darwin,
+ if($build_os eq 'Darwin')
+ {
+ # see how many processors there are, and set make flags accordingly
+ my $cpus = `sysctl hw.ncpu`;
+ if($cpus =~ m/hw.ncpu:\s(\d+)/ && $1 > 1)
+ {
+ print STDERR "$1 processors detected, will set make to perform concurrent jobs\n";
+ $sub_make_options = ' -j '.($1 + 1);
+ }
+
+=======
# see how many processors there are, and set make flags accordingly
if($build_os eq 'Darwin' || $build_os =~ /(Free|Net|Open)BSD/)
{
@@ -112,6 +133,7 @@ BEGIN
# if it's Darwin,
if($build_os eq 'Darwin')
{
+>>>>>>> 0.12
# test for fink installation
if(-d '/sw/include' && -d '/sw/lib')
{
diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp
index e5b1360d..287c4bff 100644
--- a/infrastructure/buildenv-testmain-template.cpp
+++ b/infrastructure/buildenv-testmain-template.cpp
@@ -29,6 +29,11 @@
#include <getopt.h>
#endif
+<<<<<<< HEAD
+#include <sys/stat.h>
+#include <sys/types.h>
+
+=======
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
@@ -40,6 +45,7 @@
# include <sys/un.h>
#endif
+>>>>>>> 0.12
#include <exception>
#include <string>
@@ -84,6 +90,9 @@ inline bool checkfilesleftopen() { return false; }
#define FILEDES_MAX 256
+<<<<<<< HEAD
+bool filedes_open[FILEDES_MAX];
+=======
typedef enum
{
OPEN,
@@ -93,6 +102,7 @@ typedef enum
filedes_t;
filedes_t filedes_open[FILEDES_MAX];
+>>>>>>> 0.12
bool check_filedes(bool report)
{
@@ -103,6 +113,13 @@ bool check_filedes(bool report)
{
if(::fcntl(d, F_GETFD) != -1)
{
+<<<<<<< HEAD
+ // File descriptor obviously exists
+ if (report && !filedes_open[d])
+ {
+ struct stat st;
+ if (fstat(d, &st) == 0)
+=======
// File descriptor obviously exists, but is it /dev/log?
struct stat st;
@@ -148,6 +165,7 @@ bool check_filedes(bool report)
// ignore it.
}
else if(stat_success)
+>>>>>>> 0.12
{
int m = st.st_mode;
#define flag(x) ((m & x) ? #x " " : "")
@@ -161,22 +179,47 @@ bool check_filedes(bool report)
flag(S_IFLNK) <<
flag(S_IFSOCK) <<
" or " << m << ")");
+<<<<<<< HEAD
+=======
allOk = false;
+>>>>>>> 0.12
}
else
{
BOX_FATAL("File descriptor " << d <<
" left open (and stat failed)");
+<<<<<<< HEAD
+ }
+
+ allOk = false;
+
+ }
+ else if (!report)
+ {
+ filedes_open[d] = true;
+=======
allOk = false;
}
}
else if (!report)
{
filedes_open[d] = is_syslog_socket ? SYSLOG : OPEN;
+>>>>>>> 0.12
}
}
else
{
+<<<<<<< HEAD
+ if (report && filedes_open[d])
+ {
+ BOX_FATAL("File descriptor " << d <<
+ " was open, now closed");
+ allOk = false;
+ }
+ else
+ {
+ filedes_open[d] = false;
+=======
if (report && filedes_open[d] != CLOSED)
{
if (filedes_open[d] == SYSLOG)
@@ -196,6 +239,7 @@ bool check_filedes(bool report)
else
{
filedes_open[d] = CLOSED;
+>>>>>>> 0.12
}
}
}
@@ -248,7 +292,11 @@ int main(int argc, char * const * argv)
int ch;
+<<<<<<< HEAD
+ while ((ch = getopt_long(argc, argv, "c:d:qs:t:vPTUV", longopts, NULL))
+=======
while ((ch = getopt_long(argc, argv, "c:d:qs:t:vPTUVW:", longopts, NULL))
+>>>>>>> 0.12
!= -1)
{
switch(ch)
@@ -320,6 +368,8 @@ int main(int argc, char * const * argv)
}
break;
+<<<<<<< HEAD
+=======
case 'W':
{
logLevel = Logging::GetNamedLevel(optarg);
@@ -331,6 +381,7 @@ int main(int argc, char * const * argv)
}
break;
+>>>>>>> 0.12
case 't':
{
Logging::SetProgramName(optarg);
@@ -368,7 +419,10 @@ int main(int argc, char * const * argv)
}
Logging::SetGlobalLevel((Log::Level)logLevel);
+<<<<<<< HEAD
+=======
Logging::FilterConsole((Log::Level)logLevel);
+>>>>>>> 0.12
argc -= optind - 1;
argv += optind - 1;
@@ -446,12 +500,15 @@ int main(int argc, char * const * argv)
return returncode;
}
+<<<<<<< HEAD
+=======
catch(BoxException &e)
{
printf("FAILED: Exception caught: %s: %s\n", e.what(),
e.GetMessage().c_str());
return 1;
}
+>>>>>>> 0.12
catch(std::exception &e)
{
printf("FAILED: Exception caught: %s\n", e.what());
diff --git a/infrastructure/m4/ax_check_ssl.m4 b/infrastructure/m4/ax_check_ssl.m4
index 78b99f7e..1714080c 100644
--- a/infrastructure/m4/ax_check_ssl.m4
+++ b/infrastructure/m4/ax_check_ssl.m4
@@ -27,8 +27,12 @@ AC_DEFUN([AX_CHECK_SSL], [
ax_check_ssl_found=yes
AC_CHECK_HEADERS([openssl/ssl.h],, [ax_check_ssl_found=no])
+<<<<<<< HEAD
+ AC_CHECK_LIB([ssl], [SSL_read],, [ax_check_ssl_found=no], [-lcrypto])
+=======
AC_SEARCH_LIBS([HMAC_CTX_init], [crypto])
AC_SEARCH_LIBS([SSL_read], [ssl],, [ax_check_ssl_found=no])
+>>>>>>> 0.12
if test "x$ax_check_ssl_found" = "xyes"; then
AC_DEFINE([HAVE_SSL], 1, [Define to 1 if SSL is available])
diff --git a/infrastructure/m4/vl_lib_readline.m4 b/infrastructure/m4/vl_lib_readline.m4
index e9cb72b8..e04a5f5f 100644
--- a/infrastructure/m4/vl_lib_readline.m4
+++ b/infrastructure/m4/vl_lib_readline.m4
@@ -79,6 +79,16 @@ AC_DEFUN([VL_LIB_READLINE], [
fi
])
+<<<<<<< HEAD
+dnl VL_LIB_READLINE_CHECK(name, libraries, headers, history headers)
+AC_DEFUN([VL_LIB_READLINE_CHECK], [
+ AC_CACHE_CHECK([for $1 library],
+ [vl_cv_lib_$1], [
+ ORIG_LIBS="$LIBS"
+ vl_cv_lib_$1=""
+ for readline_lib in $2; do
+ for termcap_lib in "" termcap curses ncurses; do
+=======
dnl BOX_CHECK_VAR(name, where, headers)
AC_DEFUN([BOX_CHECK_VAR], [
AC_CACHE_CHECK([for $1 $2], [vl_cv_var_$1],
@@ -97,6 +107,7 @@ AC_DEFUN([VL_LIB_READLINE_CHECK], [
vl_cv_lib_$1=""
for readline_lib in $2; do
for termcap_lib in "" termcap curses ncurses pdcurses; do
+>>>>>>> 0.12
if test -z "$termcap_lib"; then
TRY_LIB="-l$readline_lib"
else
@@ -118,6 +129,14 @@ AC_DEFUN([VL_LIB_READLINE_CHECK], [
fi
])
+<<<<<<< HEAD
+ vl_cv_lib_readline_compat_found=no
+ if test "x$vl_cv_lib_$1" != "xno"; then
+ AC_CHECK_HEADERS([$3], [vl_cv_lib_readline_compat_found=yes])
+ fi
+
+ if test "x$vl_cv_lib_readline_compat_found" = "xyes"; then
+=======
vl_cv_lib_includes=""
vl_cv_lib_readline_compat_found=no
@@ -147,6 +166,7 @@ $vl_cv_lib_includes"
BOX_CHECK_VAR([completion_matches], [in readline headers],
[$vl_cv_lib_includes])
+>>>>>>> 0.12
AC_DEFINE([HAVE_LIBREADLINE], 1,
[Define if you have a readline compatible library])
diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in
index 005f2d25..ed963c93 100755
--- a/infrastructure/makebuildenv.pl.in
+++ b/infrastructure/makebuildenv.pl.in
@@ -261,7 +261,11 @@ for(@modules_files)
push @modules,$mod;
my @md; # module dependencies
my @lo; # link line options
+<<<<<<< HEAD
+ for(@deps)
+=======
for (@deps)
+>>>>>>> 0.12
{
if(/\A-l/)
{
@@ -277,7 +281,11 @@ for(@modules_files)
# make directories, but not if we're using an external library and this a library module
my ($s,$d) = split /\//,$mod;
+<<<<<<< HEAD
+ if($s ne 'lib' || $external_lib eq '')
+=======
if ($s ne 'lib' or $external_lib eq '')
+>>>>>>> 0.12
{
mkdir "release/$s",0755;
mkdir "release/$s/$d",0755;
@@ -346,8 +354,12 @@ for my $mod (@modules, @implicit_deps)
for(grep /\.h\Z/i, @items)
{
next if /\A\._/; # Temp Mac OS Resource hack
+<<<<<<< HEAD
+ die "Header file $_ already used in module ".$hfiles{$_}."\n" if exists $hfiles{$_};
+=======
die "Header file $_ already used in module ".$hfiles{$_}.
", cannot add to $mod\n" if exists $hfiles{$_};
+>>>>>>> 0.12
$hfiles{$_} = $mod
}
}
@@ -376,11 +388,18 @@ for my $mod (@modules, @implicit_deps)
closedir DIR;
}
+<<<<<<< HEAD
+=======
# Then write a makefile for each module
+>>>>>>> 0.12
print "done\n\nGenerating Makefiles...\n";
my %module_resources_win32;
+<<<<<<< HEAD
+# Then write a makefile for each module
+=======
+>>>>>>> 0.12
for my $mod (@implicit_deps, @modules)
{
print $mod,"\n";
@@ -484,7 +503,10 @@ __E
}
my @all_deps_for_module;
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
{
# work out what dependencies need to be run
my @deps_raw;
@@ -568,16 +590,27 @@ WINDRES = @WINDRES@
DEFAULT_CXXFLAGS = @CPPFLAGS@ $default_cxxflags @CXXFLAGS_STRICT@ \\
$include_paths $extra_platform_defines \\
-DBOX_VERSION="\\"$product_version\\""
+<<<<<<< HEAD
+LDFLAGS = @LDFLAGS@ @LDADD_RDYNAMIC@
+
+.ifdef RELEASE
+CXXFLAGS = -DBOX_RELEASE_BUILD $release_flags \$(DEFAULT_CXXFLAGS)
+=======
LDFLAGS += @LDFLAGS@ @LDADD_RDYNAMIC@
.ifdef RELEASE
CXXFLAGS += -DBOX_RELEASE_BUILD $release_flags \$(DEFAULT_CXXFLAGS)
+>>>>>>> 0.12
OUTBASE = ../../release
OUTDIR = ../../release/$mod
DEPENDMAKEFLAGS = -D RELEASE
VARIENT = RELEASE
.else
+<<<<<<< HEAD
+CXXFLAGS = -g \$(DEFAULT_CXXFLAGS)
+=======
CXXFLAGS += -g \$(DEFAULT_CXXFLAGS)
+>>>>>>> 0.12
OUTBASE = ../../debug
OUTDIR = ../../debug/$mod
DEPENDMAKEFLAGS =
@@ -622,12 +655,15 @@ _PERL = \$(if \$(V),\$(PERL), @ echo " [PERL] \$@" && \$(PERL) >/dev/n
__E
}
+<<<<<<< HEAD
+=======
# if there is a Makefile.pre, include it now
if(-e "$mod/Makefile.pre")
{
print MAKE ".include <Makefile.pre>\n\n";
}
+>>>>>>> 0.12
# read directory
opendir DIR,$mod;
@@ -748,7 +784,11 @@ __E
$has_deps = 1;
$has_deps = 0 if $target_is_library;
+<<<<<<< HEAD
+ # Depenency stuff
+=======
# Dependency stuff
+>>>>>>> 0.12
my $deps_makeinfo;
if($has_deps)
{
@@ -774,6 +814,9 @@ __E
# run make for things we require
for my $dep (@all_deps_for_module)
{
+<<<<<<< HEAD
+ $deps_makeinfo .= "\t\t\$(HIDE) (cd ../../$dep; \$(MAKE)$sub_make_options -q \$(DEPENDMAKEFLAGS) -D NODEPS || \$(MAKE)$sub_make_options \$(DEPENDMAKEFLAGS) -D NODEPS)\n";
+=======
my $dep_target = "";
if ($dep =~ m|^lib/(.*)|)
{
@@ -795,12 +838,17 @@ __E
|| \$(MAKE) $sub_make_options \$(DEPENDMAKEFLAGS) -D NODEPS $dep_target \\
)
EOF
+>>>>>>> 0.12
}
$deps_makeinfo .= ".\tendif\n.endif\n\n";
}
print MAKE $deps_makeinfo if $bsd_make;
+<<<<<<< HEAD
+ # get the list of library things to add -- in order of dependency so things link properly
+ my $lib_files = join(' ',map {($_ =~ m/lib\/(.+)\Z/)?('$(OUTBASE)/'.$_.'/'.$1.'.a'):undef} (reverse(@all_deps_for_module)));
+=======
# get the list of library things to add -- in order of dependency
# so things link properly
my @lib_files;
@@ -815,6 +863,7 @@ EOF
push @lib_files, "../../$dep/lib$1.a";
}
}
+>>>>>>> 0.12
# need to see if the extra makefile fragments require extra object files
# or include any more makefiles
@@ -833,7 +882,11 @@ EOF
}
print MAKE $end_target,': ',$o_file_list;
+<<<<<<< HEAD
+ print MAKE " ",$lib_files unless $target_is_library;
+=======
print MAKE " @lib_files" unless $target_is_library;
+>>>>>>> 0.12
print MAKE "\n";
if ($target_windows)
@@ -860,6 +913,15 @@ EOF
# work out library options
# need to be... least used first, in absolute order they appear in the modules.txt file
my @libops;
+<<<<<<< HEAD
+ sub libops_fill
+ {
+ my ($m,$r) = @_;
+ push @$r,$_ for(@{$module_library_link_opts{$m}});
+ libops_fill($_,$r) for(@{$module_dependency{$m}});
+ }
+ libops_fill($mod,\@libops);
+=======
sub libops_fill
{
@@ -880,6 +942,7 @@ EOF
libops_fill($mod,\@libops);
+>>>>>>> 0.12
my $lo = '';
my %ldone;
for(@libops)
@@ -892,16 +955,24 @@ EOF
# link line...
print MAKE "\t\$(_LINK) \$(LDFLAGS) $link_line_extra " .
"-o $end_target $o_file_list " .
+<<<<<<< HEAD
+ "$lib_files$lo $platform_lib_files\n";
+ }
+=======
"@lib_files $lo $platform_lib_files\n";
}
+>>>>>>> 0.12
# tests need to copy the test file over
if($type eq 'test')
{
print MAKE "\tcp _t \$(OUTDIR)/t\n\tchmod u+x \$(OUTDIR)/t\n";
print MAKE "\tcp _t-gdb \$(OUTDIR)/t-gdb\n\tchmod u+x \$(OUTDIR)/t-gdb\n";
}
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
# dependency line?
print MAKE "\n";
diff --git a/infrastructure/makeparcels.pl.in b/infrastructure/makeparcels.pl.in
index 5afdf730..f468dc1f 100755
--- a/infrastructure/makeparcels.pl.in
+++ b/infrastructure/makeparcels.pl.in
@@ -123,7 +123,11 @@ release/common/test:
.PHONY: docs
docs:
+<<<<<<< HEAD
+ \$(MAKE) -C docs
+=======
cd docs; \$(MAKE)
+>>>>>>> 0.12
__END_OF_FRAGMENT
@@ -137,9 +141,12 @@ for my $parcel (@parcels)
my $dir = BoxPlatform::parcel_dir($parcel);
my @parcel_deps;
+<<<<<<< HEAD
+=======
# Need to use BSD install on Solaris
my $install_bin = $build_os eq 'SunOS' ? '/usr/ucb/install' : 'install';
+>>>>>>> 0.12
unless ($target_windows)
{
open SCRIPT,">parcels/scripts/install-$parcel" or die
@@ -220,11 +227,18 @@ $dir/${name}.gz: docs/man/${name}.gz
EOF
# Releases have the docs pre-made, but users
# may want to rebuild them for some reason.
+<<<<<<< HEAD
+ print MAKE <<EOF;
+.PHONY: docs/man/${name}.gz
+docs/man/${name}.gz:
+ \$(MAKE) -C docs man/${name}.gz
+=======
my $docbook_source = "docs/docbook/${name}";
$docbook_source =~ s/\.[58]$/.xml/;
print MAKE <<EOF;
docs/man/${name}.gz: $docbook_source docs/docbook/bb-man.xsl
cd docs; \$(MAKE) man/${name}.gz
+>>>>>>> 0.12
EOF
push @parcel_deps, "$dir/${name}.gz";
@@ -239,26 +253,43 @@ $dir/docs/${name}.html: docs/htmlguide/man-html/${name}.html
EOF
# Releases have the docs pre-made, but users
# may want to rebuild them for some reason.
+<<<<<<< HEAD
+ print MAKE <<EOF;
+.PHONY: docs/htmlguide/man-html/${name}.html
+docs/htmlguide/man-html/${name}.html:
+ \$(MAKE) -C docs htmlguide/man-html/${name}.html
+=======
my $docbook_source = "docs/docbook/${name}.xml";
print MAKE <<EOF;
docs/htmlguide/man-html/${name}.html: $docbook_source docs/docbook/bb-nochunk-book.xsl
cd docs; \$(MAKE) htmlguide/man-html/${name}.html
+>>>>>>> 0.12
EOF
push @parcel_deps, "$dir/docs/${name}.html";
}
elsif ($type eq 'subdir')
{
+<<<<<<< HEAD
+=======
shift @args;
my $subdir = shift @args;
+>>>>>>> 0.12
print MAKE <<EOF;
.PHONY: $name-build $name-clean
$name-build:
+<<<<<<< HEAD
+ \$(MAKE) -C $name
+
+$name-clean:
+ \$(MAKE) -C $name clean
+=======
cd $subdir; \$(MAKE) @args
$name-clean:
cd $name; \$(MAKE) clean
+>>>>>>> 0.12
EOF
push @parcel_deps, "$name-build";
push @clean_deps, "$name-clean";
@@ -303,7 +334,11 @@ EOF
if ($type eq 'html')
{
+<<<<<<< HEAD
+ $dest = "share/doc/$version";
+=======
$dest = "share/doc/@PACKAGE_TARNAME@";
+>>>>>>> 0.12
$name = "docs/$name.html";
}
@@ -314,7 +349,11 @@ EOF
$name =~ s/$/\.gz/;
}
+<<<<<<< HEAD
+ if ($install and not $target_windows)
+=======
if ($install and not $target_windows and not $type eq "subdir")
+>>>>>>> 0.12
{
my $local_install_dir = $install_into_dir;
if (defined $dest)
@@ -331,7 +370,11 @@ EOF
}
print SCRIPT "mkdir -p " .
"\${DESTDIR}$local_install_dir/\n";
+<<<<<<< HEAD
+ print SCRIPT "install $name " .
+=======
print SCRIPT "$install_bin $name " .
+>>>>>>> 0.12
"\${DESTDIR}$local_install_dir\n";
}
}
@@ -365,11 +408,22 @@ install:
cat local/install.msg
clean: @clean_deps
+<<<<<<< HEAD
+ \$(MAKE) -C docs clean
+=======
cd docs; \$(MAKE) clean
+>>>>>>> 0.12
EOF
if ($build_os eq 'CYGWIN')
{
+<<<<<<< HEAD
+ print MAKE "\tfind release debug -type f | xargs -r rm -f\n";
+}
+else
+{
+ print MAKE "\tfind release debug -type f -exec rm -f {} \\;\n";
+=======
print MAKE "\tfind release debug -type f | xargs -r rm\n";
print MAKE "\tfind . -name 'autogen_*' -type f | xargs -r rm\n";
}
@@ -377,13 +431,19 @@ else
{
print MAKE "\tfind release debug -type f -exec rm -f {} \\;\n";
print MAKE "\tfind . -name 'autogen_*' -type f -exec rm -f {} \\;\n";
+>>>>>>> 0.12
}
for my $parcel (@parcels)
{
+<<<<<<< HEAD
+ print MAKE "\trm -rf ", BoxPlatform::parcel_dir($parcel), "\n";
+ print MAKE "\trm -f ", BoxPlatform::parcel_target($parcel), "\n";
+=======
# need to use -f to avoid error if they don't exist (already cleaned)
print MAKE "\trm -rf ", BoxPlatform::parcel_dir($parcel), "\n";
print MAKE "\trm -f ", BoxPlatform::parcel_target($parcel), "\n";
+>>>>>>> 0.12
}
close MAKE;
diff --git a/infrastructure/mingw/configure.sh b/infrastructure/mingw/configure.sh
index 46a61637..5f16c558 100755
--- a/infrastructure/mingw/configure.sh
+++ b/infrastructure/mingw/configure.sh
@@ -16,12 +16,21 @@ if [ ! -r "$DEP_PATH/lib/libpcreposix.a" \
exit 2
fi
+<<<<<<< HEAD
+export CXX="g++ -mno-cygwin"
+export LD="g++ -mno-cygwin"
+export CFLAGS="-mno-cygwin -mthreads"
+export CXXFLAGS="-mno-cygwin -mthreads"
+export LDFLAGS="-mno-cygwin -mthreads"
+export LIBS="-lcrypto -lws2_32 -lgdi32"
+=======
LIBZ_PATH="${DEP_PATH}/sys-root/mingw/lib"
if [ ! -r "$LIBZ_PATH/libz.dll.a" ]; then
echo "Error: upgrade your Cygwin mingw-zlib-devel package" >&2
exit 2
fi
+>>>>>>> 0.12
if [ ! -x "configure" ]; then
if ! ./bootstrap; then
@@ -30,12 +39,16 @@ if [ ! -x "configure" ]; then
fi
fi
+<<<<<<< HEAD
+if ! ./configure --target=i686-pc-mingw32; then
+=======
if ! ./configure "$@" --target=i686-pc-mingw32 \
CFLAGS="-mno-cygwin -mthreads" \
CPPFLAGS="-mno-cygwin" \
CXXFLAGS="-mno-cygwin -mthreads" \
LDFLAGS="-Wl,-Bstatic -mno-cygwin -mthreads -L${DEP_PATH}/lib -L${LIBZ_PATH}"
then
+>>>>>>> 0.12
echo "Error: configure failed, aborting." >&2
exit 1
fi
diff --git a/infrastructure/msvc/getversion.pl b/infrastructure/msvc/getversion.pl
index 0cf9cbcb..42ae4b63 100644
--- a/infrastructure/msvc/getversion.pl
+++ b/infrastructure/msvc/getversion.pl
@@ -11,6 +11,13 @@ chdir $basedir or die "$basedir: $!";
require "$basedir\\infrastructure\\BoxPlatform.pm.in";
+<<<<<<< HEAD
+open VERSIONFILE, "> $basedir/lib/common/BoxVersion.h"
+ or die "BoxVersion.h: $!";
+print VERSIONFILE "#define BOX_VERSION \"$BoxPlatform::product_version\"\n";
+close VERSIONFILE;
+
+=======
my $verfile = "$basedir/lib/common/BoxVersion.h";
my $newver = "#define BOX_VERSION \"$BoxPlatform::product_version\"\n";
my $oldver = "";
@@ -31,4 +38,5 @@ if ($newver ne $oldver)
}
print $BoxPlatform::product_version;
+>>>>>>> 0.12
exit 0;
diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp
new file mode 100644
index 00000000..b25ed9c7
--- /dev/null
+++ b/lib/backupclient/BackupClientFileAttributes.cpp
@@ -0,0 +1,1186 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupClientFileAttributes.cpp
+// Purpose: Storage of file attributes
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <algorithm>
+#include <cstring>
+#include <new>
+#include <vector>
+
+#ifdef HAVE_SYS_XATTR_H
+#include <cerrno>
+#include <sys/xattr.h>
+#endif
+
+#include <cstring>
+
+#include "BackupClientFileAttributes.h"
+#include "CommonException.h"
+#include "FileModificationTime.h"
+#include "BoxTimeToUnix.h"
+#include "BackupStoreException.h"
+#include "CipherContext.h"
+#include "CipherBlowfish.h"
+#include "MD5Digest.h"
+
+#include "MemLeakFindOn.h"
+
+// set packing to one byte
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "BeginStructPackForWire.h"
+#else
+BEGIN_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
+#define ATTRIBUTETYPE_GENERIC_UNIX 1
+
+#define ATTRIBUTE_ENCODING_BLOWFISH 2
+
+typedef struct
+{
+ int32_t AttributeType;
+ u_int32_t UID;
+ u_int32_t GID;
+ u_int64_t ModificationTime;
+ u_int64_t AttrModificationTime;
+ u_int32_t UserDefinedFlags;
+ u_int32_t FileGenerationNumber;
+ u_int16_t Mode;
+ // Symbolic link filename may follow
+ // Extended attribute (xattr) information may follow, format is:
+ // u_int32_t Size of extended attribute block (excluding this word)
+ // For each of NumberOfAttributes (sorted by AttributeName):
+ // u_int16_t AttributeNameLength
+ // char AttributeName[AttributeNameLength]
+ // u_int32_t AttributeValueLength
+ // unsigned char AttributeValue[AttributeValueLength]
+ // AttributeName is 0 terminated, AttributeValue is not (and may be binary data)
+} attr_StreamFormat;
+
+// This has wire packing so it's compatible across platforms
+// Use wider than necessary sizes, just to be careful.
+typedef struct
+{
+ int32_t uid, gid, mode;
+ #ifdef WIN32
+ int64_t fileCreationTime;
+ #endif
+} attributeHashData;
+
+// Use default packing
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "EndStructPackForWire.h"
+#else
+END_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
+
+#define MAX_ATTRIBUTE_HASH_SECRET_LENGTH 256
+
+// Hide private static variables from the rest of the world
+// -- don't put them as static class variables to avoid openssl/evp.h being
+// included all over the project.
+namespace
+{
+ CipherContext sBlowfishEncrypt;
+ CipherContext sBlowfishDecrypt;
+ uint8_t sAttributeHashSecret[MAX_ATTRIBUTE_HASH_SECRET_LENGTH];
+ int sAttributeHashSecretLength = 0;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::BackupClientFileAttributes()
+// Purpose: Default constructor
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+BackupClientFileAttributes::BackupClientFileAttributes()
+ : mpClearAttributes(0)
+{
+ ASSERT(sizeof(u_int64_t) == sizeof(box_time_t));
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::BackupClientFileAttributes(const BackupClientFileAttributes &)
+// Purpose: Copy constructor
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+BackupClientFileAttributes::BackupClientFileAttributes(const BackupClientFileAttributes &rToCopy)
+ : StreamableMemBlock(rToCopy), // base class does the hard work
+ mpClearAttributes(0)
+{
+}
+BackupClientFileAttributes::BackupClientFileAttributes(const StreamableMemBlock &rToCopy)
+ : StreamableMemBlock(rToCopy), // base class does the hard work
+ mpClearAttributes(0)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::~BackupClientFileAttributes()
+// Purpose: Destructor
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+BackupClientFileAttributes::~BackupClientFileAttributes()
+{
+ if(mpClearAttributes)
+ {
+ delete mpClearAttributes;
+ mpClearAttributes = 0;
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes &operator=(const BackupClientFileAttributes &)
+// Purpose: Assignment operator
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+BackupClientFileAttributes &BackupClientFileAttributes::operator=(const BackupClientFileAttributes &rAttr)
+{
+ StreamableMemBlock::Set(rAttr);
+ RemoveClear(); // make sure no decrypted version held
+ return *this;
+}
+// Assume users play nice
+BackupClientFileAttributes &BackupClientFileAttributes::operator=(const StreamableMemBlock &rAttr)
+{
+ StreamableMemBlock::Set(rAttr);
+ RemoveClear(); // make sure no decrypted version held
+ return *this;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::operator==(const BackupClientFileAttributes &)
+// Purpose: Comparison operator
+// Created: 2003/10/09
+//
+// --------------------------------------------------------------------------
+bool BackupClientFileAttributes::operator==(const BackupClientFileAttributes &rAttr) const
+{
+ EnsureClearAvailable();
+ rAttr.EnsureClearAvailable();
+
+ return mpClearAttributes->operator==(*rAttr.mpClearAttributes);
+}
+// Too dangerous to allow -- put the two names the wrong way round, and it compares encrypted data.
+/*bool BackupClientFileAttributes::operator==(const StreamableMemBlock &rAttr) const
+{
+ StreamableMemBlock *pDecoded = 0;
+
+ try
+ {
+ EnsureClearAvailable();
+ StreamableMemBlock *pDecoded = MakeClear(rAttr);
+
+ // Compare using clear version
+ bool compared = mpClearAttributes->operator==(rAttr);
+
+ // Delete temporary
+ delete pDecoded;
+
+ return compared;
+ }
+ catch(...)
+ {
+ delete pDecoded;
+ throw;
+ }
+}*/
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::Compare(const BackupClientFileAttributes &, bool)
+// Purpose: Compare, optionally ignoring the attribute
+// modification time and/or modification time, and some
+// data which is irrelevant in practise (eg file
+// generation number)
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+bool BackupClientFileAttributes::Compare(const BackupClientFileAttributes &rAttr,
+ bool IgnoreAttrModTime, bool IgnoreModTime) const
+{
+ EnsureClearAvailable();
+ rAttr.EnsureClearAvailable();
+
+ // Check sizes are the same, as a first check
+ if(mpClearAttributes->GetSize() != rAttr.mpClearAttributes->GetSize())
+ {
+ BOX_TRACE("Attribute Compare: Attributes objects are "
+ "different sizes, cannot compare them: local " <<
+ mpClearAttributes->GetSize() << " bytes, remote " <<
+ rAttr.mpClearAttributes->GetSize() << " bytes");
+ return false;
+ }
+
+ // Then check the elements of the two things
+ // Bytes are checked in network order, but this doesn't matter as we're only checking for equality.
+ attr_StreamFormat *a1 = (attr_StreamFormat*)mpClearAttributes->GetBuffer();
+ attr_StreamFormat *a2 = (attr_StreamFormat*)rAttr.mpClearAttributes->GetBuffer();
+
+ #define COMPARE(attribute, message) \
+ if (a1->attribute != a2->attribute) \
+ { \
+ BOX_TRACE("Attribute Compare: " << message << " differ: " \
+ "local " << ntoh(a1->attribute) << ", " \
+ "remote " << ntoh(a2->attribute)); \
+ return false; \
+ }
+ COMPARE(AttributeType, "Attribute types");
+ COMPARE(UID, "UIDs");
+ COMPARE(GID, "GIDs");
+ COMPARE(UserDefinedFlags, "User-defined flags");
+ COMPARE(Mode, "Modes");
+
+ if(!IgnoreModTime)
+ {
+ uint64_t t1 = box_ntoh64(a1->ModificationTime);
+ uint64_t t2 = box_ntoh64(a2->ModificationTime);
+ time_t s1 = BoxTimeToSeconds(t1);
+ time_t s2 = BoxTimeToSeconds(t2);
+ if(s1 != s2)
+ {
+ BOX_TRACE("Attribute Compare: File modification "
+ "times differ: local " <<
+ FormatTime(t1, true) << " (" << s1 << "), "
+ "remote " <<
+ FormatTime(t2, true) << " (" << s2 << ")");
+ return false;
+ }
+ }
+
+ if(!IgnoreAttrModTime)
+ {
+ uint64_t t1 = box_ntoh64(a1->AttrModificationTime);
+ uint64_t t2 = box_ntoh64(a2->AttrModificationTime);
+ time_t s1 = BoxTimeToSeconds(t1);
+ time_t s2 = BoxTimeToSeconds(t2);
+ if(s1 != s2)
+ {
+ BOX_TRACE("Attribute Compare: Attribute modification "
+ "times differ: local " <<
+ FormatTime(t1, true) << " (" << s1 << "), "
+ "remote " <<
+ FormatTime(t2, true) << " (" << s2 << ")");
+ return false;
+ }
+ }
+
+ // Check symlink string?
+ unsigned int size = mpClearAttributes->GetSize();
+ if(size > sizeof(attr_StreamFormat))
+ {
+ // Symlink strings don't match. This also compares xattrs
+ int datalen = size - sizeof(attr_StreamFormat);
+
+ if(::memcmp(a1 + 1, a2 + 1, datalen) != 0)
+ {
+ std::string s1((char *)(a1 + 1), datalen);
+ std::string s2((char *)(a2 + 1), datalen);
+ BOX_TRACE("Attribute Compare: Symbolic link target "
+ "or extended attributes differ: "
+ "local " << PrintEscapedBinaryData(s1) << ", "
+ "remote " << PrintEscapedBinaryData(s2));
+ return false;
+ }
+ }
+
+ // Passes all test, must be OK
+ return true;
+}
+
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::ReadAttributes(
+// const char *Filename, bool ZeroModificationTimes,
+// box_time_t *pModTime, box_time_t *pAttrModTime,
+// int64_t *pFileSize, InodeRefType *pInodeNumber,
+// bool *pHasMultipleLinks)
+// Purpose: Read the attributes of the file, and store them
+// ready for streaming. Optionally retrieve the
+// modification time and attribute modification time.
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::ReadAttributes(const char *Filename,
+ bool ZeroModificationTimes, box_time_t *pModTime,
+ box_time_t *pAttrModTime, int64_t *pFileSize,
+ InodeRefType *pInodeNumber, bool *pHasMultipleLinks)
+{
+ StreamableMemBlock *pnewAttr = 0;
+ try
+ {
+ EMU_STRUCT_STAT st;
+ if(EMU_LSTAT(Filename, &st) != 0)
+ {
+ BOX_LOG_SYS_ERROR("Failed to stat file: '" <<
+ Filename << "'");
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ // Modification times etc
+ if(pModTime) {*pModTime = FileModificationTime(st);}
+ if(pAttrModTime) {*pAttrModTime = FileAttrModificationTime(st);}
+ if(pFileSize) {*pFileSize = st.st_size;}
+ if(pInodeNumber) {*pInodeNumber = st.st_ino;}
+ if(pHasMultipleLinks) {*pHasMultipleLinks = (st.st_nlink > 1);}
+
+ pnewAttr = new StreamableMemBlock;
+
+ FillAttributes(*pnewAttr, Filename, st, ZeroModificationTimes);
+
+#ifndef WIN32
+ // Is it a link?
+ if((st.st_mode & S_IFMT) == S_IFLNK)
+ {
+ FillAttributesLink(*pnewAttr, Filename, st);
+ }
+#endif
+
+ FillExtendedAttr(*pnewAttr, Filename);
+
+#ifdef WIN32
+ //this is to catch those problems with invalid time stamps stored...
+ //need to find out the reason why - but also a catch as well.
+
+ attr_StreamFormat *pattr =
+ (attr_StreamFormat*)pnewAttr->GetBuffer();
+ ASSERT(pattr != 0);
+
+ // __time64_t winTime = BoxTimeToSeconds(
+ // pnewAttr->ModificationTime);
+
+ u_int64_t modTime = box_ntoh64(pattr->ModificationTime);
+ box_time_t modSecs = BoxTimeToSeconds(modTime);
+ __time64_t winTime = modSecs;
+
+ // _MAX__TIME64_T doesn't seem to be defined, but the code below
+ // will throw an assertion failure if we exceed it :-)
+ // Microsoft says dates up to the year 3000 are valid, which
+ // is a bit more than 15 * 2^32. Even that doesn't seem
+ // to be true (still aborts), but it can at least hold 2^32.
+ if (winTime >= 0x100000000LL || _gmtime64(&winTime) == 0)
+ {
+ BOX_ERROR("Invalid Modification Time caught for "
+ "file: '" << Filename << "'");
+ pattr->ModificationTime = 0;
+ }
+
+ modTime = box_ntoh64(pattr->AttrModificationTime);
+ modSecs = BoxTimeToSeconds(modTime);
+ winTime = modSecs;
+
+ if (winTime > 0x100000000LL || _gmtime64(&winTime) == 0)
+ {
+ BOX_ERROR("Invalid Attribute Modification Time "
+ "caught for file: '" << Filename << "'");
+ pattr->AttrModificationTime = 0;
+ }
+#endif
+
+ // Attributes ready. Encrypt into this block
+ EncryptAttr(*pnewAttr);
+
+ // Store the new attributes
+ RemoveClear();
+ mpClearAttributes = pnewAttr;
+ pnewAttr = 0;
+ }
+ catch(...)
+ {
+ // clean up
+ delete pnewAttr;
+ pnewAttr = 0;
+ throw;
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::ReadAttributesLink()
+// Purpose: Private function, handles standard attributes for all objects
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::FillAttributes(StreamableMemBlock &outputBlock, const char *Filename, EMU_STRUCT_STAT &st, bool ZeroModificationTimes)
+{
+ outputBlock.ResizeBlock(sizeof(attr_StreamFormat));
+ attr_StreamFormat *pattr = (attr_StreamFormat*)outputBlock.GetBuffer();
+ ASSERT(pattr != 0);
+
+ // Fill in the entries
+ pattr->AttributeType = htonl(ATTRIBUTETYPE_GENERIC_UNIX);
+ pattr->UID = htonl(st.st_uid);
+ pattr->GID = htonl(st.st_gid);
+ if(ZeroModificationTimes)
+ {
+ pattr->ModificationTime = 0;
+ pattr->AttrModificationTime = 0;
+ }
+ else
+ {
+ pattr->ModificationTime = box_hton64(FileModificationTime(st));
+ pattr->AttrModificationTime = box_hton64(FileAttrModificationTime(st));
+ }
+ pattr->Mode = htons(st.st_mode);
+
+#ifndef HAVE_STRUCT_STAT_ST_FLAGS
+ pattr->UserDefinedFlags = 0;
+ pattr->FileGenerationNumber = 0;
+#else
+ pattr->UserDefinedFlags = htonl(st.st_flags);
+ pattr->FileGenerationNumber = htonl(st.st_gen);
+#endif
+}
+#ifndef WIN32
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::ReadAttributesLink()
+// Purpose: Private function, handles the case where a symbolic link is needed
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::FillAttributesLink(StreamableMemBlock &outputBlock, const char *Filename, struct stat &st)
+{
+ // Make sure we're only called for symbolic links
+ ASSERT((st.st_mode & S_IFMT) == S_IFLNK);
+
+ // Get the filename the link is linked to
+ char linkedTo[PATH_MAX+4];
+ int linkedToSize = ::readlink(Filename, linkedTo, PATH_MAX);
+ if(linkedToSize == -1)
+ {
+ BOX_LOG_SYS_ERROR("Failed to readlink '" << Filename << "'");
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+
+ int oldSize = outputBlock.GetSize();
+ outputBlock.ResizeBlock(oldSize+linkedToSize+1);
+ char* buffer = static_cast<char*>(outputBlock.GetBuffer());
+
+ // Add the path name for the symbolic link, and add 0 termination
+ std::memcpy(buffer+oldSize, linkedTo, linkedToSize);
+ buffer[oldSize+linkedToSize] = '\0';
+}
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::ReadExtendedAttr(const char *, unsigned char**)
+// Purpose: Private function, read the extended attributes of the file into the block
+// Created: 2005/06/12
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::FillExtendedAttr(StreamableMemBlock &outputBlock, const char *Filename)
+{
+#ifdef HAVE_SYS_XATTR_H
+ int listBufferSize = 10000;
+ char* list = new char[listBufferSize];
+
+ try
+ {
+ // This returns an unordered list of attribute names, each 0 terminated,
+ // concatenated together
+ int listSize = ::llistxattr(Filename, list, listBufferSize);
+
+ if(listSize>listBufferSize)
+ {
+ delete[] list, list = NULL;
+ list = new char[listSize];
+ listSize = ::llistxattr(Filename, list, listSize);
+ }
+
+ if(listSize>0)
+ {
+ // Extract list of attribute names so we can sort them
+ std::vector<std::string> attrKeys;
+ for(int i = 0; i<listSize; ++i)
+ {
+ std::string attrKey(list+i);
+ i += attrKey.size();
+ attrKeys.push_back(attrKey);
+ }
+ sort(attrKeys.begin(), attrKeys.end());
+
+ // Make initial space in block
+ int xattrSize = outputBlock.GetSize();
+ int xattrBufferSize = (xattrSize+listSize)>500 ? (xattrSize+listSize)*2 : 1000;
+ outputBlock.ResizeBlock(xattrBufferSize);
+ unsigned char* buffer = static_cast<unsigned char*>(outputBlock.GetBuffer());
+
+ // Leave space for attr block size later
+ int xattrBlockSizeOffset = xattrSize;
+ xattrSize += sizeof(u_int32_t);
+
+ // Loop for each attribute
+ for(std::vector<std::string>::const_iterator attrKeyI = attrKeys.begin(); attrKeyI!=attrKeys.end(); ++attrKeyI)
+ {
+ std::string attrKey(*attrKeyI);
+
+ if(xattrSize+sizeof(u_int16_t)+attrKey.size()+1+sizeof(u_int32_t)>static_cast<unsigned int>(xattrBufferSize))
+ {
+ xattrBufferSize = (xattrBufferSize+sizeof(u_int16_t)+attrKey.size()+1+sizeof(u_int32_t))*2;
+ outputBlock.ResizeBlock(xattrBufferSize);
+ buffer = static_cast<unsigned char*>(outputBlock.GetBuffer());
+ }
+
+ // Store length and text for attibute name
+ u_int16_t keyLength = htons(attrKey.size()+1);
+ std::memcpy(buffer+xattrSize, &keyLength, sizeof(u_int16_t));
+ xattrSize += sizeof(u_int16_t);
+ std::memcpy(buffer+xattrSize, attrKey.c_str(), attrKey.size()+1);
+ xattrSize += attrKey.size()+1;
+
+ // Leave space for value size
+ int valueSizeOffset = xattrSize;
+ xattrSize += sizeof(u_int32_t);
+
+ // Find size of attribute (must call with buffer and length 0 on some platforms,
+ // as -1 is returned if the data doesn't fit.)
+ int valueSize = ::lgetxattr(Filename, attrKey.c_str(), 0, 0);
+ if(valueSize<0)
+ {
+ BOX_LOG_SYS_ERROR("Failed to get "
+ "extended attributes size "
+ "for '" << Filename << "'");
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+
+ // Resize block, if needed
+ if(xattrSize+valueSize>xattrBufferSize)
+ {
+ xattrBufferSize = (xattrBufferSize+valueSize)*2;
+ outputBlock.ResizeBlock(xattrBufferSize);
+ buffer = static_cast<unsigned char*>(outputBlock.GetBuffer());
+ }
+
+ // This gets the attribute value (may be text or binary), no termination
+ valueSize = ::lgetxattr(Filename, attrKey.c_str(), buffer+xattrSize, xattrBufferSize-xattrSize);
+ if(valueSize<0)
+ {
+ BOX_LOG_SYS_ERROR("Failed to get "
+ "extended attributes for "
+ "'" << Filename << "'");
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+ xattrSize += valueSize;
+
+ // Fill in value size
+ u_int32_t valueLength = htonl(valueSize);
+ std::memcpy(buffer+valueSizeOffset, &valueLength, sizeof(u_int32_t));
+ }
+
+ // Fill in attribute block size
+ u_int32_t xattrBlockLength = htonl(xattrSize-xattrBlockSizeOffset-sizeof(u_int32_t));
+ std::memcpy(buffer+xattrBlockSizeOffset, &xattrBlockLength, sizeof(u_int32_t));
+
+ outputBlock.ResizeBlock(xattrSize);
+ }
+ else if(listSize<0)
+ {
+ if(errno == EOPNOTSUPP || errno == EACCES)
+ {
+ // fail silently
+ }
+ else if(errno == ERANGE)
+ {
+ BOX_ERROR("Failed to list extended "
+ "attributes of '" << Filename << "': "
+ "buffer too small, not backed up");
+ }
+ else
+ {
+ BOX_LOG_SYS_ERROR("Failed to list extended "
+ "attributes of '" << Filename << "', "
+ "not backed up");
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+ }
+ }
+ catch(...)
+ {
+ delete[] list;
+ throw;
+ }
+ delete[] list;
+#endif
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::GetModificationTimes()
+// Purpose: Returns the modification time embedded in the
+// attributes.
+// Created: 2010/02/24
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::GetModificationTimes(
+ box_time_t *pModificationTime,
+ box_time_t *pAttrModificationTime) const
+{
+ // Got something loaded
+ if(GetSize() <= 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ // Make sure there are clear attributes to use
+ EnsureClearAvailable();
+ ASSERT(mpClearAttributes != 0);
+
+ // Check if the decrypted attributes are small enough, and the type of attributes stored
+ if(mpClearAttributes->GetSize() < (int)sizeof(int32_t))
+ {
+ THROW_EXCEPTION(BackupStoreException, AttributesNotUnderstood);
+ }
+ int32_t *type = (int32_t*)mpClearAttributes->GetBuffer();
+ ASSERT(type != 0);
+ if(ntohl(*type) != ATTRIBUTETYPE_GENERIC_UNIX)
+ {
+ // Don't know what to do with these
+ THROW_EXCEPTION(BackupStoreException, AttributesNotUnderstood);
+ }
+
+ // Check there is enough space for an attributes block
+ if(mpClearAttributes->GetSize() < (int)sizeof(attr_StreamFormat))
+ {
+ // Too small
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ // Get pointer to structure
+ attr_StreamFormat *pattr = (attr_StreamFormat*)mpClearAttributes->GetBuffer();
+
+ if(pModificationTime)
+ {
+ *pModificationTime = box_ntoh64(pattr->ModificationTime);
+ }
+
+ if(pAttrModificationTime)
+ {
+ *pAttrModificationTime = box_ntoh64(pattr->AttrModificationTime);
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::WriteAttributes(const char *)
+// Purpose: Apply the stored attributes to the file
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::WriteAttributes(const char *Filename,
+ bool MakeUserWritable) const
+{
+ // Got something loaded
+ if(GetSize() <= 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ // Make sure there are clear attributes to use
+ EnsureClearAvailable();
+ ASSERT(mpClearAttributes != 0);
+
+ // Check if the decrypted attributes are small enough, and the type of attributes stored
+ if(mpClearAttributes->GetSize() < (int)sizeof(int32_t))
+ {
+ THROW_EXCEPTION(BackupStoreException, AttributesNotUnderstood);
+ }
+ int32_t *type = (int32_t*)mpClearAttributes->GetBuffer();
+ ASSERT(type != 0);
+ if(ntohl(*type) != ATTRIBUTETYPE_GENERIC_UNIX)
+ {
+ // Don't know what to do with these
+ THROW_EXCEPTION(BackupStoreException, AttributesNotUnderstood);
+ }
+
+ // Check there is enough space for an attributes block
+ if(mpClearAttributes->GetSize() < (int)sizeof(attr_StreamFormat))
+ {
+ // Too small
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ // Get pointer to structure
+ attr_StreamFormat *pattr = (attr_StreamFormat*)mpClearAttributes->GetBuffer();
+ int xattrOffset = sizeof(attr_StreamFormat);
+
+ // is it a symlink?
+ int16_t mode = ntohs(pattr->Mode);
+ if((mode & S_IFMT) == S_IFLNK)
+ {
+ // Check things are sensible
+ if(mpClearAttributes->GetSize() < (int)sizeof(attr_StreamFormat) + 1)
+ {
+ // Too small
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+#ifdef WIN32
+ BOX_WARNING("Cannot create symbolic links on Windows: '" <<
+ Filename << "'");
+#else
+ // Make a symlink, first deleting anything in the way
+ ::unlink(Filename);
+ if(::symlink((char*)(pattr + 1), Filename) != 0)
+ {
+ BOX_LOG_SYS_ERROR("Failed to symlink '" << Filename <<
+ "' to '" << (char*)(pattr + 1) << "'");
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+#endif
+
+ xattrOffset += std::strlen(reinterpret_cast<char*>(pattr+1))+1;
+ }
+
+ // If working as root, set user IDs
+ if(::geteuid() == 0)
+ {
+ #ifndef HAVE_LCHOWN
+ // only if not a link, can't set their owner on this platform
+ if((mode & S_IFMT) != S_IFLNK)
+ {
+ // Not a link, use normal chown
+ if(::chown(Filename, ntohl(pattr->UID), ntohl(pattr->GID)) != 0)
+ {
+ BOX_LOG_SYS_ERROR("Failed to change "
+ "owner of file "
+ "'" << Filename << "'");
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+ }
+ #else
+ // use the version which sets things on symlinks
+ if(::lchown(Filename, ntohl(pattr->UID), ntohl(pattr->GID)) != 0)
+ {
+ BOX_LOG_SYS_ERROR("Failed to change owner of "
+ "symbolic link '" << Filename << "'");
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+ #endif
+ }
+
+ if(static_cast<int>(xattrOffset+sizeof(u_int32_t))<=mpClearAttributes->GetSize())
+ {
+ WriteExtendedAttr(Filename, xattrOffset);
+ }
+
+ // Stop now if symlink, because otherwise it'll just be applied to the target
+ if((mode & S_IFMT) == S_IFLNK)
+ {
+ return;
+ }
+
+ // Set modification time?
+ box_time_t modtime = box_ntoh64(pattr->ModificationTime);
+ if(modtime != 0)
+ {
+ // Work out times as timevals
+ struct timeval times[2];
+
+ #ifdef WIN32
+ BoxTimeToTimeval(box_ntoh64(pattr->ModificationTime),
+ times[1]);
+ BoxTimeToTimeval(box_ntoh64(pattr->AttrModificationTime),
+ times[0]);
+ // Because stat() returns the creation time in the ctime
+ // field under Windows, and this gets saved in the
+ // AttrModificationTime field of the serialised attributes,
+ // we subvert the first parameter of emu_utimes() to allow
+ // it to be reset to the right value on the restored file.
+ #else
+ BoxTimeToTimeval(modtime, times[1]);
+ // Copy access time as well, why not, got to set it to something
+ times[0] = times[1];
+ // Attr modification time will be changed anyway,
+ // nothing that can be done about it
+ #endif
+
+ // Try to apply
+ if(::utimes(Filename, times) != 0)
+ {
+ BOX_LOG_SYS_WARNING("Failed to change times of "
+ "file '" << Filename << "' to ctime=" <<
+ BOX_FORMAT_TIMESPEC(times[0]) << ", mtime=" <<
+ BOX_FORMAT_TIMESPEC(times[1]));
+ }
+ }
+
+ if (MakeUserWritable)
+ {
+ mode |= S_IRWXU;
+ }
+
+ // Apply everything else... (allowable mode flags only)
+ // Mode must be done last (think setuid)
+ if(::chmod(Filename, mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID
+ | S_ISGID | S_ISVTX)) != 0)
+ {
+ BOX_LOG_SYS_ERROR("Failed to change permissions of file "
+ "'" << Filename << "'");
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::IsSymLink()
+// Purpose: Do these attributes represent a symbolic link?
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+bool BackupClientFileAttributes::IsSymLink() const
+{
+ EnsureClearAvailable();
+
+ // Got the right kind of thing?
+ if(mpClearAttributes->GetSize() < (int)sizeof(int32_t))
+ {
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ // Get the type of attributes stored
+ int32_t *type = (int32_t*)mpClearAttributes->GetBuffer();
+ ASSERT(type != 0);
+ if(ntohl(*type) == ATTRIBUTETYPE_GENERIC_UNIX && mpClearAttributes->GetSize() > (int)sizeof(attr_StreamFormat))
+ {
+ // Check link
+ attr_StreamFormat *pattr = (attr_StreamFormat*)mpClearAttributes->GetBuffer();
+ return ((ntohs(pattr->Mode)) & S_IFMT) == S_IFLNK;
+ }
+
+ return false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::RemoveClear()
+// Purpose: Private. Deletes any clear version of the attributes that may be held
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::RemoveClear() const
+{
+ if(mpClearAttributes)
+ {
+ delete mpClearAttributes;
+ }
+ mpClearAttributes = 0;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::EnsureClearAvailable()
+// Purpose: Private. Makes sure the clear version is available
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::EnsureClearAvailable() const
+{
+ if(mpClearAttributes == 0)
+ {
+ mpClearAttributes = MakeClear(*this);
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::WriteExtendedAttr(const char *Filename, int xattrOffset)
+// Purpose: Private function, apply the stored extended attributes to the file
+// Created: 2005/06/13
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::WriteExtendedAttr(const char *Filename, int xattrOffset) const
+{
+#ifdef HAVE_SYS_XATTR_H
+ const char* buffer = static_cast<char*>(mpClearAttributes->GetBuffer());
+
+ u_int32_t xattrBlockLength = 0;
+ std::memcpy(&xattrBlockLength, buffer+xattrOffset, sizeof(u_int32_t));
+ int xattrBlockSize = ntohl(xattrBlockLength);
+ xattrOffset += sizeof(u_int32_t);
+
+ int xattrEnd = xattrOffset+xattrBlockSize;
+ if(xattrEnd>mpClearAttributes->GetSize())
+ {
+ // Too small
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ while(xattrOffset<xattrEnd)
+ {
+ u_int16_t keyLength = 0;
+ std::memcpy(&keyLength, buffer+xattrOffset, sizeof(u_int16_t));
+ int keySize = ntohs(keyLength);
+ xattrOffset += sizeof(u_int16_t);
+
+ const char* key = buffer+xattrOffset;
+ xattrOffset += keySize;
+
+ u_int32_t valueLength = 0;
+ std::memcpy(&valueLength, buffer+xattrOffset, sizeof(u_int32_t));
+ int valueSize = ntohl(valueLength);
+ xattrOffset += sizeof(u_int32_t);
+
+ // FIXME: Warn on EOPNOTSUPP
+ if(::lsetxattr(Filename, key, buffer+xattrOffset, valueSize, 0)!=0 && errno!=EOPNOTSUPP)
+ {
+ BOX_LOG_SYS_ERROR("Failed to set extended attributes "
+ "on file '" << Filename << "'");
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+
+ xattrOffset += valueSize;
+ }
+
+ ASSERT(xattrOffset==xattrEnd);
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::MakeClear(const StreamableMemBlock &)
+// Purpose: Static. Decrypts stored attributes.
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+StreamableMemBlock *BackupClientFileAttributes::MakeClear(const StreamableMemBlock &rEncrypted)
+{
+ // New block
+ StreamableMemBlock *pdecrypted = 0;
+
+ try
+ {
+ // Check the block is big enough for IV and header
+ int ivSize = sBlowfishEncrypt.GetIVLength();
+ if(rEncrypted.GetSize() <= (ivSize + 1))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadEncryptedAttributes);
+ }
+
+ // How much space is needed for the output?
+ int maxDecryptedSize = sBlowfishDecrypt.MaxOutSizeForInBufferSize(rEncrypted.GetSize() - ivSize);
+
+ // Allocate it
+ pdecrypted = new StreamableMemBlock(maxDecryptedSize);
+
+ // ptr to block
+ uint8_t *encBlock = (uint8_t*)rEncrypted.GetBuffer();
+
+ // Check that the header has right type
+ if(encBlock[0] != ATTRIBUTE_ENCODING_BLOWFISH)
+ {
+ THROW_EXCEPTION(BackupStoreException, EncryptedAttributesHaveUnknownEncoding);
+ }
+
+ // Set IV
+ sBlowfishDecrypt.SetIV(encBlock + 1);
+
+ // Decrypt
+ int decryptedSize = sBlowfishDecrypt.TransformBlock(pdecrypted->GetBuffer(), maxDecryptedSize, encBlock + 1 + ivSize, rEncrypted.GetSize() - (ivSize + 1));
+
+ // Resize block to fit
+ pdecrypted->ResizeBlock(decryptedSize);
+ }
+ catch(...)
+ {
+ delete pdecrypted;
+ pdecrypted = 0;
+ }
+
+ return pdecrypted;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::SetBlowfishKey(const void *, int)
+// Purpose: Static. Sets the key to use for encryption and decryption.
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::SetBlowfishKey(const void *pKey, int KeyLength)
+{
+ // IVs set later
+ sBlowfishEncrypt.Reset();
+ sBlowfishEncrypt.Init(CipherContext::Encrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength));
+ sBlowfishDecrypt.Reset();
+ sBlowfishDecrypt.Init(CipherContext::Decrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength));
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::EncryptAttr(const StreamableMemBlock &)
+// Purpose: Private. Encrypt the given attributes into this block.
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::EncryptAttr(const StreamableMemBlock &rToEncrypt)
+{
+ // Free any existing block
+ FreeBlock();
+
+ // Work out the maximum amount of space we need
+ int maxEncryptedSize = sBlowfishEncrypt.MaxOutSizeForInBufferSize(rToEncrypt.GetSize());
+ // And the size of the IV
+ int ivSize = sBlowfishEncrypt.GetIVLength();
+
+ // Allocate this space
+ AllocateBlock(maxEncryptedSize + ivSize + 1);
+
+ // Store the encoding byte
+ uint8_t *block = (uint8_t*)GetBuffer();
+ block[0] = ATTRIBUTE_ENCODING_BLOWFISH;
+
+ // Generate and store an IV for this attribute block
+ int ivSize2 = 0;
+ const void *iv = sBlowfishEncrypt.SetRandomIV(ivSize2);
+ ASSERT(ivSize == ivSize2);
+
+ // Copy into the encrypted block
+ ::memcpy(block + 1, iv, ivSize);
+
+ // Do the transform
+ int encrytedSize = sBlowfishEncrypt.TransformBlock(block + 1 + ivSize, maxEncryptedSize, rToEncrypt.GetBuffer(), rToEncrypt.GetSize());
+
+ // Resize this block
+ ResizeBlock(encrytedSize + ivSize + 1);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::SetAttributeHashSecret(const void *, int)
+// Purpose: Set the secret for the filename attribute hash
+// Created: 25/4/04
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::SetAttributeHashSecret(const void *pSecret, int SecretLength)
+{
+ if(SecretLength > (int)sizeof(sAttributeHashSecret))
+ {
+ SecretLength = sizeof(sAttributeHashSecret);
+ }
+ if(SecretLength < 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ // Copy
+ ::memcpy(sAttributeHashSecret, pSecret, SecretLength);
+ sAttributeHashSecretLength = SecretLength;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::GenerateAttributeHash(
+// struct stat &, const std::string &,
+// const std::string &)
+// Purpose: Generate a 64 bit hash from the attributes, used to
+// detect changes. Include filename in the hash, so
+// that it changes from one file to another, so don't
+// reveal identical attributes.
+// Created: 25/4/04
+//
+// --------------------------------------------------------------------------
+uint64_t BackupClientFileAttributes::GenerateAttributeHash(EMU_STRUCT_STAT &st,
+ const std::string &filename, const std::string &leafname)
+{
+ if(sAttributeHashSecretLength == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, AttributeHashSecretNotSet)
+ }
+
+ // Assemble stuff we're interested in
+ attributeHashData hashData;
+ memset(&hashData, 0, sizeof(hashData));
+ // Use network byte order and large sizes to be cross platform
+ hashData.uid = htonl(st.st_uid);
+ hashData.gid = htonl(st.st_gid);
+ hashData.mode = htonl(st.st_mode);
+
+ #ifdef WIN32
+ // On Windows, the "file attribute modification time" is the
+ // file creation time, and we want to back this up, restore
+ // it and compare it.
+ //
+ // On other platforms, it's not very important and can't
+ // reliably be set to anything other than the current time.
+ hashData.fileCreationTime = box_hton64(st.st_ctime);
+ #endif
+
+ StreamableMemBlock xattr;
+ FillExtendedAttr(xattr, filename.c_str());
+
+ // Create a MD5 hash of the data, filename, and secret
+ MD5Digest digest;
+ digest.Add(&hashData, sizeof(hashData));
+ digest.Add(xattr.GetBuffer(), xattr.GetSize());
+ digest.Add(leafname.c_str(), leafname.size());
+ digest.Add(sAttributeHashSecret, sAttributeHashSecretLength);
+ digest.Finish();
+
+ // Return the first 64 bits of the hash
+ uint64_t result = *((uint64_t *)(digest.DigestAsData()));
+ return result;
+}
diff --git a/lib/backupclient/BackupClientFileAttributes.h b/lib/backupclient/BackupClientFileAttributes.h
new file mode 100644
index 00000000..f9a0d883
--- /dev/null
+++ b/lib/backupclient/BackupClientFileAttributes.h
@@ -0,0 +1,78 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupClientFileAttributes.h
+// Purpose: Storage of file attributes
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPCLIENTFILEATTRIBUTES__H
+#define BACKUPCLIENTFILEATTRIBUTES__H
+
+#include <string>
+
+#include "StreamableMemBlock.h"
+#include "BoxTime.h"
+
+EMU_STRUCT_STAT; // declaration
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: BackupClientFileAttributes
+// Purpose: Storage, streaming and application of file attributes
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+class BackupClientFileAttributes : public StreamableMemBlock
+{
+public:
+ BackupClientFileAttributes();
+ BackupClientFileAttributes(const BackupClientFileAttributes &rToCopy);
+ BackupClientFileAttributes(const StreamableMemBlock &rToCopy);
+ ~BackupClientFileAttributes();
+ BackupClientFileAttributes &operator=(const BackupClientFileAttributes &rAttr);
+ BackupClientFileAttributes &operator=(const StreamableMemBlock &rAttr);
+ bool operator==(const BackupClientFileAttributes &rAttr) const;
+// bool operator==(const StreamableMemBlock &rAttr) const; // too dangerous?
+
+ bool Compare(const BackupClientFileAttributes &rAttr, bool IgnoreAttrModTime = false, bool IgnoreModTime = false) const;
+
+ // Prevent access to base class members accidently
+ void Set();
+
+ void ReadAttributes(const char *Filename, bool ZeroModificationTimes = false,
+ box_time_t *pModTime = 0, box_time_t *pAttrModTime = 0, int64_t *pFileSize = 0,
+ InodeRefType *pInodeNumber = 0, bool *pHasMultipleLinks = 0);
+ void WriteAttributes(const char *Filename,
+ bool MakeUserWritable = false) const;
+ void GetModificationTimes(box_time_t *pModificationTime,
+ box_time_t *pAttrModificationTime) const;
+
+ bool IsSymLink() const;
+
+ static void SetBlowfishKey(const void *pKey, int KeyLength);
+ static void SetAttributeHashSecret(const void *pSecret, int SecretLength);
+
+ static uint64_t GenerateAttributeHash(EMU_STRUCT_STAT &st, const std::string &filename, const std::string &leafname);
+ static void FillExtendedAttr(StreamableMemBlock &outputBlock, const char *Filename);
+
+private:
+ static void FillAttributes(StreamableMemBlock &outputBlock,
+ const char *Filename, EMU_STRUCT_STAT &st,
+ bool ZeroModificationTimes);
+ static void FillAttributesLink(StreamableMemBlock &outputBlock, const char *Filename, struct stat &st);
+ void WriteExtendedAttr(const char *Filename, int xattrOffset) const;
+
+ void RemoveClear() const;
+ void EnsureClearAvailable() const;
+ static StreamableMemBlock *MakeClear(const StreamableMemBlock &rEncrypted);
+ void EncryptAttr(const StreamableMemBlock &rToEncrypt);
+
+private:
+ mutable StreamableMemBlock *mpClearAttributes;
+};
+
+#endif // BACKUPCLIENTFILEATTRIBUTES__H
+
diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp
index db72c4bd..f6b42af9 100644
--- a/lib/backupclient/BackupClientRestore.cpp
+++ b/lib/backupclient/BackupClientRestore.cpp
@@ -22,7 +22,11 @@
#include <errno.h>
#include "BackupClientRestore.h"
+<<<<<<< HEAD
+#include "autogen_BackupProtocolClient.h"
+=======
#include "autogen_BackupProtocol.h"
+>>>>>>> 0.12
#include "CommonException.h"
#include "BackupClientFileAttributes.h"
#include "IOStream.h"
@@ -443,8 +447,13 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection,
// list of files which is appropriate to the restore type
rConnection.QueryListDirectory(
DirectoryID,
+<<<<<<< HEAD
+ Params.RestoreDeleted?(BackupProtocolClientListDirectory::Flags_Deleted):(BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING),
+ BackupProtocolClientListDirectory::Flags_OldVersion | (Params.RestoreDeleted?(0):(BackupProtocolClientListDirectory::Flags_Deleted)),
+=======
Params.RestoreDeleted?(BackupProtocolListDirectory::Flags_Deleted):(BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING),
BackupProtocolListDirectory::Flags_OldVersion | (Params.RestoreDeleted?(0):(BackupProtocolListDirectory::Flags_Deleted)),
+>>>>>>> 0.12
true /* want attributes */);
// Retrieve the directory from the stream following
@@ -569,8 +578,11 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection,
if (Params.ContinueAfterErrors)
{
Params.ContinuedAfterError = true;
+<<<<<<< HEAD
+=======
// ensure that protocol remains usable
objectStream->Flush();
+>>>>>>> 0.12
}
else
{
@@ -841,8 +853,13 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection,
//
// --------------------------------------------------------------------------
int BackupClientRestore(BackupProtocolClient &rConnection,
+<<<<<<< HEAD
+ int64_t DirectoryID, const char *RemoteDirectoryName,
+ const char *LocalDirectoryName, bool PrintDots, bool RestoreDeleted,
+=======
int64_t DirectoryID, const std::string& RemoteDirectoryName,
const std::string& LocalDirectoryName, bool PrintDots, bool RestoreDeleted,
+>>>>>>> 0.12
bool UndeleteAfterRestoreDeleted, bool Resume,
bool ContinueAfterErrors)
{
diff --git a/lib/backupclient/BackupClientRestore.h b/lib/backupclient/BackupClientRestore.h
index 77f09c2e..79765f63 100644
--- a/lib/backupclient/BackupClientRestore.h
+++ b/lib/backupclient/BackupClientRestore.h
@@ -24,6 +24,15 @@ enum
int BackupClientRestore(BackupProtocolClient &rConnection,
int64_t DirectoryID,
+<<<<<<< HEAD
+ const char *RemoteDirectoryName,
+ const char *LocalDirectoryName,
+ bool PrintDots = false,
+ bool RestoreDeleted = false,
+ bool UndeleteAfterRestoreDeleted = false,
+ bool Resume = false,
+ bool ContinueAfterErrors = false);
+=======
const std::string& RemoteDirectoryName,
const std::string& LocalDirectoryName,
bool PrintDots,
@@ -31,6 +40,7 @@ int BackupClientRestore(BackupProtocolClient &rConnection,
bool UndeleteAfterRestoreDeleted,
bool Resume,
bool ContinueAfterErrors);
+>>>>>>> 0.12
#endif // BACKUPSCLIENTRESTORE__H
diff --git a/lib/backupclient/BackupDaemonConfigVerify.cpp b/lib/backupclient/BackupDaemonConfigVerify.cpp
index a3b95335..3104ae8e 100644
--- a/lib/backupclient/BackupDaemonConfigVerify.cpp
+++ b/lib/backupclient/BackupDaemonConfigVerify.cpp
@@ -114,19 +114,25 @@ static const ConfigurationVerifyKey verifyrootkeys[] =
ConfigurationVerifyKey("NotifyAlways", ConfigTest_IsBool, false),
// option to disable the suppression of duplicate notifications
+<<<<<<< HEAD
+=======
ConfigurationVerifyKey("MaxUploadRate", ConfigTest_IsInt),
// optional maximum speed of uploads in kbytes per second
ConfigurationVerifyKey("TcpNice", ConfigTest_IsBool, false),
// optional enable of tcp nice/background mode
+>>>>>>> 0.12
ConfigurationVerifyKey("CertificateFile", ConfigTest_Exists),
ConfigurationVerifyKey("PrivateKeyFile", ConfigTest_Exists),
ConfigurationVerifyKey("TrustedCAsFile", ConfigTest_Exists),
ConfigurationVerifyKey("KeysFile", ConfigTest_Exists),
ConfigurationVerifyKey("DataDirectory",
ConfigTest_Exists | ConfigTest_LastEntry),
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
};
const ConfigurationVerify BackupDaemonConfigVerify =
diff --git a/lib/backupclient/BackupStoreConstants.h b/lib/backupclient/BackupStoreConstants.h
new file mode 100644
index 00000000..2c33fd8f
--- /dev/null
+++ b/lib/backupclient/BackupStoreConstants.h
@@ -0,0 +1,44 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreContants.h
+// Purpose: constants for the backup system
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTORECONSTANTS__H
+#define BACKUPSTORECONSTANTS__H
+
+#define BACKUPSTORE_ROOT_DIRECTORY_ID 1
+
+#define BACKUP_STORE_SERVER_VERSION 1
+
+// Minimum size for a chunk to be compressed
+#define BACKUP_FILE_MIN_COMPRESSED_CHUNK_SIZE 256
+
+// min and max sizes for blocks
+#define BACKUP_FILE_MIN_BLOCK_SIZE 4096
+#define BACKUP_FILE_MAX_BLOCK_SIZE (512*1024)
+
+// Increase the block size if there are more than this number of blocks
+#define BACKUP_FILE_INCREASE_BLOCK_SIZE_AFTER 4096
+
+// Avoid creating blocks smaller than this
+#define BACKUP_FILE_AVOID_BLOCKS_LESS_THAN 128
+
+// Maximum number of sizes to do an rsync-like scan for
+#define BACKUP_FILE_DIFF_MAX_BLOCK_SIZES 64
+
+// When doing rsync scans, do not scan for blocks smaller than
+#define BACKUP_FILE_DIFF_MIN_BLOCK_SIZE 128
+
+// A limit to stop diffing running out of control: If more than this
+// times the number of blocks in the original index are found, stop
+// looking. This stops really bad cases of diffing files containing
+// all the same byte using huge amounts of memory and processor time.
+// This is a multiple of the number of blocks in the diff from file.
+#define BACKUP_FILE_DIFF_MAX_BLOCK_FIND_MULTIPLE 4096
+
+#endif // BACKUPSTORECONSTANTS__H
+
diff --git a/lib/backupclient/BackupStoreDirectory.cpp b/lib/backupclient/BackupStoreDirectory.cpp
new file mode 100644
index 00000000..0d06da34
--- /dev/null
+++ b/lib/backupclient/BackupStoreDirectory.cpp
@@ -0,0 +1,568 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreDirectory.h
+// Purpose: Representation of a backup directory
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <sys/types.h>
+
+#include "BackupStoreDirectory.h"
+#include "IOStream.h"
+#include "BackupStoreException.h"
+#include "BackupStoreObjectMagic.h"
+
+#include "MemLeakFindOn.h"
+
+// set packing to one byte
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "BeginStructPackForWire.h"
+#else
+BEGIN_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
+typedef struct
+{
+ int32_t mMagicValue; // also the version number
+ int32_t mNumEntries;
+ int64_t mObjectID; // this object ID
+ int64_t mContainerID; // ID of container
+ uint64_t mAttributesModTime;
+ int32_t mOptionsPresent; // bit mask of optional sections / features present
+ // Then a StreamableMemBlock for attributes
+} dir_StreamFormat;
+
+typedef enum
+{
+ Option_DependencyInfoPresent = 1
+} dir_StreamFormatOptions;
+
+typedef struct
+{
+ uint64_t mModificationTime;
+ int64_t mObjectID;
+ int64_t mSizeInBlocks;
+ uint64_t mAttributesHash;
+ int16_t mFlags; // order smaller items after bigger ones (for alignment)
+ // Then a BackupStoreFilename
+ // Then a StreamableMemBlock for attributes
+} en_StreamFormat;
+
+typedef struct
+{
+ int64_t mDependsNewer;
+ int64_t mDependsOlder;
+} en_StreamFormatDepends;
+
+// Use default packing
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "EndStructPackForWire.h"
+#else
+END_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::BackupStoreDirectory()
+// Purpose: Constructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::BackupStoreDirectory()
+ : mRevisionID(0), mObjectID(0), mContainerID(0), mAttributesModTime(0), mUserInfo1(0)
+{
+ ASSERT(sizeof(u_int64_t) == sizeof(box_time_t));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreDirectory::BackupStoreDirectory(int64_t, int64_t)
+// Purpose: Constructor giving object and container IDs
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::BackupStoreDirectory(int64_t ObjectID, int64_t ContainerID)
+ : mRevisionID(0), mObjectID(ObjectID), mContainerID(ContainerID), mAttributesModTime(0), mUserInfo1(0)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::~BackupStoreDirectory()
+// Purpose: Destructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::~BackupStoreDirectory()
+{
+ for(std::vector<Entry*>::iterator i(mEntries.begin()); i != mEntries.end(); ++i)
+ {
+ delete (*i);
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::ReadFromStream(IOStream &, int)
+// Purpose: Reads the directory contents from a stream. Exceptions will yeild incomplete reads.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreDirectory::ReadFromStream(IOStream &rStream, int Timeout)
+{
+ // Get the header
+ dir_StreamFormat hdr;
+ if(!rStream.ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Check magic value...
+ if(OBJECTMAGIC_DIR_MAGIC_VALUE != ntohl(hdr.mMagicValue))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadDirectoryFormat)
+ }
+
+ // Get data
+ mObjectID = box_ntoh64(hdr.mObjectID);
+ mContainerID = box_ntoh64(hdr.mContainerID);
+ mAttributesModTime = box_ntoh64(hdr.mAttributesModTime);
+
+ // Options
+ int32_t options = ntohl(hdr.mOptionsPresent);
+
+ // Get attributes
+ mAttributes.ReadFromStream(rStream, Timeout);
+
+ // Decode count
+ int count = ntohl(hdr.mNumEntries);
+
+ // Clear existing list
+ for(std::vector<Entry*>::iterator i = mEntries.begin();
+ i != mEntries.end(); i++)
+ {
+ delete (*i);
+ }
+ mEntries.clear();
+
+ // Read them in!
+ for(int c = 0; c < count; ++c)
+ {
+ Entry *pen = new Entry;
+ try
+ {
+ // Read from stream
+ pen->ReadFromStream(rStream, Timeout);
+
+ // Add to list
+ mEntries.push_back(pen);
+ }
+ catch(...)
+ {
+ delete pen;
+ throw;
+ }
+ }
+
+ // Read in dependency info?
+ if(options & Option_DependencyInfoPresent)
+ {
+ // Read in extra dependency data
+ for(int c = 0; c < count; ++c)
+ {
+ mEntries[c]->ReadFromStreamDependencyInfo(rStream, Timeout);
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::WriteToStream(IOStream &, int16_t, int16_t, bool, bool)
+// Purpose: Writes a selection of entries to a stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreDirectory::WriteToStream(IOStream &rStream, int16_t FlagsMustBeSet, int16_t FlagsNotToBeSet, bool StreamAttributes, bool StreamDependencyInfo) const
+{
+ // Get count of entries
+ int32_t count = mEntries.size();
+ if(FlagsMustBeSet != Entry::Flags_INCLUDE_EVERYTHING || FlagsNotToBeSet != Entry::Flags_EXCLUDE_NOTHING)
+ {
+ // Need to count the entries
+ count = 0;
+ Iterator i(*this);
+ while(i.Next(FlagsMustBeSet, FlagsNotToBeSet) != 0)
+ {
+ count++;
+ }
+ }
+
+ // Check that sensible IDs have been set
+ ASSERT(mObjectID != 0);
+ ASSERT(mContainerID != 0);
+
+ // Need dependency info?
+ bool dependencyInfoRequired = false;
+ if(StreamDependencyInfo)
+ {
+ Iterator i(*this);
+ Entry *pen = 0;
+ while((pen = i.Next(FlagsMustBeSet, FlagsNotToBeSet)) != 0)
+ {
+ if(pen->HasDependencies())
+ {
+ dependencyInfoRequired = true;
+ }
+ }
+ }
+
+ // Options
+ int32_t options = 0;
+ if(dependencyInfoRequired) options |= Option_DependencyInfoPresent;
+
+ // Build header
+ dir_StreamFormat hdr;
+ hdr.mMagicValue = htonl(OBJECTMAGIC_DIR_MAGIC_VALUE);
+ hdr.mNumEntries = htonl(count);
+ hdr.mObjectID = box_hton64(mObjectID);
+ hdr.mContainerID = box_hton64(mContainerID);
+ hdr.mAttributesModTime = box_hton64(mAttributesModTime);
+ hdr.mOptionsPresent = htonl(options);
+
+ // Write header
+ rStream.Write(&hdr, sizeof(hdr));
+
+ // Write the attributes?
+ if(StreamAttributes)
+ {
+ mAttributes.WriteToStream(rStream);
+ }
+ else
+ {
+ // Write a blank header instead
+ StreamableMemBlock::WriteEmptyBlockToStream(rStream);
+ }
+
+ // Then write all the entries
+ Iterator i(*this);
+ Entry *pen = 0;
+ while((pen = i.Next(FlagsMustBeSet, FlagsNotToBeSet)) != 0)
+ {
+ pen->WriteToStream(rStream);
+ }
+
+ // Write dependency info?
+ if(dependencyInfoRequired)
+ {
+ Iterator i(*this);
+ Entry *pen = 0;
+ while((pen = i.Next(FlagsMustBeSet, FlagsNotToBeSet)) != 0)
+ {
+ pen->WriteToStreamDependencyInfo(rStream);
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::AddEntry(const Entry &)
+// Purpose: Adds entry to directory (no checking)
+// Created: 2003/08/27
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::Entry *BackupStoreDirectory::AddEntry(const Entry &rEntryToCopy)
+{
+ Entry *pnew = new Entry(rEntryToCopy);
+ try
+ {
+ mEntries.push_back(pnew);
+ }
+ catch(...)
+ {
+ delete pnew;
+ throw;
+ }
+
+ return pnew;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::AddEntry(const BackupStoreFilename &, int64_t, int64_t, int16_t)
+// Purpose: Adds entry to directory (no checking)
+// Created: 2003/08/27
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::Entry *BackupStoreDirectory::AddEntry(const BackupStoreFilename &rName, box_time_t ModificationTime, int64_t ObjectID, int64_t SizeInBlocks, int16_t Flags, box_time_t AttributesModTime)
+{
+ Entry *pnew = new Entry(rName, ModificationTime, ObjectID, SizeInBlocks, Flags, AttributesModTime);
+ try
+ {
+ mEntries.push_back(pnew);
+ }
+ catch(...)
+ {
+ delete pnew;
+ throw;
+ }
+
+ return pnew;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::DeleteEntry(int64_t)
+// Purpose: Deletes entry with given object ID (uses linear search, maybe a little inefficient)
+// Created: 2003/08/27
+//
+// --------------------------------------------------------------------------
+void BackupStoreDirectory::DeleteEntry(int64_t ObjectID)
+{
+ for(std::vector<Entry*>::iterator i(mEntries.begin());
+ i != mEntries.end(); ++i)
+ {
+ if((*i)->mObjectID == ObjectID)
+ {
+ // Delete
+ delete (*i);
+ // Remove from list
+ mEntries.erase(i);
+ // Done
+ return;
+ }
+ }
+
+ // Not found
+ THROW_EXCEPTION(BackupStoreException, CouldNotFindEntryInDirectory)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::FindEntryByID(int64_t)
+// Purpose: Finds a specific entry. Returns 0 if the entry doesn't exist.
+// Created: 12/11/03
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::Entry *BackupStoreDirectory::FindEntryByID(int64_t ObjectID) const
+{
+ for(std::vector<Entry*>::const_iterator i(mEntries.begin());
+ i != mEntries.end(); ++i)
+ {
+ if((*i)->mObjectID == ObjectID)
+ {
+ // Found
+ return (*i);
+ }
+ }
+
+ // Not found
+ return 0;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::Entry::Entry()
+// Purpose: Constructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::Entry::Entry()
+ : mModificationTime(0),
+ mObjectID(0),
+ mSizeInBlocks(0),
+ mFlags(0),
+ mAttributesHash(0),
+ mMinMarkNumber(0),
+ mMarkNumber(0),
+ mDependsNewer(0),
+ mDependsOlder(0)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::Entry::~Entry()
+// Purpose: Destructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::Entry::~Entry()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::Entry::Entry(const Entry &)
+// Purpose: Copy constructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::Entry::Entry(const Entry &rToCopy)
+ : mName(rToCopy.mName),
+ mModificationTime(rToCopy.mModificationTime),
+ mObjectID(rToCopy.mObjectID),
+ mSizeInBlocks(rToCopy.mSizeInBlocks),
+ mFlags(rToCopy.mFlags),
+ mAttributesHash(rToCopy.mAttributesHash),
+ mAttributes(rToCopy.mAttributes),
+ mMinMarkNumber(rToCopy.mMinMarkNumber),
+ mMarkNumber(rToCopy.mMarkNumber),
+ mDependsNewer(rToCopy.mDependsNewer),
+ mDependsOlder(rToCopy.mDependsOlder)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::Entry::Entry(const BackupStoreFilename &, int64_t, int64_t, int16_t)
+// Purpose: Constructor from values
+// Created: 2003/08/27
+//
+// --------------------------------------------------------------------------
+BackupStoreDirectory::Entry::Entry(const BackupStoreFilename &rName, box_time_t ModificationTime, int64_t ObjectID, int64_t SizeInBlocks, int16_t Flags, uint64_t AttributesHash)
+ : mName(rName),
+ mModificationTime(ModificationTime),
+ mObjectID(ObjectID),
+ mSizeInBlocks(SizeInBlocks),
+ mFlags(Flags),
+ mAttributesHash(AttributesHash),
+ mMinMarkNumber(0),
+ mMarkNumber(0),
+ mDependsNewer(0),
+ mDependsOlder(0)
+{
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::Entry::TryReading(IOStream &, int)
+// Purpose: Read an entry from a stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreDirectory::Entry::ReadFromStream(IOStream &rStream, int Timeout)
+{
+ // Grab the raw bytes from the stream which compose the header
+ en_StreamFormat entry;
+ if(!rStream.ReadFullBuffer(&entry, sizeof(entry), 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Do reading first before modifying the variables, to be more exception safe
+
+ // Get the filename
+ BackupStoreFilename name;
+ name.ReadFromStream(rStream, Timeout);
+
+ // Get the attributes
+ mAttributes.ReadFromStream(rStream, Timeout);
+
+ // Store the rest of the bits
+ mModificationTime = box_ntoh64(entry.mModificationTime);
+ mObjectID = box_ntoh64(entry.mObjectID);
+ mSizeInBlocks = box_ntoh64(entry.mSizeInBlocks);
+ mAttributesHash = box_ntoh64(entry.mAttributesHash);
+ mFlags = ntohs(entry.mFlags);
+ mName = name;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::Entry::WriteToStream(IOStream &)
+// Purpose: Writes the entry to a stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreDirectory::Entry::WriteToStream(IOStream &rStream) const
+{
+ // Build a structure
+ en_StreamFormat entry;
+ entry.mModificationTime = box_hton64(mModificationTime);
+ entry.mObjectID = box_hton64(mObjectID);
+ entry.mSizeInBlocks = box_hton64(mSizeInBlocks);
+ entry.mAttributesHash = box_hton64(mAttributesHash);
+ entry.mFlags = htons(mFlags);
+
+ // Write it
+ rStream.Write(&entry, sizeof(entry));
+
+ // Write the filename
+ mName.WriteToStream(rStream);
+
+ // Write any attributes
+ mAttributes.WriteToStream(rStream);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::Entry::ReadFromStreamDependencyInfo(IOStream &, int)
+// Purpose: Read the optional dependency info from a stream
+// Created: 13/7/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreDirectory::Entry::ReadFromStreamDependencyInfo(IOStream &rStream, int Timeout)
+{
+ // Grab the raw bytes from the stream which compose the header
+ en_StreamFormatDepends depends;
+ if(!rStream.ReadFullBuffer(&depends, sizeof(depends), 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Store the data
+ mDependsNewer = box_ntoh64(depends.mDependsNewer);
+ mDependsOlder = box_ntoh64(depends.mDependsOlder);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDirectory::Entry::WriteToStreamDependencyInfo(IOStream &)
+// Purpose: Write the optional dependency info to a stream
+// Created: 13/7/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreDirectory::Entry::WriteToStreamDependencyInfo(IOStream &rStream) const
+{
+ // Build structure
+ en_StreamFormatDepends depends;
+ depends.mDependsNewer = box_hton64(mDependsNewer);
+ depends.mDependsOlder = box_hton64(mDependsOlder);
+ // Write
+ rStream.Write(&depends, sizeof(depends));
+}
+
+
+
diff --git a/lib/backupclient/BackupStoreDirectory.h b/lib/backupclient/BackupStoreDirectory.h
new file mode 100644
index 00000000..958eee81
--- /dev/null
+++ b/lib/backupclient/BackupStoreDirectory.h
@@ -0,0 +1,268 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreDirectory.h
+// Purpose: Representation of a backup directory
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREDIRECTORY__H
+#define BACKUPSTOREDIRECTORY__H
+
+#include <string>
+#include <vector>
+
+#include "BackupStoreFilenameClear.h"
+#include "StreamableMemBlock.h"
+#include "BoxTime.h"
+
+class IOStream;
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: BackupStoreDirectory
+// Purpose: In memory representation of a directory
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+class BackupStoreDirectory
+{
+public:
+ BackupStoreDirectory();
+ BackupStoreDirectory(int64_t ObjectID, int64_t ContainerID);
+private:
+ // Copying not allowed
+ BackupStoreDirectory(const BackupStoreDirectory &rToCopy);
+public:
+ ~BackupStoreDirectory();
+
+ class Entry
+ {
+ public:
+ friend class BackupStoreDirectory;
+
+ Entry();
+ ~Entry();
+ Entry(const Entry &rToCopy);
+ Entry(const BackupStoreFilename &rName, box_time_t ModificationTime, int64_t ObjectID, int64_t SizeInBlocks, int16_t Flags, uint64_t AttributesHash);
+
+ void ReadFromStream(IOStream &rStream, int Timeout);
+ void WriteToStream(IOStream &rStream) const;
+
+ const BackupStoreFilename &GetName() const {return mName;}
+ box_time_t GetModificationTime() const {return mModificationTime;}
+ int64_t GetObjectID() const {return mObjectID;}
+ int64_t GetSizeInBlocks() const {return mSizeInBlocks;}
+ int16_t GetFlags() const {return mFlags;}
+ void AddFlags(int16_t Flags) {mFlags |= Flags;}
+ void RemoveFlags(int16_t Flags) {mFlags &= ~Flags;}
+
+ // Some things can be changed
+ void SetName(const BackupStoreFilename &rNewName) {mName = rNewName;}
+ void SetSizeInBlocks(int64_t SizeInBlocks) {mSizeInBlocks = SizeInBlocks;}
+
+ // Attributes
+ bool HasAttributes() const {return !mAttributes.IsEmpty();}
+ void SetAttributes(const StreamableMemBlock &rAttr, uint64_t AttributesHash) {mAttributes.Set(rAttr); mAttributesHash = AttributesHash;}
+ const StreamableMemBlock &GetAttributes() const {return mAttributes;}
+ uint64_t GetAttributesHash() const {return mAttributesHash;}
+
+ // Marks
+ // The lowest mark number a version of a file of this name has ever had
+ uint32_t GetMinMarkNumber() const {return mMinMarkNumber;}
+ // The mark number on this file
+ uint32_t GetMarkNumber() const {return mMarkNumber;}
+
+ // Make sure these flags are synced with those in backupprocotol.txt
+ // ListDirectory command
+ enum
+ {
+ Flags_INCLUDE_EVERYTHING = -1,
+ Flags_EXCLUDE_NOTHING = 0,
+ Flags_EXCLUDE_EVERYTHING = 31, // make sure this is kept as sum of ones below!
+ Flags_File = 1,
+ Flags_Dir = 2,
+ Flags_Deleted = 4,
+ Flags_OldVersion = 8,
+ Flags_RemoveASAP = 16 // if this flag is set, housekeeping will remove it as it is marked Deleted or OldVersion
+ };
+ // characters for textual listing of files -- see bbackupquery/BackupQueries
+ #define BACKUPSTOREDIRECTORY_ENTRY_FLAGS_DISPLAY_NAMES "fdXoR"
+
+ bool inline MatchesFlags(int16_t FlagsMustBeSet, int16_t FlagsNotToBeSet)
+ {
+ return ((FlagsMustBeSet == Flags_INCLUDE_EVERYTHING) || ((mFlags & FlagsMustBeSet) == FlagsMustBeSet))
+ && ((mFlags & FlagsNotToBeSet) == 0);
+ };
+
+ // Get dependency info
+ // new version this depends on
+ int64_t GetDependsNewer() const {return mDependsNewer;}
+ void SetDependsNewer(int64_t ObjectID) {mDependsNewer = ObjectID;}
+ // older version which depends on this
+ int64_t GetDependsOlder() const {return mDependsOlder;}
+ void SetDependsOlder(int64_t ObjectID) {mDependsOlder = ObjectID;}
+
+ // Dependency info saving
+ bool HasDependencies() {return mDependsNewer != 0 || mDependsOlder != 0;}
+ void ReadFromStreamDependencyInfo(IOStream &rStream, int Timeout);
+ void WriteToStreamDependencyInfo(IOStream &rStream) const;
+
+ private:
+ BackupStoreFilename mName;
+ box_time_t mModificationTime;
+ int64_t mObjectID;
+ int64_t mSizeInBlocks;
+ int16_t mFlags;
+ uint64_t mAttributesHash;
+ StreamableMemBlock mAttributes;
+ uint32_t mMinMarkNumber;
+ uint32_t mMarkNumber;
+
+ uint64_t mDependsNewer; // new version this depends on
+ uint64_t mDependsOlder; // older version which depends on this
+ };
+
+ void ReadFromStream(IOStream &rStream, int Timeout);
+ void WriteToStream(IOStream &rStream,
+ int16_t FlagsMustBeSet = Entry::Flags_INCLUDE_EVERYTHING,
+ int16_t FlagsNotToBeSet = Entry::Flags_EXCLUDE_NOTHING,
+ bool StreamAttributes = true, bool StreamDependencyInfo = true) const;
+
+ Entry *AddEntry(const Entry &rEntryToCopy);
+ Entry *AddEntry(const BackupStoreFilename &rName, box_time_t ModificationTime, int64_t ObjectID, int64_t SizeInBlocks, int16_t Flags, box_time_t AttributesModTime);
+ void DeleteEntry(int64_t ObjectID);
+ Entry *FindEntryByID(int64_t ObjectID) const;
+
+ int64_t GetObjectID() const {return mObjectID;}
+ int64_t GetContainerID() const {return mContainerID;}
+
+ // Need to be able to update the container ID when moving objects
+ void SetContainerID(int64_t ContainerID) {mContainerID = ContainerID;}
+
+ // Purely for use of server -- not serialised into streams
+ int64_t GetRevisionID() const {return mRevisionID;}
+ void SetRevisionID(int64_t RevisionID) {mRevisionID = RevisionID;}
+
+ unsigned int GetNumberOfEntries() const {return mEntries.size();}
+
+ // User info -- not serialised into streams
+ int64_t GetUserInfo1_SizeInBlocks() const {return mUserInfo1;}
+ void SetUserInfo1_SizeInBlocks(int64_t UserInfo1) {mUserInfo1 = UserInfo1;}
+
+ // Attributes
+ bool HasAttributes() const {return !mAttributes.IsEmpty();}
+ void SetAttributes(const StreamableMemBlock &rAttr, box_time_t AttributesModTime) {mAttributes.Set(rAttr); mAttributesModTime = AttributesModTime;}
+ const StreamableMemBlock &GetAttributes() const {return mAttributes;}
+ box_time_t GetAttributesModTime() const {return mAttributesModTime;}
+
+ class Iterator
+ {
+ public:
+ Iterator(const BackupStoreDirectory &rDir)
+ : mrDir(rDir), i(rDir.mEntries.begin())
+ {
+ }
+
+ BackupStoreDirectory::Entry *Next(int16_t FlagsMustBeSet = Entry::Flags_INCLUDE_EVERYTHING, int16_t FlagsNotToBeSet = Entry::Flags_EXCLUDE_NOTHING)
+ {
+ // Skip over things which don't match the required flags
+ while(i != mrDir.mEntries.end() && !(*i)->MatchesFlags(FlagsMustBeSet, FlagsNotToBeSet))
+ {
+ ++i;
+ }
+ // Not the last one?
+ if(i == mrDir.mEntries.end())
+ {
+ return 0;
+ }
+ // Return entry, and increment
+ return (*(i++));
+ }
+
+ // WARNING: This function is really very inefficient.
+ // Only use when you want to look up ONE filename, not in a loop looking up lots.
+ // In a looping situation, cache the decrypted filenames in another memory structure.
+ BackupStoreDirectory::Entry *FindMatchingClearName(const BackupStoreFilenameClear &rFilename, int16_t FlagsMustBeSet = Entry::Flags_INCLUDE_EVERYTHING, int16_t FlagsNotToBeSet = Entry::Flags_EXCLUDE_NOTHING)
+ {
+ // Skip over things which don't match the required flags or filename
+ while( (i != mrDir.mEntries.end())
+ && ( (!(*i)->MatchesFlags(FlagsMustBeSet, FlagsNotToBeSet))
+ || (BackupStoreFilenameClear((*i)->GetName()).GetClearFilename() != rFilename.GetClearFilename()) ) )
+ {
+ ++i;
+ }
+ // Not the last one?
+ if(i == mrDir.mEntries.end())
+ {
+ return 0;
+ }
+ // Return entry, and increment
+ return (*(i++));
+ }
+
+ private:
+ const BackupStoreDirectory &mrDir;
+ std::vector<Entry*>::const_iterator i;
+ };
+
+ friend class Iterator;
+
+ class ReverseIterator
+ {
+ public:
+ ReverseIterator(const BackupStoreDirectory &rDir)
+ : mrDir(rDir), i(rDir.mEntries.rbegin())
+ {
+ }
+
+ BackupStoreDirectory::Entry *Next(int16_t FlagsMustBeSet = Entry::Flags_INCLUDE_EVERYTHING, int16_t FlagsNotToBeSet = Entry::Flags_EXCLUDE_NOTHING)
+ {
+ // Skip over things which don't match the required flags
+ while(i != mrDir.mEntries.rend() && !(*i)->MatchesFlags(FlagsMustBeSet, FlagsNotToBeSet))
+ {
+ ++i;
+ }
+ // Not the last one?
+ if(i == mrDir.mEntries.rend())
+ {
+ return 0;
+ }
+ // Return entry, and increment
+ return (*(i++));
+ }
+
+ private:
+ const BackupStoreDirectory &mrDir;
+ std::vector<Entry*>::const_reverse_iterator i;
+ };
+
+ friend class ReverseIterator;
+
+ // For recovery of the store
+ // Implemented in BackupStoreCheck2.cpp
+ bool CheckAndFix();
+ void AddUnattactedObject(const BackupStoreFilename &rName, box_time_t ModificationTime, int64_t ObjectID, int64_t SizeInBlocks, int16_t Flags);
+ bool NameInUse(const BackupStoreFilename &rName);
+ // Don't use these functions in normal code!
+
+ // For testing
+ void TESTONLY_SetObjectID(int64_t ObjectID) {mObjectID = ObjectID;}
+
+ // Debug and diagonistics
+ void Dump(void *clibFileHandle, bool ToTrace); // first arg is FILE *, but avoid including stdio.h everywhere
+
+private:
+ int64_t mRevisionID;
+ int64_t mObjectID;
+ int64_t mContainerID;
+ std::vector<Entry*> mEntries;
+ box_time_t mAttributesModTime;
+ StreamableMemBlock mAttributes;
+ int64_t mUserInfo1;
+};
+
+#endif // BACKUPSTOREDIRECTORY__H
+
diff --git a/lib/backupclient/BackupStoreException.h b/lib/backupclient/BackupStoreException.h
new file mode 100644
index 00000000..981dfa60
--- /dev/null
+++ b/lib/backupclient/BackupStoreException.h
@@ -0,0 +1,17 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreException.h
+// Purpose: Exception
+// Created: 2003/07/08
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREEXCEPTION__H
+#define BACKUPSTOREEXCEPTION__H
+
+// Compatibility
+#include "autogen_BackupStoreException.h"
+
+#endif // BACKUPSTOREEXCEPTION__H
+
diff --git a/lib/backupclient/BackupStoreException.txt b/lib/backupclient/BackupStoreException.txt
new file mode 100644
index 00000000..528a8c94
--- /dev/null
+++ b/lib/backupclient/BackupStoreException.txt
@@ -0,0 +1,71 @@
+EXCEPTION BackupStore 4
+
+Internal 0
+BadAccountDatabaseFile 1
+AccountDatabaseNoSuchEntry 2
+InvalidBackupStoreFilename 3
+UnknownFilenameEncoding 4
+CouldntReadEntireStructureFromStream 5
+BadDirectoryFormat 6
+CouldNotFindEntryInDirectory 7
+OutputFileAlreadyExists 8
+OSFileError 9
+StreamDoesntHaveRequiredFeatures 10
+BadBackupStoreFile 11
+CouldNotLoadStoreInfo 12
+BadStoreInfoOnLoad 13
+StoreInfoIsReadOnly 14
+StoreInfoDirNotInList 15
+StoreInfoBlockDeltaMakesValueNegative 16
+DirectoryHasBeenDeleted 17
+StoreInfoNotInitialised 18
+StoreInfoAlreadyLoaded 19
+StoreInfoNotLoaded 20
+ReadFileFromStreamTimedOut 21
+FileWrongSizeAfterBeingStored 22
+AddedFileDoesNotVerify 23
+StoreInfoForWrongAccount 24
+ContextIsReadOnly 25
+AttributesNotLoaded 26
+AttributesNotUnderstood 27
+WrongServerVersion 28 # client side
+ClientMarkerNotAsExpected 29 Another process logged into the store and modified it while this process was running. Check you're not running two or more clients on the same account.
+NameAlreadyExistsInDirectory 30
+BerkelyDBFailure 31 # client side
+InodeMapIsReadOnly 32 # client side
+InodeMapNotOpen 33 # client side
+FilenameEncryptionKeyNotKnown 34
+FilenameEncryptionNoKeyForSpecifiedMethod 35
+FilenameEncryptionNotSetup 36
+CouldntLoadClientKeyMaterial 37
+BadEncryptedAttributes 38
+EncryptedAttributesHaveUnknownEncoding 39
+OutputSizeTooSmallForChunk 40
+BadEncodedChunk 41
+NotEnoughSpaceToDecodeChunk 42
+ChunkHasUnknownEncoding 43
+ChunkContainsBadCompressedData 44
+CantWriteToEncodedFileStream 45
+Temp_FileEncodeStreamDidntReadBuffer 46
+CantWriteToDecodedFileStream 47
+WhenDecodingExpectedToReadButCouldnt 48
+BackupStoreFileFailedIntegrityCheck 49
+ThereIsNoDataInASymLink 50
+IVLengthForEncodedBlockSizeDoesntMeetLengthRequirements 51
+BlockEntryEncodingDidntGiveExpectedLength 52
+CouldNotFindUnusedIDDuringAllocation 53
+AddedFileExceedsStorageLimit 54
+CannotDiffAnIncompleteStoreFile 55
+CannotDecodeDiffedFilesWithoutCombining 56
+FailedToReadBlockOnCombine 57
+OnCombineFromFileIsIncomplete 58
+BadNotifySysadminEventCode 59
+InternalAlgorithmErrorCheckIDNotMonotonicallyIncreasing 60
+CouldNotLockStoreAccount 61 Another process is accessing this account -- is a client connected to the server?
+AttributeHashSecretNotSet 62
+AEScipherNotSupportedByInstalledOpenSSL 63 The system needs to be compiled with support for OpenSSL 0.9.7 or later to be able to decode files encrypted with AES
+SignalReceived 64 A signal was received by the process, restart or terminate needed. Exception thrown to abort connection.
+IncompatibleFromAndDiffFiles 65 Attempt to use a diff and a from file together, when they're not related
+DiffFromIDNotFoundInDirectory 66 When uploading via a diff, the diff from file must be in the same directory
+PatchChainInfoBadInDirectory 67 A directory contains inconsistent information. Run bbstoreaccounts check to fix it.
+UnknownObjectRefCountRequested 68 A reference count was requested for an object whose reference count is not known.
diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp
new file mode 100644
index 00000000..17e145a3
--- /dev/null
+++ b/lib/backupclient/BackupStoreFile.cpp
@@ -0,0 +1,1556 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFile.cpp
+// Purpose: Utils for manipulating files
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+#endif
+
+#include <sys/stat.h>
+#include <string.h>
+#include <new>
+#include <string.h>
+
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ #include <stdio.h>
+#endif
+
+#include "BackupStoreFile.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreFileCryptVar.h"
+#include "BackupStoreFilename.h"
+#include "BackupStoreException.h"
+#include "IOStream.h"
+#include "Guards.h"
+#include "FileModificationTime.h"
+#include "FileStream.h"
+#include "BackupClientFileAttributes.h"
+#include "BackupStoreObjectMagic.h"
+#include "Compress.h"
+#include "CipherContext.h"
+#include "CipherBlowfish.h"
+#include "CipherAES.h"
+#include "BackupStoreConstants.h"
+#include "CollectInBufferStream.h"
+#include "RollingChecksum.h"
+#include "MD5Digest.h"
+#include "ReadGatherStream.h"
+#include "Random.h"
+#include "BackupStoreFileEncodeStream.h"
+#include "Logging.h"
+
+#include "MemLeakFindOn.h"
+
+using namespace BackupStoreFileCryptVar;
+
+// How big a buffer to use for copying files
+#define COPY_BUFFER_SIZE (8*1024)
+
+// Statistics
+BackupStoreFileStats BackupStoreFile::msStats = {0,0,0};
+
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ bool sWarnedAboutBackwardsCompatiblity = false;
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::EncodeFile(IOStream &, IOStream &)
+// Purpose: Encode a file into something for storing on file server.
+// Requires a real filename so full info can be stored.
+//
+// Returns a stream. Most of the work is done by the stream
+// when data is actually requested -- the file will be held
+// open until the stream is deleted or the file finished.
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<IOStream> BackupStoreFile::EncodeFile(const char *Filename,
+ int64_t ContainerID, const BackupStoreFilename &rStoreFilename,
+ int64_t *pModificationTime, ReadLoggingStream::Logger* pLogger,
+ RunStatusProvider* pRunStatusProvider)
+{
+ // Create the stream
+ std::auto_ptr<IOStream> stream(new BackupStoreFileEncodeStream);
+
+ // Do the initial setup
+ ((BackupStoreFileEncodeStream*)stream.get())->Setup(Filename,
+ 0 /* no recipe, just encode */,
+ ContainerID, rStoreFilename, pModificationTime, pLogger,
+ pRunStatusProvider);
+
+ // Return the stream for the caller
+ return stream;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::VerifyEncodedFileFormat(IOStream &)
+// Purpose: Verify that an encoded file meets the format requirements.
+// Doesn't verify that the data is intact and can be decoded.
+// Optionally returns the ID of the file which it is diffed from,
+// and the (original) container ID.
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFile::VerifyEncodedFileFormat(IOStream &rFile, int64_t *pDiffFromObjectIDOut, int64_t *pContainerIDOut)
+{
+ // Get the size of the file
+ int64_t fileSize = rFile.BytesLeftToRead();
+ if(fileSize == IOStream::SizeOfStreamUnknown)
+ {
+ THROW_EXCEPTION(BackupStoreException, StreamDoesntHaveRequiredFeatures)
+ }
+
+ // Get the header...
+ file_StreamFormat hdr;
+ if(!rFile.ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */))
+ {
+ // Couldn't read header
+ return false;
+ }
+
+ // Check magic number
+ if(ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ && ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V0
+#endif
+ )
+ {
+ return false;
+ }
+
+ // Get a filename, see if it loads OK
+ try
+ {
+ BackupStoreFilename fn;
+ fn.ReadFromStream(rFile, IOStream::TimeOutInfinite);
+ }
+ catch(...)
+ {
+ // an error occured while reading it, so that's not good
+ return false;
+ }
+
+ // Skip the attributes -- because they're encrypted, the server can't tell whether they're OK or not
+ try
+ {
+ int32_t size_s;
+ if(!rFile.ReadFullBuffer(&size_s, sizeof(size_s), 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+ int size = ntohl(size_s);
+ // Skip forward the size
+ rFile.Seek(size, IOStream::SeekType_Relative);
+ }
+ catch(...)
+ {
+ // an error occured while reading it, so that's not good
+ return false;
+ }
+
+ // Get current position in file -- the end of the header
+ int64_t headerEnd = rFile.GetPosition();
+
+ // Get number of blocks
+ int64_t numBlocks = box_ntoh64(hdr.mNumBlocks);
+
+ // Calculate where the block index will be, check it's reasonable
+ int64_t blockIndexLoc = fileSize - ((numBlocks * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader));
+ if(blockIndexLoc < headerEnd)
+ {
+ // Not enough space left for the block index, let alone the blocks themselves
+ return false;
+ }
+
+ // Load the block index header
+ rFile.Seek(blockIndexLoc, IOStream::SeekType_Absolute);
+ file_BlockIndexHeader blkhdr;
+ if(!rFile.ReadFullBuffer(&blkhdr, sizeof(blkhdr), 0 /* not interested in bytes read if this fails */))
+ {
+ // Couldn't read block index header -- assume bad file
+ return false;
+ }
+
+ // Check header
+ if((ntohl(blkhdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ && ntohl(blkhdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0
+#endif
+ )
+ || (int64_t)box_ntoh64(blkhdr.mNumBlocks) != numBlocks)
+ {
+ // Bad header -- either magic value or number of blocks is wrong
+ return false;
+ }
+
+ // Flag for recording whether a block is referenced from another file
+ bool blockFromOtherFileReferenced = false;
+
+ // Read the index, checking that the length values all make sense
+ int64_t currentBlockStart = headerEnd;
+ for(int64_t b = 0; b < numBlocks; ++b)
+ {
+ // Read block entry
+ file_BlockIndexEntry blk;
+ if(!rFile.ReadFullBuffer(&blk, sizeof(blk), 0 /* not interested in bytes read if this fails */))
+ {
+ // Couldn't read block index entry -- assume bad file
+ return false;
+ }
+
+ // Check size and location
+ int64_t blkSize = box_ntoh64(blk.mEncodedSize);
+ if(blkSize <= 0)
+ {
+ // Mark that this file references another file
+ blockFromOtherFileReferenced = true;
+ }
+ else
+ {
+ // This block is actually in this file
+ if((currentBlockStart + blkSize) > blockIndexLoc)
+ {
+ // Encoded size makes the block run over the index
+ return false;
+ }
+
+ // Move the current block start ot the end of this block
+ currentBlockStart += blkSize;
+ }
+ }
+
+ // Check that there's no empty space
+ if(currentBlockStart != blockIndexLoc)
+ {
+ return false;
+ }
+
+ // Check that if another block is references, then the ID is there, and if one isn't there is no ID.
+ int64_t otherID = box_ntoh64(blkhdr.mOtherFileID);
+ if((otherID != 0 && blockFromOtherFileReferenced == false)
+ || (otherID == 0 && blockFromOtherFileReferenced == true))
+ {
+ // Doesn't look good!
+ return false;
+ }
+
+ // Does the caller want the other ID?
+ if(pDiffFromObjectIDOut)
+ {
+ *pDiffFromObjectIDOut = otherID;
+ }
+
+ // Does the caller want the container ID?
+ if(pContainerIDOut)
+ {
+ *pContainerIDOut = box_ntoh64(hdr.mContainerID);
+ }
+
+ // Passes all tests
+ return true;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodeFile(IOStream &, const char *)
+// Purpose: Decode a file. Will set file attributes. File must not exist.
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::DecodeFile(IOStream &rEncodedFile, const char *DecodedFilename, int Timeout, const BackupClientFileAttributes *pAlterativeAttr)
+{
+ // Does file exist?
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(DecodedFilename, &st) == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, OutputFileAlreadyExists)
+ }
+
+ // Try, delete output file if error
+ try
+ {
+ // Make a stream for outputting this file
+ FileStream out(DecodedFilename, O_WRONLY | O_CREAT | O_EXCL);
+
+ // Get the decoding stream
+ std::auto_ptr<DecodedStream> stream(DecodeFileStream(rEncodedFile, Timeout, pAlterativeAttr));
+
+ // Is it a symlink?
+ if(!stream->IsSymLink())
+ {
+ // Copy it out to the file
+ stream->CopyStreamTo(out);
+ }
+
+ out.Close();
+
+ // The stream might have uncertain size, in which case
+ // we need to drain it to get the
+ // Protocol::ProtocolStreamHeader_EndOfStream byte
+ // out of our connection stream.
+ char buffer[1];
+ int drained = rEncodedFile.Read(buffer, 1);
+
+ // The Read will return 0 if we are actually at the end
+ // of the stream, but some tests decode files directly,
+ // in which case we are actually positioned at the start
+ // of the block index. I hope that reading an extra byte
+ // doesn't hurt!
+ // ASSERT(drained == 0);
+
+ // Write the attributes
+ try
+ {
+ stream->GetAttributes().WriteAttributes(DecodedFilename);
+ }
+ catch (std::exception& e)
+ {
+ BOX_WARNING("Failed to restore attributes on " <<
+ DecodedFilename << ": " << e.what());
+ }
+ }
+ catch(...)
+ {
+ ::unlink(DecodedFilename);
+ throw;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodeFileStream(IOStream &, int, const BackupClientFileAttributes *)
+// Purpose: Return a stream which will decode the encrypted file data on the fly.
+// Accepts streams in block index first, or main header first, order. In the latter case,
+// the stream must be Seek()able.
+//
+// Before you use the returned stream, call IsSymLink() -- symlink streams won't allow
+// you to read any data to enforce correct logic. See BackupStoreFile::DecodeFile() implementation.
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<BackupStoreFile::DecodedStream> BackupStoreFile::DecodeFileStream(IOStream &rEncodedFile, int Timeout, const BackupClientFileAttributes *pAlterativeAttr)
+{
+ // Create stream
+ std::auto_ptr<DecodedStream> stream(new DecodedStream(rEncodedFile, Timeout));
+
+ // Get it ready
+ stream->Setup(pAlterativeAttr);
+
+ // Return to caller
+ return stream;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::DecodedStream(IOStream &, int)
+// Purpose: Constructor
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+BackupStoreFile::DecodedStream::DecodedStream(IOStream &rEncodedFile, int Timeout)
+ : mrEncodedFile(rEncodedFile),
+ mTimeout(Timeout),
+ mNumBlocks(0),
+ mpBlockIndex(0),
+ mpEncodedData(0),
+ mpClearData(0),
+ mClearDataSize(0),
+ mCurrentBlock(-1),
+ mCurrentBlockClearSize(0),
+ mPositionInCurrentBlock(0),
+ mEntryIVBase(42) // different to default value in the encoded stream!
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ , mIsOldVersion(false)
+#endif
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::~DecodedStream()
+// Purpose: Desctructor
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+BackupStoreFile::DecodedStream::~DecodedStream()
+{
+ // Free any allocated memory
+ if(mpBlockIndex)
+ {
+ ::free(mpBlockIndex);
+ }
+ if(mpEncodedData)
+ {
+ BackupStoreFile::CodingChunkFree(mpEncodedData);
+ }
+ if(mpClearData)
+ {
+ ::free(mpClearData);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::Setup(const BackupClientFileAttributes *)
+// Purpose: Get the stream ready to decode -- reads in headers
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::DecodedStream::Setup(const BackupClientFileAttributes *pAlterativeAttr)
+{
+ // Get the size of the file
+ int64_t fileSize = mrEncodedFile.BytesLeftToRead();
+
+ // Get the magic number to work out which order the stream is in
+ int32_t magic;
+ if(!mrEncodedFile.ReadFullBuffer(&magic, sizeof(magic), 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ // Couldn't read magic value
+ THROW_EXCEPTION(BackupStoreException, WhenDecodingExpectedToReadButCouldnt)
+ }
+
+ bool inFileOrder = true;
+ switch(ntohl(magic))
+ {
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ case OBJECTMAGIC_FILE_MAGIC_VALUE_V0:
+ mIsOldVersion = true;
+ // control flows on
+#endif
+ case OBJECTMAGIC_FILE_MAGIC_VALUE_V1:
+ inFileOrder = true;
+ break;
+
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ case OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0:
+ mIsOldVersion = true;
+ // control flows on
+#endif
+ case OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1:
+ inFileOrder = false;
+ break;
+
+ default:
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // If not in file order, then the index list must be read now
+ if(!inFileOrder)
+ {
+ ReadBlockIndex(true /* have already read and verified the magic number */);
+ }
+
+ // Get header
+ file_StreamFormat hdr;
+ if(inFileOrder)
+ {
+ // Read the header, without the magic number
+ if(!mrEncodedFile.ReadFullBuffer(((uint8_t*)&hdr) + sizeof(magic), sizeof(hdr) - sizeof(magic),
+ 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, WhenDecodingExpectedToReadButCouldnt)
+ }
+ // Put in magic number
+ hdr.mMagicValue = magic;
+ }
+ else
+ {
+ // Not in file order, so need to read the full header
+ if(!mrEncodedFile.ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, WhenDecodingExpectedToReadButCouldnt)
+ }
+ }
+
+ // Check magic number
+ if(ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ && ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V0
+#endif
+ )
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Get the filename
+ mFilename.ReadFromStream(mrEncodedFile, mTimeout);
+
+ // Get the attributes (either from stream, or supplied attributes)
+ if(pAlterativeAttr != 0)
+ {
+ // Read dummy attributes
+ BackupClientFileAttributes attr;
+ attr.ReadFromStream(mrEncodedFile, mTimeout);
+
+ // Set to supplied attributes
+ mAttributes = *pAlterativeAttr;
+ }
+ else
+ {
+ // Read the attributes from the stream
+ mAttributes.ReadFromStream(mrEncodedFile, mTimeout);
+ }
+
+ // If it is in file order, go and read the file attributes
+ // Requires that the stream can seek
+ if(inFileOrder)
+ {
+ // Make sure the file size is known
+ if(fileSize == IOStream::SizeOfStreamUnknown)
+ {
+ THROW_EXCEPTION(BackupStoreException, StreamDoesntHaveRequiredFeatures)
+ }
+
+ // Store current location (beginning of encoded blocks)
+ int64_t endOfHeaderPos = mrEncodedFile.GetPosition();
+
+ // Work out where the index is
+ int64_t numBlocks = box_ntoh64(hdr.mNumBlocks);
+ int64_t blockHeaderPos = fileSize - ((numBlocks * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader));
+
+ // Seek to that position
+ mrEncodedFile.Seek(blockHeaderPos, IOStream::SeekType_Absolute);
+
+ // Read the block index
+ ReadBlockIndex(false /* magic number still to be read */);
+
+ // Seek back to the end of header position, ready for reading the chunks
+ mrEncodedFile.Seek(endOfHeaderPos, IOStream::SeekType_Absolute);
+ }
+
+ // Check view of blocks from block header and file header match
+ if(mNumBlocks != (int64_t)box_ntoh64(hdr.mNumBlocks))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Need to allocate some memory for the two blocks for reading encoded data, and clear data
+ if(mNumBlocks > 0)
+ {
+ // Find the maximum encoded data size
+ int32_t maxEncodedDataSize = 0;
+ const file_BlockIndexEntry *entry = (file_BlockIndexEntry *)mpBlockIndex;
+ ASSERT(entry != 0);
+ for(int64_t e = 0; e < mNumBlocks; e++)
+ {
+ // Get the clear and encoded size
+ int32_t encodedSize = box_ntoh64(entry[e].mEncodedSize);
+ ASSERT(encodedSize > 0);
+
+ // Larger?
+ if(encodedSize > maxEncodedDataSize) maxEncodedDataSize = encodedSize;
+ }
+
+ // Allocate those blocks!
+ mpEncodedData = (uint8_t*)BackupStoreFile::CodingChunkAlloc(maxEncodedDataSize + 32);
+
+ // Allocate the block for the clear data, using the hint from the header.
+ // If this is wrong, things will exception neatly later on, so it can't be used
+ // to do anything more than cause an error on downloading.
+ mClearDataSize = OutputBufferSizeForKnownOutputSize(ntohl(hdr.mMaxBlockClearSize)) + 32;
+ mpClearData = (uint8_t*)::malloc(mClearDataSize);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::ReadBlockIndex(bool)
+// Purpose: Read the block index from the stream, and store in internal buffer (minus header)
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::DecodedStream::ReadBlockIndex(bool MagicAlreadyRead)
+{
+ // Header
+ file_BlockIndexHeader blkhdr;
+
+ // Read it in -- way depends on how whether the magic number has already been read
+ if(MagicAlreadyRead)
+ {
+ // Read the header, without the magic number
+ if(!mrEncodedFile.ReadFullBuffer(((uint8_t*)&blkhdr) + sizeof(blkhdr.mMagicValue), sizeof(blkhdr) - sizeof(blkhdr.mMagicValue),
+ 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, WhenDecodingExpectedToReadButCouldnt)
+ }
+ }
+ else
+ {
+ // Magic not already read, so need to read the full header
+ if(!mrEncodedFile.ReadFullBuffer(&blkhdr, sizeof(blkhdr), 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, WhenDecodingExpectedToReadButCouldnt)
+ }
+
+ // Check magic value
+ if(ntohl(blkhdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ && ntohl(blkhdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0
+#endif
+ )
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ }
+
+ // Get the number of blocks out of the header
+ mNumBlocks = box_ntoh64(blkhdr.mNumBlocks);
+
+ // Read the IV base
+ mEntryIVBase = box_ntoh64(blkhdr.mEntryIVBase);
+
+ // Load the block entries in?
+ if(mNumBlocks > 0)
+ {
+ // How big is the index?
+ int64_t indexSize = sizeof(file_BlockIndexEntry) * mNumBlocks;
+
+ // Allocate some memory
+ mpBlockIndex = ::malloc(indexSize);
+ if(mpBlockIndex == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ // Read it in
+ if(!mrEncodedFile.ReadFullBuffer(mpBlockIndex, indexSize, 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, WhenDecodingExpectedToReadButCouldnt)
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::Read(void *, int, int)
+// Purpose: As interface. Reads decrpyted data.
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+int BackupStoreFile::DecodedStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ // Symlinks don't have data. So can't read it. Not even zero bytes.
+ if(IsSymLink())
+ {
+ // Don't allow reading in this case
+ THROW_EXCEPTION(BackupStoreException, ThereIsNoDataInASymLink);
+ }
+
+ // Already finished?
+ if(mCurrentBlock >= mNumBlocks)
+ {
+ // At end of stream, nothing to do
+ return 0;
+ }
+
+ int bytesToRead = NBytes;
+ uint8_t *output = (uint8_t*)pBuffer;
+
+ while(bytesToRead > 0 && mCurrentBlock < mNumBlocks)
+ {
+ // Anything left in the current block?
+ if(mPositionInCurrentBlock < mCurrentBlockClearSize)
+ {
+ // Copy data out of this buffer
+ int s = mCurrentBlockClearSize - mPositionInCurrentBlock;
+ if(s > bytesToRead) s = bytesToRead; // limit to requested data
+
+ // Copy
+ ::memcpy(output, mpClearData + mPositionInCurrentBlock, s);
+
+ // Update positions
+ output += s;
+ mPositionInCurrentBlock += s;
+ bytesToRead -= s;
+ }
+
+ // Need to get some more data?
+ if(bytesToRead > 0 && mPositionInCurrentBlock >= mCurrentBlockClearSize)
+ {
+ // Number of next block
+ ++mCurrentBlock;
+ if(mCurrentBlock >= mNumBlocks)
+ {
+ // Stop now!
+ break;
+ }
+
+ // Get the size from the block index
+ const file_BlockIndexEntry *entry = (file_BlockIndexEntry *)mpBlockIndex;
+ int32_t encodedSize = box_ntoh64(entry[mCurrentBlock].mEncodedSize);
+ if(encodedSize <= 0)
+ {
+ // The caller is attempting to decode a file which is the direct result of a diff
+ // operation, and so does not contain all the data.
+ // It needs to be combined with the previous version first.
+ THROW_EXCEPTION(BackupStoreException, CannotDecodeDiffedFilesWithoutCombining)
+ }
+
+ // Load in next block
+ if(!mrEncodedFile.ReadFullBuffer(mpEncodedData, encodedSize, 0 /* not interested in bytes read if this fails */, mTimeout))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, WhenDecodingExpectedToReadButCouldnt)
+ }
+
+ // Decode the data
+ mCurrentBlockClearSize = BackupStoreFile::DecodeChunk(mpEncodedData, encodedSize, mpClearData, mClearDataSize);
+
+ // Calculate IV for this entry
+ uint64_t iv = mEntryIVBase;
+ iv += mCurrentBlock;
+ // Convert to network byte order before encrypting with it, so that restores work on
+ // platforms with different endiannesses.
+ iv = box_hton64(iv);
+ sBlowfishDecryptBlockEntry.SetIV(&iv);
+
+ // Decrypt the encrypted section
+ file_BlockIndexEntryEnc entryEnc;
+ int sectionSize = sBlowfishDecryptBlockEntry.TransformBlock(&entryEnc, sizeof(entryEnc),
+ entry[mCurrentBlock].mEnEnc, sizeof(entry[mCurrentBlock].mEnEnc));
+ if(sectionSize != sizeof(entryEnc))
+ {
+ THROW_EXCEPTION(BackupStoreException, BlockEntryEncodingDidntGiveExpectedLength)
+ }
+
+ // Make sure this is the right size
+ if(mCurrentBlockClearSize != (int32_t)ntohl(entryEnc.mSize))
+ {
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ if(!mIsOldVersion)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ // Versions 0.05 and previous of Box Backup didn't properly handle endianess of the
+ // IV for the encrypted section. Try again, with the thing the other way round
+ iv = box_swap64(iv);
+ sBlowfishDecryptBlockEntry.SetIV(&iv);
+ int sectionSize = sBlowfishDecryptBlockEntry.TransformBlock(&entryEnc, sizeof(entryEnc),
+ entry[mCurrentBlock].mEnEnc, sizeof(entry[mCurrentBlock].mEnEnc));
+ if(sectionSize != sizeof(entryEnc))
+ {
+ THROW_EXCEPTION(BackupStoreException, BlockEntryEncodingDidntGiveExpectedLength)
+ }
+ if(mCurrentBlockClearSize != (int32_t)ntohl(entryEnc.mSize))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ else
+ {
+ // Warn and log this issue
+ if(!sWarnedAboutBackwardsCompatiblity)
+ {
+ BOX_WARNING("WARNING: Decoded one or more files using backwards compatibility mode for block index.");
+ sWarnedAboutBackwardsCompatiblity = true;
+ }
+ }
+#else
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+#endif
+ }
+
+ // Check the digest
+ MD5Digest md5;
+ md5.Add(mpClearData, mCurrentBlockClearSize);
+ md5.Finish();
+ if(!md5.DigestMatches((uint8_t*)entryEnc.mStrongChecksum))
+ {
+ THROW_EXCEPTION(BackupStoreException, BackupStoreFileFailedIntegrityCheck)
+ }
+
+ // Set vars to say what's happening
+ mPositionInCurrentBlock = 0;
+ }
+ }
+
+ ASSERT(bytesToRead >= 0);
+ ASSERT(bytesToRead <= NBytes);
+
+ return NBytes - bytesToRead;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::IsSymLink()
+// Purpose: Is the unencoded file actually a symlink?
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFile::DecodedStream::IsSymLink()
+{
+ // First, check in with the attributes
+ if(!mAttributes.IsSymLink())
+ {
+ return false;
+ }
+
+ // So the attributes think it is a symlink.
+ // Consistency check...
+ if(mNumBlocks != 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::Write(const void *, int)
+// Purpose: As interface. Throws exception, as you can't write to this stream.
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::DecodedStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(BackupStoreException, CantWriteToDecodedFileStream)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::StreamDataLeft()
+// Purpose: As interface. Any data left?
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFile::DecodedStream::StreamDataLeft()
+{
+ return mCurrentBlock < mNumBlocks;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodedStream::StreamClosed()
+// Purpose: As interface. Always returns true, no writing allowed.
+// Created: 9/12/03
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFile::DecodedStream::StreamClosed()
+{
+ // Can't write to this stream!
+ return true;
+}
+
+
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::SetBlowfishKey(const void *, int)
+// Purpose: Static. Sets the key to use for encryption and decryption.
+// Created: 7/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::SetBlowfishKeys(const void *pKey, int KeyLength, const void *pBlockEntryKey, int BlockEntryKeyLength)
+{
+ // IVs set later
+ sBlowfishEncrypt.Reset();
+ sBlowfishEncrypt.Init(CipherContext::Encrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength));
+ sBlowfishDecrypt.Reset();
+ sBlowfishDecrypt.Init(CipherContext::Decrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength));
+
+ sBlowfishEncryptBlockEntry.Reset();
+ sBlowfishEncryptBlockEntry.Init(CipherContext::Encrypt, CipherBlowfish(CipherDescription::Mode_CBC, pBlockEntryKey, BlockEntryKeyLength));
+ sBlowfishEncryptBlockEntry.UsePadding(false);
+ sBlowfishDecryptBlockEntry.Reset();
+ sBlowfishDecryptBlockEntry.Init(CipherContext::Decrypt, CipherBlowfish(CipherDescription::Mode_CBC, pBlockEntryKey, BlockEntryKeyLength));
+ sBlowfishDecryptBlockEntry.UsePadding(false);
+}
+
+
+#ifndef HAVE_OLD_SSL
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::SetAESKey(const void *, int)
+// Purpose: Sets the AES key to use for file data encryption. Will select AES as
+// the cipher to use when encrypting.
+// Created: 27/4/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::SetAESKey(const void *pKey, int KeyLength)
+{
+ // Setup context
+ sAESEncrypt.Reset();
+ sAESEncrypt.Init(CipherContext::Encrypt, CipherAES(CipherDescription::Mode_CBC, pKey, KeyLength));
+ sAESDecrypt.Reset();
+ sAESDecrypt.Init(CipherContext::Decrypt, CipherAES(CipherDescription::Mode_CBC, pKey, KeyLength));
+
+ // Set encryption to use this key, instead of the "default" blowfish key
+ spEncrypt = &sAESEncrypt;
+ sEncryptCipherType = HEADER_AES_ENCODING;
+}
+#endif
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::MaxBlockSizeForChunkSize(int)
+// Purpose: The maximum output size of a block, given the chunk size
+// Created: 7/12/03
+//
+// --------------------------------------------------------------------------
+int BackupStoreFile::MaxBlockSizeForChunkSize(int ChunkSize)
+{
+ // Calculate... the maximum size of output by first the largest it could be after compression,
+ // which is encrypted, and has a 1 bytes header and the IV added, plus 1 byte for luck
+ // And then on top, add 128 bytes just to make sure. (Belts and braces approach to fixing
+ // an problem where a rather non-compressable file didn't fit in a block buffer.)
+ return sBlowfishEncrypt.MaxOutSizeForInBufferSize(Compress_MaxSizeForCompressedData(ChunkSize)) + 1 + 1
+ + sBlowfishEncrypt.GetIVLength() + 128;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::EncodeChunk(const void *, int, BackupStoreFile::EncodingBuffer &)
+// Purpose: Encodes a chunk (encryption, possible compressed beforehand)
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+int BackupStoreFile::EncodeChunk(const void *Chunk, int ChunkSize, BackupStoreFile::EncodingBuffer &rOutput)
+{
+ ASSERT(spEncrypt != 0);
+
+ // Check there's some space in the output block
+ if(rOutput.mBufferSize < 256)
+ {
+ rOutput.Reallocate(256);
+ }
+
+ // Check alignment of the block
+ ASSERT((((uint32_t)(long)rOutput.mpBuffer) % BACKUPSTOREFILE_CODING_BLOCKSIZE) == BACKUPSTOREFILE_CODING_OFFSET);
+
+ // Want to compress it?
+ bool compressChunk = (ChunkSize >= BACKUP_FILE_MIN_COMPRESSED_CHUNK_SIZE);
+
+ // Build header
+ uint8_t header = sEncryptCipherType << HEADER_ENCODING_SHIFT;
+ if(compressChunk) header |= HEADER_CHUNK_IS_COMPRESSED;
+
+ // Store header
+ rOutput.mpBuffer[0] = header;
+ int outOffset = 1;
+
+ // Setup cipher, and store the IV
+ int ivLen = 0;
+ const void *iv = spEncrypt->SetRandomIV(ivLen);
+ ::memcpy(rOutput.mpBuffer + outOffset, iv, ivLen);
+ outOffset += ivLen;
+
+ // Start encryption process
+ spEncrypt->Begin();
+
+ #define ENCODECHUNK_CHECK_SPACE(ToEncryptSize) \
+ { \
+ if((rOutput.mBufferSize - outOffset) < ((ToEncryptSize) + 128)) \
+ { \
+ rOutput.Reallocate(rOutput.mBufferSize + (ToEncryptSize) + 128); \
+ } \
+ }
+
+ // Encode the chunk
+ if(compressChunk)
+ {
+ // buffer to compress into
+ uint8_t buffer[2048];
+
+ // Set compressor with all the chunk as an input
+ Compress<true> compress;
+ compress.Input(Chunk, ChunkSize);
+ compress.FinishInput();
+
+ // Get and encrypt output
+ while(!compress.OutputHasFinished())
+ {
+ int s = compress.Output(buffer, sizeof(buffer));
+ if(s > 0)
+ {
+ ENCODECHUNK_CHECK_SPACE(s)
+ outOffset += spEncrypt->Transform(rOutput.mpBuffer + outOffset, rOutput.mBufferSize - outOffset, buffer, s);
+ }
+ else
+ {
+ // Should never happen, as we put all the input in in one go.
+ // So if this happens, it means there's a logical problem somewhere
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+ }
+ ENCODECHUNK_CHECK_SPACE(16)
+ outOffset += spEncrypt->Final(rOutput.mpBuffer + outOffset, rOutput.mBufferSize - outOffset);
+ }
+ else
+ {
+ // Straight encryption
+ ENCODECHUNK_CHECK_SPACE(ChunkSize)
+ outOffset += spEncrypt->Transform(rOutput.mpBuffer + outOffset, rOutput.mBufferSize - outOffset, Chunk, ChunkSize);
+ ENCODECHUNK_CHECK_SPACE(16)
+ outOffset += spEncrypt->Final(rOutput.mpBuffer + outOffset, rOutput.mBufferSize - outOffset);
+ }
+
+ ASSERT(outOffset < rOutput.mBufferSize); // first check should have sorted this -- merely logic check
+
+ return outOffset;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::DecodeChunk(const void *, int, void *, int)
+// Purpose: Decode an encoded chunk -- use OutputBufferSizeForKnownOutputSize() to find
+// the extra output buffer size needed before calling.
+// See notes in EncodeChunk() for notes re alignment of the
+// encoded data.
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+int BackupStoreFile::DecodeChunk(const void *Encoded, int EncodedSize, void *Output, int OutputSize)
+{
+ // Check alignment of the encoded block
+ ASSERT((((uint32_t)(long)Encoded) % BACKUPSTOREFILE_CODING_BLOCKSIZE) == BACKUPSTOREFILE_CODING_OFFSET);
+
+ // First check
+ if(EncodedSize < 1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadEncodedChunk)
+ }
+
+ const uint8_t *input = (uint8_t*)Encoded;
+
+ // Get header, make checks, etc
+ uint8_t header = input[0];
+ bool chunkCompressed = (header & HEADER_CHUNK_IS_COMPRESSED) == HEADER_CHUNK_IS_COMPRESSED;
+ uint8_t encodingType = (header >> HEADER_ENCODING_SHIFT);
+ if(encodingType != HEADER_BLOWFISH_ENCODING && encodingType != HEADER_AES_ENCODING)
+ {
+ THROW_EXCEPTION(BackupStoreException, ChunkHasUnknownEncoding)
+ }
+
+#ifndef HAVE_OLD_SSL
+ // Choose cipher
+ CipherContext &cipher((encodingType == HEADER_AES_ENCODING)?sAESDecrypt:sBlowfishDecrypt);
+#else
+ // AES not supported with this version of OpenSSL
+ if(encodingType == HEADER_AES_ENCODING)
+ {
+ THROW_EXCEPTION(BackupStoreException, AEScipherNotSupportedByInstalledOpenSSL)
+ }
+ CipherContext &cipher(sBlowfishDecrypt);
+#endif
+
+ // Check enough space for header, an IV and one byte of input
+ int ivLen = cipher.GetIVLength();
+ if(EncodedSize < (1 + ivLen + 1))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadEncodedChunk)
+ }
+
+ // Set IV in decrypt context, and start
+ cipher.SetIV(input + 1);
+ cipher.Begin();
+
+ // Setup vars for code
+ int inOffset = 1 + ivLen;
+ uint8_t *output = (uint8_t*)Output;
+ int outOffset = 0;
+
+ // Do action
+ if(chunkCompressed)
+ {
+ // Do things in chunks
+ uint8_t buffer[2048];
+ int inputBlockLen = cipher.InSizeForOutBufferSize(sizeof(buffer));
+
+ // Decompressor
+ Compress<false> decompress;
+
+ while(inOffset < EncodedSize)
+ {
+ // Decrypt a block
+ int bl = inputBlockLen;
+ if(bl > (EncodedSize - inOffset)) bl = EncodedSize - inOffset; // not too long
+ int s = cipher.Transform(buffer, sizeof(buffer), input + inOffset, bl);
+ inOffset += bl;
+
+ // Decompress the decrypted data
+ if(s > 0)
+ {
+ decompress.Input(buffer, s);
+ int os = 0;
+ do
+ {
+ os = decompress.Output(output + outOffset, OutputSize - outOffset);
+ outOffset += os;
+ } while(os > 0);
+
+ // Check that there's space left in the output buffer -- there always should be
+ if(outOffset >= OutputSize)
+ {
+ THROW_EXCEPTION(BackupStoreException, NotEnoughSpaceToDecodeChunk)
+ }
+ }
+ }
+
+ // Get any compressed data remaining in the cipher context and compression
+ int s = cipher.Final(buffer, sizeof(buffer));
+ decompress.Input(buffer, s);
+ decompress.FinishInput();
+ while(!decompress.OutputHasFinished())
+ {
+ int os = decompress.Output(output + outOffset, OutputSize - outOffset);
+ outOffset += os;
+
+ // Check that there's space left in the output buffer -- there always should be
+ if(outOffset >= OutputSize)
+ {
+ THROW_EXCEPTION(BackupStoreException, NotEnoughSpaceToDecodeChunk)
+ }
+ }
+ }
+ else
+ {
+ // Easy decryption
+ outOffset += cipher.Transform(output + outOffset, OutputSize - outOffset, input + inOffset, EncodedSize - inOffset);
+ outOffset += cipher.Final(output + outOffset, OutputSize - outOffset);
+ }
+
+ return outOffset;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::ReorderFileToStreamOrder(IOStream *, bool)
+// Purpose: Returns a stream which gives a Stream order version of the encoded file.
+// If TakeOwnership == true, then the input stream will be deleted when the
+// returned stream is deleted.
+// The input stream must be seekable.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<IOStream> BackupStoreFile::ReorderFileToStreamOrder(IOStream *pStream, bool TakeOwnership)
+{
+ ASSERT(pStream != 0);
+
+ // Get the size of the file
+ int64_t fileSize = pStream->BytesLeftToRead();
+ if(fileSize == IOStream::SizeOfStreamUnknown)
+ {
+ THROW_EXCEPTION(BackupStoreException, StreamDoesntHaveRequiredFeatures)
+ }
+
+ // Read the header
+ int bytesRead = 0;
+ file_StreamFormat hdr;
+ bool readBlock = pStream->ReadFullBuffer(&hdr, sizeof(hdr), &bytesRead);
+
+ // Seek backwards to put the file pointer back where it was before we started this
+ pStream->Seek(0 - bytesRead, IOStream::SeekType_Relative);
+
+ // Check we got a block
+ if(!readBlock)
+ {
+ // Couldn't read header -- assume file bad
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Check magic number
+ if(ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ && ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V0
+#endif
+ )
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Get number of blocks
+ int64_t numBlocks = box_ntoh64(hdr.mNumBlocks);
+
+ // Calculate where the block index will be, check it's reasonable
+ int64_t blockIndexSize = ((numBlocks * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader));
+ int64_t blockIndexLoc = fileSize - blockIndexSize;
+ if(blockIndexLoc < 0)
+ {
+ // Doesn't look good!
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Build a reordered stream
+ std::auto_ptr<IOStream> reordered(new ReadGatherStream(TakeOwnership));
+
+ // Set it up...
+ ReadGatherStream &rreordered(*((ReadGatherStream*)reordered.get()));
+ int component = rreordered.AddComponent(pStream);
+ // Send out the block index
+ rreordered.AddBlock(component, blockIndexSize, true, blockIndexLoc);
+ // And then the rest of the file
+ rreordered.AddBlock(component, blockIndexLoc, true, 0);
+
+ return reordered;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::ResetStats()
+// Purpose: Reset the gathered statistics
+// Created: 20/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::ResetStats()
+{
+ msStats.mBytesInEncodedFiles = 0;
+ msStats.mBytesAlreadyOnServer = 0;
+ msStats.mTotalFileStreamSize = 0;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::CompareFileContentsAgainstBlockIndex(const char *, IOStream &)
+// Purpose: Compares the contents of a file against the checksums contained in the
+// block index. Returns true if the checksums match, meaning the file is
+// extremely likely to match the original. Will always consume the entire index.
+// Created: 21/1/04
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFile::CompareFileContentsAgainstBlockIndex(const char *Filename, IOStream &rBlockIndex, int Timeout)
+{
+ // is it a symlink?
+ bool sourceIsSymlink = false;
+ {
+ EMU_STRUCT_STAT st;
+ if(EMU_LSTAT(Filename, &st) == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+ if((st.st_mode & S_IFMT) == S_IFLNK)
+ {
+ sourceIsSymlink = true;
+ }
+ }
+
+ // Open file, if it's not a symlink
+ std::auto_ptr<FileStream> in;
+ if(!sourceIsSymlink)
+ {
+ in.reset(new FileStream(Filename));
+ }
+
+ // Read header
+ file_BlockIndexHeader hdr;
+ if(!rBlockIndex.ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Check magic
+ if(hdr.mMagicValue != (int32_t)htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ && hdr.mMagicValue != (int32_t)htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0)
+#endif
+ )
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ bool isOldVersion = hdr.mMagicValue == (int32_t)htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0);
+#endif
+
+ // Get basic information
+ int64_t numBlocks = box_ntoh64(hdr.mNumBlocks);
+ uint64_t entryIVBase = box_ntoh64(hdr.mEntryIVBase);
+
+ //TODO: Verify that these sizes look reasonable
+
+ // setup
+ void *data = 0;
+ int32_t dataSize = -1;
+ bool matches = true;
+ int64_t totalSizeInBlockIndex = 0;
+
+ try
+ {
+ for(int64_t b = 0; b < numBlocks; ++b)
+ {
+ // Read an entry from the stream
+ file_BlockIndexEntry entry;
+ if(!rBlockIndex.ReadFullBuffer(&entry, sizeof(entry), 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ // Couldn't read entry
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Calculate IV for this entry
+ uint64_t iv = entryIVBase;
+ iv += b;
+ iv = box_hton64(iv);
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ if(isOldVersion)
+ {
+ // Reverse the IV for compatibility
+ iv = box_swap64(iv);
+ }
+#endif
+ sBlowfishDecryptBlockEntry.SetIV(&iv);
+
+ // Decrypt the encrypted section
+ file_BlockIndexEntryEnc entryEnc;
+ int sectionSize = sBlowfishDecryptBlockEntry.TransformBlock(&entryEnc, sizeof(entryEnc),
+ entry.mEnEnc, sizeof(entry.mEnEnc));
+ if(sectionSize != sizeof(entryEnc))
+ {
+ THROW_EXCEPTION(BackupStoreException, BlockEntryEncodingDidntGiveExpectedLength)
+ }
+
+ // Size of block
+ int32_t blockClearSize = ntohl(entryEnc.mSize);
+ if(blockClearSize < 0 || blockClearSize > (BACKUP_FILE_MAX_BLOCK_SIZE + 1024))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ totalSizeInBlockIndex += blockClearSize;
+
+ // Make sure there's enough memory allocated to load the block in
+ if(dataSize < blockClearSize)
+ {
+ // Too small, free the block if it's already allocated
+ if(data != 0)
+ {
+ ::free(data);
+ data = 0;
+ }
+ // Allocate a block
+ data = ::malloc(blockClearSize + 128);
+ if(data == 0)
+ {
+ throw std::bad_alloc();
+ }
+ dataSize = blockClearSize + 128;
+ }
+
+ // Load in the block from the file, if it's not a symlink
+ if(!sourceIsSymlink)
+ {
+ if(in->Read(data, blockClearSize) != blockClearSize)
+ {
+ // Not enough data left in the file, can't possibly match
+ matches = false;
+ }
+ else
+ {
+ // Check the checksum
+ MD5Digest md5;
+ md5.Add(data, blockClearSize);
+ md5.Finish();
+ if(!md5.DigestMatches(entryEnc.mStrongChecksum))
+ {
+ // Checksum didn't match
+ matches = false;
+ }
+ }
+ }
+
+ // Keep on going regardless, to make sure the entire block index stream is read
+ // -- must always be consistent about what happens with the stream.
+ }
+ }
+ catch(...)
+ {
+ // clean up in case of errors
+ if(data != 0)
+ {
+ ::free(data);
+ data = 0;
+ }
+ throw;
+ }
+
+ // free block
+ if(data != 0)
+ {
+ ::free(data);
+ data = 0;
+ }
+
+ // Check for data left over if it's not a symlink
+ if(!sourceIsSymlink)
+ {
+ // Anything left to read in the file?
+ if(in->BytesLeftToRead() != 0)
+ {
+ // File has extra data at the end
+ matches = false;
+ }
+ }
+
+ // Symlinks must have zero size on server
+ if(sourceIsSymlink)
+ {
+ matches = (totalSizeInBlockIndex == 0);
+ }
+
+ return matches;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::EncodingBuffer::EncodingBuffer()
+// Purpose: Constructor
+// Created: 25/11/04
+//
+// --------------------------------------------------------------------------
+BackupStoreFile::EncodingBuffer::EncodingBuffer()
+ : mpBuffer(0),
+ mBufferSize(0)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::EncodingBuffer::~EncodingBuffer()
+// Purpose: Destructor
+// Created: 25/11/04
+//
+// --------------------------------------------------------------------------
+BackupStoreFile::EncodingBuffer::~EncodingBuffer()
+{
+ if(mpBuffer != 0)
+ {
+ BackupStoreFile::CodingChunkFree(mpBuffer);
+ mpBuffer = 0;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::EncodingBuffer::Allocate(int)
+// Purpose: Do initial allocation of block
+// Created: 25/11/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::EncodingBuffer::Allocate(int Size)
+{
+ ASSERT(mpBuffer == 0);
+ uint8_t *buffer = (uint8_t*)BackupStoreFile::CodingChunkAlloc(Size);
+ if(buffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+ mpBuffer = buffer;
+ mBufferSize = Size;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::EncodingBuffer::Reallocate(int)
+// Purpose: Reallocate the block. Try not to call this, it has to copy
+// the entire contents as the block can't be reallocated straight.
+// Created: 25/11/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::EncodingBuffer::Reallocate(int NewSize)
+{
+ BOX_TRACE("Reallocating EncodingBuffer from " << mBufferSize <<
+ " to " << NewSize);
+ ASSERT(mpBuffer != 0);
+ uint8_t *buffer = (uint8_t*)BackupStoreFile::CodingChunkAlloc(NewSize);
+ if(buffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+ // Copy data
+ ::memcpy(buffer, mpBuffer, (NewSize > mBufferSize)?mBufferSize:NewSize);
+
+ // Free old
+ BackupStoreFile::CodingChunkFree(mpBuffer);
+
+ // Store new buffer
+ mpBuffer = buffer;
+ mBufferSize = NewSize;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiffTimer::DiffTimer();
+// Purpose: Constructor
+// Created: 2005/02/01
+//
+// --------------------------------------------------------------------------
+DiffTimer::DiffTimer()
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiffTimer::DiffTimer();
+// Purpose: Destructor
+// Created: 2005/02/01
+//
+// --------------------------------------------------------------------------
+DiffTimer::~DiffTimer()
+{
+}
diff --git a/lib/backupclient/BackupStoreFile.h b/lib/backupclient/BackupStoreFile.h
new file mode 100644
index 00000000..f4c60919
--- /dev/null
+++ b/lib/backupclient/BackupStoreFile.h
@@ -0,0 +1,228 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFile.h
+// Purpose: Utils for manipulating files
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREFILE__H
+#define BACKUPSTOREFILE__H
+
+#include <cstdlib>
+#include <memory>
+#include <cstdlib>
+
+#include "BackupClientFileAttributes.h"
+#include "BackupStoreFilename.h"
+#include "IOStream.h"
+#include "ReadLoggingStream.h"
+#include "RunStatusProvider.h"
+
+typedef struct
+{
+ int64_t mBytesInEncodedFiles;
+ int64_t mBytesAlreadyOnServer;
+ int64_t mTotalFileStreamSize;
+} BackupStoreFileStats;
+
+// Uncomment to disable backwards compatibility
+//#define BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+
+
+// Output buffer to EncodeChunk and input data to DecodeChunk must
+// have specific alignment, see function comments.
+#define BACKUPSTOREFILE_CODING_BLOCKSIZE 16
+#define BACKUPSTOREFILE_CODING_OFFSET 15
+
+// Have some memory allocation commands, note closing "Off" at end of file.
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: DiffTimer
+// Purpose: Interface for classes that can keep track of diffing time,
+// and send SSL keepalive messages
+// Created: 2006/01/19
+//
+// --------------------------------------------------------------------------
+class DiffTimer
+{
+public:
+ DiffTimer();
+ virtual ~DiffTimer();
+public:
+ virtual void DoKeepAlive() = 0;
+ virtual int GetMaximumDiffingTime() = 0;
+ virtual bool IsManaged() = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: BackupStoreFile
+// Purpose: Class to hold together utils for manipulating files.
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+class BackupStoreFile
+{
+public:
+ class DecodedStream : public IOStream
+ {
+ friend class BackupStoreFile;
+ private:
+ DecodedStream(IOStream &rEncodedFile, int Timeout);
+ DecodedStream(const DecodedStream &); // not allowed
+ DecodedStream &operator=(const DecodedStream &); // not allowed
+ public:
+ ~DecodedStream();
+
+ // Stream functions
+ virtual int Read(void *pBuffer, int NBytes, int Timeout);
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+ // Accessor functions
+ const BackupClientFileAttributes &GetAttributes() {return mAttributes;}
+ const BackupStoreFilename &GetFilename() {return mFilename;}
+ int64_t GetNumBlocks() {return mNumBlocks;} // primarily for tests
+
+ bool IsSymLink();
+
+ private:
+ void Setup(const BackupClientFileAttributes *pAlterativeAttr);
+ void ReadBlockIndex(bool MagicAlreadyRead);
+
+ private:
+ IOStream &mrEncodedFile;
+ int mTimeout;
+ BackupClientFileAttributes mAttributes;
+ BackupStoreFilename mFilename;
+ int64_t mNumBlocks;
+ void *mpBlockIndex;
+ uint8_t *mpEncodedData;
+ uint8_t *mpClearData;
+ int mClearDataSize;
+ int mCurrentBlock;
+ int mCurrentBlockClearSize;
+ int mPositionInCurrentBlock;
+ uint64_t mEntryIVBase;
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ bool mIsOldVersion;
+#endif
+ };
+
+
+ // Main interface
+ static std::auto_ptr<IOStream> EncodeFile(const char *Filename,
+ int64_t ContainerID, const BackupStoreFilename &rStoreFilename,
+ int64_t *pModificationTime = 0,
+ ReadLoggingStream::Logger* pLogger = NULL,
+ RunStatusProvider* pRunStatusProvider = NULL);
+ static std::auto_ptr<IOStream> EncodeFileDiff
+ (
+ const char *Filename, int64_t ContainerID,
+ const BackupStoreFilename &rStoreFilename,
+ int64_t DiffFromObjectID, IOStream &rDiffFromBlockIndex,
+ int Timeout,
+ DiffTimer *pDiffTimer,
+ int64_t *pModificationTime = 0,
+ bool *pIsCompletelyDifferent = 0
+ );
+ static bool VerifyEncodedFileFormat(IOStream &rFile, int64_t *pDiffFromObjectIDOut = 0, int64_t *pContainerIDOut = 0);
+ static void CombineFile(IOStream &rDiff, IOStream &rDiff2, IOStream &rFrom, IOStream &rOut);
+ static void CombineDiffs(IOStream &rDiff1, IOStream &rDiff2, IOStream &rDiff2b, IOStream &rOut);
+ static void ReverseDiffFile(IOStream &rDiff, IOStream &rFrom, IOStream &rFrom2, IOStream &rOut, int64_t ObjectIDOfFrom, bool *pIsCompletelyDifferent = 0);
+ static void DecodeFile(IOStream &rEncodedFile, const char *DecodedFilename, int Timeout, const BackupClientFileAttributes *pAlterativeAttr = 0);
+ static std::auto_ptr<BackupStoreFile::DecodedStream> DecodeFileStream(IOStream &rEncodedFile, int Timeout, const BackupClientFileAttributes *pAlterativeAttr = 0);
+ static bool CompareFileContentsAgainstBlockIndex(const char *Filename, IOStream &rBlockIndex, int Timeout);
+ static std::auto_ptr<IOStream> CombineFileIndices(IOStream &rDiff, IOStream &rFrom, bool DiffIsIndexOnly = false, bool FromIsIndexOnly = false);
+
+ // Stream manipulation
+ static std::auto_ptr<IOStream> ReorderFileToStreamOrder(IOStream *pStream, bool TakeOwnership);
+ static void MoveStreamPositionToBlockIndex(IOStream &rStream);
+
+ // Crypto setup
+ static void SetBlowfishKeys(const void *pKey, int KeyLength, const void *pBlockEntryKey, int BlockEntryKeyLength);
+#ifndef HAVE_OLD_SSL
+ static void SetAESKey(const void *pKey, int KeyLength);
+#endif
+
+ // Allocation of properly aligning chunks for decoding and encoding chunks
+ inline static void *CodingChunkAlloc(int Size)
+ {
+ uint8_t *a = (uint8_t*)malloc((Size) + (BACKUPSTOREFILE_CODING_BLOCKSIZE * 3));
+ if(a == 0) return 0;
+ // Align to main block size
+ ASSERT(sizeof(unsigned long) >= sizeof(void*)); // make sure casting the right pointer size
+ uint8_t adjustment = BACKUPSTOREFILE_CODING_BLOCKSIZE
+ - (uint8_t)(((unsigned long)a) % BACKUPSTOREFILE_CODING_BLOCKSIZE);
+ uint8_t *b = (a + adjustment);
+ // Store adjustment
+ *b = adjustment;
+ // Return offset
+ return b + BACKUPSTOREFILE_CODING_OFFSET;
+ }
+ inline static void CodingChunkFree(void *Block)
+ {
+ // Check alignment is as expected
+ ASSERT(sizeof(unsigned long) >= sizeof(void*)); // make sure casting the right pointer size
+ ASSERT((uint8_t)(((unsigned long)Block) % BACKUPSTOREFILE_CODING_BLOCKSIZE) == BACKUPSTOREFILE_CODING_OFFSET);
+ uint8_t *a = (uint8_t*)Block;
+ a -= BACKUPSTOREFILE_CODING_OFFSET;
+ // Adjust downwards...
+ a -= *a;
+ free(a);
+ }
+
+ static void DiffTimerExpired();
+
+ // Building blocks
+ class EncodingBuffer
+ {
+ public:
+ EncodingBuffer();
+ ~EncodingBuffer();
+ private:
+ // No copying
+ EncodingBuffer(const EncodingBuffer &);
+ EncodingBuffer &operator=(const EncodingBuffer &);
+ public:
+ void Allocate(int Size);
+ void Reallocate(int NewSize);
+
+ uint8_t *mpBuffer;
+ int mBufferSize;
+ };
+ static int MaxBlockSizeForChunkSize(int ChunkSize);
+ static int EncodeChunk(const void *Chunk, int ChunkSize, BackupStoreFile::EncodingBuffer &rOutput);
+
+ // Caller should know how big the output size is, but also allocate a bit more memory to cover various
+ // overheads allowed for in checks
+ static inline int OutputBufferSizeForKnownOutputSize(int KnownChunkSize)
+ {
+ // Plenty big enough
+ return KnownChunkSize + 256;
+ }
+ static int DecodeChunk(const void *Encoded, int EncodedSize, void *Output, int OutputSize);
+
+ // Statisitics, not designed to be completely reliable
+ static void ResetStats();
+ static BackupStoreFileStats msStats;
+
+ // For debug
+#ifndef BOX_RELEASE_BUILD
+ static bool TraceDetailsOfDiffProcess;
+#endif
+
+ // For decoding encoded files
+ static void DumpFile(void *clibFileHandle, bool ToTrace, IOStream &rFile);
+};
+
+#include "MemLeakFindOff.h"
+
+#endif // BACKUPSTOREFILE__H
diff --git a/lib/backupclient/BackupStoreFileCmbDiff.cpp b/lib/backupclient/BackupStoreFileCmbDiff.cpp
new file mode 100644
index 00000000..1a88fa3f
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileCmbDiff.cpp
@@ -0,0 +1,326 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileCmbDiff.cpp
+// Purpose: Combine two diffs together
+// Created: 12/7/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <new>
+#include <stdlib.h>
+
+#include "BackupStoreFile.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreObjectMagic.h"
+#include "BackupStoreException.h"
+#include "BackupStoreConstants.h"
+#include "BackupStoreFilename.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::CombineDiffs(IOStream &, IOStream &, IOStream &rOut)
+// Purpose: Given two diffs, combine them into a single diff, to produce a diff
+// which, combined with the original file, creates the result of applying
+// rDiff, then rDiff2. Two opens of rDiff2 are required
+// Created: 12/7/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::CombineDiffs(IOStream &rDiff1, IOStream &rDiff2, IOStream &rDiff2b, IOStream &rOut)
+{
+ // Skip header of first diff, record where the data starts, and skip to the index
+ int64_t diff1DataStarts = 0;
+ {
+ // Read the header for the From file
+ file_StreamFormat diff1Hdr;
+ if(!rDiff1.ReadFullBuffer(&diff1Hdr, sizeof(diff1Hdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ if(ntohl(diff1Hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ // Skip over the filename and attributes of the From file
+ // BLOCK
+ {
+ BackupStoreFilename filename2;
+ filename2.ReadFromStream(rDiff1, IOStream::TimeOutInfinite);
+ int32_t size_s;
+ if(!rDiff1.ReadFullBuffer(&size_s, sizeof(size_s), 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+ int size = ntohl(size_s);
+ // Skip forward the size
+ rDiff1.Seek(size, IOStream::SeekType_Relative);
+ }
+ // Record position
+ diff1DataStarts = rDiff1.GetPosition();
+ // Skip to index
+ rDiff1.Seek(0 - (((box_ntoh64(diff1Hdr.mNumBlocks)) * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader)), IOStream::SeekType_End);
+ }
+
+ // Read the index of the first diff
+ // Header first
+ file_BlockIndexHeader diff1IdxHdr;
+ if(!rDiff1.ReadFullBuffer(&diff1IdxHdr, sizeof(diff1IdxHdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+ if(ntohl(diff1IdxHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ int64_t diff1NumBlocks = box_ntoh64(diff1IdxHdr.mNumBlocks);
+ // Allocate some memory
+ int64_t *diff1BlockStartPositions = (int64_t*)::malloc((diff1NumBlocks + 1) * sizeof(int64_t));
+ if(diff1BlockStartPositions == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ // Buffer data
+ void *buffer = 0;
+ int bufferSize = 0;
+
+ try
+ {
+ // Then the entries:
+ // For each entry, want to know if it's in the file, and if so, how big it is.
+ // We'll store this as an array of file positions in the file, with an additioal
+ // entry on the end so that we can work out the length of the last block.
+ // If an entry isn't in the file, then store 0 - (position in other file).
+ int64_t diff1Position = diff1DataStarts;
+ for(int64_t b = 0; b < diff1NumBlocks; ++b)
+ {
+ file_BlockIndexEntry e;
+ if(!rDiff1.ReadFullBuffer(&e, sizeof(e), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Where's the block?
+ int64_t blockEn = box_ntoh64(e.mEncodedSize);
+ if(blockEn <= 0)
+ {
+ // Just store the negated block number
+ diff1BlockStartPositions[b] = blockEn;
+ }
+ else
+ {
+ // Block is present in this file
+ diff1BlockStartPositions[b] = diff1Position;
+ diff1Position += blockEn;
+ }
+ }
+
+ // Finish off the list, so the last entry can have it's size calcuated.
+ diff1BlockStartPositions[diff1NumBlocks] = diff1Position;
+
+ // Now read the second diff's header, copying it to the out file
+ file_StreamFormat diff2Hdr;
+ if(!rDiff2.ReadFullBuffer(&diff2Hdr, sizeof(diff2Hdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ if(ntohl(diff2Hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ // Copy
+ rOut.Write(&diff2Hdr, sizeof(diff2Hdr));
+ // Copy over filename and attributes
+ // BLOCK
+ {
+ BackupStoreFilename filename;
+ filename.ReadFromStream(rDiff2, IOStream::TimeOutInfinite);
+ filename.WriteToStream(rOut);
+ StreamableMemBlock attr;
+ attr.ReadFromStream(rDiff2, IOStream::TimeOutInfinite);
+ attr.WriteToStream(rOut);
+ }
+
+ // Get to the index of rDiff2b, and read the header
+ MoveStreamPositionToBlockIndex(rDiff2b);
+ file_BlockIndexHeader diff2IdxHdr;
+ if(!rDiff2b.ReadFullBuffer(&diff2IdxHdr, sizeof(diff2IdxHdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+ if(ntohl(diff2IdxHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ int64_t diff2NumBlocks = box_ntoh64(diff2IdxHdr.mNumBlocks);
+ int64_t diff2IndexEntriesStart = rDiff2b.GetPosition();
+
+ // Then read all the entries
+ int64_t diff2FilePosition = rDiff2.GetPosition();
+ for(int64_t b = 0; b < diff2NumBlocks; ++b)
+ {
+ file_BlockIndexEntry e;
+ if(!rDiff2b.ReadFullBuffer(&e, sizeof(e), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // What do to next about copying data
+ bool copyBlock = false;
+ int copySize = 0;
+ int64_t copyFrom = 0;
+ bool fromFileDiff1 = false;
+
+ // Where's the block?
+ int64_t blockEn = box_ntoh64(e.mEncodedSize);
+ if(blockEn > 0)
+ {
+ // Block is present in this file -- copy to out
+ copyBlock = true;
+ copyFrom = diff2FilePosition;
+ copySize = (int)blockEn;
+
+ // Move pointer onwards
+ diff2FilePosition += blockEn;
+ }
+ else
+ {
+ // Block isn't present here -- is it present in the old one?
+ int64_t blockIndex = 0 - blockEn;
+ if(blockIndex < 0 || blockIndex > diff1NumBlocks)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ if(diff1BlockStartPositions[blockIndex] > 0)
+ {
+ // Block is in the old diff file, copy it across
+ copyBlock = true;
+ copyFrom = diff1BlockStartPositions[blockIndex];
+ int nb = blockIndex + 1;
+ while(diff1BlockStartPositions[nb] <= 0)
+ {
+ // This is safe, because the last entry will terminate it properly!
+ ++nb;
+ ASSERT(nb <= diff1NumBlocks);
+ }
+ copySize = diff1BlockStartPositions[nb] - copyFrom;
+ fromFileDiff1 = true;
+ }
+ }
+ //TRACE4("%d %d %lld %d\n", copyBlock, copySize, copyFrom, fromFileDiff1);
+
+ // Copy data to the output file?
+ if(copyBlock)
+ {
+ // Allocate enough space
+ if(bufferSize < copySize || buffer == 0)
+ {
+ // Free old block
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ buffer = 0;
+ bufferSize = 0;
+ }
+ // Allocate new block
+ buffer = ::malloc(copySize);
+ if(buffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+ bufferSize = copySize;
+ }
+ ASSERT(bufferSize >= copySize);
+
+ // Load in the data
+ if(fromFileDiff1)
+ {
+ rDiff1.Seek(copyFrom, IOStream::SeekType_Absolute);
+ if(!rDiff1.ReadFullBuffer(buffer, copySize, 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ }
+ else
+ {
+ rDiff2.Seek(copyFrom, IOStream::SeekType_Absolute);
+ if(!rDiff2.ReadFullBuffer(buffer, copySize, 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ }
+ // Write out data
+ rOut.Write(buffer, copySize);
+ }
+ }
+
+ // Write the modified header
+ diff2IdxHdr.mOtherFileID = diff1IdxHdr.mOtherFileID;
+ rOut.Write(&diff2IdxHdr, sizeof(diff2IdxHdr));
+
+ // Then we'll write out the index, reading the data again
+ rDiff2b.Seek(diff2IndexEntriesStart, IOStream::SeekType_Absolute);
+ for(int64_t b = 0; b < diff2NumBlocks; ++b)
+ {
+ file_BlockIndexEntry e;
+ if(!rDiff2b.ReadFullBuffer(&e, sizeof(e), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Where's the block?
+ int64_t blockEn = box_ntoh64(e.mEncodedSize);
+
+ // If it's not in this file, it needs modification...
+ if(blockEn <= 0)
+ {
+ int64_t blockIndex = 0 - blockEn;
+ // In another file. Need to translate this against the other diff
+ if(diff1BlockStartPositions[blockIndex] > 0)
+ {
+ // Block is in the first diff file, stick in size
+ int nb = blockIndex + 1;
+ while(diff1BlockStartPositions[nb] <= 0)
+ {
+ // This is safe, because the last entry will terminate it properly!
+ ++nb;
+ ASSERT(nb <= diff1NumBlocks);
+ }
+ int64_t size = diff1BlockStartPositions[nb] - diff1BlockStartPositions[blockIndex];
+ e.mEncodedSize = box_hton64(size);
+ }
+ else
+ {
+ // Block in the original file, use translated value
+ e.mEncodedSize = box_hton64(diff1BlockStartPositions[blockIndex]);
+ }
+ }
+
+ // Write entry
+ rOut.Write(&e, sizeof(e));
+ }
+ }
+ catch(...)
+ {
+ // clean up
+ ::free(diff1BlockStartPositions);
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ }
+ throw;
+ }
+
+ // Clean up allocated memory
+ ::free(diff1BlockStartPositions);
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ }
+}
+
diff --git a/lib/backupclient/BackupStoreFileCmbIdx.cpp b/lib/backupclient/BackupStoreFileCmbIdx.cpp
new file mode 100644
index 00000000..c8bcc3b9
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileCmbIdx.cpp
@@ -0,0 +1,324 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileCmbIdx.cpp
+// Purpose: Combine indicies of a delta file and the file it's a diff from.
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <new>
+#include <string.h>
+
+#include "BackupStoreFile.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreObjectMagic.h"
+#include "BackupStoreException.h"
+#include "BackupStoreConstants.h"
+#include "BackupStoreFilename.h"
+
+#include "MemLeakFindOn.h"
+
+// Hide from outside world
+namespace
+{
+
+class BSFCombinedIndexStream : public IOStream
+{
+public:
+ BSFCombinedIndexStream(IOStream *pDiff);
+ ~BSFCombinedIndexStream();
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+ virtual void Initialise(IOStream &rFrom);
+
+private:
+ IOStream *mpDiff;
+ bool mIsInitialised;
+ bool mHeaderWritten;
+ file_BlockIndexHeader mHeader;
+ int64_t mNumEntriesToGo;
+ int64_t mNumEntriesInFromFile;
+ int64_t *mFromBlockSizes; // NOTE: Entries in network byte order
+};
+
+};
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::CombineFileIndices(IOStream &, IOStream &, bool)
+// Purpose: Given a diff file and the file it's a diff from, return a stream from which
+// can be read the index of the combined file, without actually combining them.
+// The stream of the diff must have a lifetime greater than or equal to the
+// lifetime of the returned stream object. The full "from" file stream
+// only needs to exist during the actual function call.
+// If you pass in dodgy files which aren't related, then you will either
+// get an error or bad results. So don't do that.
+// If DiffIsIndexOnly is true, then rDiff is assumed to be a stream positioned
+// at the beginning of the block index. Similarly for FromIsIndexOnly.
+// WARNING: Reads of the returned streams with buffer sizes less than 64 bytes
+// will not return any data.
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<IOStream> BackupStoreFile::CombineFileIndices(IOStream &rDiff, IOStream &rFrom, bool DiffIsIndexOnly, bool FromIsIndexOnly)
+{
+ // Reposition file pointers?
+ if(!DiffIsIndexOnly)
+ {
+ MoveStreamPositionToBlockIndex(rDiff);
+ }
+ if(!FromIsIndexOnly)
+ {
+ MoveStreamPositionToBlockIndex(rFrom);
+ }
+
+ // Create object
+ std::auto_ptr<IOStream> stream(new BSFCombinedIndexStream(&rDiff));
+
+ // Initialise it
+ ((BSFCombinedIndexStream *)stream.get())->Initialise(rFrom);
+
+ // And return the stream
+ return stream;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BSFCombinedIndexStream::BSFCombinedIndexStream()
+// Purpose: Private class. Constructor.
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+BSFCombinedIndexStream::BSFCombinedIndexStream(IOStream *pDiff)
+ : mpDiff(pDiff),
+ mIsInitialised(false),
+ mHeaderWritten(false),
+ mNumEntriesToGo(0),
+ mNumEntriesInFromFile(0),
+ mFromBlockSizes(0)
+{
+ ASSERT(mpDiff != 0);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BSFCombinedIndexStream::~BSFCombinedIndexStream()
+// Purpose: Private class. Destructor.
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+BSFCombinedIndexStream::~BSFCombinedIndexStream()
+{
+ if(mFromBlockSizes != 0)
+ {
+ ::free(mFromBlockSizes);
+ mFromBlockSizes = 0;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BSFCombinedIndexStream::Initialise(IOStream &)
+// Purpose: Private class. Initalise from the streams (diff passed in constructor).
+// Both streams must have file pointer positioned at the block index.
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+void BSFCombinedIndexStream::Initialise(IOStream &rFrom)
+{
+ // Paranoia is good.
+ if(mIsInitialised)
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ // Look at the diff file: Read in the header
+ if(!mpDiff->ReadFullBuffer(&mHeader, sizeof(mHeader), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+ if(ntohl(mHeader.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Read relevant data.
+ mNumEntriesToGo = box_ntoh64(mHeader.mNumBlocks);
+
+ // Adjust a bit to reflect the fact it's no longer a diff
+ mHeader.mOtherFileID = box_hton64(0);
+
+ // Now look at the from file: Read header
+ file_BlockIndexHeader fromHdr;
+ if(!rFrom.ReadFullBuffer(&fromHdr, sizeof(fromHdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+ if(ntohl(fromHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Then... allocate memory for the list of sizes
+ mNumEntriesInFromFile = box_ntoh64(fromHdr.mNumBlocks);
+ mFromBlockSizes = (int64_t*)::malloc(mNumEntriesInFromFile * sizeof(int64_t));
+ if(mFromBlockSizes == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ // And read them all in!
+ for(int64_t b = 0; b < mNumEntriesInFromFile; ++b)
+ {
+ file_BlockIndexEntry e;
+ if(!rFrom.ReadFullBuffer(&e, sizeof(e), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Check that the from file isn't a delta in itself
+ if(box_ntoh64(e.mEncodedSize) <= 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, OnCombineFromFileIsIncomplete)
+ }
+
+ // Store size (in network byte order)
+ mFromBlockSizes[b] = e.mEncodedSize;
+ }
+
+ // Flag as initialised
+ mIsInitialised = true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BSFCombinedIndexStream::Read(void *, int, int)
+// Purpose: Private class. As interface.
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+int BSFCombinedIndexStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ // Paranoia is good.
+ if(!mIsInitialised || mFromBlockSizes == 0 || mpDiff == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ int written = 0;
+
+ // Header output yet?
+ if(!mHeaderWritten)
+ {
+ // Enough space?
+ if(NBytes < (int)sizeof(mHeader)) return 0;
+
+ // Copy in
+ ::memcpy(pBuffer, &mHeader, sizeof(mHeader));
+ NBytes -= sizeof(mHeader);
+ written += sizeof(mHeader);
+
+ // Flag it's done
+ mHeaderWritten = true;
+ }
+
+ // How many entries can be written?
+ int entriesToWrite = NBytes / sizeof(file_BlockIndexEntry);
+ if(entriesToWrite > mNumEntriesToGo)
+ {
+ entriesToWrite = mNumEntriesToGo;
+ }
+
+ // Setup ready to go
+ file_BlockIndexEntry *poutput = (file_BlockIndexEntry*)(((uint8_t*)pBuffer) + written);
+
+ // Write entries
+ for(int b = 0; b < entriesToWrite; ++b)
+ {
+ if(!mpDiff->ReadFullBuffer(&(poutput[b]), sizeof(file_BlockIndexEntry), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Does this need adjusting?
+ int s = box_ntoh64(poutput[b].mEncodedSize);
+ if(s <= 0)
+ {
+ // A reference to a block in the from file
+ int block = 0 - s;
+ ASSERT(block >= 0);
+ if(block >= mNumEntriesInFromFile)
+ {
+ // That's not good, the block doesn't exist
+ THROW_EXCEPTION(BackupStoreException, OnCombineFromFileIsIncomplete)
+ }
+
+ // Adjust the entry in the buffer
+ poutput[b].mEncodedSize = mFromBlockSizes[block]; // stored in network byte order, no translation necessary
+ }
+ }
+
+ // Update written count
+ written += entriesToWrite * sizeof(file_BlockIndexEntry);
+ mNumEntriesToGo -= entriesToWrite;
+
+ return written;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BSFCombinedIndexStream::Write(const void *, int)
+// Purpose: Private class. As interface.
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+void BSFCombinedIndexStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(BackupStoreException, StreamDoesntHaveRequiredFeatures)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BSFCombinedIndexStream::StreamDataLeft()
+// Purpose: Private class. As interface
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+bool BSFCombinedIndexStream::StreamDataLeft()
+{
+ return (!mHeaderWritten) || (mNumEntriesToGo > 0);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BSFCombinedIndexStream::StreamClosed()
+// Purpose: Private class. As interface.
+// Created: 8/7/04
+//
+// --------------------------------------------------------------------------
+bool BSFCombinedIndexStream::StreamClosed()
+{
+ return true; // doesn't do writing
+}
+
diff --git a/lib/backupclient/BackupStoreFileCombine.cpp b/lib/backupclient/BackupStoreFileCombine.cpp
new file mode 100644
index 00000000..baa331f0
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileCombine.cpp
@@ -0,0 +1,410 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileCombine.cpp
+// Purpose: File combining for BackupStoreFile
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <new>
+
+#include "BackupStoreFile.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreObjectMagic.h"
+#include "BackupStoreException.h"
+#include "BackupStoreConstants.h"
+#include "BackupStoreFilename.h"
+#include "FileStream.h"
+
+#include "MemLeakFindOn.h"
+
+typedef struct
+{
+ int64_t mFilePosition;
+} FromIndexEntry;
+
+static void LoadFromIndex(IOStream &rFrom, FromIndexEntry *pIndex, int64_t NumEntries);
+static void CopyData(IOStream &rDiffData, IOStream &rDiffIndex, int64_t DiffNumBlocks, IOStream &rFrom, FromIndexEntry *pFromIndex, int64_t FromNumBlocks, IOStream &rOut);
+static void WriteNewIndex(IOStream &rDiff, int64_t DiffNumBlocks, FromIndexEntry *pFromIndex, int64_t FromNumBlocks, IOStream &rOut);
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::CombineFile(IOStream &, IOStream &, IOStream &)
+// Purpose: Where rDiff is a store file which is incomplete as a result of a
+// diffing operation, rFrom is the file it is diffed from, and
+// rOut is the stream in which to place the result, the old file
+// and new file are combined into a file containing all the data.
+// rDiff2 is the same file as rDiff, opened again to get two
+// independent streams to the same file.
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::CombineFile(IOStream &rDiff, IOStream &rDiff2, IOStream &rFrom, IOStream &rOut)
+{
+ // Read and copy the header.
+ file_StreamFormat hdr;
+ if(!rDiff.ReadFullBuffer(&hdr, sizeof(hdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ if(ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ // Copy
+ rOut.Write(&hdr, sizeof(hdr));
+ // Copy over filename and attributes
+ // BLOCK
+ {
+ BackupStoreFilename filename;
+ filename.ReadFromStream(rDiff, IOStream::TimeOutInfinite);
+ filename.WriteToStream(rOut);
+ StreamableMemBlock attr;
+ attr.ReadFromStream(rDiff, IOStream::TimeOutInfinite);
+ attr.WriteToStream(rOut);
+ }
+
+ // Read the header for the From file
+ file_StreamFormat fromHdr;
+ if(!rFrom.ReadFullBuffer(&fromHdr, sizeof(fromHdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ if(ntohl(fromHdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ // Skip over the filename and attributes of the From file
+ // BLOCK
+ {
+ BackupStoreFilename filename2;
+ filename2.ReadFromStream(rFrom, IOStream::TimeOutInfinite);
+ int32_t size_s;
+ if(!rFrom.ReadFullBuffer(&size_s, sizeof(size_s), 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+ int size = ntohl(size_s);
+ // Skip forward the size
+ rFrom.Seek(size, IOStream::SeekType_Relative);
+ }
+
+ // Allocate memory for the block index of the From file
+ int64_t fromNumBlocks = box_ntoh64(fromHdr.mNumBlocks);
+ // NOTE: An extra entry is required so that the length of the last block can be calculated
+ FromIndexEntry *pFromIndex = (FromIndexEntry*)::malloc((fromNumBlocks+1) * sizeof(FromIndexEntry));
+ if(pFromIndex == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ try
+ {
+ // Load the index from the From file, calculating the offsets in the
+ // file as we go along, and enforce that everything should be present.
+ LoadFromIndex(rFrom, pFromIndex, fromNumBlocks);
+
+ // Read in the block index of the Diff file in small chunks, and output data
+ // for each block, either from this file, or the other file.
+ int64_t diffNumBlocks = box_ntoh64(hdr.mNumBlocks);
+ CopyData(rDiff /* positioned at start of data */, rDiff2, diffNumBlocks, rFrom, pFromIndex, fromNumBlocks, rOut);
+
+ // Read in the block index again, and output the new block index, simply
+ // filling in the sizes of blocks from the old file.
+ WriteNewIndex(rDiff, diffNumBlocks, pFromIndex, fromNumBlocks, rOut);
+
+ // Free buffers
+ ::free(pFromIndex);
+ pFromIndex = 0;
+ }
+ catch(...)
+ {
+ // Clean up
+ if(pFromIndex != 0)
+ {
+ ::free(pFromIndex);
+ pFromIndex = 0;
+ }
+ throw;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static LoadFromIndex(IOStream &, FromIndexEntry *, int64_t)
+// Purpose: Static. Load the index from the From file
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+static void LoadFromIndex(IOStream &rFrom, FromIndexEntry *pIndex, int64_t NumEntries)
+{
+ ASSERT(pIndex != 0);
+ ASSERT(NumEntries >= 0);
+
+ // Get the starting point in the file
+ int64_t filePos = rFrom.GetPosition();
+
+ // Jump to the end of the file to read the index
+ rFrom.Seek(0 - ((NumEntries * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader)), IOStream::SeekType_End);
+
+ // Read block index header
+ file_BlockIndexHeader blkhdr;
+ if(!rFrom.ReadFullBuffer(&blkhdr, sizeof(blkhdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ if(ntohl(blkhdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1
+ || (int64_t)box_ntoh64(blkhdr.mNumBlocks) != NumEntries)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // And then the block entries
+ for(int64_t b = 0; b < NumEntries; ++b)
+ {
+ // Read
+ file_BlockIndexEntry en;
+ if(!rFrom.ReadFullBuffer(&en, sizeof(en), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+
+ // Add to list
+ pIndex[b].mFilePosition = filePos;
+
+ // Encoded size?
+ int64_t encodedSize = box_ntoh64(en.mEncodedSize);
+ // Check that the block is actually there
+ if(encodedSize <= 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, OnCombineFromFileIsIncomplete)
+ }
+
+ // Move file pointer on
+ filePos += encodedSize;
+ }
+
+ // Store the position in the very last entry, so the size of the last entry can be calculated
+ pIndex[NumEntries].mFilePosition = filePos;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static CopyData(IOStream &, IOStream &, int64_t, IOStream &, FromIndexEntry *, int64_t, IOStream &)
+// Purpose: Static. Copy data from the Diff and From file to the out file.
+// rDiffData is at beginning of data.
+// rDiffIndex at any position.
+// rFrom is at any position.
+// rOut is after the header, ready for data
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+static void CopyData(IOStream &rDiffData, IOStream &rDiffIndex, int64_t DiffNumBlocks,
+ IOStream &rFrom, FromIndexEntry *pFromIndex, int64_t FromNumBlocks, IOStream &rOut)
+{
+ // Jump to the end of the diff file to read the index
+ rDiffIndex.Seek(0 - ((DiffNumBlocks * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader)), IOStream::SeekType_End);
+
+ // Read block index header
+ file_BlockIndexHeader diffBlkhdr;
+ if(!rDiffIndex.ReadFullBuffer(&diffBlkhdr, sizeof(diffBlkhdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ if(ntohl(diffBlkhdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1
+ || (int64_t)box_ntoh64(diffBlkhdr.mNumBlocks) != DiffNumBlocks)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Record where the From file is
+ int64_t fromPos = rFrom.GetPosition();
+
+ // Buffer data
+ void *buffer = 0;
+ int bufferSize = 0;
+
+ try
+ {
+ // Read the blocks in!
+ for(int64_t b = 0; b < DiffNumBlocks; ++b)
+ {
+ // Read
+ file_BlockIndexEntry en;
+ if(!rDiffIndex.ReadFullBuffer(&en, sizeof(en), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+
+ // What's the size value stored in the entry
+ int64_t encodedSize = box_ntoh64(en.mEncodedSize);
+
+ // How much data will be read?
+ int32_t blockSize = 0;
+ if(encodedSize > 0)
+ {
+ // The block is actually in the diff file
+ blockSize = encodedSize;
+ }
+ else
+ {
+ // It's in the from file. First, check to see if it's valid
+ int64_t blockIdx = (0 - encodedSize);
+ if(blockIdx > FromNumBlocks)
+ {
+ // References a block which doesn't actually exist
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ // Calculate size. This operation is safe because of the extra entry at the end
+ blockSize = pFromIndex[blockIdx + 1].mFilePosition - pFromIndex[blockIdx].mFilePosition;
+ }
+ ASSERT(blockSize > 0);
+
+ // Make sure there's memory available to copy this
+ if(bufferSize < blockSize || buffer == 0)
+ {
+ // Free old block
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ buffer = 0;
+ bufferSize = 0;
+ }
+ // Allocate new block
+ buffer = ::malloc(blockSize);
+ if(buffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+ bufferSize = blockSize;
+ }
+ ASSERT(bufferSize >= blockSize);
+
+ // Load in data from one of the files
+ if(encodedSize > 0)
+ {
+ // Load from diff file
+ if(!rDiffData.ReadFullBuffer(buffer, blockSize, 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ }
+ else
+ {
+ // Locate and read the data from the from file
+ int64_t blockIdx = (0 - encodedSize);
+ // Seek if necessary
+ if(fromPos != pFromIndex[blockIdx].mFilePosition)
+ {
+ rFrom.Seek(pFromIndex[blockIdx].mFilePosition, IOStream::SeekType_Absolute);
+ fromPos = pFromIndex[blockIdx].mFilePosition;
+ }
+ // Read
+ if(!rFrom.ReadFullBuffer(buffer, blockSize, 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+
+ // Update fromPos to current position
+ fromPos += blockSize;
+ }
+
+ // Write data to out file
+ rOut.Write(buffer, blockSize);
+ }
+
+ // Free buffer, if allocated
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ buffer = 0;
+ }
+ }
+ catch(...)
+ {
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ buffer = 0;
+ }
+ throw;
+ }
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static WriteNewIndex(IOStream &, int64_t, FromIndexEntry *, int64_t, IOStream &)
+// Purpose: Write the index to the out file, just copying from the diff file and
+// adjusting the entries.
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+static void WriteNewIndex(IOStream &rDiff, int64_t DiffNumBlocks, FromIndexEntry *pFromIndex, int64_t FromNumBlocks, IOStream &rOut)
+{
+ // Jump to the end of the diff file to read the index
+ rDiff.Seek(0 - ((DiffNumBlocks * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader)), IOStream::SeekType_End);
+
+ // Read block index header
+ file_BlockIndexHeader diffBlkhdr;
+ if(!rDiff.ReadFullBuffer(&diffBlkhdr, sizeof(diffBlkhdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ if(ntohl(diffBlkhdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1
+ || (int64_t)box_ntoh64(diffBlkhdr.mNumBlocks) != DiffNumBlocks)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Write it out with a blanked out other file ID
+ diffBlkhdr.mOtherFileID = box_hton64(0);
+ rOut.Write(&diffBlkhdr, sizeof(diffBlkhdr));
+
+ // Rewrite the index
+ for(int64_t b = 0; b < DiffNumBlocks; ++b)
+ {
+ file_BlockIndexEntry en;
+ if(!rDiff.ReadFullBuffer(&en, sizeof(en), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+
+ // What's the size value stored in the entry
+ int64_t encodedSize = box_ntoh64(en.mEncodedSize);
+
+ // Need to adjust it?
+ if(encodedSize <= 0)
+ {
+ // This actually refers to a block in the from file. So rewrite this.
+ int64_t blockIdx = (0 - encodedSize);
+ if(blockIdx > FromNumBlocks)
+ {
+ // References a block which doesn't actually exist
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ // Calculate size. This operation is safe because of the extra entry at the end
+ int32_t blockSize = pFromIndex[blockIdx + 1].mFilePosition - pFromIndex[blockIdx].mFilePosition;
+ // Then replace entry
+ en.mEncodedSize = box_hton64(((uint64_t)blockSize));
+ }
+
+ // Write entry
+ rOut.Write(&en, sizeof(en));
+ }
+}
+
+
+
+
+
diff --git a/lib/backupclient/BackupStoreFileCryptVar.cpp b/lib/backupclient/BackupStoreFileCryptVar.cpp
new file mode 100644
index 00000000..e826de4e
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileCryptVar.cpp
@@ -0,0 +1,31 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileCryptVar.cpp
+// Purpose: Cryptographic keys for backup store files
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include "BackupStoreFileCryptVar.h"
+#include "BackupStoreFileWire.h"
+
+#include "MemLeakFindOn.h"
+
+CipherContext BackupStoreFileCryptVar::sBlowfishEncrypt;
+CipherContext BackupStoreFileCryptVar::sBlowfishDecrypt;
+
+#ifndef HAVE_OLD_SSL
+ CipherContext BackupStoreFileCryptVar::sAESEncrypt;
+ CipherContext BackupStoreFileCryptVar::sAESDecrypt;
+#endif
+
+// Default to blowfish
+CipherContext *BackupStoreFileCryptVar::spEncrypt = &BackupStoreFileCryptVar::sBlowfishEncrypt;
+uint8_t BackupStoreFileCryptVar::sEncryptCipherType = HEADER_BLOWFISH_ENCODING;
+
+CipherContext BackupStoreFileCryptVar::sBlowfishEncryptBlockEntry;
+CipherContext BackupStoreFileCryptVar::sBlowfishDecryptBlockEntry;
+
diff --git a/lib/backupclient/BackupStoreFileCryptVar.h b/lib/backupclient/BackupStoreFileCryptVar.h
new file mode 100644
index 00000000..566813c8
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileCryptVar.h
@@ -0,0 +1,39 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileCryptVar.h
+// Purpose: Cryptographic keys for backup store files
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREFILECRYPTVAR__H
+#define BACKUPSTOREFILECRYPTVAR__H
+
+#include "CipherContext.h"
+
+// Hide private static variables from the rest of the world by putting them
+// as static variables in a namespace.
+// -- don't put them as static class variables to avoid openssl/evp.h being
+// included all over the project.
+namespace BackupStoreFileCryptVar
+{
+ // Keys for the main file data
+ extern CipherContext sBlowfishEncrypt;
+ extern CipherContext sBlowfishDecrypt;
+ // Use AES when available
+#ifndef HAVE_OLD_SSL
+ extern CipherContext sAESEncrypt;
+ extern CipherContext sAESDecrypt;
+#endif
+ // How encoding will be done
+ extern CipherContext *spEncrypt;
+ extern uint8_t sEncryptCipherType;
+
+ // Keys for the block indicies
+ extern CipherContext sBlowfishEncryptBlockEntry;
+ extern CipherContext sBlowfishDecryptBlockEntry;
+}
+
+#endif // BACKUPSTOREFILECRYPTVAR__H
+
diff --git a/lib/backupclient/BackupStoreFileDiff.cpp b/lib/backupclient/BackupStoreFileDiff.cpp
new file mode 100644
index 00000000..5705c3aa
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileDiff.cpp
@@ -0,0 +1,1046 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileDiff.cpp
+// Purpose: Functions relating to diffing BackupStoreFiles
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <string.h>
+
+#include <new>
+#include <map>
+
+#ifdef HAVE_TIME_H
+ #include <time.h>
+#elif HAVE_SYS_TIME_H
+ #include <sys/time.h>
+#endif
+
+#include "BackupStoreConstants.h"
+#include "BackupStoreException.h"
+#include "BackupStoreFile.h"
+#include "BackupStoreFileCryptVar.h"
+#include "BackupStoreFileEncodeStream.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreObjectMagic.h"
+#include "CommonException.h"
+#include "FileStream.h"
+#include "MD5Digest.h"
+#include "RollingChecksum.h"
+#include "Timer.h"
+
+#include "MemLeakFindOn.h"
+
+#include <cstring>
+
+using namespace BackupStoreFileCryptVar;
+using namespace BackupStoreFileCreation;
+
+// By default, don't trace out details of the diff as we go along -- would fill up logs significantly.
+// But it's useful for the test.
+#ifndef BOX_RELEASE_BUILD
+ bool BackupStoreFile::TraceDetailsOfDiffProcess = false;
+#endif
+
+static void LoadIndex(IOStream &rBlockIndex, int64_t ThisID, BlocksAvailableEntry **ppIndex, int64_t &rNumBlocksOut, int Timeout, bool &rCanDiffFromThis);
+static void FindMostUsedSizes(BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES]);
+static void SearchForMatchingBlocks(IOStream &rFile,
+ std::map<int64_t, int64_t> &rFoundBlocks, BlocksAvailableEntry *pIndex,
+ int64_t NumBlocks, int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES],
+ DiffTimer *pDiffTimer);
+static void SetupHashTable(BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t BlockSize, BlocksAvailableEntry **pHashTable);
+static bool SecondStageMatch(BlocksAvailableEntry *pFirstInHashList, RollingChecksum &fastSum, uint8_t *pBeginnings, uint8_t *pEndings, int Offset, int32_t BlockSize, int64_t FileBlockNumber,
+BlocksAvailableEntry *pIndex, std::map<int64_t, int64_t> &rFoundBlocks);
+static void GenerateRecipe(BackupStoreFileEncodeStream::Recipe &rRecipe, BlocksAvailableEntry *pIndex, int64_t NumBlocks, std::map<int64_t, int64_t> &rFoundBlocks, int64_t SizeOfInputFile);
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::MoveStreamPositionToBlockIndex(IOStream &)
+// Purpose: Move the file pointer in this stream to just before the block index.
+// Assumes that the stream is at the beginning, seekable, and
+// reading from the stream is OK.
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::MoveStreamPositionToBlockIndex(IOStream &rStream)
+{
+ // Size of file
+ int64_t fileSize = rStream.BytesLeftToRead();
+
+ // Get header
+ file_StreamFormat hdr;
+
+ // Read the header
+ if(!rStream.ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */, IOStream::TimeOutInfinite))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Check magic number
+ if(ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ && ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V0
+#endif
+ )
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Work out where the index is
+ int64_t numBlocks = box_ntoh64(hdr.mNumBlocks);
+ int64_t blockHeaderPosFromEnd = ((numBlocks * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader));
+
+ // Sanity check
+ if(blockHeaderPosFromEnd > static_cast<int64_t>(fileSize - sizeof(file_StreamFormat)))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Seek to that position
+ rStream.Seek(0 - blockHeaderPosFromEnd, IOStream::SeekType_End);
+
+ // Done. Stream now in right position (as long as the file is formatted correctly)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::EncodeFileDiff(const char *, int64_t, const BackupStoreFilename &, int64_t, IOStream &, int64_t *)
+// Purpose: Similar to EncodeFile, but takes the object ID of the file it's
+// diffing from, and the index of the blocks in a stream. It'll then
+// calculate which blocks can be reused from that old file.
+// The timeout is the timeout value for reading the diff block index.
+// If pIsCompletelyDifferent != 0, it will be set to true if the
+// the two files are completely different (do not share any block), false otherwise.
+//
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<IOStream> BackupStoreFile::EncodeFileDiff
+(
+ const char *Filename, int64_t ContainerID,
+ const BackupStoreFilename &rStoreFilename, int64_t DiffFromObjectID,
+ IOStream &rDiffFromBlockIndex, int Timeout, DiffTimer *pDiffTimer,
+ int64_t *pModificationTime, bool *pIsCompletelyDifferent)
+{
+ // Is it a symlink?
+ {
+ EMU_STRUCT_STAT st;
+ if(EMU_LSTAT(Filename, &st) != 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+ if((st.st_mode & S_IFLNK) == S_IFLNK)
+ {
+ // Don't do diffs for symlinks
+ if(pIsCompletelyDifferent != 0)
+ {
+ *pIsCompletelyDifferent = true;
+ }
+ return EncodeFile(Filename, ContainerID, rStoreFilename, pModificationTime);
+ }
+ }
+
+ // Load in the blocks
+ BlocksAvailableEntry *pindex = 0;
+ int64_t blocksInIndex = 0;
+ bool canDiffFromThis = false;
+ LoadIndex(rDiffFromBlockIndex, DiffFromObjectID, &pindex, blocksInIndex, Timeout, canDiffFromThis);
+ // BOX_TRACE("Diff: Blocks in index: " << blocksInIndex);
+
+ if(!canDiffFromThis)
+ {
+ // Don't do diffing...
+ if(pIsCompletelyDifferent != 0)
+ {
+ *pIsCompletelyDifferent = true;
+ }
+ return EncodeFile(Filename, ContainerID, rStoreFilename, pModificationTime);
+ }
+
+ // Pointer to recipe we're going to create
+ BackupStoreFileEncodeStream::Recipe *precipe = 0;
+
+ try
+ {
+ // Find which sizes should be scanned
+ int32_t sizesToScan[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES];
+ FindMostUsedSizes(pindex, blocksInIndex, sizesToScan);
+
+ // Flag for reporting to the user
+ bool completelyDifferent;
+
+ // BLOCK
+ {
+ // Search the file to find matching blocks
+ std::map<int64_t, int64_t> foundBlocks; // map of offset in file to index in block index
+ int64_t sizeOfInputFile = 0;
+ // BLOCK
+ {
+ FileStream file(Filename);
+ // Get size of file
+ sizeOfInputFile = file.BytesLeftToRead();
+ // Find all those lovely matching blocks
+ SearchForMatchingBlocks(file, foundBlocks, pindex,
+ blocksInIndex, sizesToScan, pDiffTimer);
+
+ // Is it completely different?
+ completelyDifferent = (foundBlocks.size() == 0);
+ }
+
+ // Create a recipe -- if the two files are completely different, don't put the from file ID in the recipe.
+ precipe = new BackupStoreFileEncodeStream::Recipe(pindex, blocksInIndex, completelyDifferent?(0):(DiffFromObjectID));
+ BlocksAvailableEntry *pindexKeptRef = pindex; // we need this later, but must set pindex == 0 now, because of exceptions
+ pindex = 0; // Recipe now has ownership
+
+ // Fill it in
+ GenerateRecipe(*precipe, pindexKeptRef, blocksInIndex, foundBlocks, sizeOfInputFile);
+ }
+ // foundBlocks no longer required
+
+ // Create the stream
+ std::auto_ptr<IOStream> stream(new BackupStoreFileEncodeStream);
+
+ // Do the initial setup
+ ((BackupStoreFileEncodeStream*)stream.get())->Setup(Filename, precipe, ContainerID, rStoreFilename, pModificationTime);
+ precipe = 0; // Stream has taken ownership of this
+
+ // Tell user about completely different status?
+ if(pIsCompletelyDifferent != 0)
+ {
+ *pIsCompletelyDifferent = completelyDifferent;
+ }
+
+ // Return the stream for the caller
+ return stream;
+ }
+ catch(...)
+ {
+ // cleanup
+ if(pindex != 0)
+ {
+ ::free(pindex);
+ pindex = 0;
+ }
+ if(precipe != 0)
+ {
+ delete precipe;
+ precipe = 0;
+ }
+ throw;
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static LoadIndex(IOStream &, int64_t, BlocksAvailableEntry **, int64_t, bool &)
+// Purpose: Read in an index, and decrypt, and store in the in memory block format.
+// rCanDiffFromThis is set to false if the version of the from file is too old.
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+static void LoadIndex(IOStream &rBlockIndex, int64_t ThisID, BlocksAvailableEntry **ppIndex, int64_t &rNumBlocksOut, int Timeout, bool &rCanDiffFromThis)
+{
+ // Reset
+ rNumBlocksOut = 0;
+ rCanDiffFromThis = false;
+
+ // Read header
+ file_BlockIndexHeader hdr;
+ if(!rBlockIndex.ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ // Couldn't read header
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
+ // Check against backwards comptaibility stuff
+ if(hdr.mMagicValue == (int32_t)htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0))
+ {
+ // Won't diff against old version
+
+ // Absorb rest of stream
+ char buffer[2048];
+ while(rBlockIndex.StreamDataLeft())
+ {
+ rBlockIndex.Read(buffer, sizeof(buffer), 1000 /* 1 sec timeout */);
+ }
+
+ // Tell caller
+ rCanDiffFromThis = false;
+ return;
+ }
+#endif
+
+ // Check magic
+ if(hdr.mMagicValue != (int32_t)htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Check that we're not trying to diff against a file which references blocks from another file
+ if(((int64_t)box_ntoh64(hdr.mOtherFileID)) != 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, CannotDiffAnIncompleteStoreFile)
+ }
+
+ // Mark as an acceptable diff.
+ rCanDiffFromThis = true;
+
+ // Get basic information
+ int64_t numBlocks = box_ntoh64(hdr.mNumBlocks);
+ uint64_t entryIVBase = box_ntoh64(hdr.mEntryIVBase);
+
+ //TODO: Verify that these sizes look reasonable
+
+ // Allocate space for the index
+ BlocksAvailableEntry *pindex = (BlocksAvailableEntry*)::malloc(sizeof(BlocksAvailableEntry) * numBlocks);
+ if(pindex == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ try
+ {
+ for(int64_t b = 0; b < numBlocks; ++b)
+ {
+ // Read an entry from the stream
+ file_BlockIndexEntry entry;
+ if(!rBlockIndex.ReadFullBuffer(&entry, sizeof(entry), 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ // Couldn't read entry
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Calculate IV for this entry
+ uint64_t iv = entryIVBase;
+ iv += b;
+ // Network byte order
+ iv = box_hton64(iv);
+ sBlowfishDecryptBlockEntry.SetIV(&iv);
+
+ // Decrypt the encrypted section
+ file_BlockIndexEntryEnc entryEnc;
+ int sectionSize = sBlowfishDecryptBlockEntry.TransformBlock(&entryEnc, sizeof(entryEnc),
+ entry.mEnEnc, sizeof(entry.mEnEnc));
+ if(sectionSize != sizeof(entryEnc))
+ {
+ THROW_EXCEPTION(BackupStoreException, BlockEntryEncodingDidntGiveExpectedLength)
+ }
+
+ // Check that we're not trying to diff against a file which references blocks from another file
+ if(((int64_t)box_ntoh64(entry.mEncodedSize)) <= 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, CannotDiffAnIncompleteStoreFile)
+ }
+
+ // Store all the required information
+ pindex[b].mpNextInHashList = 0; // hash list not set up yet
+ pindex[b].mSize = ntohl(entryEnc.mSize);
+ pindex[b].mWeakChecksum = ntohl(entryEnc.mWeakChecksum);
+ ::memcpy(pindex[b].mStrongChecksum, entryEnc.mStrongChecksum, sizeof(pindex[b].mStrongChecksum));
+ }
+
+ // Store index pointer for called
+ ASSERT(ppIndex != 0);
+ *ppIndex = pindex;
+
+ // Store number of blocks for caller
+ rNumBlocksOut = numBlocks;
+
+ }
+ catch(...)
+ {
+ // clean up and send the exception along its way
+ ::free(pindex);
+ throw;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static FindMostUsedSizes(BlocksAvailableEntry *, int64_t, int32_t[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES])
+// Purpose: Finds the most commonly used block sizes in the index
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+static void FindMostUsedSizes(BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES])
+{
+ // Array for lengths
+ int64_t sizeCounts[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES];
+
+ // Set arrays to lots of zeros (= unused entries)
+ for(int l = 0; l < BACKUP_FILE_DIFF_MAX_BLOCK_SIZES; ++l)
+ {
+ Sizes[l] = 0;
+ sizeCounts[l] = 0;
+ }
+
+ // Array for collecting sizes
+ std::map<int32_t, int64_t> foundSizes;
+
+ // Run through blocks and make a count of the entries
+ for(int64_t b = 0; b < NumBlocks; ++b)
+ {
+ // Only if the block size is bigger than the minimum size we'll scan for
+ if(pIndex[b].mSize > BACKUP_FILE_DIFF_MIN_BLOCK_SIZE)
+ {
+ // Find entry?
+ std::map<int32_t, int64_t>::const_iterator f(foundSizes.find(pIndex[b].mSize));
+ if(f != foundSizes.end())
+ {
+ // Increment existing entry
+ foundSizes[pIndex[b].mSize] = foundSizes[pIndex[b].mSize] + 1;
+ }
+ else
+ {
+ // New entry
+ foundSizes[pIndex[b].mSize] = 1;
+ }
+ }
+ }
+
+ // Make the block sizes
+ for(std::map<int32_t, int64_t>::const_iterator i(foundSizes.begin()); i != foundSizes.end(); ++i)
+ {
+ // Find the position of the size in the array
+ for(int t = 0; t < BACKUP_FILE_DIFF_MAX_BLOCK_SIZES; ++t)
+ {
+ // Instead of sorting on the raw count of blocks,
+ // take the file area covered by this block size.
+ if(i->second * i->first > sizeCounts[t] * Sizes[t])
+ {
+ // Then this size belong before this entry -- shuffle them up
+ for(int s = (BACKUP_FILE_DIFF_MAX_BLOCK_SIZES - 1); s >= t; --s)
+ {
+ Sizes[s] = Sizes[s-1];
+ sizeCounts[s] = sizeCounts[s-1];
+ }
+
+ // Insert this size
+ Sizes[t] = i->first;
+ sizeCounts[t] = i->second;
+
+ // Shouldn't do any more searching
+ break;
+ }
+ }
+ }
+
+ // trace the size table in debug builds
+#ifndef BOX_RELEASE_BUILD
+ if(BackupStoreFile::TraceDetailsOfDiffProcess)
+ {
+ for(int t = 0; t < BACKUP_FILE_DIFF_MAX_BLOCK_SIZES; ++t)
+ {
+ BOX_TRACE("Diff block size " << t << ": " <<
+ Sizes[t] << " (count = " <<
+ sizeCounts[t] << ")");
+ }
+ }
+#endif
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static SearchForMatchingBlocks(IOStream &, std::map<int64_t, int64_t> &, BlocksAvailableEntry *, int64_t, int32_t[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES])
+// Purpose: Find the matching blocks within the file.
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t> &rFoundBlocks,
+ BlocksAvailableEntry *pIndex, int64_t NumBlocks,
+ int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES], DiffTimer *pDiffTimer)
+{
+ Timer maximumDiffingTime(0, "MaximumDiffingTime");
+
+ if(pDiffTimer && pDiffTimer->IsManaged())
+ {
+ maximumDiffingTime = Timer(pDiffTimer->GetMaximumDiffingTime(),
+ "MaximumDiffingTime");
+ }
+
+ std::map<int64_t, int32_t> goodnessOfFit;
+
+ // Allocate the hash lookup table
+ BlocksAvailableEntry **phashTable = (BlocksAvailableEntry **)::malloc(sizeof(BlocksAvailableEntry *) * (64*1024));
+
+ // Choose a size for the buffer, just a little bit more than the maximum block size
+ int32_t bufSize = Sizes[0];
+ for(int z = 1; z < BACKUP_FILE_DIFF_MAX_BLOCK_SIZES; ++z)
+ {
+ if(Sizes[z] > bufSize) bufSize = Sizes[z];
+ }
+ bufSize += 4;
+ ASSERT(bufSize > Sizes[0]);
+ ASSERT(bufSize > 0);
+ if(bufSize > (BACKUP_FILE_MAX_BLOCK_SIZE + 1024))
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // TODO: Because we read in the file a scanned block size at a time,
+ // it is likely to be inefficient. Probably will be much better to
+ // calculate checksums for all block sizes in a single pass.
+
+ // Allocate the buffers.
+ uint8_t *pbuffer0 = (uint8_t *)::malloc(bufSize);
+ uint8_t *pbuffer1 = (uint8_t *)::malloc(bufSize);
+ try
+ {
+ // Check buffer allocation
+ if(pbuffer0 == 0 || pbuffer1 == 0 || phashTable == 0)
+ {
+ // If a buffer got allocated, it will be cleaned up in the catch block
+ throw std::bad_alloc();
+ }
+
+ // Flag to abort the run, if too many blocks are found -- avoid using
+ // huge amounts of processor time when files contain many similar blocks.
+ bool abortSearch = false;
+
+ // Search for each block size in turn
+ // NOTE: Do the smallest size first, so that the scheme for adding
+ // entries in the found list works as expected and replaces smallers block
+ // with larger blocks when it finds matches at the same offset in the file.
+ for(int s = BACKUP_FILE_DIFF_MAX_BLOCK_SIZES - 1; s >= 0; --s)
+ {
+ ASSERT(Sizes[s] <= bufSize);
+ BOX_TRACE("Diff pass " << s << ", for block size " <<
+ Sizes[s]);
+
+ // Check we haven't finished
+ if(Sizes[s] == 0)
+ {
+ // empty entry, try next size
+ continue;
+ }
+
+ // Set up the hash table entries
+ SetupHashTable(pIndex, NumBlocks, Sizes[s], phashTable);
+
+ // Shift file position to beginning
+ rFile.Seek(0, IOStream::SeekType_Absolute);
+
+ // Read first block
+ if(rFile.Read(pbuffer0, Sizes[s]) != Sizes[s])
+ {
+ // Size of file too short to match -- do next size
+ continue;
+ }
+
+ // Setup block pointers
+ uint8_t *beginnings = pbuffer0;
+ uint8_t *endings = pbuffer1;
+ int offset = 0;
+
+ // Calculate the first checksum, ready for rolling
+ RollingChecksum rolling(beginnings, Sizes[s]);
+
+ // Then roll, until the file is exhausted
+ int64_t fileBlockNumber = 0;
+ int64_t fileOffset = 0;
+ int rollOverInitialBytes = 0;
+ while(true)
+ {
+ if(maximumDiffingTime.HasExpired())
+ {
+ ASSERT(pDiffTimer != NULL);
+ BOX_INFO("MaximumDiffingTime reached - "
+ "suspending file diff");
+ abortSearch = true;
+ break;
+ }
+
+ if(pDiffTimer)
+ {
+ pDiffTimer->DoKeepAlive();
+ }
+
+ // Load in another block of data, and record how big it is
+ int bytesInEndings = rFile.Read(endings, Sizes[s]);
+ int tmp;
+
+ // Skip any bytes from a previous matched block
+ if(rollOverInitialBytes > 0 && offset < bytesInEndings)
+ {
+ int spaceLeft = bytesInEndings - offset;
+ int thisRoll = (rollOverInitialBytes > spaceLeft) ? spaceLeft : rollOverInitialBytes;
+
+ rolling.RollForwardSeveral(beginnings+offset, endings+offset, Sizes[s], thisRoll);
+
+ offset += thisRoll;
+ fileOffset += thisRoll;
+ rollOverInitialBytes -= thisRoll;
+
+ if(rollOverInitialBytes)
+ {
+ goto refresh;
+ }
+ }
+
+ if(goodnessOfFit.count(fileOffset))
+ {
+ tmp = goodnessOfFit[fileOffset];
+ }
+ else
+ {
+ tmp = 0;
+ }
+
+ if(tmp >= Sizes[s])
+ {
+ // Skip over bigger ready-matched blocks completely
+ rollOverInitialBytes = tmp;
+ int spaceLeft = bytesInEndings - offset;
+ int thisRoll = (rollOverInitialBytes > spaceLeft) ? spaceLeft : rollOverInitialBytes;
+
+ rolling.RollForwardSeveral(beginnings+offset, endings+offset, Sizes[s], thisRoll);
+
+ offset += thisRoll;
+ fileOffset += thisRoll;
+ rollOverInitialBytes -= thisRoll;
+
+ if(rollOverInitialBytes)
+ {
+ goto refresh;
+ }
+ }
+
+ while(offset < bytesInEndings)
+ {
+ // Is current checksum in hash list?
+ uint16_t hash = rolling.GetComponentForHashing();
+ if(phashTable[hash] != 0 && (goodnessOfFit.count(fileOffset) == 0 || goodnessOfFit[fileOffset] < Sizes[s]))
+ {
+ if(SecondStageMatch(phashTable[hash], rolling, beginnings, endings, offset, Sizes[s], fileBlockNumber, pIndex, rFoundBlocks))
+ {
+ BOX_TRACE("Found block match for " << hash << " of " << Sizes[s] << " bytes at offset " << fileOffset);
+ goodnessOfFit[fileOffset] = Sizes[s];
+
+ // Block matched, roll the checksum forward to the next block without doing
+ // any more comparisons, because these are pointless (as any more matches will be ignored when
+ // the recipe is generated) and just take up valuable processor time. Edge cases are
+ // especially nasty, using huge amounts of time and memory.
+ int skip = Sizes[s];
+ if(offset < bytesInEndings && skip > 0)
+ {
+ int spaceLeft = bytesInEndings - offset;
+ int thisRoll = (skip > spaceLeft) ? spaceLeft : skip;
+
+ rolling.RollForwardSeveral(beginnings+offset, endings+offset, Sizes[s], thisRoll);
+
+ offset += thisRoll;
+ fileOffset += thisRoll;
+ skip -= thisRoll;
+ }
+ // Not all the bytes necessary will have been skipped, so get them
+ // skipped after the next block is loaded.
+ rollOverInitialBytes = skip;
+
+ // End this loop, so the final byte isn't used again
+ break;
+ }
+ else
+ {
+ BOX_TRACE("False alarm match for " << hash << " of " << Sizes[s] << " bytes at offset " << fileOffset);
+ }
+
+ int64_t NumBlocksFound = static_cast<int64_t>(
+ rFoundBlocks.size());
+ int64_t MaxBlocksFound = NumBlocks *
+ BACKUP_FILE_DIFF_MAX_BLOCK_FIND_MULTIPLE;
+
+ if(NumBlocksFound > MaxBlocksFound)
+ {
+ abortSearch = true;
+ break;
+ }
+ }
+
+ // Roll checksum forward
+ rolling.RollForward(beginnings[offset], endings[offset], Sizes[s]);
+
+ // Increment offsets
+ ++offset;
+ ++fileOffset;
+ }
+
+ if(abortSearch) break;
+
+ refresh:
+ // Finished?
+ if(bytesInEndings != Sizes[s])
+ {
+ // No more data in file -- check the final block
+ // (Do a copy and paste of 5 lines of code instead of introducing a comparison for
+ // each byte of the file)
+ uint16_t hash = rolling.GetComponentForHashing();
+ if(phashTable[hash] != 0 && (goodnessOfFit.count(fileOffset) == 0 || goodnessOfFit[fileOffset] < Sizes[s]))
+ {
+ if(SecondStageMatch(phashTable[hash], rolling, beginnings, endings, offset, Sizes[s], fileBlockNumber, pIndex, rFoundBlocks))
+ {
+ goodnessOfFit[fileOffset] = Sizes[s];
+ }
+ }
+
+ // finish
+ break;
+ }
+
+ // Switch buffers, reset offset
+ beginnings = endings;
+ endings = (beginnings == pbuffer0)?(pbuffer1):(pbuffer0); // ie the other buffer
+ offset = 0;
+
+ // And count the blocks which have been done
+ ++fileBlockNumber;
+ }
+
+ if(abortSearch) break;
+ }
+
+ // Free buffers and hash table
+ ::free(pbuffer1);
+ pbuffer1 = 0;
+ ::free(pbuffer0);
+ pbuffer0 = 0;
+ ::free(phashTable);
+ phashTable = 0;
+ }
+ catch(...)
+ {
+ // Cleanup and throw
+ if(pbuffer1 != 0) ::free(pbuffer1);
+ if(pbuffer0 != 0) ::free(pbuffer0);
+ if(phashTable != 0) ::free(phashTable);
+ throw;
+ }
+
+#ifndef BOX_RELEASE_BUILD
+ if(BackupStoreFile::TraceDetailsOfDiffProcess)
+ {
+ // Trace out the found blocks in debug mode
+ BOX_TRACE("Diff: list of found blocks");
+ BOX_TRACE("======== ======== ======== ========");
+ BOX_TRACE(" Offset BlkIdx Size Movement");
+ for(std::map<int64_t, int64_t>::const_iterator i(rFoundBlocks.begin()); i != rFoundBlocks.end(); ++i)
+ {
+ int64_t orgLoc = 0;
+ for(int64_t b = 0; b < i->second; ++b)
+ {
+ orgLoc += pIndex[b].mSize;
+ }
+ BOX_TRACE(std::setw(8) << i->first << " " <<
+ std::setw(8) << i->second << " " <<
+ std::setw(8) << pIndex[i->second].mSize <<
+ " " <<
+ std::setw(8) << (i->first - orgLoc));
+ }
+ BOX_TRACE("======== ======== ======== ========");
+ }
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static SetupHashTable(BlocksAvailableEntry *, int64_t, in32_t, BlocksAvailableEntry **)
+// Purpose: Set up the hash table ready for a scan
+// Created: 14/1/04
+//
+// --------------------------------------------------------------------------
+static void SetupHashTable(BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t BlockSize, BlocksAvailableEntry **pHashTable)
+{
+ // Set all entries in the hash table to zero
+ ::memset(pHashTable, 0, (sizeof(BlocksAvailableEntry *) * (64*1024)));
+
+ // Scan through the blocks, building the hash table
+ for(int64_t b = 0; b < NumBlocks; ++b)
+ {
+ // Only look at the required block size
+ if(pIndex[b].mSize == BlockSize)
+ {
+ // Get the value under which to hash this entry
+ uint16_t hash = RollingChecksum::ExtractHashingComponent(pIndex[b].mWeakChecksum);
+
+ // Already present in table?
+ if(pHashTable[hash] != 0)
+ {
+ //BOX_TRACE("Another hash entry for " << hash << " found");
+ // Yes -- need to set the pointer in this entry to the current entry to build the linked list
+ pIndex[b].mpNextInHashList = pHashTable[hash];
+ }
+
+ // Put a pointer to this entry in the hash table
+ pHashTable[hash] = pIndex + b;
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static bool SecondStageMatch(xxx)
+// Purpose: When a match in the hash table is found, scan for second stage match using strong checksum.
+// Created: 14/1/04
+//
+// --------------------------------------------------------------------------
+static bool SecondStageMatch(BlocksAvailableEntry *pFirstInHashList, RollingChecksum &fastSum, uint8_t *pBeginnings, uint8_t *pEndings,
+ int Offset, int32_t BlockSize, int64_t FileBlockNumber, BlocksAvailableEntry *pIndex, std::map<int64_t, int64_t> &rFoundBlocks)
+{
+ // Check parameters
+ ASSERT(pBeginnings != 0);
+ ASSERT(pEndings != 0);
+ ASSERT(Offset >= 0);
+ ASSERT(BlockSize > 0);
+ ASSERT(pFirstInHashList != 0);
+ ASSERT(pIndex != 0);
+
+#ifndef BOX_RELEASE_BUILD
+ uint16_t DEBUG_Hash = fastSum.GetComponentForHashing();
+#endif
+ uint32_t Checksum = fastSum.GetChecksum();
+
+ // Before we go to the expense of the MD5, make sure it's a darn good match on the checksum we already know.
+ BlocksAvailableEntry *scan = pFirstInHashList;
+ bool found=false;
+ while(scan != 0)
+ {
+ if(scan->mWeakChecksum == Checksum)
+ {
+ found = true;
+ break;
+ }
+ scan = scan->mpNextInHashList;
+ }
+ if(!found)
+ {
+ return false;
+ }
+
+ // Calculate the strong MD5 digest for this block
+ MD5Digest strong;
+ // Add the data from the beginnings
+ strong.Add(pBeginnings + Offset, BlockSize - Offset);
+ // Add any data from the endings
+ if(Offset > 0)
+ {
+ strong.Add(pEndings, Offset);
+ }
+ strong.Finish();
+
+ // Then go through the entries in the hash list, comparing with the strong digest calculated
+ scan = pFirstInHashList;
+ //BOX_TRACE("second stage match");
+ while(scan != 0)
+ {
+ //BOX_TRACE("scan size " << scan->mSize <<
+ // ", block size " << BlockSize <<
+ // ", hash " << Hash);
+ ASSERT(scan->mSize == BlockSize);
+ ASSERT(RollingChecksum::ExtractHashingComponent(scan->mWeakChecksum) == DEBUG_Hash);
+
+ // Compare?
+ if(strong.DigestMatches(scan->mStrongChecksum))
+ {
+ //BOX_TRACE("Match!\n");
+ // Found! Add to list of found blocks...
+ int64_t fileOffset = (FileBlockNumber * BlockSize) + Offset;
+ int64_t blockIndex = (scan - pIndex); // pointer arthmitic is frowned upon. But most efficient way of doing it here -- alternative is to use more memory
+
+ // We do NOT search for smallest blocks first, as this code originally assumed.
+ // To prevent this from potentially overwriting a better match, the caller must determine
+ // the relative "goodness" of any existing match and this one, and avoid the call if it
+ // could be detrimental.
+ rFoundBlocks[fileOffset] = blockIndex;
+
+ // No point in searching further, report success
+ return true;
+ }
+
+ // Next
+ scan = scan->mpNextInHashList;
+ }
+
+ // Not matched
+ return false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static GenerateRecipe(BackupStoreFileEncodeStream::Recipe &, BlocksAvailableEntry *, int64_t, std::map<int64_t, int64_t> &)
+// Purpose: Fills in the recipe from the found block list
+// Created: 15/1/04
+//
+// --------------------------------------------------------------------------
+static void GenerateRecipe(BackupStoreFileEncodeStream::Recipe &rRecipe, BlocksAvailableEntry *pIndex,
+ int64_t NumBlocks, std::map<int64_t, int64_t> &rFoundBlocks, int64_t SizeOfInputFile)
+{
+ // NOTE: This function could be a lot more sophisiticated. For example, if
+ // a small block overlaps a big block like this
+ // ****
+ // *******************************
+ // then the small block will be used, not the big one. But it'd be better to
+ // just ignore the small block and keep the big one. However, some stats should
+ // be gathered about real world files before writing complex code which might
+ // go wrong.
+
+ // Initialise a blank instruction
+ BackupStoreFileEncodeStream::RecipeInstruction instruction;
+ #define RESET_INSTRUCTION \
+ instruction.mSpaceBefore = 0; \
+ instruction.mBlocks = 0; \
+ instruction.mpStartBlock = 0;
+ RESET_INSTRUCTION
+
+ // First, a special case for when there are no found blocks
+ if(rFoundBlocks.size() == 0)
+ {
+ // No blocks, just a load of space
+ instruction.mSpaceBefore = SizeOfInputFile;
+ rRecipe.push_back(instruction);
+
+ #ifndef BOX_RELEASE_BUILD
+ if(BackupStoreFile::TraceDetailsOfDiffProcess)
+ {
+ BOX_TRACE("Diff: Default recipe generated, " <<
+ SizeOfInputFile << " bytes of file");
+ }
+ #endif
+
+ // Don't do anything
+ return;
+ }
+
+ // Current location
+ int64_t loc = 0;
+
+ // Then iterate through the list, generating the recipe
+ std::map<int64_t, int64_t>::const_iterator i(rFoundBlocks.begin());
+ ASSERT(i != rFoundBlocks.end()); // check logic
+
+ // Counting for debug tracing
+#ifndef BOX_RELEASE_BUILD
+ int64_t debug_NewBytesFound = 0;
+ int64_t debug_OldBlocksUsed = 0;
+#endif
+
+ for(; i != rFoundBlocks.end(); ++i)
+ {
+ // Remember... map is (position in file) -> (index of block in pIndex)
+
+ if(i->first < loc)
+ {
+ // This block overlaps the last one
+ continue;
+ }
+ else if(i->first > loc)
+ {
+ // There's a gap between the end of the last thing and this block.
+ // If there's an instruction waiting, push it onto the list
+ if(instruction.mSpaceBefore != 0 || instruction.mpStartBlock != 0)
+ {
+ rRecipe.push_back(instruction);
+ }
+ // Start a new instruction, with the gap ready
+ RESET_INSTRUCTION
+ instruction.mSpaceBefore = i->first - loc;
+ // Move location forward to match
+ loc += instruction.mSpaceBefore;
+#ifndef BOX_RELEASE_BUILD
+ debug_NewBytesFound += instruction.mSpaceBefore;
+#endif
+ }
+
+ // First, does the current instruction need pushing back, because this block is not
+ // sequential to the last one?
+ if(instruction.mpStartBlock != 0 && (pIndex + i->second) != (instruction.mpStartBlock + instruction.mBlocks))
+ {
+ rRecipe.push_back(instruction);
+ RESET_INSTRUCTION
+ }
+
+ // Add in this block
+ if(instruction.mpStartBlock == 0)
+ {
+ // This block starts a new instruction
+ instruction.mpStartBlock = pIndex + i->second;
+ instruction.mBlocks = 1;
+ }
+ else
+ {
+ // It continues the previous section of blocks
+ instruction.mBlocks += 1;
+ }
+
+#ifndef BOX_RELEASE_BUILD
+ debug_OldBlocksUsed++;
+#endif
+
+ // Move location forward
+ loc += pIndex[i->second].mSize;
+ }
+
+ // Push the last instruction generated
+ rRecipe.push_back(instruction);
+
+ // Is there any space left at the end which needs sending?
+ if(loc != SizeOfInputFile)
+ {
+ RESET_INSTRUCTION
+ instruction.mSpaceBefore = SizeOfInputFile - loc;
+#ifndef BOX_RELEASE_BUILD
+ debug_NewBytesFound += instruction.mSpaceBefore;
+#endif
+ rRecipe.push_back(instruction);
+ }
+
+ // dump out the recipe
+#ifndef BOX_RELEASE_BUILD
+ BOX_TRACE("Diff: " <<
+ debug_NewBytesFound << " new bytes found, " <<
+ debug_OldBlocksUsed << " old blocks used");
+ if(BackupStoreFile::TraceDetailsOfDiffProcess)
+ {
+ BOX_TRACE("Diff: Recipe generated (size " << rRecipe.size());
+ BOX_TRACE("======== ========= ========");
+ BOX_TRACE("Space b4 FirstBlk NumBlks");
+ {
+ for(unsigned int e = 0; e < rRecipe.size(); ++e)
+ {
+ char b[64];
+#ifdef WIN32
+ sprintf(b, "%8I64d", (int64_t)(rRecipe[e].mpStartBlock - pIndex));
+#else
+ sprintf(b, "%8lld", (int64_t)(rRecipe[e].mpStartBlock - pIndex));
+#endif
+ BOX_TRACE(std::setw(8) <<
+ rRecipe[e].mSpaceBefore <<
+ " " <<
+ ((rRecipe[e].mpStartBlock == 0)?" -":b) <<
+ " " << std::setw(8) <<
+ rRecipe[e].mBlocks);
+ }
+ }
+ BOX_TRACE("======== ========= ========");
+ }
+#endif
+}
diff --git a/lib/backupclient/BackupStoreFileEncodeStream.cpp b/lib/backupclient/BackupStoreFileEncodeStream.cpp
new file mode 100644
index 00000000..54c2463d
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileEncodeStream.cpp
@@ -0,0 +1,715 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileEncodeStream.cpp
+// Purpose: Implement stream-based file encoding for the backup store
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <string.h>
+
+#include "BackupClientFileAttributes.h"
+#include "BackupStoreConstants.h"
+#include "BackupStoreException.h"
+#include "BackupStoreFile.h"
+#include "BackupStoreFileCryptVar.h"
+#include "BackupStoreFileEncodeStream.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreObjectMagic.h"
+#include "BoxTime.h"
+#include "FileStream.h"
+#include "Random.h"
+#include "RollingChecksum.h"
+
+#include "MemLeakFindOn.h"
+
+#include <cstring>
+
+using namespace BackupStoreFileCryptVar;
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::BackupStoreFileEncodeStream
+// Purpose: Constructor (opens file)
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+BackupStoreFileEncodeStream::BackupStoreFileEncodeStream()
+ : mpRecipe(0),
+ mpFile(0),
+ mpLogging(0),
+ mpRunStatusProvider(NULL),
+ mStatus(Status_Header),
+ mSendData(true),
+ mTotalBlocks(0),
+ mAbsoluteBlockNumber(-1),
+ mInstructionNumber(-1),
+ mNumBlocks(0),
+ mCurrentBlock(-1),
+ mCurrentBlockEncodedSize(0),
+ mPositionInCurrentBlock(0),
+ mBlockSize(BACKUP_FILE_MIN_BLOCK_SIZE),
+ mLastBlockSize(0),
+ mpRawBuffer(0),
+ mAllocatedBufferSize(0),
+ mEntryIVBase(0)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::~BackupStoreFileEncodeStream()
+// Purpose: Destructor
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+BackupStoreFileEncodeStream::~BackupStoreFileEncodeStream()
+{
+ // Free buffers
+ if(mpRawBuffer)
+ {
+ ::free(mpRawBuffer);
+ mpRawBuffer = 0;
+ }
+
+ // Close the file, which we might have open
+ if(mpFile)
+ {
+ delete mpFile;
+ mpFile = 0;
+ }
+
+ // Clear up logging stream
+ if(mpLogging)
+ {
+ delete mpLogging;
+ mpLogging = 0;
+ }
+
+ // Free the recipe
+ if(mpRecipe != 0)
+ {
+ delete mpRecipe;
+ mpRecipe = 0;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::Setup(const char *, Recipe *, int64_t, const BackupStoreFilename &, int64_t *)
+// Purpose: Reads file information, and builds file header reading for sending.
+// Takes ownership of the Recipe.
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFileEncodeStream::Setup(const char *Filename,
+ BackupStoreFileEncodeStream::Recipe *pRecipe,
+ int64_t ContainerID, const BackupStoreFilename &rStoreFilename,
+ int64_t *pModificationTime, ReadLoggingStream::Logger* pLogger,
+ RunStatusProvider* pRunStatusProvider)
+{
+ // Pointer to a blank recipe which we might create
+ BackupStoreFileEncodeStream::Recipe *pblankRecipe = 0;
+
+ try
+ {
+ // Get file attributes
+ box_time_t modTime = 0;
+ int64_t fileSize = 0;
+ BackupClientFileAttributes attr;
+ attr.ReadAttributes(Filename, false /* no zeroing of modification times */, &modTime,
+ 0 /* not interested in attr mod time */, &fileSize);
+
+ // Might need to create a blank recipe...
+ if(pRecipe == 0)
+ {
+ pblankRecipe = new BackupStoreFileEncodeStream::Recipe(0, 0);
+
+ BackupStoreFileEncodeStream::RecipeInstruction instruction;
+ instruction.mSpaceBefore = fileSize; // whole file
+ instruction.mBlocks = 0; // no blocks
+ instruction.mpStartBlock = 0; // no block
+ pblankRecipe->push_back(instruction);
+
+ pRecipe = pblankRecipe;
+ }
+
+ // Tell caller?
+ if(pModificationTime != 0)
+ {
+ *pModificationTime = modTime;
+ }
+
+ // Go through each instruction in the recipe and work out how many blocks
+ // it will add, and the max clear size of these blocks
+ int maxBlockClearSize = 0;
+ for(uint64_t inst = 0; inst < pRecipe->size(); ++inst)
+ {
+ if((*pRecipe)[inst].mSpaceBefore > 0)
+ {
+ // Calculate the number of blocks the space before requires
+ int64_t numBlocks;
+ int32_t blockSize, lastBlockSize;
+ CalculateBlockSizes((*pRecipe)[inst].mSpaceBefore, numBlocks, blockSize, lastBlockSize);
+ // Add to accumlated total
+ mTotalBlocks += numBlocks;
+ // Update maximum clear size
+ if(blockSize > maxBlockClearSize) maxBlockClearSize = blockSize;
+ if(lastBlockSize > maxBlockClearSize) maxBlockClearSize = lastBlockSize;
+ }
+
+ // Add number of blocks copied from the previous file
+ mTotalBlocks += (*pRecipe)[inst].mBlocks;
+
+ // Check for bad things
+ if((*pRecipe)[inst].mBlocks < 0 || ((*pRecipe)[inst].mBlocks != 0 && (*pRecipe)[inst].mpStartBlock == 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ // Run through blocks to get the max clear size
+ for(int32_t b = 0; b < (*pRecipe)[inst].mBlocks; ++b)
+ {
+ if((*pRecipe)[inst].mpStartBlock[b].mSize > maxBlockClearSize) maxBlockClearSize = (*pRecipe)[inst].mpStartBlock[b].mSize;
+ }
+ }
+
+ // Send data? (symlinks don't have any data in them)
+ mSendData = !attr.IsSymLink();
+
+ // If not data is being sent, then the max clear block size is zero
+ if(!mSendData)
+ {
+ maxBlockClearSize = 0;
+ }
+
+ // Header
+ file_StreamFormat hdr;
+ hdr.mMagicValue = htonl(OBJECTMAGIC_FILE_MAGIC_VALUE_V1);
+ hdr.mNumBlocks = (mSendData)?(box_hton64(mTotalBlocks)):(0);
+ hdr.mContainerID = box_hton64(ContainerID);
+ hdr.mModificationTime = box_hton64(modTime);
+ // add a bit to make it harder to tell what's going on -- try not to give away too much info about file size
+ hdr.mMaxBlockClearSize = htonl(maxBlockClearSize + 128);
+ hdr.mOptions = 0; // no options defined yet
+
+ // Write header to stream
+ mData.Write(&hdr, sizeof(hdr));
+
+ // Write filename to stream
+ rStoreFilename.WriteToStream(mData);
+
+ // Write attributes to stream
+ attr.WriteToStream(mData);
+
+ // Allocate some buffers for writing data
+ if(mSendData)
+ {
+ // Open the file
+ mpFile = new FileStream(Filename);
+
+ if (pLogger)
+ {
+ // Create logging stream
+ mpLogging = new ReadLoggingStream(*mpFile,
+ *pLogger);
+ }
+ else
+ {
+ // re-use FileStream instead
+ mpLogging = mpFile;
+ mpFile = NULL;
+ }
+
+ // Work out the largest possible block required for the encoded data
+ mAllocatedBufferSize = BackupStoreFile::MaxBlockSizeForChunkSize(maxBlockClearSize);
+
+ // Then allocate two blocks of this size
+ mpRawBuffer = (uint8_t*)::malloc(mAllocatedBufferSize);
+ if(mpRawBuffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+#ifndef BOX_RELEASE_BUILD
+ // In debug builds, make sure that the reallocation code is exercised.
+ mEncodedBuffer.Allocate(mAllocatedBufferSize / 4);
+#else
+ mEncodedBuffer.Allocate(mAllocatedBufferSize);
+#endif
+ }
+ else
+ {
+ // Write an empty block index for the symlink
+ file_BlockIndexHeader blkhdr;
+ blkhdr.mMagicValue = htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1);
+ blkhdr.mOtherFileID = box_hton64(0); // not other file ID
+ blkhdr.mEntryIVBase = box_hton64(0);
+ blkhdr.mNumBlocks = box_hton64(0);
+ mData.Write(&blkhdr, sizeof(blkhdr));
+ }
+
+ // Ready for reading
+ mData.SetForReading();
+
+ // Update stats
+ BackupStoreFile::msStats.mBytesInEncodedFiles += fileSize;
+
+ // Finally, store the pointer to the recipe, when we know exceptions won't occur
+ mpRecipe = pRecipe;
+ }
+ catch(...)
+ {
+ // Clean up any blank recipe
+ if(pblankRecipe != 0)
+ {
+ delete pblankRecipe;
+ pblankRecipe = 0;
+ }
+ throw;
+ }
+
+ mpRunStatusProvider = pRunStatusProvider;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::CalculateBlockSizes(int64_t &, int32_t &, int32_t &)
+// Purpose: Calculates the sizes of blocks in a section of the file
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFileEncodeStream::CalculateBlockSizes(int64_t DataSize, int64_t &rNumBlocksOut, int32_t &rBlockSizeOut, int32_t &rLastBlockSizeOut)
+{
+ // How many blocks, and how big?
+ rBlockSizeOut = BACKUP_FILE_MIN_BLOCK_SIZE / 2;
+ do
+ {
+ rBlockSizeOut *= 2;
+
+ rNumBlocksOut = (DataSize + rBlockSizeOut - 1) / rBlockSizeOut;
+
+ } while(rBlockSizeOut < BACKUP_FILE_MAX_BLOCK_SIZE && rNumBlocksOut > BACKUP_FILE_INCREASE_BLOCK_SIZE_AFTER);
+
+ // Last block size
+ rLastBlockSizeOut = DataSize - ((rNumBlocksOut - 1) * rBlockSizeOut);
+
+ // Avoid small blocks?
+ if(rLastBlockSizeOut < BACKUP_FILE_AVOID_BLOCKS_LESS_THAN
+ && rNumBlocksOut > 1)
+ {
+ // Add the small bit of data to the last block
+ --rNumBlocksOut;
+ rLastBlockSizeOut += rBlockSizeOut;
+ }
+
+ // checks!
+ ASSERT((((rNumBlocksOut-1) * rBlockSizeOut) + rLastBlockSizeOut) == DataSize);
+ //TRACE4("CalcBlockSize, sz %lld, num %lld, blocksize %d, last %d\n", DataSize, rNumBlocksOut, (int32_t)rBlockSizeOut, (int32_t)rLastBlockSizeOut);
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::Read(void *, int, int)
+// Purpose: As interface -- generates encoded file data on the fly from the raw file
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+int BackupStoreFileEncodeStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ // Check there's something to do.
+ if(mStatus == Status_Finished)
+ {
+ return 0;
+ }
+
+ if(mpRunStatusProvider && mpRunStatusProvider->StopRun())
+ {
+ THROW_EXCEPTION(BackupStoreException, SignalReceived);
+ }
+
+ int bytesToRead = NBytes;
+ uint8_t *buffer = (uint8_t*)pBuffer;
+
+ while(bytesToRead > 0 && mStatus != Status_Finished)
+ {
+ if(mStatus == Status_Header || mStatus == Status_BlockListing)
+ {
+ // Header or block listing phase -- send from the buffered stream
+
+ // Send bytes from the data buffer
+ int b = mData.Read(buffer, bytesToRead, Timeout);
+ bytesToRead -= b;
+ buffer += b;
+
+ // Check to see if all the data has been used from this stream
+ if(!mData.StreamDataLeft())
+ {
+ // Yes, move on to next phase (or finish, if there's no file data)
+ if(!mSendData)
+ {
+ mStatus = Status_Finished;
+ }
+ else
+ {
+ // Reset the buffer so it can be used for the next phase
+ mData.Reset();
+
+ // Get buffer ready for index?
+ if(mStatus == Status_Header)
+ {
+ // Just finished doing the stream header, create the block index header
+ file_BlockIndexHeader blkhdr;
+ blkhdr.mMagicValue = htonl(OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1);
+ ASSERT(mpRecipe != 0);
+ blkhdr.mOtherFileID = box_hton64(mpRecipe->GetOtherFileID());
+ blkhdr.mNumBlocks = box_hton64(mTotalBlocks);
+
+ // Generate the IV base
+ Random::Generate(&mEntryIVBase, sizeof(mEntryIVBase));
+ blkhdr.mEntryIVBase = box_hton64(mEntryIVBase);
+
+ mData.Write(&blkhdr, sizeof(blkhdr));
+ }
+
+ ++mStatus;
+ }
+ }
+ }
+ else if(mStatus == Status_Blocks)
+ {
+ // Block sending phase
+
+ if(mPositionInCurrentBlock >= mCurrentBlockEncodedSize)
+ {
+ // Next block!
+ ++mCurrentBlock;
+ ++mAbsoluteBlockNumber;
+ if(mCurrentBlock >= mNumBlocks)
+ {
+ // Output extra blocks for this instruction and move forward in file
+ if(mInstructionNumber >= 0)
+ {
+ SkipPreviousBlocksInInstruction();
+ }
+
+ // Is there another instruction to go?
+ ++mInstructionNumber;
+
+ // Skip instructions which don't contain any data
+ while(mInstructionNumber < static_cast<int64_t>(mpRecipe->size())
+ && (*mpRecipe)[mInstructionNumber].mSpaceBefore == 0)
+ {
+ SkipPreviousBlocksInInstruction();
+ ++mInstructionNumber;
+ }
+
+ if(mInstructionNumber >= static_cast<int64_t>(mpRecipe->size()))
+ {
+ // End of blocks, go to next phase
+ ++mStatus;
+
+ // Set the data to reading so the index can be written
+ mData.SetForReading();
+ }
+ else
+ {
+ // Get ready for this instruction
+ SetForInstruction();
+ }
+ }
+
+ // Can't use 'else' here as SetForInstruction() will change this
+ if(mCurrentBlock < mNumBlocks)
+ {
+ EncodeCurrentBlock();
+ }
+ }
+
+ // Send data from the current block (if there's data to send)
+ if(mPositionInCurrentBlock < mCurrentBlockEncodedSize)
+ {
+ // How much data to put in the buffer?
+ int s = mCurrentBlockEncodedSize - mPositionInCurrentBlock;
+ if(s > bytesToRead) s = bytesToRead;
+
+ // Copy it in
+ ::memcpy(buffer, mEncodedBuffer.mpBuffer + mPositionInCurrentBlock, s);
+
+ // Update variables
+ bytesToRead -= s;
+ buffer += s;
+ mPositionInCurrentBlock += s;
+ }
+ }
+ else
+ {
+ // Should never get here, as it'd be an invalid status
+ ASSERT(false);
+ }
+ }
+
+ // Add encoded size to stats
+ BackupStoreFile::msStats.mTotalFileStreamSize += (NBytes - bytesToRead);
+
+ // Return size of data to caller
+ return NBytes - bytesToRead;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::StorePreviousBlocksInInstruction()
+// Purpose: Private. Stores the blocks of the old file referenced in the current
+// instruction into the index and skips over the data in the file
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFileEncodeStream::SkipPreviousBlocksInInstruction()
+{
+ // Check something is necessary
+ if((*mpRecipe)[mInstructionNumber].mpStartBlock == 0 || (*mpRecipe)[mInstructionNumber].mBlocks == 0)
+ {
+ return;
+ }
+
+ // Index of the first block in old file (being diffed from)
+ int firstIndex = mpRecipe->BlockPtrToIndex((*mpRecipe)[mInstructionNumber].mpStartBlock);
+
+ int64_t sizeToSkip = 0;
+
+ for(int32_t b = 0; b < (*mpRecipe)[mInstructionNumber].mBlocks; ++b)
+ {
+ // Update stats
+ BackupStoreFile::msStats.mBytesAlreadyOnServer += (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize;
+
+ // Store the entry
+ StoreBlockIndexEntry(0 - (firstIndex + b),
+ (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize,
+ (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mWeakChecksum,
+ (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mStrongChecksum);
+
+ // Increment the absolute block number -- kept encryption IV in sync
+ ++mAbsoluteBlockNumber;
+
+ // Add the size of this block to the size to skip
+ sizeToSkip += (*mpRecipe)[mInstructionNumber].mpStartBlock[b].mSize;
+ }
+
+ // Move forward in the stream
+ mpLogging->Seek(sizeToSkip, IOStream::SeekType_Relative);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::SetForInstruction()
+// Purpose: Private. Sets the state of the internal variables for the current instruction in the recipe
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFileEncodeStream::SetForInstruction()
+{
+ // Calculate block sizes
+ CalculateBlockSizes((*mpRecipe)[mInstructionNumber].mSpaceBefore, mNumBlocks, mBlockSize, mLastBlockSize);
+
+ // Set variables
+ mCurrentBlock = 0;
+ mCurrentBlockEncodedSize = 0;
+ mPositionInCurrentBlock = 0;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::EncodeCurrentBlock()
+// Purpose: Private. Encodes the current block, and writes the block data to the index
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFileEncodeStream::EncodeCurrentBlock()
+{
+ // How big is the block, raw?
+ int blockRawSize = mBlockSize;
+ if(mCurrentBlock == (mNumBlocks - 1))
+ {
+ blockRawSize = mLastBlockSize;
+ }
+ ASSERT(blockRawSize < mAllocatedBufferSize);
+
+ // Check file open
+ if(mpLogging == 0)
+ {
+ // File should be open, but isn't. So logical error.
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ // Read the data in
+ if(!mpLogging->ReadFullBuffer(mpRawBuffer, blockRawSize,
+ 0 /* not interested in size if failure */))
+ {
+ // TODO: Do something more intelligent, and abort
+ // this upload because the file has changed.
+ THROW_EXCEPTION(BackupStoreException,
+ Temp_FileEncodeStreamDidntReadBuffer)
+ }
+
+ // Encode it
+ mCurrentBlockEncodedSize = BackupStoreFile::EncodeChunk(mpRawBuffer,
+ blockRawSize, mEncodedBuffer);
+
+ //TRACE2("Encode: Encoded size of block %d is %d\n", (int32_t)mCurrentBlock, (int32_t)mCurrentBlockEncodedSize);
+
+ // Create block listing data -- generate checksums
+ RollingChecksum weakChecksum(mpRawBuffer, blockRawSize);
+ MD5Digest strongChecksum;
+ strongChecksum.Add(mpRawBuffer, blockRawSize);
+ strongChecksum.Finish();
+
+ // Add entry to the index
+ StoreBlockIndexEntry(mCurrentBlockEncodedSize, blockRawSize,
+ weakChecksum.GetChecksum(), strongChecksum.DigestAsData());
+
+ // Set vars to reading this block
+ mPositionInCurrentBlock = 0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::StoreBlockIndexEntry(int64_t, int32_t, uint32_t, uint8_t *)
+// Purpose: Private. Adds an entry to the index currently being stored for sending at end of the stream.
+// Created: 16/1/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFileEncodeStream::StoreBlockIndexEntry(int64_t EncSizeOrBlkIndex, int32_t ClearSize, uint32_t WeakChecksum, uint8_t *pStrongChecksum)
+{
+ // First, the encrypted section
+ file_BlockIndexEntryEnc entryEnc;
+ entryEnc.mSize = htonl(ClearSize);
+ entryEnc.mWeakChecksum = htonl(WeakChecksum);
+ ::memcpy(entryEnc.mStrongChecksum, pStrongChecksum, sizeof(entryEnc.mStrongChecksum));
+
+ // Then the clear section
+ file_BlockIndexEntry entry;
+ entry.mEncodedSize = box_hton64(((uint64_t)EncSizeOrBlkIndex));
+
+ // Then encrypt the encryted section
+ // Generate the IV from the block number
+ if(sBlowfishEncryptBlockEntry.GetIVLength() != sizeof(mEntryIVBase))
+ {
+ THROW_EXCEPTION(BackupStoreException, IVLengthForEncodedBlockSizeDoesntMeetLengthRequirements)
+ }
+ uint64_t iv = mEntryIVBase;
+ iv += mAbsoluteBlockNumber;
+ // Convert to network byte order before encrypting with it, so that restores work on
+ // platforms with different endiannesses.
+ iv = box_hton64(iv);
+ sBlowfishEncryptBlockEntry.SetIV(&iv);
+
+ // Encode the data
+ int encodedSize = sBlowfishEncryptBlockEntry.TransformBlock(entry.mEnEnc, sizeof(entry.mEnEnc), &entryEnc, sizeof(entryEnc));
+ if(encodedSize != sizeof(entry.mEnEnc))
+ {
+ THROW_EXCEPTION(BackupStoreException, BlockEntryEncodingDidntGiveExpectedLength)
+ }
+
+ // Save to data block for sending at the end of the stream
+ mData.Write(&entry, sizeof(entry));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::Write(const void *, int)
+// Purpose: As interface. Exceptions.
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFileEncodeStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(BackupStoreException, CantWriteToEncodedFileStream)
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::StreamDataLeft()
+// Purpose: As interface -- end of stream reached?
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFileEncodeStream::StreamDataLeft()
+{
+ return (mStatus != Status_Finished);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::StreamClosed()
+// Purpose: As interface
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFileEncodeStream::StreamClosed()
+{
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::Recipe::Recipe(BackupStoreFileCreation::BlocksAvailableEntry *, int64_t)
+// Purpose: Constructor. Takes ownership of the block index, and will delete it when it's deleted
+// Created: 15/1/04
+//
+// --------------------------------------------------------------------------
+BackupStoreFileEncodeStream::Recipe::Recipe(BackupStoreFileCreation::BlocksAvailableEntry *pBlockIndex,
+ int64_t NumBlocksInIndex, int64_t OtherFileID)
+ : mpBlockIndex(pBlockIndex),
+ mNumBlocksInIndex(NumBlocksInIndex),
+ mOtherFileID(OtherFileID)
+{
+ ASSERT((mpBlockIndex == 0) || (NumBlocksInIndex != 0))
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFileEncodeStream::Recipe::~Recipe()
+// Purpose: Destructor
+// Created: 15/1/04
+//
+// --------------------------------------------------------------------------
+BackupStoreFileEncodeStream::Recipe::~Recipe()
+{
+ // Free the block index, if there is one
+ if(mpBlockIndex != 0)
+ {
+ ::free(mpBlockIndex);
+ }
+}
+
+
+
+
diff --git a/lib/backupclient/BackupStoreFileEncodeStream.h b/lib/backupclient/BackupStoreFileEncodeStream.h
new file mode 100644
index 00000000..c5fa780a
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileEncodeStream.h
@@ -0,0 +1,135 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileEncodeStream.h
+// Purpose: Implement stream-based file encoding for the backup store
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREFILEENCODESTREAM__H
+#define BACKUPSTOREFILEENCODESTREAM__H
+
+#include <vector>
+
+#include "IOStream.h"
+#include "BackupStoreFilename.h"
+#include "CollectInBufferStream.h"
+#include "MD5Digest.h"
+#include "BackupStoreFile.h"
+#include "ReadLoggingStream.h"
+#include "RunStatusProvider.h"
+
+namespace BackupStoreFileCreation
+{
+ // Diffing and creation of files share some implementation details.
+ typedef struct _BlocksAvailableEntry
+ {
+ struct _BlocksAvailableEntry *mpNextInHashList;
+ int32_t mSize; // size in clear
+ uint32_t mWeakChecksum; // weak, rolling checksum
+ uint8_t mStrongChecksum[MD5Digest::DigestLength]; // strong digest based checksum
+ } BlocksAvailableEntry;
+
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: BackupStoreFileEncodeStream
+// Purpose: Encode a file into a stream
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+class BackupStoreFileEncodeStream : public IOStream
+{
+public:
+ BackupStoreFileEncodeStream();
+ ~BackupStoreFileEncodeStream();
+
+ typedef struct
+ {
+ int64_t mSpaceBefore; // amount of bytes which aren't taken out of blocks which go
+ int32_t mBlocks; // number of block to reuse, starting at this one
+ BackupStoreFileCreation::BlocksAvailableEntry *mpStartBlock; // may be null
+ } RecipeInstruction;
+
+ class Recipe : public std::vector<RecipeInstruction>
+ {
+ // NOTE: This class is rather tied in with the implementation of diffing.
+ public:
+ Recipe(BackupStoreFileCreation::BlocksAvailableEntry *pBlockIndex, int64_t NumBlocksInIndex,
+ int64_t OtherFileID = 0);
+ ~Recipe();
+
+ int64_t GetOtherFileID() {return mOtherFileID;}
+ int64_t BlockPtrToIndex(BackupStoreFileCreation::BlocksAvailableEntry *pBlock)
+ {
+ return pBlock - mpBlockIndex;
+ }
+
+ private:
+ BackupStoreFileCreation::BlocksAvailableEntry *mpBlockIndex;
+ int64_t mNumBlocksInIndex;
+ int64_t mOtherFileID;
+ };
+
+ void Setup(const char *Filename, Recipe *pRecipe, int64_t ContainerID,
+ const BackupStoreFilename &rStoreFilename,
+ int64_t *pModificationTime,
+ ReadLoggingStream::Logger* pLogger = NULL,
+ RunStatusProvider* pRunStatusProvider = NULL);
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout);
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+private:
+ enum
+ {
+ Status_Header = 0,
+ Status_Blocks = 1,
+ Status_BlockListing = 2,
+ Status_Finished = 3
+ };
+
+private:
+ void EncodeCurrentBlock();
+ void CalculateBlockSizes(int64_t DataSize, int64_t &rNumBlocksOut, int32_t &rBlockSizeOut, int32_t &rLastBlockSizeOut);
+ void SkipPreviousBlocksInInstruction();
+ void SetForInstruction();
+ void StoreBlockIndexEntry(int64_t WncSizeOrBlkIndex, int32_t ClearSize, uint32_t WeakChecksum, uint8_t *pStrongChecksum);
+
+private:
+ Recipe *mpRecipe;
+ IOStream *mpFile; // source file
+ CollectInBufferStream mData; // buffer for header and index entries
+ IOStream *mpLogging;
+ RunStatusProvider* mpRunStatusProvider;
+ int mStatus;
+ bool mSendData; // true if there's file data to send (ie not a symlink)
+ int64_t mTotalBlocks; // Total number of blocks in the file
+ int64_t mAbsoluteBlockNumber; // The absolute block number currently being output
+ // Instruction number
+ int64_t mInstructionNumber;
+ // All the below are within the current instruction
+ int64_t mNumBlocks; // number of blocks. Last one will be a different size to the rest in most cases
+ int64_t mCurrentBlock;
+ int32_t mCurrentBlockEncodedSize;
+ int32_t mPositionInCurrentBlock; // for reading out
+ int32_t mBlockSize; // Basic block size of most of the blocks in the file
+ int32_t mLastBlockSize; // the size (unencoded) of the last block in the file
+ // Buffers
+ uint8_t *mpRawBuffer; // buffer for raw data
+ BackupStoreFile::EncodingBuffer mEncodedBuffer;
+ // buffer for encoded data
+ int32_t mAllocatedBufferSize; // size of above two allocated blocks
+ uint64_t mEntryIVBase; // base for block entry IV
+};
+
+
+
+#endif // BACKUPSTOREFILEENCODESTREAM__H
+
diff --git a/lib/backupclient/BackupStoreFileRevDiff.cpp b/lib/backupclient/BackupStoreFileRevDiff.cpp
new file mode 100644
index 00000000..509eef61
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileRevDiff.cpp
@@ -0,0 +1,258 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileRevDiff.cpp
+// Purpose: Reverse a patch, to build a new patch from new to old files
+// Created: 12/7/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <new>
+#include <stdlib.h>
+
+#include "BackupStoreFile.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreObjectMagic.h"
+#include "BackupStoreException.h"
+#include "BackupStoreConstants.h"
+#include "BackupStoreFilename.h"
+
+#include "MemLeakFindOn.h"
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFile::ReverseDiffFile(IOStream &, IOStream &, IOStream &, IOStream &, int64_t)
+// Purpose: Reverse a patch, to build a new patch from new to old files. Takes
+// two independent copies to the From file, for efficiency.
+// Created: 12/7/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFile::ReverseDiffFile(IOStream &rDiff, IOStream &rFrom, IOStream &rFrom2, IOStream &rOut, int64_t ObjectIDOfFrom, bool *pIsCompletelyDifferent)
+{
+ // Read and copy the header from the from file to the out file -- beginnings of the patch
+ file_StreamFormat hdr;
+ if(!rFrom.ReadFullBuffer(&hdr, sizeof(hdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ if(ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+ // Copy
+ rOut.Write(&hdr, sizeof(hdr));
+ // Copy over filename and attributes
+ // BLOCK
+ {
+ BackupStoreFilename filename;
+ filename.ReadFromStream(rFrom, IOStream::TimeOutInfinite);
+ filename.WriteToStream(rOut);
+ StreamableMemBlock attr;
+ attr.ReadFromStream(rFrom, IOStream::TimeOutInfinite);
+ attr.WriteToStream(rOut);
+ }
+
+ // Build an index of common blocks.
+ // For each block in the from file, we want to know it's index in the
+ // diff file. Allocate memory for this information.
+ int64_t fromNumBlocks = box_ntoh64(hdr.mNumBlocks);
+ int64_t *pfromIndexInfo = (int64_t*)::malloc(fromNumBlocks * sizeof(int64_t));
+ if(pfromIndexInfo == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ // Buffer data
+ void *buffer = 0;
+ int bufferSize = 0;
+
+ // flag
+ bool isCompletelyDifferent = true;
+
+ try
+ {
+ // Initialise the index to be all 0, ie not filled in yet
+ for(int64_t i = 0; i < fromNumBlocks; ++i)
+ {
+ pfromIndexInfo[i] = 0;
+ }
+
+ // Within the from file, skip to the index
+ MoveStreamPositionToBlockIndex(rDiff);
+
+ // Read in header of index
+ file_BlockIndexHeader diffIdxHdr;
+ if(!rDiff.ReadFullBuffer(&diffIdxHdr, sizeof(diffIdxHdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+ if(ntohl(diffIdxHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // And then read in each entry
+ int64_t diffNumBlocks = box_ntoh64(diffIdxHdr.mNumBlocks);
+ for(int64_t b = 0; b < diffNumBlocks; ++b)
+ {
+ file_BlockIndexEntry e;
+ if(!rDiff.ReadFullBuffer(&e, sizeof(e), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Where's the block?
+ int64_t blockEn = box_ntoh64(e.mEncodedSize);
+ if(blockEn > 0)
+ {
+ // Block is in the delta file, is ignored for now -- not relevant to rebuilding the from file
+ }
+ else
+ {
+ // Block is in the original file, store which block it is in this file
+ int64_t fromIndex = 0 - blockEn;
+ if(fromIndex < 0 || fromIndex >= fromNumBlocks)
+ {
+ THROW_EXCEPTION(BackupStoreException, IncompatibleFromAndDiffFiles)
+ }
+
+ // Store information about where it is in the new file
+ // NOTE: This is slight different to how it'll be stored in the final index.
+ pfromIndexInfo[fromIndex] = -1 - b;
+ }
+ }
+
+ // Open the index for the second copy of the from file
+ MoveStreamPositionToBlockIndex(rFrom2);
+
+ // Read in header of index
+ file_BlockIndexHeader fromIdxHdr;
+ if(!rFrom2.ReadFullBuffer(&fromIdxHdr, sizeof(fromIdxHdr), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+ if(ntohl(fromIdxHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1
+ || box_ntoh64(fromIdxHdr.mOtherFileID) != 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // So, we can now start building the data in the file
+ int64_t filePosition = rFrom.GetPosition();
+ for(int64_t b = 0; b < fromNumBlocks; ++b)
+ {
+ // Read entry from from index
+ file_BlockIndexEntry e;
+ if(!rFrom2.ReadFullBuffer(&e, sizeof(e), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Get size
+ int64_t blockSize = box_hton64(e.mEncodedSize);
+ if(blockSize < 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
+ }
+
+ // Copy this block?
+ if(pfromIndexInfo[b] == 0)
+ {
+ // Copy it, first move to file location
+ rFrom.Seek(filePosition, IOStream::SeekType_Absolute);
+
+ // Make sure there's memory available to copy this
+ if(bufferSize < blockSize || buffer == 0)
+ {
+ // Free old block
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ buffer = 0;
+ bufferSize = 0;
+ }
+ // Allocate new block
+ buffer = ::malloc(blockSize);
+ if(buffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+ bufferSize = blockSize;
+ }
+ ASSERT(bufferSize >= blockSize);
+
+ // Copy the block
+ if(!rFrom.ReadFullBuffer(buffer, blockSize, 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
+ }
+ rOut.Write(buffer, blockSize);
+
+ // Store the size
+ pfromIndexInfo[b] = blockSize;
+ }
+ else
+ {
+ // Block isn't needed, so it's not completely different
+ isCompletelyDifferent = false;
+ }
+ filePosition += blockSize;
+ }
+
+ // Then write the index, modified header first
+ fromIdxHdr.mOtherFileID = isCompletelyDifferent?0:(box_hton64(ObjectIDOfFrom));
+ rOut.Write(&fromIdxHdr, sizeof(fromIdxHdr));
+
+ // Move to start of index entries
+ rFrom.Seek(filePosition + sizeof(file_BlockIndexHeader), IOStream::SeekType_Absolute);
+
+ // Then copy modified entries
+ for(int64_t b = 0; b < fromNumBlocks; ++b)
+ {
+ // Read entry from from index
+ file_BlockIndexEntry e;
+ if(!rFrom.ReadFullBuffer(&e, sizeof(e), 0))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // Modify...
+ int64_t s = pfromIndexInfo[b];
+ // Adjust to reflect real block index (remember 0 has a different meaning here)
+ if(s < 0) ++s;
+ // Insert
+ e.mEncodedSize = box_hton64(s);
+ // Write
+ rOut.Write(&e, sizeof(e));
+ }
+ }
+ catch(...)
+ {
+ ::free(pfromIndexInfo);
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ }
+ throw;
+ }
+
+ // Free memory used (oh for finally {} blocks)
+ ::free(pfromIndexInfo);
+ if(buffer != 0)
+ {
+ ::free(buffer);
+ }
+
+ // return completely different flag
+ if(pIsCompletelyDifferent != 0)
+ {
+ *pIsCompletelyDifferent = isCompletelyDifferent;
+ }
+}
+
+
+
diff --git a/lib/backupclient/BackupStoreFileWire.h b/lib/backupclient/BackupStoreFileWire.h
new file mode 100644
index 00000000..49e94aa5
--- /dev/null
+++ b/lib/backupclient/BackupStoreFileWire.h
@@ -0,0 +1,74 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFileWire.h
+// Purpose: On the wire / disc formats for backup store files
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREFILEWIRE__H
+#define BACKUPSTOREFILEWIRE__H
+
+#include "MD5Digest.h"
+
+// set packing to one byte
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "BeginStructPackForWire.h"
+#else
+BEGIN_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
+typedef struct
+{
+ int32_t mMagicValue; // also the version number
+ int64_t mNumBlocks; // number of blocks contained in the file
+ int64_t mContainerID;
+ int64_t mModificationTime;
+ int32_t mMaxBlockClearSize; // Maximum clear size that can be expected for a block
+ int32_t mOptions; // bitmask of options used
+ // Then a BackupStoreFilename
+ // Then a BackupClientFileAttributes
+} file_StreamFormat;
+
+typedef struct
+{
+ int32_t mMagicValue; // different magic value
+ int64_t mOtherFileID; // the file ID of the 'other' file which may be referenced by the index
+ uint64_t mEntryIVBase; // base value for block IV
+ int64_t mNumBlocks; // repeat of value in file header
+} file_BlockIndexHeader;
+
+typedef struct
+{
+ int32_t mSize; // size in clear
+ uint32_t mWeakChecksum; // weak, rolling checksum
+ uint8_t mStrongChecksum[MD5Digest::DigestLength]; // strong digest based checksum
+} file_BlockIndexEntryEnc;
+
+typedef struct
+{
+ union
+ {
+ int64_t mEncodedSize; // size encoded, if > 0
+ int64_t mOtherBlockIndex; // 0 - block number in other file, if <= 0
+ };
+ uint8_t mEnEnc[sizeof(file_BlockIndexEntryEnc)]; // Encoded section
+} file_BlockIndexEntry;
+
+// Use default packing
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "EndStructPackForWire.h"
+#else
+END_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
+// header for blocks of compressed data in files
+#define HEADER_CHUNK_IS_COMPRESSED 1 // bit
+#define HEADER_ENCODING_SHIFT 1 // shift value
+#define HEADER_BLOWFISH_ENCODING 1 // value stored in bits 1 -- 7
+#define HEADER_AES_ENCODING 2 // value stored in bits 1 -- 7
+
+
+#endif // BACKUPSTOREFILEWIRE__H
+
diff --git a/lib/backupclient/BackupStoreFilename.cpp b/lib/backupclient/BackupStoreFilename.cpp
new file mode 100644
index 00000000..72cd1acd
--- /dev/null
+++ b/lib/backupclient/BackupStoreFilename.cpp
@@ -0,0 +1,281 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFilename.cpp
+// Purpose: Filename for the backup store
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "BackupStoreFilename.h"
+#include "Protocol.h"
+#include "BackupStoreException.h"
+#include "IOStream.h"
+#include "Guards.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::BackupStoreFilename()
+// Purpose: Default constructor -- creates an invalid filename
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreFilename::BackupStoreFilename()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::BackupStoreFilename(const BackupStoreFilename &)
+// Purpose: Copy constructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreFilename::BackupStoreFilename(const BackupStoreFilename &rToCopy)
+ : mEncryptedName(rToCopy.mEncryptedName)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::~BackupStoreFilename()
+// Purpose: Destructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreFilename::~BackupStoreFilename()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::CheckValid(bool)
+// Purpose: Checks the encoded filename for validity
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFilename::CheckValid(bool ExceptionIfInvalid) const
+{
+ bool ok = true;
+
+ if(mEncryptedName.size() < 2)
+ {
+ // Isn't long enough to have a header
+ ok = false;
+ }
+ else
+ {
+ // Check size is consistent
+ unsigned int dsize = BACKUPSTOREFILENAME_GET_SIZE(this->mEncryptedName);
+ if(dsize != mEncryptedName.size())
+ {
+ ok = false;
+ }
+
+ // And encoding is an accepted value
+ unsigned int encoding = BACKUPSTOREFILENAME_GET_ENCODING(this->mEncryptedName);
+ if(encoding < Encoding_Min || encoding > Encoding_Max)
+ {
+ ok = false;
+ }
+ }
+
+ // Exception?
+ if(!ok && ExceptionIfInvalid)
+ {
+ THROW_EXCEPTION(BackupStoreException, InvalidBackupStoreFilename)
+ }
+
+ return ok;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::ReadFromProtocol(Protocol &)
+// Purpose: Reads the filename from the protocol object
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilename::ReadFromProtocol(Protocol &rProtocol)
+{
+ // Read the header
+ char hdr[2];
+ rProtocol.Read(hdr, 2);
+
+ // How big is it?
+ int dsize = BACKUPSTOREFILENAME_GET_SIZE(hdr);
+
+ // Fetch rest of data, relying on the Protocol to error on stupidly large sizes for us
+ std::string data;
+ rProtocol.Read(data, dsize - 2);
+
+ // assign to this string, storing the header and the extra data
+ mEncryptedName.assign(hdr, 2);
+ mEncryptedName.append(data.c_str(), data.size());
+
+ // Check it
+ CheckValid();
+
+ // Alert derived classes
+ EncodedFilenameChanged();
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::WriteToProtocol(Protocol &)
+// Purpose: Writes the filename to the protocol object
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilename::WriteToProtocol(Protocol &rProtocol) const
+{
+ CheckValid();
+
+ rProtocol.Write(mEncryptedName.c_str(), mEncryptedName.size());
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::ReadFromStream(IOStream &)
+// Purpose: Reads the filename from a stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilename::ReadFromStream(IOStream &rStream, int Timeout)
+{
+ // Read the header
+ char hdr[2];
+ if(!rStream.ReadFullBuffer(hdr, 2, 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+
+ // How big is it?
+ unsigned int dsize = BACKUPSTOREFILENAME_GET_SIZE(hdr);
+
+ // Assume most filenames are small
+ char buf[256];
+ if(dsize < sizeof(buf))
+ {
+ // Fetch rest of data, relying on the Protocol to error on stupidly large sizes for us
+ if(!rStream.ReadFullBuffer(buf + 2, dsize - 2, 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+ // Copy in header
+ buf[0] = hdr[0]; buf[1] = hdr[1];
+
+ // assign to this string, storing the header and the extra data
+ mEncryptedName.assign(buf, dsize);
+ }
+ else
+ {
+ // Block of memory to hold it
+ MemoryBlockGuard<char*> dataB(dsize+2);
+ char *data = dataB;
+
+ // Fetch rest of data, relying on the Protocol to error on stupidly large sizes for us
+ if(!rStream.ReadFullBuffer(data + 2, dsize - 2, 0 /* not interested in bytes read if this fails */, Timeout))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
+ }
+ // Copy in header
+ data[0] = hdr[0]; data[1] = hdr[1];
+
+ // assign to this string, storing the header and the extra data
+ mEncryptedName.assign(data, dsize);
+ }
+
+ // Check it
+ CheckValid();
+
+ // Alert derived classes
+ EncodedFilenameChanged();
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::WriteToStream(IOStream &)
+// Purpose: Writes the filename to a stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilename::WriteToStream(IOStream &rStream) const
+{
+ CheckValid();
+
+ rStream.Write(mEncryptedName.c_str(), mEncryptedName.size());
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::EncodedFilenameChanged()
+// Purpose: The encoded filename stored has changed
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilename::EncodedFilenameChanged()
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::IsEncrypted()
+// Purpose: Returns true if the filename is stored using an encrypting encoding
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+bool BackupStoreFilename::IsEncrypted() const
+{
+ return BACKUPSTOREFILENAME_GET_ENCODING(this->mEncryptedName) !=
+ Encoding_Clear;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilename::SetAsClearFilename(const char *)
+// Purpose: Sets this object to be a valid filename, but with a
+// filename in the clear. Used on the server to create
+// filenames when there's no way of encrypting it.
+// Created: 22/4/04
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilename::SetAsClearFilename(const char *Clear)
+{
+ // Make std::string from the clear name
+ std::string toEncode(Clear);
+
+ // Make an encoded string
+ char hdr[2];
+ BACKUPSTOREFILENAME_MAKE_HDR(hdr, toEncode.size()+2, Encoding_Clear);
+ std::string encoded(hdr, 2);
+ encoded += toEncode;
+ ASSERT(encoded.size() == toEncode.size() + 2);
+
+ // Store the encoded string
+ mEncryptedName.assign(encoded);
+
+ // Stuff which must be done
+ EncodedFilenameChanged();
+ CheckValid(false);
+}
+
+
+
diff --git a/lib/backupclient/BackupStoreFilename.h b/lib/backupclient/BackupStoreFilename.h
new file mode 100644
index 00000000..80db9516
--- /dev/null
+++ b/lib/backupclient/BackupStoreFilename.h
@@ -0,0 +1,107 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFilename.h
+// Purpose: Filename for the backup store
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREFILENAME__H
+#define BACKUPSTOREFILENAME__H
+
+#include <string>
+
+class Protocol;
+class IOStream;
+
+// #define BACKUPSTOREFILEAME_MALLOC_ALLOC_BASE_TYPE
+// don't define this -- the problem of memory usage still appears without this.
+// It's just that this class really showed up the problem. Instead, malloc allocation
+// is globally defined in BoxPlatform.h, for troublesome libraries.
+
+#ifdef BACKUPSTOREFILEAME_MALLOC_ALLOC_BASE_TYPE
+ // Use a malloc_allocated string, because the STL default allocators really screw up with
+ // memory allocation, particularly with this class.
+ // Makes a few things a bit messy and inefficient with conversions.
+ // Given up using this, and use global malloc allocation instead, but thought it
+ // worth leaving this code in just in case it's useful for the future.
+ typedef std::basic_string<char, std::string_char_traits<char>, std::malloc_alloc> BackupStoreFilename_base;
+ // If this is changed, change GetClearFilename() back to returning a reference.
+#else
+ typedef std::string BackupStoreFilename_base;
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: BackupStoreFilename
+// Purpose: Filename for the backup store
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+class BackupStoreFilename /* : public BackupStoreFilename_base */
+{
+private:
+ std::string mEncryptedName;
+
+public:
+ BackupStoreFilename();
+ BackupStoreFilename(const BackupStoreFilename &rToCopy);
+ virtual ~BackupStoreFilename();
+
+ bool CheckValid(bool ExceptionIfInvalid = true) const;
+
+ void ReadFromProtocol(Protocol &rProtocol);
+ void WriteToProtocol(Protocol &rProtocol) const;
+
+ void ReadFromStream(IOStream &rStream, int Timeout);
+ void WriteToStream(IOStream &rStream) const;
+
+ void SetAsClearFilename(const char *Clear);
+
+ // Check that it's encrypted
+ bool IsEncrypted() const;
+
+ // These enumerated types belong in the base class so
+ // the CheckValid() function can make sure that the encoding
+ // is a valid encoding
+ enum
+ {
+ Encoding_Min = 1,
+ Encoding_Clear = 1,
+ Encoding_Blowfish = 2,
+ Encoding_Max = 2
+ };
+
+ const std::string& GetEncodedFilename() const
+ {
+ return mEncryptedName;
+ }
+
+ bool operator==(const BackupStoreFilename& rOther) const
+ {
+ return mEncryptedName == rOther.mEncryptedName;
+ }
+
+ bool operator!=(const BackupStoreFilename& rOther) const
+ {
+ return mEncryptedName != rOther.mEncryptedName;
+ }
+
+protected:
+ virtual void EncodedFilenameChanged();
+ void SetEncodedFilename(const std::string &rEncoded)
+ {
+ mEncryptedName = rEncoded;
+ }
+};
+
+// On the wire utilities for class and derived class
+#define BACKUPSTOREFILENAME_GET_SIZE(hdr) (( ((uint8_t)((hdr)[0])) | ( ((uint8_t)((hdr)[1])) << 8)) >> 2)
+#define BACKUPSTOREFILENAME_GET_ENCODING(hdr) (((hdr)[0]) & 0x3)
+
+#define BACKUPSTOREFILENAME_MAKE_HDR(hdr, size, encoding) {uint16_t h = (((uint16_t)size) << 2) | (encoding); ((hdr)[0]) = h & 0xff; ((hdr)[1]) = h >> 8;}
+
+#endif // BACKUPSTOREFILENAME__H
+
diff --git a/lib/backupclient/BackupStoreFilenameClear.cpp b/lib/backupclient/BackupStoreFilenameClear.cpp
new file mode 100644
index 00000000..e529d8d3
--- /dev/null
+++ b/lib/backupclient/BackupStoreFilenameClear.cpp
@@ -0,0 +1,335 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFilenameClear.cpp
+// Purpose: BackupStoreFilenames in the clear
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "BackupStoreFilenameClear.h"
+#include "BackupStoreException.h"
+#include "CipherContext.h"
+#include "CipherBlowfish.h"
+#include "Guards.h"
+#include "Logging.h"
+
+#include "MemLeakFindOn.h"
+
+// Hide private variables from the rest of the world
+namespace
+{
+ int sEncodeMethod = BackupStoreFilename::Encoding_Clear;
+ CipherContext sBlowfishEncrypt;
+ CipherContext sBlowfishDecrypt;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::BackupStoreFilenameClear()
+// Purpose: Default constructor, creates an invalid filename
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreFilenameClear::BackupStoreFilenameClear()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::BackupStoreFilenameClear(const std::string &)
+// Purpose: Creates a filename, encoding from the given string
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreFilenameClear::BackupStoreFilenameClear(const std::string &rToEncode)
+{
+ SetClearFilename(rToEncode);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::BackupStoreFilenameClear(const BackupStoreFilenameClear &)
+// Purpose: Copy constructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreFilenameClear::BackupStoreFilenameClear(const BackupStoreFilenameClear &rToCopy)
+ : BackupStoreFilename(rToCopy),
+ mClearFilename(rToCopy.mClearFilename)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::BackupStoreFilenameClear(const BackupStoreFilename &rToCopy)
+// Purpose: Copy from base class
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreFilenameClear::BackupStoreFilenameClear(const BackupStoreFilename &rToCopy)
+ : BackupStoreFilename(rToCopy)
+{
+ // Will get a clear filename when it's required
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::~BackupStoreFilenameClear()
+// Purpose: Destructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+BackupStoreFilenameClear::~BackupStoreFilenameClear()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::GetClearFilename()
+// Purpose: Get the unencoded filename
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+#ifdef BACKUPSTOREFILEAME_MALLOC_ALLOC_BASE_TYPE
+const std::string BackupStoreFilenameClear::GetClearFilename() const
+{
+ MakeClearAvailable();
+ // When modifying, remember to change back to reference return if at all possible
+ // -- returns an object rather than a reference to allow easy use with other code.
+ return std::string(mClearFilename.c_str(), mClearFilename.size());
+}
+#else
+const std::string &BackupStoreFilenameClear::GetClearFilename() const
+{
+ MakeClearAvailable();
+ return mClearFilename;
+}
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::SetClearFilename(const std::string &)
+// Purpose: Encode and make available the clear filename
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilenameClear::SetClearFilename(const std::string &rToEncode)
+{
+ // Only allow Blowfish encodings
+ if(sEncodeMethod != Encoding_Blowfish)
+ {
+ THROW_EXCEPTION(BackupStoreException, FilenameEncryptionNotSetup)
+ }
+
+ // Make an encoded string with blowfish encryption
+ EncryptClear(rToEncode, sBlowfishEncrypt, Encoding_Blowfish);
+
+ // Store the clear filename
+ mClearFilename.assign(rToEncode.c_str(), rToEncode.size());
+
+ // Make sure we did the right thing
+ if(!CheckValid(false))
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::MakeClearAvailable()
+// Purpose: Private. Make sure the clear filename is available
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilenameClear::MakeClearAvailable() const
+{
+ if(!mClearFilename.empty())
+ return; // nothing to do
+
+ // Check valid
+ CheckValid();
+
+ // Decode the header
+ int size = BACKUPSTOREFILENAME_GET_SIZE(GetEncodedFilename());
+ int encoding = BACKUPSTOREFILENAME_GET_ENCODING(GetEncodedFilename());
+
+ // Decode based on encoding given in the header
+ switch(encoding)
+ {
+ case Encoding_Clear:
+ BOX_TRACE("**** BackupStoreFilename encoded with "
+ "Clear encoding ****");
+ mClearFilename.assign(GetEncodedFilename().c_str() + 2,
+ size - 2);
+ break;
+
+ case Encoding_Blowfish:
+ DecryptEncoded(sBlowfishDecrypt);
+ break;
+
+ default:
+ THROW_EXCEPTION(BackupStoreException, UnknownFilenameEncoding)
+ break;
+ }
+}
+
+
+// Buffer for encoding and decoding -- do this all in one single buffer to
+// avoid lots of string allocation, which stuffs up memory usage.
+// These static memory vars are, of course, not thread safe, but we don't use threads.
+static int sEncDecBufferSize = 0;
+static MemoryBlockGuard<uint8_t *> *spEncDecBuffer = 0;
+
+static void EnsureEncDecBufferSize(int BufSize)
+{
+ if(spEncDecBuffer == 0)
+ {
+#ifndef WIN32
+ BOX_TRACE("Allocating filename encoding/decoding buffer "
+ "with size " << BufSize);
+#endif
+ spEncDecBuffer = new MemoryBlockGuard<uint8_t *>(BufSize);
+ MEMLEAKFINDER_NOT_A_LEAK(spEncDecBuffer);
+ MEMLEAKFINDER_NOT_A_LEAK(*spEncDecBuffer);
+ sEncDecBufferSize = BufSize;
+ }
+ else
+ {
+ if(sEncDecBufferSize < BufSize)
+ {
+ BOX_TRACE("Reallocating filename encoding/decoding "
+ "buffer from " << sEncDecBufferSize <<
+ " to " << BufSize);
+ spEncDecBuffer->Resize(BufSize);
+ sEncDecBufferSize = BufSize;
+ MEMLEAKFINDER_NOT_A_LEAK(*spEncDecBuffer);
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::EncryptClear(const std::string &, CipherContext &, int)
+// Purpose: Private. Assigns the encoded filename string, encrypting.
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilenameClear::EncryptClear(const std::string &rToEncode, CipherContext &rCipherContext, int StoreAsEncoding)
+{
+ // Work out max size
+ int maxOutSize = rCipherContext.MaxOutSizeForInBufferSize(rToEncode.size()) + 4;
+
+ // Make sure encode/decode buffer has enough space
+ EnsureEncDecBufferSize(maxOutSize);
+
+ // Pointer to buffer
+ uint8_t *buffer = *spEncDecBuffer;
+
+ // Encode -- do entire block in one go
+ int encSize = rCipherContext.TransformBlock(buffer + 2, sEncDecBufferSize - 2, rToEncode.c_str(), rToEncode.size());
+ // and add in header size
+ encSize += 2;
+
+ // Adjust header
+ BACKUPSTOREFILENAME_MAKE_HDR(buffer, encSize, StoreAsEncoding);
+
+ // Store the encoded string
+ SetEncodedFilename(std::string((char*)buffer, encSize));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::DecryptEncoded(CipherContext &)
+// Purpose: Decrypt the encoded filename using the cipher context
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilenameClear::DecryptEncoded(CipherContext &rCipherContext) const
+{
+ const std::string& rEncoded = GetEncodedFilename();
+
+ // Work out max size
+ int maxOutSize = rCipherContext.MaxOutSizeForInBufferSize(rEncoded.size()) + 4;
+
+ // Make sure encode/decode buffer has enough space
+ EnsureEncDecBufferSize(maxOutSize);
+
+ // Pointer to buffer
+ uint8_t *buffer = *spEncDecBuffer;
+
+ // Decrypt
+ const char *str = rEncoded.c_str() + 2;
+ int sizeOut = rCipherContext.TransformBlock(buffer, sEncDecBufferSize, str, rEncoded.size() - 2);
+
+ // Assign to this
+ mClearFilename.assign((char*)buffer, sizeOut);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::EncodedFilenameChanged()
+// Purpose: The encoded filename stored has changed
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilenameClear::EncodedFilenameChanged()
+{
+ BackupStoreFilename::EncodedFilenameChanged();
+
+ // Delete stored filename in clear
+ mClearFilename.erase();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::SetBlowfishKey(const void *, int)
+// Purpose: Set the key used for Blowfish encryption of filenames
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilenameClear::SetBlowfishKey(const void *pKey, int KeyLength, const void *pIV, int IVLength)
+{
+ // Initialisation vector not used. Can't use a different vector for each filename as
+ // that would stop comparisions on the server working.
+ sBlowfishEncrypt.Reset();
+ sBlowfishEncrypt.Init(CipherContext::Encrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength));
+ ASSERT(sBlowfishEncrypt.GetIVLength() == IVLength);
+ sBlowfishEncrypt.SetIV(pIV);
+ sBlowfishDecrypt.Reset();
+ sBlowfishDecrypt.Init(CipherContext::Decrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength));
+ ASSERT(sBlowfishDecrypt.GetIVLength() == IVLength);
+ sBlowfishDecrypt.SetIV(pIV);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreFilenameClear::SetEncodingMethod(int)
+// Purpose: Set the encoding method used for filenames
+// Created: 1/12/03
+//
+// --------------------------------------------------------------------------
+void BackupStoreFilenameClear::SetEncodingMethod(int Method)
+{
+ sEncodeMethod = Method;
+}
+
+
+
diff --git a/lib/backupclient/BackupStoreFilenameClear.h b/lib/backupclient/BackupStoreFilenameClear.h
new file mode 100644
index 00000000..d4c45701
--- /dev/null
+++ b/lib/backupclient/BackupStoreFilenameClear.h
@@ -0,0 +1,60 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreFilenameClear.h
+// Purpose: BackupStoreFilenames in the clear
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREFILENAMECLEAR__H
+#define BACKUPSTOREFILENAMECLEAR__H
+
+#include "BackupStoreFilename.h"
+
+class CipherContext;
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: BackupStoreFilenameClear
+// Purpose: BackupStoreFilenames, handling conversion from and to the in the clear version
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+class BackupStoreFilenameClear : public BackupStoreFilename
+{
+public:
+ BackupStoreFilenameClear();
+ BackupStoreFilenameClear(const std::string &rToEncode);
+ BackupStoreFilenameClear(const BackupStoreFilenameClear &rToCopy);
+ BackupStoreFilenameClear(const BackupStoreFilename &rToCopy);
+ virtual ~BackupStoreFilenameClear();
+
+ // Because we need to use a different allocator for this class to avoid
+ // nasty things happening, can't return this as a reference. Which is a
+ // pity. But probably not too bad.
+#ifdef BACKUPSTOREFILEAME_MALLOC_ALLOC_BASE_TYPE
+ const std::string GetClearFilename() const;
+#else
+ const std::string &GetClearFilename() const;
+#endif
+ void SetClearFilename(const std::string &rToEncode);
+
+ // Setup for encryption of filenames
+ static void SetBlowfishKey(const void *pKey, int KeyLength, const void *pIV, int IVLength);
+ static void SetEncodingMethod(int Method);
+
+protected:
+ void MakeClearAvailable() const;
+ virtual void EncodedFilenameChanged();
+ void EncryptClear(const std::string &rToEncode, CipherContext &rCipherContext, int StoreAsEncoding);
+ void DecryptEncoded(CipherContext &rCipherContext) const;
+
+private:
+ mutable BackupStoreFilename_base mClearFilename;
+};
+
+#endif // BACKUPSTOREFILENAMECLEAR__H
+
+
diff --git a/lib/backupclient/BackupStoreObjectMagic.h b/lib/backupclient/BackupStoreObjectMagic.h
new file mode 100644
index 00000000..7ee600a2
--- /dev/null
+++ b/lib/backupclient/BackupStoreObjectMagic.h
@@ -0,0 +1,31 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BackupStoreObjectMagic.h
+// Purpose: Magic values for the start of objects in the backup store
+// Created: 19/11/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef BACKUPSTOREOBJECTMAGIC__H
+#define BACKUPSTOREOBJECTMAGIC__H
+
+// Each of these values is the first 4 bytes of the object file.
+// Remember to swap from network to host byte order.
+
+// Magic value for file streams
+#define OBJECTMAGIC_FILE_MAGIC_VALUE_V1 0x66696C65
+// Do not use v0 in any new code!
+#define OBJECTMAGIC_FILE_MAGIC_VALUE_V0 0x46494C45
+
+// Magic for the block index at the file stream -- used to
+// ensure streams are reordered as expected
+#define OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1 0x62696478
+// Do not use v0 in any new code!
+#define OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V0 0x46426C6B
+
+// Magic value for directory streams
+#define OBJECTMAGIC_DIR_MAGIC_VALUE 0x4449525F
+
+#endif // BACKUPSTOREOBJECTMAGIC__H
+
diff --git a/lib/backupclient/Makefile.extra b/lib/backupclient/Makefile.extra
new file mode 100644
index 00000000..df3319df
--- /dev/null
+++ b/lib/backupclient/Makefile.extra
@@ -0,0 +1,16 @@
+
+MAKEPROTOCOL = ../../lib/server/makeprotocol.pl
+
+GEN_CMD_SRV = $(MAKEPROTOCOL) Client ../../bin/bbstored/backupprotocol.txt
+
+# AUTOGEN SEEDING
+autogen_BackupProtocolClient.cpp autogen_BackupProtocolClient.h: $(MAKEPROTOCOL) ../../bin/bbstored/backupprotocol.txt
+ $(_PERL) $(GEN_CMD_SRV)
+
+
+MAKEEXCEPTION = ../../lib/common/makeexception.pl
+
+# AUTOGEN SEEDING
+autogen_BackupStoreException.h autogen_BackupStoreException.cpp: $(MAKEEXCEPTION) BackupStoreException.txt
+ $(_PERL) $(MAKEEXCEPTION) BackupStoreException.txt
+
diff --git a/lib/backupclient/RunStatusProvider.h b/lib/backupclient/RunStatusProvider.h
new file mode 100644
index 00000000..89f361ca
--- /dev/null
+++ b/lib/backupclient/RunStatusProvider.h
@@ -0,0 +1,29 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: RunStatusProvider.h
+// Purpose: Declares the RunStatusProvider interface.
+// Created: 2008/08/14
+//
+// --------------------------------------------------------------------------
+
+#ifndef RUNSTATUSPROVIDER__H
+#define RUNSTATUSPROVIDER__H
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: RunStatusProvider
+// Purpose: Provides a StopRun() method which returns true if
+// the current backup should be halted.
+// Created: 2005/11/15
+//
+// --------------------------------------------------------------------------
+class RunStatusProvider
+{
+ public:
+ virtual ~RunStatusProvider() { }
+ virtual bool StopRun() = 0;
+};
+
+#endif // RUNSTATUSPROVIDER__H
diff --git a/lib/backupstore/BackupStoreAccountDatabase.cpp b/lib/backupstore/BackupStoreAccountDatabase.cpp
index 201491a3..ec44de0e 100644
--- a/lib/backupstore/BackupStoreAccountDatabase.cpp
+++ b/lib/backupstore/BackupStoreAccountDatabase.cpp
@@ -40,7 +40,11 @@ public:
// Created: 2003/08/20
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+BackupStoreAccountDatabase::BackupStoreAccountDatabase(const char *Filename)
+=======
BackupStoreAccountDatabase::BackupStoreAccountDatabase(const std::string& Filename)
+>>>>>>> 0.12
: pImpl(new _BackupStoreAccountDatabase)
{
pImpl->mFilename = Filename;
@@ -123,7 +127,11 @@ BackupStoreAccountDatabase::Entry::~Entry()
// Created: 2003/08/21
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+std::auto_ptr<BackupStoreAccountDatabase> BackupStoreAccountDatabase::Read(const char *Filename)
+=======
std::auto_ptr<BackupStoreAccountDatabase> BackupStoreAccountDatabase::Read(const std::string& Filename)
+>>>>>>> 0.12
{
// Database object to use
std::auto_ptr<BackupStoreAccountDatabase> db(new BackupStoreAccountDatabase(Filename));
diff --git a/lib/backupstore/BackupStoreAccountDatabase.h b/lib/backupstore/BackupStoreAccountDatabase.h
index f9665c7d..cb19b01b 100644
--- a/lib/backupstore/BackupStoreAccountDatabase.h
+++ b/lib/backupstore/BackupStoreAccountDatabase.h
@@ -31,11 +31,19 @@ public:
friend class _BackupStoreAccountDatabase; // to stop compiler warnings
~BackupStoreAccountDatabase();
private:
+<<<<<<< HEAD
+ BackupStoreAccountDatabase(const char *Filename);
+ BackupStoreAccountDatabase(const BackupStoreAccountDatabase &);
+public:
+
+ static std::auto_ptr<BackupStoreAccountDatabase> Read(const char *Filename);
+=======
BackupStoreAccountDatabase(const std::string& Filename);
BackupStoreAccountDatabase(const BackupStoreAccountDatabase &);
public:
static std::auto_ptr<BackupStoreAccountDatabase> Read(const std::string& Filename);
+>>>>>>> 0.12
void Write();
class Entry
diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp
index 18500fc1..8cb23a6a 100644
--- a/lib/backupstore/BackupStoreAccounts.cpp
+++ b/lib/backupstore/BackupStoreAccounts.cpp
@@ -11,6 +11,16 @@
#include <stdio.h>
+<<<<<<< HEAD
+#include "BoxPortsAndFiles.h"
+#include "BackupStoreAccounts.h"
+#include "BackupStoreAccountDatabase.h"
+#include "BackupStoreRefCountDatabase.h"
+#include "RaidFileWrite.h"
+#include "BackupStoreInfo.h"
+#include "BackupStoreDirectory.h"
+#include "BackupStoreConstants.h"
+=======
#include "BackupStoreAccounts.h"
#include "BackupStoreAccountDatabase.h"
#include "BackupStoreConstants.h"
@@ -21,6 +31,7 @@
#include "BoxPortsAndFiles.h"
#include "RaidFileWrite.h"
#include "StoreStructure.h"
+>>>>>>> 0.12
#include "UnixUser.h"
#include "MemLeakFindOn.h"
@@ -57,8 +68,13 @@ BackupStoreAccounts::~BackupStoreAccounts()
// Function
// Name: BackupStoreAccounts::Create(int32_t, int, int64_t, int64_t, const std::string &)
// Purpose: Create a new account on the specified disc set.
+<<<<<<< HEAD
+// If rAsUsername is not empty, then the account information will be written under the
+// username specified.
+=======
// If rAsUsername is not empty, then the account information will be written under the
// username specified.
+>>>>>>> 0.12
// Created: 2003/08/21
//
// --------------------------------------------------------------------------
@@ -104,7 +120,10 @@ void BackupStoreAccounts::Create(int32_t ID, int DiscSet, int64_t SizeSoftLimit,
std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(ID, dirName, DiscSet, false /* ReadWrite */));
info->ChangeBlocksUsed(rootDirSize);
info->ChangeBlocksInDirectories(rootDirSize);
+<<<<<<< HEAD
+=======
info->AdjustNumDirectories(1);
+>>>>>>> 0.12
// Save it back
info->Save();
@@ -170,6 +189,9 @@ bool BackupStoreAccounts::AccountExists(int32_t ID)
return mrDatabase.EntryExists(ID);
}
+<<<<<<< HEAD
+
+=======
void BackupStoreAccounts::LockAccount(int32_t ID, NamedLock& rNamedLock)
{
const BackupStoreAccountDatabase::Entry &en(mrDatabase.GetEntry(ID));
@@ -201,3 +223,4 @@ void BackupStoreAccounts::LockAccount(int32_t ID, NamedLock& rNamedLock)
"lock on account " << ID);
}
}
+>>>>>>> 0.12
diff --git a/lib/backupstore/BackupStoreAccounts.h b/lib/backupstore/BackupStoreAccounts.h
index 3163f15c..e0e420bb 100644
--- a/lib/backupstore/BackupStoreAccounts.h
+++ b/lib/backupstore/BackupStoreAccounts.h
@@ -13,7 +13,10 @@
#include <string>
#include "BackupStoreAccountDatabase.h"
+<<<<<<< HEAD
+=======
#include "NamedLock.h"
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
@@ -32,8 +35,12 @@ private:
BackupStoreAccounts(const BackupStoreAccounts &rToCopy);
public:
+<<<<<<< HEAD
+ void Create(int32_t ID, int DiscSet, int64_t SizeSoftLimit, int64_t SizeHardLimit, const std::string &rAsUsername);
+=======
void Create(int32_t ID, int DiscSet, int64_t SizeSoftLimit,
int64_t SizeHardLimit, const std::string &rAsUsername);
+>>>>>>> 0.12
bool AccountExists(int32_t ID);
void GetAccountRoot(int32_t ID, std::string &rRootDirOut, int &rDiscSetOut) const;
@@ -42,7 +49,10 @@ public:
{
return MakeAccountRootDir(rEntry.GetID(), rEntry.GetDiscSet());
}
+<<<<<<< HEAD
+=======
void LockAccount(int32_t ID, NamedLock& rNamedLock);
+>>>>>>> 0.12
private:
static std::string MakeAccountRootDir(int32_t ID, int DiscSet);
diff --git a/lib/backupstore/BackupStoreCheck.cpp b/lib/backupstore/BackupStoreCheck.cpp
index f2302337..79a61a77 100644
--- a/lib/backupstore/BackupStoreCheck.cpp
+++ b/lib/backupstore/BackupStoreCheck.cpp
@@ -11,6 +11,19 @@
#include <stdio.h>
#include <string.h>
+<<<<<<< HEAD
+#include <unistd.h>
+
+#include "BackupStoreCheck.h"
+#include "StoreStructure.h"
+#include "RaidFileRead.h"
+#include "RaidFileWrite.h"
+#include "autogen_BackupStoreException.h"
+#include "BackupStoreObjectMagic.h"
+#include "BackupStoreFile.h"
+#include "BackupStoreDirectory.h"
+#include "BackupStoreConstants.h"
+=======
#ifdef HAVE_UNISTD_H
# include <unistd.h>
@@ -29,6 +42,7 @@
#include "RaidFileWrite.h"
#include "StoreStructure.h"
#include "Utils.h"
+>>>>>>> 0.12
#include "MemLeakFindOn.h"
@@ -54,6 +68,11 @@ BackupStoreCheck::BackupStoreCheck(const std::string &rStoreRoot, int DiscSetNum
mLostDirNameSerial(0),
mLostAndFoundDirectoryID(0),
mBlocksUsed(0),
+<<<<<<< HEAD
+ mBlocksInOldFiles(0),
+ mBlocksInDeletedFiles(0),
+ mBlocksInDirectories(0)
+=======
mBlocksInCurrentFiles(0),
mBlocksInOldFiles(0),
mBlocksInDeletedFiles(0),
@@ -62,6 +81,7 @@ BackupStoreCheck::BackupStoreCheck(const std::string &rStoreRoot, int DiscSetNum
mNumOldFiles(0),
mNumDeletedFiles(0),
mNumDirectories(0)
+>>>>>>> 0.12
{
}
@@ -85,16 +105,51 @@ BackupStoreCheck::~BackupStoreCheck()
//
// Function
// Name: BackupStoreCheck::Check()
+<<<<<<< HEAD
+// Purpose: Perform the check on the given account
+=======
// Purpose: Perform the check on the given account. You need to
// hold a lock on the account before calling this!
+>>>>>>> 0.12
// Created: 21/4/04
//
// --------------------------------------------------------------------------
void BackupStoreCheck::Check()
{
+<<<<<<< HEAD
+ // Lock the account
+ {
+ std::string writeLockFilename;
+ StoreStructure::MakeWriteLockFilename(mStoreRoot, mDiscSetNumber, writeLockFilename);
+
+ bool gotLock = false;
+ int triesLeft = 8;
+ do
+ {
+ gotLock = mAccountLock.TryAndGetLock(writeLockFilename.c_str(), 0600 /* restrictive file permissions */);
+
+ if(!gotLock)
+ {
+ --triesLeft;
+ ::sleep(1);
+ }
+ } while(!gotLock && triesLeft > 0);
+
+ if(!gotLock)
+ {
+ // Couldn't lock the account -- just stop now
+ if(!mQuiet)
+ {
+ BOX_ERROR("Failed to lock the account -- did not check.\nTry again later after the client has disconnected.\nAlternatively, forcibly kill the server.");
+ }
+ THROW_EXCEPTION(BackupStoreException, CouldNotLockStoreAccount)
+ }
+ }
+=======
std::string writeLockFilename;
StoreStructure::MakeWriteLockFilename(mStoreRoot, mDiscSetNumber, writeLockFilename);
ASSERT(FileExists(writeLockFilename));
+>>>>>>> 0.12
if(!mQuiet && mFixErrors)
{
@@ -284,6 +339,8 @@ int64_t BackupStoreCheck::CheckObjectsScanDir(int64_t StartID, int Level, const
// Read in all the directories, and recurse downwards
{
+<<<<<<< HEAD
+=======
// If any of the directories is missing, create it.
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mDiscSetNumber));
@@ -311,6 +368,7 @@ int64_t BackupStoreCheck::CheckObjectsScanDir(int64_t StartID, int Level, const
}
}
+>>>>>>> 0.12
std::vector<std::string> dirs;
RaidFileRead::ReadDirectoryContents(mDiscSetNumber, rDirName,
RaidFileRead::DirReadType_DirsOnly, dirs);
@@ -333,7 +391,11 @@ int64_t BackupStoreCheck::CheckObjectsScanDir(int64_t StartID, int Level, const
}
else
{
+<<<<<<< HEAD
+ BOX_WARNING("Spurious or invalid directory " <<
+=======
BOX_ERROR("Spurious or invalid directory " <<
+>>>>>>> 0.12
rDirName << DIRECTORY_SEPARATOR <<
(*i) << " found, " <<
(mFixErrors?"deleting":"delete manually"));
@@ -350,8 +412,12 @@ int64_t BackupStoreCheck::CheckObjectsScanDir(int64_t StartID, int Level, const
//
// Function
// Name: BackupStoreCheck::CheckObjectsDir(int64_t)
+<<<<<<< HEAD
+// Purpose: Check all the files within this directory which has the given starting ID.
+=======
// Purpose: Check all the files within this directory which has
// the given starting ID.
+>>>>>>> 0.12
// Created: 22/4/04
//
// --------------------------------------------------------------------------
@@ -399,6 +465,15 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
// Filename is valid, mark as existing
idsPresent[n] = true;
}
+<<<<<<< HEAD
+ else
+ {
+ // info file in root dir is OK!
+ if(StartID != 0 || ::strcmp("info", (*i).c_str()) != 0)
+ {
+ fileOK = false;
+ }
+=======
// No other files should be present in subdirectories
else if(StartID != 0)
{
@@ -412,12 +487,17 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
else
{
fileOK = false;
+>>>>>>> 0.12
}
if(!fileOK)
{
// Unexpected or bad file, delete it
+<<<<<<< HEAD
+ BOX_WARNING("Spurious file " << dirName <<
+=======
BOX_ERROR("Spurious file " << dirName <<
+>>>>>>> 0.12
DIRECTORY_SEPARATOR << (*i) << " found" <<
(mFixErrors?", deleting":""));
++mNumberErrorsFound;
@@ -440,7 +520,11 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
if(!CheckAndAddObject(StartID | i, dirName + leaf))
{
// File was bad, delete it
+<<<<<<< HEAD
+ BOX_WARNING("Corrupted file " << dirName <<
+=======
BOX_ERROR("Corrupted file " << dirName <<
+>>>>>>> 0.12
leaf << " found" <<
(mFixErrors?", deleting":""));
++mNumberErrorsFound;
@@ -458,6 +542,15 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+// Name: BackupStoreCheck::CheckAndAddObject(int64_t, const std::string &)
+// Purpose: Check a specific object and add it to the list if it's OK -- if
+// there are any errors with the reading, return false and it'll be deleted.
+// Created: 21/4/04
+//
+// --------------------------------------------------------------------------
+bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID, const std::string &rFilename)
+=======
// Name: BackupStoreCheck::CheckAndAddObject(int64_t,
// const std::string &)
// Purpose: Check a specific object and add it to the list
@@ -468,6 +561,7 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
// --------------------------------------------------------------------------
bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID,
const std::string &rFilename)
+>>>>>>> 0.12
{
// Info on object...
bool isFile = true;
@@ -477,12 +571,19 @@ bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID,
try
{
// Open file
+<<<<<<< HEAD
+ std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(mDiscSetNumber, rFilename));
+ size = file->GetDiscUsageInBlocks();
+
+ // Read in first four bytes -- don't have to worry about retrying if not all bytes read as is RaidFile
+=======
std::auto_ptr<RaidFileRead> file(
RaidFileRead::Open(mDiscSetNumber, rFilename));
size = file->GetDiscUsageInBlocks();
// Read in first four bytes -- don't have to worry about
// retrying if not all bytes read as is RaidFile
+>>>>>>> 0.12
uint32_t signature;
if(file->Read(&signature, sizeof(signature)) != sizeof(signature))
{
@@ -513,6 +614,16 @@ bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID,
return false;
break;
}
+<<<<<<< HEAD
+
+ // Add to usage counts
+ mBlocksUsed += size;
+ if(!isFile)
+ {
+ mBlocksInDirectories += size;
+ }
+=======
+>>>>>>> 0.12
}
catch(...)
{
@@ -525,6 +636,12 @@ bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID,
{
return false;
}
+<<<<<<< HEAD
+
+ // Add to list of IDs known about
+ AddID(ObjectID, containerID, size, isFile);
+
+=======
// Add to list of IDs known about
AddID(ObjectID, containerID, size, isFile);
@@ -576,6 +693,7 @@ bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID,
}
}
+>>>>>>> 0.12
// Report success
return true;
}
@@ -585,15 +703,23 @@ bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID,
//
// Function
// Name: BackupStoreCheck::CheckFile(int64_t, IOStream &)
+<<<<<<< HEAD
+// Purpose: Do check on file, return original container ID if OK, or -1 on error
+=======
// Purpose: Do check on file, return original container ID
// if OK, or -1 on error
+>>>>>>> 0.12
// Created: 22/4/04
//
// --------------------------------------------------------------------------
int64_t BackupStoreCheck::CheckFile(int64_t ObjectID, IOStream &rStream)
{
+<<<<<<< HEAD
+ // Check that it's not the root directory ID. Having a file as the root directory would be bad.
+=======
// Check that it's not the root directory ID. Having a file as
// the root directory would be bad.
+>>>>>>> 0.12
if(ObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
{
// Get that dodgy thing deleted!
@@ -603,8 +729,12 @@ int64_t BackupStoreCheck::CheckFile(int64_t ObjectID, IOStream &rStream)
// Check the format of the file, and obtain the container ID
int64_t originalContainerID = -1;
+<<<<<<< HEAD
+ if(!BackupStoreFile::VerifyEncodedFileFormat(rStream, 0 /* don't want diffing from ID */,
+=======
if(!BackupStoreFile::VerifyEncodedFileFormat(rStream,
0 /* don't want diffing from ID */,
+>>>>>>> 0.12
&originalContainerID))
{
// Didn't verify
@@ -619,8 +749,12 @@ int64_t BackupStoreCheck::CheckFile(int64_t ObjectID, IOStream &rStream)
//
// Function
// Name: BackupStoreCheck::CheckDirInitial(int64_t, IOStream &)
+<<<<<<< HEAD
+// Purpose: Do initial check on directory, return container ID if OK, or -1 on error
+=======
// Purpose: Do initial check on directory, return container ID
// if OK, or -1 on error
+>>>>>>> 0.12
// Created: 22/4/04
//
// --------------------------------------------------------------------------
@@ -659,12 +793,16 @@ void BackupStoreCheck::CheckDirectories()
// This phase will check all the files in the directories, make
// a note of all directories which are missing, and do initial fixing.
+<<<<<<< HEAD
+ // Scan all objects
+=======
// The root directory is not contained inside another directory, so
// it has no directory entry to scan, but we have to count it
// somewhere, so we'll count it here.
mNumDirectories++;
// Scan all objects.
+>>>>>>> 0.12
for(Info_t::const_iterator i(mInfo.begin()); i != mInfo.end(); ++i)
{
IDBlock *pblock = i->second;
@@ -685,6 +823,24 @@ void BackupStoreCheck::CheckDirectories()
}
// Flag for modifications
+<<<<<<< HEAD
+ bool isModified = false;
+
+ // Check for validity
+ if(dir.CheckAndFix())
+ {
+ // Wasn't quite right, and has been modified
+ BOX_WARNING("Directory ID " <<
+ BOX_FORMAT_OBJECTID(pblock->mID[e]) <<
+ " has bad structure");
+ ++mNumberErrorsFound;
+ isModified = true;
+ }
+
+ // Go through, and check that everything in that directory exists and is valid
+ std::vector<int64_t> toDelete;
+
+=======
bool isModified = CheckDirectory(dir);
// Check the directory again, now that entries have been removed
@@ -715,10 +871,157 @@ void BackupStoreCheck::CheckDirectories()
}
// Count valid entries
+>>>>>>> 0.12
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = 0;
while((en = i.Next()) != 0)
{
+<<<<<<< HEAD
+ // Lookup the item
+ int32_t iIndex;
+ IDBlock *piBlock = LookupID(en->GetObjectID(), iIndex);
+ bool badEntry = false;
+ if(piBlock != 0)
+ {
+ // Found. Get flags
+ uint8_t iflags = GetFlags(piBlock, iIndex);
+
+ // Is the type the same?
+ if(((iflags & Flags_IsDir) == Flags_IsDir)
+ != ((en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) == BackupStoreDirectory::Entry::Flags_Dir))
+ {
+ // Entry is of wrong type
+ BOX_WARNING("Directory ID " <<
+ BOX_FORMAT_OBJECTID(pblock->mID[e]) <<
+ " references object " <<
+ BOX_FORMAT_OBJECTID(en->GetObjectID()) <<
+ " which has a different type than expected.");
+ badEntry = true;
+ }
+ else
+ {
+ // Check that the entry is not already contained.
+ if(iflags & Flags_IsContained)
+ {
+ BOX_WARNING("Directory ID " <<
+ BOX_FORMAT_OBJECTID(pblock->mID[e]) <<
+ " references object " <<
+ BOX_FORMAT_OBJECTID(en->GetObjectID()) <<
+ " which is already contained.");
+ badEntry = true;
+ }
+ else
+ {
+ // Not already contained -- mark as contained
+ SetFlags(piBlock, iIndex, iflags | Flags_IsContained);
+
+ // Check that the container ID of the object is correct
+ if(piBlock->mContainer[iIndex] != pblock->mID[e])
+ {
+ // Needs fixing...
+ if(iflags & Flags_IsDir)
+ {
+ // Add to will fix later list
+ BOX_WARNING("Directory ID " << BOX_FORMAT_OBJECTID(en->GetObjectID()) << " has wrong container ID.");
+ mDirsWithWrongContainerID.push_back(en->GetObjectID());
+ }
+ else
+ {
+ // This is OK for files, they might move
+ BOX_WARNING("File ID " << BOX_FORMAT_OBJECTID(en->GetObjectID()) << " has different container ID, probably moved");
+ }
+
+ // Fix entry for now
+ piBlock->mContainer[iIndex] = pblock->mID[e];
+ }
+ }
+ }
+
+ // Check the object size, if it's OK and a file
+ if(!badEntry && !((iflags & Flags_IsDir) == Flags_IsDir))
+ {
+ if(en->GetSizeInBlocks() != piBlock->mObjectSizeInBlocks[iIndex])
+ {
+ // Correct
+ en->SetSizeInBlocks(piBlock->mObjectSizeInBlocks[iIndex]);
+ // Mark as changed
+ isModified = true;
+ // Tell user
+ BOX_WARNING("Directory ID " << BOX_FORMAT_OBJECTID(pblock->mID[e]) << " has wrong size for object " << BOX_FORMAT_OBJECTID(en->GetObjectID()));
+ }
+ }
+ }
+ else
+ {
+ // Item can't be found. Is it a directory?
+ if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir)
+ {
+ // Store the directory for later attention
+ mDirsWhichContainLostDirs[en->GetObjectID()] = pblock->mID[e];
+ }
+ else
+ {
+ // Just remove the entry
+ badEntry = true;
+ BOX_WARNING("Directory ID " << BOX_FORMAT_OBJECTID(pblock->mID[e]) << " references object " << BOX_FORMAT_OBJECTID(en->GetObjectID()) << " which does not exist.");
+ }
+ }
+
+ // Is this entry worth keeping?
+ if(badEntry)
+ {
+ toDelete.push_back(en->GetObjectID());
+ }
+ else
+ {
+ // Add to sizes?
+ if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion)
+ {
+ mBlocksInOldFiles += en->GetSizeInBlocks();
+ }
+ if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted)
+ {
+ mBlocksInDeletedFiles += en->GetSizeInBlocks();
+ }
+ }
+ }
+
+ if(toDelete.size() > 0)
+ {
+ // Delete entries from directory
+ for(std::vector<int64_t>::const_iterator d(toDelete.begin()); d != toDelete.end(); ++d)
+ {
+ dir.DeleteEntry(*d);
+ }
+
+ // Mark as modified
+ isModified = true;
+
+ // Check the directory again, now that entries have been removed
+ dir.CheckAndFix();
+
+ // Errors found
+ ++mNumberErrorsFound;
+ }
+
+ if(isModified && mFixErrors)
+ {
+ BOX_WARNING("Fixing directory ID " << BOX_FORMAT_OBJECTID(pblock->mID[e]));
+
+ // Save back to disc
+ RaidFileWrite fixed(mDiscSetNumber, filename);
+ fixed.Open(true /* allow overwriting */);
+ dir.WriteToStream(fixed);
+ // Commit it
+ fixed.Commit(true /* convert to raid representation now */);
+ }
+ }
+ }
+ }
+
+}
+
+=======
int32_t iIndex;
IDBlock *piBlock = LookupID(en->GetObjectID(), iIndex);
@@ -951,4 +1254,5 @@ bool BackupStoreCheck::CheckDirectoryEntry(BackupStoreDirectory::Entry& rEntry,
return !badEntry;
}
+>>>>>>> 0.12
diff --git a/lib/backupstore/BackupStoreCheck.h b/lib/backupstore/BackupStoreCheck.h
index 178a873a..cddd8a4d 100644
--- a/lib/backupstore/BackupStoreCheck.h
+++ b/lib/backupstore/BackupStoreCheck.h
@@ -16,8 +16,11 @@
#include <set>
#include "NamedLock.h"
+<<<<<<< HEAD
+=======
#include "BackupStoreDirectory.h"
+>>>>>>> 0.12
class IOStream;
class BackupStoreFilename;
@@ -28,8 +31,14 @@ The following problems can be fixed:
* Spurious files deleted
* Corrupted files deleted
* Root ID as file, deleted
+<<<<<<< HEAD
+ * Dirs with wrong object id inside, deleted
+ * Direcetory entries pointing to non-existant files, deleted
+ * Doubly references files have second reference deleted
+=======
* Dirs with wrong object id in header, deleted
* Doubly referenced files have second reference deleted
+>>>>>>> 0.12
* Wrong directory container IDs fixed
* Missing root recreated
* Reattach files which exist, but aren't referenced
@@ -42,9 +51,13 @@ The following problems can be fixed:
* Inside directories,
- only one object per name has old version clear
- IDs aren't duplicated
+<<<<<<< HEAD
+ * Bad store info files regenerated
+=======
- entries pointing to non-existant files are deleted
- patches depending on non-existent objects are deleted
* Bad store info and refcount files regenerated
+>>>>>>> 0.12
* Bad sizes of files in directories fixed
*/
@@ -85,10 +98,13 @@ public:
void Check();
bool ErrorsFound() {return mNumberErrorsFound > 0;}
+<<<<<<< HEAD
+=======
inline int64_t GetNumErrorsFound()
{
return mNumberErrorsFound;
}
+>>>>>>> 0.12
private:
enum
@@ -127,9 +143,12 @@ private:
int64_t CheckObjectsScanDir(int64_t StartID, int Level, const std::string &rDirName);
void CheckObjectsDir(int64_t StartID);
bool CheckAndAddObject(int64_t ObjectID, const std::string &rFilename);
+<<<<<<< HEAD
+=======
bool CheckDirectory(BackupStoreDirectory& dir);
bool CheckDirectoryEntry(BackupStoreDirectory::Entry& rEntry,
int64_t DirectoryID, bool& rIsModified);
+>>>>>>> 0.12
int64_t CheckFile(int64_t ObjectID, IOStream &rStream);
int64_t CheckDirInitial(int64_t ObjectID, IOStream &rStream);
@@ -166,12 +185,19 @@ private:
#else
#define DUMP_OBJECT_INFO
#endif
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
private:
std::string mStoreRoot;
int mDiscSetNumber;
int32_t mAccountID;
+<<<<<<< HEAD
+=======
std::string mAccountName;
+>>>>>>> 0.12
bool mFixErrors;
bool mQuiet;
@@ -190,8 +216,12 @@ private:
// List of stuff to fix
std::vector<BackupStoreCheck_ID_t> mDirsWithWrongContainerID;
// This is a map of lost dir ID -> existing dir ID
+<<<<<<< HEAD
+ std::map<BackupStoreCheck_ID_t, BackupStoreCheck_ID_t> mDirsWhichContainLostDirs;
+=======
std::map<BackupStoreCheck_ID_t, BackupStoreCheck_ID_t>
mDirsWhichContainLostDirs;
+>>>>>>> 0.12
// Set of extra directories added
std::set<BackupStoreCheck_ID_t> mDirsAdded;
@@ -202,6 +232,11 @@ private:
// Usage
int64_t mBlocksUsed;
+<<<<<<< HEAD
+ int64_t mBlocksInOldFiles;
+ int64_t mBlocksInDeletedFiles;
+ int64_t mBlocksInDirectories;
+=======
int64_t mBlocksInCurrentFiles;
int64_t mBlocksInOldFiles;
int64_t mBlocksInDeletedFiles;
@@ -210,6 +245,7 @@ private:
int64_t mNumOldFiles;
int64_t mNumDeletedFiles;
int64_t mNumDirectories;
+>>>>>>> 0.12
};
#endif // BACKUPSTORECHECK__H
diff --git a/lib/backupstore/BackupStoreCheck2.cpp b/lib/backupstore/BackupStoreCheck2.cpp
index 90e21e7f..341ac524 100644
--- a/lib/backupstore/BackupStoreCheck2.cpp
+++ b/lib/backupstore/BackupStoreCheck2.cpp
@@ -12,6 +12,19 @@
#include <stdio.h>
#include <string.h>
+<<<<<<< HEAD
+#include "BackupStoreCheck.h"
+#include "StoreStructure.h"
+#include "RaidFileRead.h"
+#include "RaidFileWrite.h"
+#include "autogen_BackupStoreException.h"
+#include "BackupStoreObjectMagic.h"
+#include "BackupStoreFile.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreDirectory.h"
+#include "BackupStoreConstants.h"
+#include "BackupStoreInfo.h"
+=======
#include "autogen_BackupStoreException.h"
#include "BackupStoreCheck.h"
#include "BackupStoreConstants.h"
@@ -24,6 +37,7 @@
#include "RaidFileRead.h"
#include "RaidFileWrite.h"
#include "StoreStructure.h"
+>>>>>>> 0.12
#include "MemLeakFindOn.h"
@@ -138,7 +152,11 @@ void BackupStoreCheck::CheckUnattachedObjects()
if((flags & Flags_IsContained) == 0)
{
// Unattached object...
+<<<<<<< HEAD
+ BOX_WARNING("Object " <<
+=======
BOX_ERROR("Object " <<
+>>>>>>> 0.12
BOX_FORMAT_OBJECTID(pblock->mID[e]) <<
" is unattached.");
++mNumberErrorsFound;
@@ -158,7 +176,10 @@ void BackupStoreCheck::CheckUnattachedObjects()
int64_t diffFromObjectID = 0;
std::string filename;
StoreStructure::MakeObjectFilename(pblock->mID[e], mStoreRoot, mDiscSetNumber, filename, false /* don't attempt to make sure the dir exists */);
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
// The easiest way to do this is to verify it again. Not such a bad penalty, because
// this really shouldn't be done very often.
{
@@ -384,7 +405,11 @@ void BackupStoreDirectoryFixer::InsertObject(int64_t ObjectID, bool IsDirectory,
}
// Add a new entry in an appropriate place
+<<<<<<< HEAD
+ mDirectory.AddUnattactedObject(objectStoreFilename, modTime,
+=======
mDirectory.AddUnattachedObject(objectStoreFilename, modTime,
+>>>>>>> 0.12
ObjectID, sizeInBlocks,
IsDirectory?(BackupStoreDirectory::Entry::Flags_Dir):(BackupStoreDirectory::Entry::Flags_File));
}
@@ -575,6 +600,19 @@ void BackupStoreCheck::FixDirsWithLostDirs()
void BackupStoreCheck::WriteNewStoreInfo()
{
// Attempt to load the existing store info file
+<<<<<<< HEAD
+ std::auto_ptr<BackupStoreInfo> poldInfo;
+ try
+ {
+ poldInfo.reset(BackupStoreInfo::Load(mAccountID, mStoreRoot, mDiscSetNumber, true /* read only */).release());
+ }
+ catch(...)
+ {
+ BOX_WARNING("Load of existing store info failed, regenerating.");
+ ++mNumberErrorsFound;
+ }
+
+=======
std::auto_ptr<BackupStoreInfo> pOldInfo;
try
{
@@ -592,14 +630,19 @@ void BackupStoreCheck::WriteNewStoreInfo()
"deleted files: " << mNumDeletedFiles << "), "
"directories: " << mNumDirectories);
+>>>>>>> 0.12
// Minimum soft and hard limits
int64_t minSoft = ((mBlocksUsed * 11) / 10) + 1024;
int64_t minHard = ((minSoft * 11) / 10) + 1024;
// Need to do anything?
+<<<<<<< HEAD
+ if(poldInfo.get() != 0 && mNumberErrorsFound == 0 && poldInfo->GetAccountID() == mAccountID)
+=======
if(pOldInfo.get() != 0 &&
mNumberErrorsFound == 0 &&
pOldInfo->GetAccountID() == mAccountID)
+>>>>>>> 0.12
{
// Leave the store info as it is, no need to alter it because nothing really changed,
// and the only essential thing was that the account ID was correct, which is was.
@@ -611,6 +654,23 @@ void BackupStoreCheck::WriteNewStoreInfo()
// Work out the new limits
int64_t softLimit = minSoft;
int64_t hardLimit = minHard;
+<<<<<<< HEAD
+ if(poldInfo.get() != 0 && poldInfo->GetBlocksSoftLimit() > minSoft)
+ {
+ softLimit = poldInfo->GetBlocksSoftLimit();
+ }
+ else
+ {
+ BOX_WARNING("Soft limit for account changed to ensure housekeeping doesn't delete files on next run.");
+ }
+ if(poldInfo.get() != 0 && poldInfo->GetBlocksHardLimit() > minHard)
+ {
+ hardLimit = poldInfo->GetBlocksHardLimit();
+ }
+ else
+ {
+ BOX_WARNING("Hard limit for account changed to ensure housekeeping doesn't delete files on next run.");
+=======
if(pOldInfo.get() != 0 && pOldInfo->GetBlocksSoftLimit() > minSoft)
{
softLimit = pOldInfo->GetBlocksSoftLimit();
@@ -628,6 +688,7 @@ void BackupStoreCheck::WriteNewStoreInfo()
{
BOX_WARNING("Hard limit for account changed to ensure "
"housekeeping doesn't delete files on next run.");
+>>>>>>> 0.12
}
// Object ID
@@ -638,6 +699,10 @@ void BackupStoreCheck::WriteNewStoreInfo()
}
// Build a new store info
+<<<<<<< HEAD
+ std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::CreateForRegeneration(
+ mAccountID,
+=======
std::auto_ptr<MemBlockStream> extra_data;
if(pOldInfo.get())
{
@@ -650,15 +715,22 @@ void BackupStoreCheck::WriteNewStoreInfo()
std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::CreateForRegeneration(
mAccountID,
mAccountName,
+>>>>>>> 0.12
mStoreRoot,
mDiscSetNumber,
lastObjID,
mBlocksUsed,
+<<<<<<< HEAD
+=======
mBlocksInCurrentFiles,
+>>>>>>> 0.12
mBlocksInOldFiles,
mBlocksInDeletedFiles,
mBlocksInDirectories,
softLimit,
+<<<<<<< HEAD
+ hardLimit));
+=======
hardLimit,
(pOldInfo.get() ? pOldInfo->IsAccountEnabled() : true),
*extra_data));
@@ -671,6 +743,7 @@ void BackupStoreCheck::WriteNewStoreInfo()
{
mNumberErrorsFound += info->ReportChangesTo(*pOldInfo);
}
+>>>>>>> 0.12
// Save to disc?
if(mFixErrors)
@@ -697,12 +770,16 @@ bool BackupStoreDirectory::CheckAndFix()
bool changed = false;
// Check that if a file depends on a new version, that version is in this directory
+<<<<<<< HEAD
+ {
+=======
bool restart;
do
{
restart = false;
+>>>>>>> 0.12
std::vector<Entry*>::iterator i(mEntries.begin());
for(; i != mEntries.end(); ++i)
{
@@ -713,7 +790,11 @@ bool BackupStoreDirectory::CheckAndFix()
if(newerEn == 0)
{
// Depends on something, but it isn't there.
+<<<<<<< HEAD
+ BOX_TRACE("Entry id " << FMT_i <<
+=======
BOX_WARNING("Entry id " << FMT_i <<
+>>>>>>> 0.12
" removed because depends "
"on newer version " <<
FMT_OID(dependsNewer) <<
@@ -723,12 +804,20 @@ bool BackupStoreDirectory::CheckAndFix()
delete *i;
mEntries.erase(i);
+<<<<<<< HEAD
+ // Start again at the beginning of the vector, the iterator is now invalid
+ i = mEntries.begin();
+
+ // Mark as changed
+ changed = true;
+=======
// Mark as changed
changed = true;
// Start again at the beginning of the vector, the iterator is now invalid
restart = true;
break;
+>>>>>>> 0.12
}
else
{
@@ -750,7 +839,10 @@ bool BackupStoreDirectory::CheckAndFix()
}
}
}
+<<<<<<< HEAD
+=======
while(restart);
+>>>>>>> 0.12
// Check that if a file has a dependency marked, it exists, and remove it if it doesn't
{
@@ -875,7 +967,11 @@ bool BackupStoreDirectory::CheckAndFix()
// erase the thing from the list
Entry *pentry = (*i);
mEntries.erase(i);
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
// And delete the entry object
delete pentry;
@@ -893,12 +989,20 @@ bool BackupStoreDirectory::CheckAndFix()
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+// Name: BackupStoreDirectory::AddUnattactedObject(...)
+=======
// Name: BackupStoreDirectory::AddUnattachedObject(...)
+>>>>>>> 0.12
// Purpose: Adds an object which is currently unattached. Assume that CheckAndFix() will be called afterwards.
// Created: 22/4/04
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+void BackupStoreDirectory::AddUnattactedObject(const BackupStoreFilename &rName,
+=======
void BackupStoreDirectory::AddUnattachedObject(const BackupStoreFilename &rName,
+>>>>>>> 0.12
box_time_t ModificationTime, int64_t ObjectID, int64_t SizeInBlocks, int16_t Flags)
{
Entry *pnew = new Entry(rName, ModificationTime, ObjectID, SizeInBlocks, Flags,
diff --git a/lib/backupstore/BackupStoreCheckData.cpp b/lib/backupstore/BackupStoreCheckData.cpp
index ec606d52..c89b5082 100644
--- a/lib/backupstore/BackupStoreCheckData.cpp
+++ b/lib/backupstore/BackupStoreCheckData.cpp
@@ -65,11 +65,23 @@ void BackupStoreCheck::AddID(BackupStoreCheck_ID_t ID,
if(mpInfoLastBlock == 0 || mInfoLastBlockEntries >= BACKUPSTORECHECK_BLOCK_SIZE)
{
// No. Allocate a new one
+<<<<<<< HEAD
+ IDBlock *pblk = (IDBlock*)::malloc(sizeof(IDBlock));
+=======
IDBlock *pblk = (IDBlock*)calloc(1, sizeof(IDBlock));
+>>>>>>> 0.12
if(pblk == 0)
{
throw std::bad_alloc();
}
+<<<<<<< HEAD
+ // Zero all the flags entries
+ for(int z = 0; z < (BACKUPSTORECHECK_BLOCK_SIZE * Flags__NumFlags / Flags__NumItemsPerEntry); ++z)
+ {
+ pblk->mFlags[z] = 0;
+ }
+=======
+>>>>>>> 0.12
// Store in map
mInfo[ID] = pblk;
// Allocated and stored OK, setup for use
@@ -136,8 +148,13 @@ BackupStoreCheck::IDBlock *BackupStoreCheck::LookupID(BackupStoreCheck_ID_t ID,
pblock = ib->second;
}
+<<<<<<< HEAD
+ ASSERT(pblock != 0);
+ if(pblock == 0) return 0;
+=======
if(pblock == 0) return 0;
ASSERT(pblock != 0);
+>>>>>>> 0.12
// How many entries are there in the block
int32_t bentries = (pblock == mpInfoLastBlock)?mInfoLastBlockEntries:BACKUPSTORECHECK_BLOCK_SIZE;
diff --git a/lib/backupstore/BackupStoreConfigVerify.cpp b/lib/backupstore/BackupStoreConfigVerify.cpp
index 921adfa4..c2344634 100644
--- a/lib/backupstore/BackupStoreConfigVerify.cpp
+++ b/lib/backupstore/BackupStoreConfigVerify.cpp
@@ -38,7 +38,17 @@ static const ConfigurationVerifyKey verifyrootkeys[] =
ConfigTest_Exists | ConfigTest_IsInt),
ConfigurationVerifyKey("ExtendedLogging", ConfigTest_IsBool, false),
// make value "yes" to enable in config file
+<<<<<<< HEAD
+
+ #ifdef WIN32
+ ConfigurationVerifyKey("RaidFileConf", ConfigTest_LastEntry)
+ #else
+ ConfigurationVerifyKey("RaidFileConf", ConfigTest_LastEntry,
+ BOX_FILE_RAIDFILE_DEFAULT_CONFIG)
+ #endif
+=======
ConfigurationVerifyKey("RaidFileConf", ConfigTest_LastEntry)
+>>>>>>> 0.12
};
const ConfigurationVerify BackupConfigFileVerify =
diff --git a/lib/backupstore/BackupStoreInfo.cpp b/lib/backupstore/BackupStoreInfo.cpp
index b6714709..c58ae99a 100644
--- a/lib/backupstore/BackupStoreInfo.cpp
+++ b/lib/backupstore/BackupStoreInfo.cpp
@@ -11,7 +11,10 @@
#include <algorithm>
+<<<<<<< HEAD
+=======
#include "Archive.h"
+>>>>>>> 0.12
#include "BackupStoreInfo.h"
#include "BackupStoreException.h"
#include "RaidFileWrite.h"
@@ -19,12 +22,57 @@
#include "MemLeakFindOn.h"
+<<<<<<< HEAD
+// set packing to one byte
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "BeginStructPackForWire.h"
+#else
+BEGIN_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
+// ******************
+// make sure the defaults in CreateNew are modified!
+// ******************
+typedef struct
+{
+ int32_t mMagicValue; // also the version number
+ int32_t mAccountID;
+ int64_t mClientStoreMarker;
+ int64_t mLastObjectIDUsed;
+ int64_t mBlocksUsed;
+ int64_t mBlocksInOldFiles;
+ int64_t mBlocksInDeletedFiles;
+ int64_t mBlocksInDirectories;
+ int64_t mBlocksSoftLimit;
+ int64_t mBlocksHardLimit;
+ uint32_t mCurrentMarkNumber;
+ uint32_t mOptionsPresent; // bit mask of optional elements present
+ int64_t mNumberDeletedDirectories;
+ // Then loads of int64_t IDs for the deleted directories
+} info_StreamFormat;
+
+#define INFO_MAGIC_VALUE 0x34832476
+
+// Use default packing
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "EndStructPackForWire.h"
+#else
+END_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
+=======
+>>>>>>> 0.12
#ifdef BOX_RELEASE_BUILD
#define NUM_DELETED_DIRS_BLOCK 256
#else
#define NUM_DELETED_DIRS_BLOCK 2
#endif
+<<<<<<< HEAD
+#define INFO_FILENAME "info"
+
+=======
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -41,6 +89,10 @@ BackupStoreInfo::BackupStoreInfo()
mClientStoreMarker(0),
mLastObjectIDUsed(-1),
mBlocksUsed(0),
+<<<<<<< HEAD
+ mBlocksInOldFiles(0),
+ mBlocksInDeletedFiles(0)
+=======
mBlocksInCurrentFiles(0),
mBlocksInOldFiles(0),
mBlocksInDeletedFiles(0),
@@ -50,6 +102,7 @@ BackupStoreInfo::BackupStoreInfo()
mNumDeletedFiles(0),
mNumDirectories(0),
mAccountEnabled(true)
+>>>>>>> 0.12
{
}
@@ -75,6 +128,41 @@ BackupStoreInfo::~BackupStoreInfo()
// --------------------------------------------------------------------------
void BackupStoreInfo::CreateNew(int32_t AccountID, const std::string &rRootDir, int DiscSet, int64_t BlockSoftLimit, int64_t BlockHardLimit)
{
+<<<<<<< HEAD
+ // Initial header (is entire file)
+ info_StreamFormat hdr = {
+ htonl(INFO_MAGIC_VALUE), // mMagicValue
+ htonl(AccountID), // mAccountID
+ 0, // mClientStoreMarker
+ box_hton64(1), // mLastObjectIDUsed (which is the root directory)
+ 0, // mBlocksUsed
+ 0, // mBlocksInOldFiles
+ 0, // mBlocksInDeletedFiles
+ 0, // mBlocksInDirectories
+ box_hton64(BlockSoftLimit), // mBlocksSoftLimit
+ box_hton64(BlockHardLimit), // mBlocksHardLimit
+ 0, // mCurrentMarkNumber
+ 0, // mOptionsPresent
+ 0 // mNumberDeletedDirectories
+ };
+
+ // Generate the filename
+ ASSERT(rRootDir[rRootDir.size() - 1] == '/' ||
+ rRootDir[rRootDir.size() - 1] == DIRECTORY_SEPARATOR_ASCHAR);
+ std::string fn(rRootDir + INFO_FILENAME);
+
+ // Open the file for writing
+ RaidFileWrite rf(DiscSet, fn);
+ rf.Open(false); // no overwriting, as this is a new file
+
+ // Write header
+ rf.Write(&hdr, sizeof(hdr));
+
+ // Commit it to disc, converting it to RAID now
+ rf.Commit(true);
+
+ // Done.
+=======
BackupStoreInfo info;
info.mAccountID = AccountID;
info.mDiscSet = DiscSet;
@@ -90,11 +178,40 @@ void BackupStoreInfo::CreateNew(int32_t AccountID, const std::string &rRootDir,
info.mExtraData.SetForReading(); // extra data is empty in this case
info.Save(false);
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+// Name: BackupStoreInfo::Load(int32_t, const std::string &, int, bool)
+// Purpose: Loads the info from disc, given the root information. Can be marked as read only.
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<BackupStoreInfo> BackupStoreInfo::Load(int32_t AccountID, const std::string &rRootDir, int DiscSet, bool ReadOnly, int64_t *pRevisionID)
+{
+ // Generate the filename
+ std::string fn(rRootDir + DIRECTORY_SEPARATOR INFO_FILENAME);
+
+ // Open the file for reading (passing on optional request for revision ID)
+ std::auto_ptr<RaidFileRead> rf(RaidFileRead::Open(DiscSet, fn, pRevisionID));
+
+ // Read in a header
+ info_StreamFormat hdr;
+ if(!rf->ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(BackupStoreException, CouldNotLoadStoreInfo)
+ }
+
+ // Check it
+ if(ntohl(hdr.mMagicValue) != INFO_MAGIC_VALUE || (int32_t)ntohl(hdr.mAccountID) != AccountID)
+ {
+ THROW_EXCEPTION(BackupStoreException, BadStoreInfoOnLoad)
+ }
+
+=======
// Name: BackupStoreInfo::Load(int32_t, const std::string &,
// int, bool)
// Purpose: Loads the info from disc, given the root
@@ -138,6 +255,7 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::Load(int32_t AccountID,
fn, BackupStoreException, BadStoreInfoOnLoad);
}
+>>>>>>> 0.12
// Make new object
std::auto_ptr<BackupStoreInfo> info(new BackupStoreInfo);
@@ -146,6 +264,23 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::Load(int32_t AccountID,
info->mDiscSet = DiscSet;
info->mFilename = fn;
info->mReadOnly = ReadOnly;
+<<<<<<< HEAD
+
+ // Insert info from file
+ info->mClientStoreMarker = box_ntoh64(hdr.mClientStoreMarker);
+ info->mLastObjectIDUsed = box_ntoh64(hdr.mLastObjectIDUsed);
+ info->mBlocksUsed = box_ntoh64(hdr.mBlocksUsed);
+ info->mBlocksInOldFiles = box_ntoh64(hdr.mBlocksInOldFiles);
+ info->mBlocksInDeletedFiles = box_ntoh64(hdr.mBlocksInDeletedFiles);
+ info->mBlocksInDirectories = box_ntoh64(hdr.mBlocksInDirectories);
+ info->mBlocksSoftLimit = box_ntoh64(hdr.mBlocksSoftLimit);
+ info->mBlocksHardLimit = box_ntoh64(hdr.mBlocksHardLimit);
+
+ // Load up array of deleted objects
+ int64_t numDelObj = box_ntoh64(hdr.mNumberDeletedDirectories);
+
+ // Then load them in
+=======
int64_t numDelObj = 0;
if (v1)
@@ -213,6 +348,7 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::Load(int32_t AccountID,
}
// Then load the list of deleted directories
+>>>>>>> 0.12
if(numDelObj > 0)
{
int64_t objs[NUM_DELETED_DIRS_BLOCK];
@@ -244,6 +380,8 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::Load(int32_t AccountID,
{
THROW_EXCEPTION(BackupStoreException, BadStoreInfoOnLoad)
}
+<<<<<<< HEAD
+=======
if(v2)
{
@@ -264,6 +402,7 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::Load(int32_t AccountID,
rf->CopyStreamTo(info->mExtraData);
}
info->mExtraData.SetForReading();
+>>>>>>> 0.12
// return it to caller
return info;
@@ -278,6 +417,14 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::Load(int32_t AccountID,
// Created: 23/4/04
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+std::auto_ptr<BackupStoreInfo> BackupStoreInfo::CreateForRegeneration(int32_t AccountID, const std::string &rRootDir,
+ int DiscSet, int64_t LastObjectID, int64_t BlocksUsed, int64_t BlocksInOldFiles,
+ int64_t BlocksInDeletedFiles, int64_t BlocksInDirectories, int64_t BlockSoftLimit, int64_t BlockHardLimit)
+{
+ // Generate the filename
+ std::string fn(rRootDir + DIRECTORY_SEPARATOR INFO_FILENAME);
+=======
std::auto_ptr<BackupStoreInfo> BackupStoreInfo::CreateForRegeneration(
int32_t AccountID, const std::string& rAccountName,
const std::string &rRootDir, int DiscSet,
@@ -289,12 +436,23 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::CreateForRegeneration(
{
// Generate the filename
std::string fn(rRootDir + INFO_FILENAME);
+>>>>>>> 0.12
// Make new object
std::auto_ptr<BackupStoreInfo> info(new BackupStoreInfo);
// Put in basic info
info->mAccountID = AccountID;
+<<<<<<< HEAD
+ info->mDiscSet = DiscSet;
+ info->mFilename = fn;
+ info->mReadOnly = false;
+
+ // Insert info starting info
+ info->mClientStoreMarker = 0;
+ info->mLastObjectIDUsed = LastObjectID;
+ info->mBlocksUsed = BlocksUsed;
+=======
info->mAccountName = rAccountName;
info->mDiscSet = DiscSet;
info->mFilename = fn;
@@ -305,16 +463,21 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::CreateForRegeneration(
info->mLastObjectIDUsed = LastObjectID;
info->mBlocksUsed = BlocksUsed;
info->mBlocksInCurrentFiles = BlocksInCurrentFiles;
+>>>>>>> 0.12
info->mBlocksInOldFiles = BlocksInOldFiles;
info->mBlocksInDeletedFiles = BlocksInDeletedFiles;
info->mBlocksInDirectories = BlocksInDirectories;
info->mBlocksSoftLimit = BlockSoftLimit;
info->mBlocksHardLimit = BlockHardLimit;
+<<<<<<< HEAD
+
+=======
info->mAccountEnabled = AccountEnabled;
ExtraData.CopyStreamTo(info->mExtraData);
info->mExtraData.SetForReading();
+>>>>>>> 0.12
// return it to caller
return info;
}
@@ -323,12 +486,20 @@ std::auto_ptr<BackupStoreInfo> BackupStoreInfo::CreateForRegeneration(
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+// Name: BackupStoreInfo::Save()
+=======
// Name: BackupStoreInfo::Save(bool allowOverwrite)
+>>>>>>> 0.12
// Purpose: Save modified info back to disc
// Created: 2003/08/28
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+void BackupStoreInfo::Save()
+=======
void BackupStoreInfo::Save(bool allowOverwrite)
+>>>>>>> 0.12
{
// Make sure we're initialised (although should never come to this)
if(mFilename.empty() || mAccountID == -1 || mDiscSet == -1)
@@ -344,6 +515,29 @@ void BackupStoreInfo::Save(bool allowOverwrite)
// Then... open a write file
RaidFileWrite rf(mDiscSet, mFilename);
+<<<<<<< HEAD
+ rf.Open(true); // allow overwriting
+
+ // Make header
+ info_StreamFormat hdr;
+ hdr.mMagicValue = htonl(INFO_MAGIC_VALUE);
+ hdr.mAccountID = htonl(mAccountID);
+ hdr.mClientStoreMarker = box_hton64(mClientStoreMarker);
+ hdr.mLastObjectIDUsed = box_hton64(mLastObjectIDUsed);
+ hdr.mBlocksUsed = box_hton64(mBlocksUsed);
+ hdr.mBlocksInOldFiles = box_hton64(mBlocksInOldFiles);
+ hdr.mBlocksInDeletedFiles = box_hton64(mBlocksInDeletedFiles);
+ hdr.mBlocksInDirectories = box_hton64(mBlocksInDirectories);
+ hdr.mBlocksSoftLimit = box_hton64(mBlocksSoftLimit);
+ hdr.mBlocksHardLimit = box_hton64(mBlocksHardLimit);
+ hdr.mCurrentMarkNumber = 0;
+ hdr.mOptionsPresent = 0;
+ hdr.mNumberDeletedDirectories = box_hton64(mDeletedDirectories.size());
+
+ // Write header
+ rf.Write(&hdr, sizeof(hdr));
+
+=======
rf.Open(allowOverwrite);
// Make header
@@ -370,6 +564,7 @@ void BackupStoreInfo::Save(bool allowOverwrite)
int64_t numDelObj = mDeletedDirectories.size();
archive.Write(numDelObj);
+>>>>>>> 0.12
// Write the deleted object list
if(mDeletedDirectories.size() > 0)
{
@@ -397,12 +592,15 @@ void BackupStoreInfo::Save(bool allowOverwrite)
tosave -= b;
}
}
+<<<<<<< HEAD
+=======
archive.Write(mAccountEnabled);
mExtraData.Seek(0, IOStream::SeekType_Absolute);
mExtraData.CopyStreamTo(rf);
mExtraData.Seek(0, IOStream::SeekType_Absolute);
+>>>>>>> 0.12
// Commit it to disc, converting it to RAID now
rf.Commit(true);
@@ -411,6 +609,9 @@ void BackupStoreInfo::Save(bool allowOverwrite)
mIsModified = false;
}
+<<<<<<< HEAD
+
+=======
int BackupStoreInfo::ReportChangesTo(BackupStoreInfo& rOldInfo)
{
int numChanges = 0;
@@ -460,6 +661,7 @@ int BackupStoreInfo::ReportChangesTo(BackupStoreInfo& rOldInfo)
\
field += delta; \
mIsModified = true;
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
@@ -471,6 +673,20 @@ int BackupStoreInfo::ReportChangesTo(BackupStoreInfo& rOldInfo)
// --------------------------------------------------------------------------
void BackupStoreInfo::ChangeBlocksUsed(int64_t Delta)
{
+<<<<<<< HEAD
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoIsReadOnly)
+ }
+ if((mBlocksUsed + Delta) < 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoBlockDeltaMakesValueNegative)
+ }
+
+ mBlocksUsed += Delta;
+
+ mIsModified = true;
+=======
APPLY_DELTA(mBlocksUsed, Delta);
}
@@ -486,6 +702,7 @@ void BackupStoreInfo::ChangeBlocksUsed(int64_t Delta)
void BackupStoreInfo::ChangeBlocksInCurrentFiles(int64_t Delta)
{
APPLY_DELTA(mBlocksInCurrentFiles, Delta);
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -498,7 +715,22 @@ void BackupStoreInfo::ChangeBlocksInCurrentFiles(int64_t Delta)
// --------------------------------------------------------------------------
void BackupStoreInfo::ChangeBlocksInOldFiles(int64_t Delta)
{
+<<<<<<< HEAD
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoIsReadOnly)
+ }
+ if((mBlocksInOldFiles + Delta) < 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoBlockDeltaMakesValueNegative)
+ }
+
+ mBlocksInOldFiles += Delta;
+
+ mIsModified = true;
+=======
APPLY_DELTA(mBlocksInOldFiles, Delta);
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -511,7 +743,22 @@ void BackupStoreInfo::ChangeBlocksInOldFiles(int64_t Delta)
// --------------------------------------------------------------------------
void BackupStoreInfo::ChangeBlocksInDeletedFiles(int64_t Delta)
{
+<<<<<<< HEAD
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoIsReadOnly)
+ }
+ if((mBlocksInDeletedFiles + Delta) < 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoBlockDeltaMakesValueNegative)
+ }
+
+ mBlocksInDeletedFiles += Delta;
+
+ mIsModified = true;
+=======
APPLY_DELTA(mBlocksInDeletedFiles, Delta);
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -524,6 +771,22 @@ void BackupStoreInfo::ChangeBlocksInDeletedFiles(int64_t Delta)
// --------------------------------------------------------------------------
void BackupStoreInfo::ChangeBlocksInDirectories(int64_t Delta)
{
+<<<<<<< HEAD
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoIsReadOnly)
+ }
+ if((mBlocksInDirectories + Delta) < 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoBlockDeltaMakesValueNegative)
+ }
+
+ mBlocksInDirectories += Delta;
+
+ mIsModified = true;
+}
+
+=======
APPLY_DELTA(mBlocksInDirectories, Delta);
}
@@ -546,6 +809,7 @@ void BackupStoreInfo::AdjustNumDirectories(int64_t increase)
{
APPLY_DELTA(mNumDirectories, increase);
}
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
@@ -689,6 +953,8 @@ void BackupStoreInfo::SetClientStoreMarker(int64_t ClientStoreMarker)
}
+<<<<<<< HEAD
+=======
// --------------------------------------------------------------------------
//
// Function
@@ -708,4 +974,5 @@ void BackupStoreInfo::SetAccountName(const std::string& rName)
mIsModified = true;
}
+>>>>>>> 0.12
diff --git a/lib/backupstore/BackupStoreInfo.h b/lib/backupstore/BackupStoreInfo.h
index 752cc44a..db2a62ef 100644
--- a/lib/backupstore/BackupStoreInfo.h
+++ b/lib/backupstore/BackupStoreInfo.h
@@ -14,6 +14,10 @@
#include <string>
#include <vector>
+<<<<<<< HEAD
+class BackupStoreCheck;
+
+=======
#include "CollectInBufferStream.h"
class BackupStoreCheck;
@@ -59,6 +63,7 @@ END_STRUCTURE_PACKING_FOR_WIRE
#define INFO_FILENAME "info"
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Class
@@ -89,19 +94,33 @@ public:
bool IsModified() const {return mIsModified;}
// Save modified infomation back to store
+<<<<<<< HEAD
+ void Save();
+=======
void Save(bool allowOverwrite = true);
+>>>>>>> 0.12
// Data access functions
int32_t GetAccountID() const {return mAccountID;}
int64_t GetLastObjectIDUsed() const {return mLastObjectIDUsed;}
int64_t GetBlocksUsed() const {return mBlocksUsed;}
+<<<<<<< HEAD
+=======
int64_t GetBlocksInCurrentFiles() const {return mBlocksInCurrentFiles;}
+>>>>>>> 0.12
int64_t GetBlocksInOldFiles() const {return mBlocksInOldFiles;}
int64_t GetBlocksInDeletedFiles() const {return mBlocksInDeletedFiles;}
int64_t GetBlocksInDirectories() const {return mBlocksInDirectories;}
const std::vector<int64_t> &GetDeletedDirectories() const {return mDeletedDirectories;}
int64_t GetBlocksSoftLimit() const {return mBlocksSoftLimit;}
int64_t GetBlocksHardLimit() const {return mBlocksHardLimit;}
+<<<<<<< HEAD
+ bool IsReadOnly() const {return mReadOnly;}
+ int GetDiscSetNumber() const {return mDiscSet;}
+
+ // Data modification functions
+ void ChangeBlocksUsed(int64_t Delta);
+=======
int64_t GetNumFiles() const {return mNumFiles;}
int64_t GetNumOldFiles() const {return mNumOldFiles;}
int64_t GetNumDeletedFiles() const {return mNumDeletedFiles;}
@@ -115,6 +134,7 @@ public:
// Data modification functions
void ChangeBlocksUsed(int64_t Delta);
void ChangeBlocksInCurrentFiles(int64_t Delta);
+>>>>>>> 0.12
void ChangeBlocksInOldFiles(int64_t Delta);
void ChangeBlocksInDeletedFiles(int64_t Delta);
void ChangeBlocksInDirectories(int64_t Delta);
@@ -122,15 +142,31 @@ public:
void AddDeletedDirectory(int64_t DirID);
void RemovedDeletedDirectory(int64_t DirID);
void ChangeLimits(int64_t BlockSoftLimit, int64_t BlockHardLimit);
+<<<<<<< HEAD
+=======
void AdjustNumFiles(int64_t increase);
void AdjustNumOldFiles(int64_t increase);
void AdjustNumDeletedFiles(int64_t increase);
void AdjustNumDirectories(int64_t increase);
+>>>>>>> 0.12
// Object IDs
int64_t AllocateObjectID();
// Client marker set and get
+<<<<<<< HEAD
+ int64_t GetClientStoreMarker() {return mClientStoreMarker;}
+ void SetClientStoreMarker(int64_t ClientStoreMarker);
+
+private:
+ static std::auto_ptr<BackupStoreInfo> CreateForRegeneration(int32_t AccountID, const std::string &rRootDir,
+ int DiscSet, int64_t LastObjectID, int64_t BlocksUsed, int64_t BlocksInOldFiles,
+ int64_t BlocksInDeletedFiles, int64_t BlocksInDirectories, int64_t BlockSoftLimit, int64_t BlockHardLimit);
+
+private:
+ // Location information
+ int32_t mAccountID;
+=======
int64_t GetClientStoreMarker() const {return mClientStoreMarker;}
void SetClientStoreMarker(int64_t ClientStoreMarker);
@@ -158,6 +194,7 @@ private:
// they now define the sizes of fields on disk (via Archive).
int32_t mAccountID;
std::string mAccountName;
+>>>>>>> 0.12
int mDiscSet;
std::string mFilename;
bool mReadOnly;
@@ -169,12 +206,21 @@ private:
// Account information
int64_t mLastObjectIDUsed;
int64_t mBlocksUsed;
+<<<<<<< HEAD
+=======
int64_t mBlocksInCurrentFiles;
+>>>>>>> 0.12
int64_t mBlocksInOldFiles;
int64_t mBlocksInDeletedFiles;
int64_t mBlocksInDirectories;
int64_t mBlocksSoftLimit;
int64_t mBlocksHardLimit;
+<<<<<<< HEAD
+ std::vector<int64_t> mDeletedDirectories;
+};
+
+
+=======
int64_t mNumFiles;
int64_t mNumOldFiles;
int64_t mNumDeletedFiles;
@@ -184,6 +230,7 @@ private:
CollectInBufferStream mExtraData;
};
+>>>>>>> 0.12
#endif // BACKUPSTOREINFO__H
diff --git a/lib/backupstore/BackupStoreRefCountDatabase.cpp b/lib/backupstore/BackupStoreRefCountDatabase.cpp
index 26f9acca..642e260c 100644
--- a/lib/backupstore/BackupStoreRefCountDatabase.cpp
+++ b/lib/backupstore/BackupStoreRefCountDatabase.cpp
@@ -61,7 +61,11 @@ std::string BackupStoreRefCountDatabase::GetFilename(const
ASSERT(RootDir[RootDir.size() - 1] == '/' ||
RootDir[RootDir.size() - 1] == DIRECTORY_SEPARATOR_ASCHAR);
+<<<<<<< HEAD
+ std::string fn(RootDir + "refcount.db");
+=======
std::string fn(RootDir + REFCOUNT_FILENAME ".db");
+>>>>>>> 0.12
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(rAccount.GetDiscSet()));
return RaidFileUtil::MakeWriteFileName(rdiscSet, fn);
@@ -91,9 +95,15 @@ void BackupStoreRefCountDatabase::Create(const
// Open the file for writing
if (FileExists(Filename) && !AllowOverwrite)
{
+<<<<<<< HEAD
+ BOX_ERROR("Attempted to overwrite refcount database file: " <<
+ Filename);
+ THROW_EXCEPTION(RaidFileException, CannotOverwriteExistingFile);
+=======
THROW_FILE_ERROR("Failed to overwrite refcount database: "
"not allowed here", Filename, RaidFileException,
CannotOverwriteExistingFile);
+>>>>>>> 0.12
}
int flags = O_CREAT | O_BINARY | O_RDWR;
@@ -134,18 +144,26 @@ std::auto_ptr<BackupStoreRefCountDatabase> BackupStoreRefCountDatabase::Load(
refcount_StreamFormat hdr;
if(!dbfile->ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */))
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(BackupStoreException, CouldNotLoadStoreInfo)
+=======
THROW_FILE_ERROR("Failed to read refcount database: "
"short read", filename, BackupStoreException,
CouldNotLoadStoreInfo);
+>>>>>>> 0.12
}
// Check it
if(ntohl(hdr.mMagicValue) != REFCOUNT_MAGIC_VALUE ||
(int32_t)ntohl(hdr.mAccountID) != rAccount.GetID())
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(BackupStoreException, BadStoreInfoOnLoad)
+=======
THROW_FILE_ERROR("Failed to read refcount database: "
"bad magic number", filename, BackupStoreException,
BadStoreInfoOnLoad);
+>>>>>>> 0.12
}
// Make new object
@@ -162,6 +180,92 @@ std::auto_ptr<BackupStoreRefCountDatabase> BackupStoreRefCountDatabase::Load(
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+// Name: BackupStoreRefCountDatabase::Save()
+// Purpose: Save modified info back to disc
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+/*
+void BackupStoreRefCountDatabase::Save()
+{
+ // Make sure we're initialised (although should never come to this)
+ if(mFilename.empty() || mAccount.GetID() == 0)
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ // Can we do this?
+ if(mReadOnly)
+ {
+ THROW_EXCEPTION(BackupStoreException, StoreInfoIsReadOnly)
+ }
+
+ // Then... open a write file
+ RaidFileWrite rf(mAccount.GetDiscSet(), mFilename);
+ rf.Open(true); // allow overwriting
+
+ // Make header
+ info_StreamFormat hdr;
+ hdr.mMagicValue = htonl(INFO_MAGIC_VALUE);
+ hdr.mAccountID = htonl(mAccountID);
+ hdr.mClientStoreMarker = box_hton64(mClientStoreMarker);
+ hdr.mLastObjectIDUsed = box_hton64(mLastObjectIDUsed);
+ hdr.mBlocksUsed = box_hton64(mBlocksUsed);
+ hdr.mBlocksInOldFiles = box_hton64(mBlocksInOldFiles);
+ hdr.mBlocksInDeletedFiles = box_hton64(mBlocksInDeletedFiles);
+ hdr.mBlocksInDirectories = box_hton64(mBlocksInDirectories);
+ hdr.mBlocksSoftLimit = box_hton64(mBlocksSoftLimit);
+ hdr.mBlocksHardLimit = box_hton64(mBlocksHardLimit);
+ hdr.mCurrentMarkNumber = 0;
+ hdr.mOptionsPresent = 0;
+ hdr.mNumberDeletedDirectories = box_hton64(mDeletedDirectories.size());
+
+ // Write header
+ rf.Write(&hdr, sizeof(hdr));
+
+ // Write the deleted object list
+ if(mDeletedDirectories.size() > 0)
+ {
+ int64_t objs[NUM_DELETED_DIRS_BLOCK];
+
+ int tosave = mDeletedDirectories.size();
+ std::vector<int64_t>::iterator i(mDeletedDirectories.begin());
+ while(tosave > 0)
+ {
+ // How many in this one?
+ int b = (tosave > NUM_DELETED_DIRS_BLOCK)?NUM_DELETED_DIRS_BLOCK:((int)(tosave));
+
+ // Add them
+ for(int t = 0; t < b; ++t)
+ {
+ ASSERT(i != mDeletedDirectories.end());
+ objs[t] = box_hton64((*i));
+ i++;
+ }
+
+ // Write
+ rf.Write(objs, b * sizeof(int64_t));
+
+ // Number saved
+ tosave -= b;
+ }
+ }
+
+ // Commit it to disc, converting it to RAID now
+ rf.Commit(true);
+
+ // Mark is as not modified
+ mIsModified = false;
+}
+*/
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+=======
+>>>>>>> 0.12
// Name: BackupStoreRefCountDatabase::GetRefCount(int64_t
// ObjectID)
// Purpose: Get the number of references to the specified object
@@ -176,10 +280,17 @@ BackupStoreRefCountDatabase::GetRefCount(int64_t ObjectID) const
if (GetSize() < offset + GetEntrySize())
{
+<<<<<<< HEAD
+ BOX_ERROR("attempted read of unknown refcount for object " <<
+ BOX_FORMAT_OBJECTID(ObjectID));
+ THROW_EXCEPTION(BackupStoreException,
+ UnknownObjectRefCountRequested);
+=======
THROW_FILE_ERROR("Failed to read refcount database: "
"attempted read of unknown refcount for object " <<
BOX_FORMAT_OBJECTID(ObjectID), mFilename,
BackupStoreException, UnknownObjectRefCountRequested);
+>>>>>>> 0.12
}
mapDatabaseFile->Seek(offset, SEEK_SET);
@@ -188,9 +299,15 @@ BackupStoreRefCountDatabase::GetRefCount(int64_t ObjectID) const
if (mapDatabaseFile->Read(&refcount, sizeof(refcount)) !=
sizeof(refcount))
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("short read on refcount database: " <<
+ mFilename);
+ THROW_EXCEPTION(BackupStoreException, CouldNotLoadStoreInfo);
+=======
THROW_FILE_ERROR("Failed to read refcount database: "
"short read at offset " << offset, mFilename,
BackupStoreException, CouldNotLoadStoreInfo);
+>>>>>>> 0.12
}
return ntohl(refcount);
diff --git a/lib/common/Archive.h b/lib/common/Archive.h
index 6d5ce88b..139cc5fd 100644
--- a/lib/common/Archive.h
+++ b/lib/common/Archive.h
@@ -45,7 +45,10 @@ public:
{
Write((int) Item);
}
+<<<<<<< HEAD
+=======
void WriteExact(uint32_t Item) { Write((int)Item); }
+>>>>>>> 0.12
void Write(int Item)
{
int32_t privItem = htonl(Item);
@@ -56,7 +59,10 @@ public:
int64_t privItem = box_hton64(Item);
mrStream.Write(&privItem, sizeof(privItem));
}
+<<<<<<< HEAD
+=======
void WriteExact(uint64_t Item) { Write(Item); }
+>>>>>>> 0.12
void Write(uint64_t Item)
{
uint64_t privItem = box_hton64(Item);
@@ -81,7 +87,11 @@ public:
int privItem;
Read(privItem);
+<<<<<<< HEAD
+ if (privItem)
+=======
if(privItem)
+>>>>>>> 0.12
{
rItemOut = true;
}
@@ -90,6 +100,8 @@ public:
rItemOut = false;
}
}
+<<<<<<< HEAD
+=======
void ReadIfPresent(bool &rItemOut, bool ValueIfNotPresent)
{
int privItem;
@@ -97,6 +109,7 @@ public:
rItemOut = privItem ? true : false;
}
void ReadExact(uint32_t &rItemOut) { Read((int&)rItemOut); }
+>>>>>>> 0.12
void Read(int &rItemOut)
{
int32_t privItem;
@@ -106,6 +119,8 @@ public:
}
rItemOut = ntohl(privItem);
}
+<<<<<<< HEAD
+=======
void ReadIfPresent(int &rItemOut, int ValueIfNotPresent)
{
int32_t privItem;
@@ -125,6 +140,7 @@ public:
THROW_EXCEPTION(CommonException, ArchiveBlockIncompleteRead)
}
}
+>>>>>>> 0.12
void Read(int64_t &rItemOut)
{
int64_t privItem;
@@ -134,7 +150,10 @@ public:
}
rItemOut = box_ntoh64(privItem);
}
+<<<<<<< HEAD
+=======
void ReadExact(uint64_t &rItemOut) { Read(rItemOut); }
+>>>>>>> 0.12
void Read(uint64_t &rItemOut)
{
uint64_t privItem;
diff --git a/lib/common/BannerText.h b/lib/common/BannerText.h
index f0772c9c..ae3ff841 100644
--- a/lib/common/BannerText.h
+++ b/lib/common/BannerText.h
@@ -10,6 +10,11 @@
#ifndef BANNERTEXT__H
#define BANNERTEXT__H
+<<<<<<< HEAD
+#define BANNER_TEXT(UtilityName) \
+ "Box " UtilityName " v" BOX_VERSION ", (c) Ben Summers and " \
+ "contributors 2003-2010"
+=======
#ifdef NEED_BOX_VERSION_H
# include "BoxVersion.h"
#endif
@@ -17,6 +22,7 @@
#define BANNER_TEXT(UtilityName) \
"Box " UtilityName " v" BOX_VERSION ", (c) Ben Summers and " \
"contributors 2003-2011"
+>>>>>>> 0.12
#endif // BANNERTEXT__H
diff --git a/lib/common/Box.h b/lib/common/Box.h
index 316f4364..91b4967b 100644
--- a/lib/common/Box.h
+++ b/lib/common/Box.h
@@ -17,8 +17,11 @@
#include "BoxPlatform.h"
+<<<<<<< HEAD
+=======
#include <memory>
+>>>>>>> 0.12
// uncomment this line to enable full memory leak finding on all
// malloc-ed blocks (at least, ones used by the STL)
//#define MEMLEAKFINDER_FULL_MALLOC_MONITORING
@@ -40,6 +43,10 @@
#include "Logging.h"
#ifndef BOX_RELEASE_BUILD
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
extern bool AssertFailuresToSyslog;
#define ASSERT_FAILS_TO_SYSLOG_ON {AssertFailuresToSyslog = true;}
void BoxDebugAssertFailed(const char *cond, const char *file, int line);
@@ -70,6 +77,10 @@
// Exception names
#define EXCEPTION_CODENAMES_EXTENDED
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
#else
#define ASSERT_FAILS_TO_SYSLOG_ON
#define ASSERT(cond)
@@ -80,6 +91,11 @@
// Box Backup builds release get extra information for exception logging
#define EXCEPTION_CODENAMES_EXTENDED
#define EXCEPTION_CODENAMES_EXTENDED_WITH_DESCRIPTION
+<<<<<<< HEAD
+
+#endif
+
+=======
#endif
#if defined DEBUG_LEAKS
@@ -94,6 +110,7 @@
#endif
#endif // DEBUG_LEAKS || BOX_RELEASE_BUILD
+>>>>>>> 0.12
#ifdef BOX_MEMORY_LEAK_TESTING
// Memory leak testing
#include "MemLeakFinder.h"
@@ -114,6 +131,10 @@
#define THROW_EXCEPTION(type, subtype) \
{ \
+<<<<<<< HEAD
+ if(!HideExceptionMessageGuard::ExceptionsHidden()) \
+ { \
+=======
if((!HideExceptionMessageGuard::ExceptionsHidden() \
&& !HideSpecificExceptionGuard::IsHidden( \
type::ExceptionType, type::subtype)) \
@@ -126,6 +147,7 @@
guard.reset(new Logging::Guard(Log::EVERYTHING)); \
} \
\
+>>>>>>> 0.12
OPTIONAL_DO_BACKTRACE \
BOX_WARNING("Exception thrown: " \
#type "(" #subtype ") " \
@@ -138,6 +160,14 @@
{ \
std::ostringstream _box_throw_line; \
_box_throw_line << message; \
+<<<<<<< HEAD
+ if(!HideExceptionMessageGuard::ExceptionsHidden()) \
+ { \
+ OPTIONAL_DO_BACKTRACE \
+ BOX_WARNING("Exception thrown: " \
+ #type "(" #subtype ") (" << message << \
+ ") at " __FILE__ "(" << __LINE__ << ")") \
+=======
if((!HideExceptionMessageGuard::ExceptionsHidden() \
&& !HideSpecificExceptionGuard::IsHidden( \
type::ExceptionType, type::subtype)) \
@@ -155,6 +185,7 @@
#type "(" #subtype ") (" << \
_box_throw_line.str() << \
") at " __FILE__ ":" << __LINE__) \
+>>>>>>> 0.12
} \
throw type(type::subtype, _box_throw_line.str()); \
}
diff --git a/lib/common/BoxConfig-MSVC.h b/lib/common/BoxConfig-MSVC.h
index eeb25d2e..bfa0dcaf 100644
--- a/lib/common/BoxConfig-MSVC.h
+++ b/lib/common/BoxConfig-MSVC.h
@@ -76,9 +76,12 @@
/* Define to 1 if you have the <execinfo.h> header file. */
/* #undef HAVE_EXECINFO_H */
+<<<<<<< HEAD
+=======
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
+>>>>>>> 0.12
/* Define to 1 if you have the `flock' function. */
/* #undef HAVE_FLOCK */
@@ -185,7 +188,11 @@
/* Define to 1 if you have the `setproctitle' function. */
/* #undef HAVE_SETPROCTITLE */
+<<<<<<< HEAD
+
+=======
#define HAVE_SETPROCTITLE 1
+>>>>>>> 0.12
/* Define to 1 if you have the `setxattr' function. */
/* #undef HAVE_SETXATTR */
diff --git a/lib/common/BoxException.h b/lib/common/BoxException.h
index 361f04e8..ad5aba4f 100644
--- a/lib/common/BoxException.h
+++ b/lib/common/BoxException.h
@@ -29,7 +29,10 @@ public:
virtual unsigned int GetType() const throw() = 0;
virtual unsigned int GetSubType() const throw() = 0;
+<<<<<<< HEAD
+=======
virtual const std::string& GetMessage() const = 0;
+>>>>>>> 0.12
private:
};
diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h
index 53a967e8..2c7ffcf6 100644
--- a/lib/common/BoxPlatform.h
+++ b/lib/common/BoxPlatform.h
@@ -23,7 +23,11 @@
#ifdef _MSC_VER
#include "BoxConfig-MSVC.h"
+<<<<<<< HEAD
+#include "BoxVersion.h"
+=======
#define NEED_BOX_VERSION_H
+>>>>>>> 0.12
#else
#include "BoxConfig.h"
#endif
@@ -159,6 +163,9 @@
#define INFTIM -1
#endif
+<<<<<<< HEAD
+// for Unix compatibility with Windows :-)
+=======
// Define O_BINARY for Unix compatibility with Windows :-)
// MSVC 2010 and newer MinGW define this in fcntl.h, which is probably
// not included by this point, so include it now so that we can detect
@@ -168,6 +175,7 @@
# include <fcntl.h>
#endif
+>>>>>>> 0.12
#ifndef O_BINARY
#define O_BINARY 0
#endif
diff --git a/lib/common/BoxPortsAndFiles.h.in b/lib/common/BoxPortsAndFiles.h.in
index 047a828f..55616da7 100644
--- a/lib/common/BoxPortsAndFiles.h.in
+++ b/lib/common/BoxPortsAndFiles.h.in
@@ -32,6 +32,14 @@
#define BOX_GET_DEFAULT_BBSTORED_CONFIG_FILE \
GetDefaultConfigFilePath("bbstored.conf").c_str()
#else
+<<<<<<< HEAD
+#define BOX_FILE_BBACKUPD_DEFAULT_CONFIG "@sysconfdir_expanded@/boxbackup/bbackupd.conf"
+#define BOX_FILE_RAIDFILE_DEFAULT_CONFIG "@sysconfdir_expanded@/boxbackup/raidfile.conf"
+#define BOX_FILE_BBSTORED_DEFAULT_CONFIG "@sysconfdir_expanded@/boxbackup/bbstored.conf"
+#define BOX_FILE_BBACKUPD_OLD_CONFIG "@sysconfdir_expanded@/box/bbackupd.conf"
+#define BOX_FILE_RAIDFILE_OLD_CONFIG "@sysconfdir_expanded@/box/raidfile.conf"
+#define BOX_FILE_BBSTORED_OLD_CONFIG "@sysconfdir_expanded@/box/bbstored.conf"
+=======
#define BOX_FILE_BBACKUPD_OLD_CONFIG "@sysconfdir_expanded@/box/bbackupd.conf"
#define BOX_FILE_RAIDFILE_OLD_CONFIG "@sysconfdir_expanded@/box/raidfile.conf"
#define BOX_FILE_BBSTORED_OLD_CONFIG "@sysconfdir_expanded@/box/bbstored.conf"
@@ -41,6 +49,7 @@
std::string("@sysconfdir_expanded@/boxbackup/raidfile.conf")
#define BOX_GET_DEFAULT_BBSTORED_CONFIG_FILE \
std::string("@sysconfdir_expanded@/boxbackup/bbstored.conf")
+>>>>>>> 0.12
#endif
#endif // BOXPORTSANDFILES__H
diff --git a/lib/common/BoxTime.cpp b/lib/common/BoxTime.cpp
index f62b1c35..ead3410b 100644
--- a/lib/common/BoxTime.cpp
+++ b/lib/common/BoxTime.cpp
@@ -94,6 +94,8 @@ std::string FormatTime(box_time_t time, bool includeDate, bool showMicros)
return buf.str();
}
+<<<<<<< HEAD
+=======
// --------------------------------------------------------------------------
//
// Function
@@ -143,3 +145,4 @@ void ShortSleep(box_time_t duration, bool logDuration)
#endif
}
+>>>>>>> 0.12
diff --git a/lib/common/BoxTime.h b/lib/common/BoxTime.h
index 3108d809..d688ff10 100644
--- a/lib/common/BoxTime.h
+++ b/lib/common/BoxTime.h
@@ -11,16 +11,25 @@
#define BOXTIME__H
// Time is presented as an unsigned 64 bit integer, in microseconds
+<<<<<<< HEAD
+typedef uint64_t box_time_t;
+=======
typedef int64_t box_time_t;
+>>>>>>> 0.12
#define NANO_SEC_IN_SEC (1000000000LL)
#define NANO_SEC_IN_USEC (1000)
#define NANO_SEC_IN_USEC_LL (1000LL)
#define MICRO_SEC_IN_SEC (1000000)
#define MICRO_SEC_IN_SEC_LL (1000000LL)
+<<<<<<< HEAD
+#define MILLI_SEC_IN_NANO_SEC (1000)
+#define MILLI_SEC_IN_NANO_SEC_LL (1000LL)
+=======
#define MICRO_SEC_IN_MILLI_SEC (1000)
#define MILLI_SEC_IN_SEC (1000)
#define MILLI_SEC_IN_SEC_LL (1000LL)
+>>>>>>> 0.12
box_time_t GetCurrentBoxTime();
@@ -28,17 +37,24 @@ inline box_time_t SecondsToBoxTime(time_t Seconds)
{
return ((box_time_t)Seconds * MICRO_SEC_IN_SEC_LL);
}
+<<<<<<< HEAD
+=======
inline uint64_t MilliSecondsToBoxTime(int64_t milliseconds)
{
return ((box_time_t)milliseconds * 1000);
}
+>>>>>>> 0.12
inline time_t BoxTimeToSeconds(box_time_t Time)
{
return Time / MICRO_SEC_IN_SEC_LL;
}
inline uint64_t BoxTimeToMilliSeconds(box_time_t Time)
{
+<<<<<<< HEAD
+ return Time / MILLI_SEC_IN_NANO_SEC_LL;
+=======
return Time / MILLI_SEC_IN_SEC_LL;
+>>>>>>> 0.12
}
inline uint64_t BoxTimeToMicroSeconds(box_time_t Time)
{
@@ -48,6 +64,9 @@ inline uint64_t BoxTimeToMicroSeconds(box_time_t Time)
std::string FormatTime(box_time_t time, bool includeDate,
bool showMicros = false);
+<<<<<<< HEAD
+=======
void ShortSleep(box_time_t duration, bool logDuration);
+>>>>>>> 0.12
#endif // BOXTIME__H
diff --git a/lib/common/CommonException.txt b/lib/common/CommonException.txt
index 05da2709..885a9197 100644
--- a/lib/common/CommonException.txt
+++ b/lib/common/CommonException.txt
@@ -45,6 +45,8 @@ IOStreamGetLineNotEnoughDataToIgnore 37 Bad value passed to IOStreamGetLine::Ign
TempDirPathTooLong 38 Your temporary directory path is too long. Check the TMP and TEMP environment variables.
ArchiveBlockIncompleteRead 39 The Store Object Info File is too short or corrupted, and will be rewritten automatically when the next backup completes.
AccessDenied 40 Access to the file or directory was denied. Please check the permissions.
+<<<<<<< HEAD
+=======
DatabaseOpenFailed 41 Failed to open the database file
DatabaseReadFailed 42 Failed to read a record from the database file
DatabaseWriteFailed 43 Failed to write a record from the database file
@@ -55,3 +57,4 @@ DatabaseRecordAlreadyExists 47 The database already contains a record with this
DatabaseRecordBadSize 48 The database contains a record with an invalid size
DatabaseIterateFailed 49 Failed to iterate over the database keys
ReferenceNotFound 50 The database does not contain an expected reference
+>>>>>>> 0.12
diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp
index 0b123675..ecc4eb12 100644
--- a/lib/common/DebugMemLeakFinder.cpp
+++ b/lib/common/DebugMemLeakFinder.cpp
@@ -7,10 +7,18 @@
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+
+#ifndef BOX_RELEASE_BUILD
+
+#include "Box.h"
+
+=======
#include "Box.h"
#ifdef BOX_MEMORY_LEAK_TESTING
+>>>>>>> 0.12
#undef malloc
#undef realloc
#undef free
@@ -19,6 +27,13 @@
#include <unistd.h>
#endif
+<<<<<<< HEAD
+#include <map>
+#include <stdio.h>
+#include <string.h>
+#include <set>
+#include <cstdlib> // for std::atexit
+=======
#include <signal.h>
#include <stdio.h>
#include <string.h>
@@ -26,6 +41,7 @@
#include <cstdlib> // for std::atexit
#include <map>
#include <set>
+>>>>>>> 0.12
#include "MemLeakFinder.h"
@@ -74,6 +90,8 @@ namespace
size_t sNotLeaksPreNum = 0;
}
+<<<<<<< HEAD
+=======
void memleakfinder_report_on_signal(int unused)
{
// this is not safe! do not send SIGUSR1 to a process
@@ -81,6 +99,7 @@ void memleakfinder_report_on_signal(int unused)
memleakfinder_report_usage_summary();
}
+>>>>>>> 0.12
void memleakfinder_init()
{
ASSERT(!memleakfinder_initialised);
@@ -92,6 +111,8 @@ void memleakfinder_init()
}
memleakfinder_initialised = true;
+<<<<<<< HEAD
+=======
#if defined WIN32
// no signals, no way to trigger event yet
@@ -107,6 +128,7 @@ void memleakfinder_init()
}
ASSERT(oldact.sa_handler == 0);
#endif // WIN32
+>>>>>>> 0.12
}
MemLeakSuppressionGuard::MemLeakSuppressionGuard()
@@ -164,6 +186,8 @@ void *memleakfinder_malloc(size_t size, const char *file, int line)
return b;
}
+<<<<<<< HEAD
+=======
void *memleakfinder_calloc(size_t blocks, size_t size, const char *file, int line)
{
void *block = memleakfinder_malloc(blocks * size, file, line);
@@ -174,6 +198,7 @@ void *memleakfinder_calloc(size_t blocks, size_t size, const char *file, int lin
return block;
}
+>>>>>>> 0.12
void *memleakfinder_realloc(void *ptr, size_t size)
{
InternalAllocGuard guard;
@@ -379,6 +404,8 @@ int memleakfinder_numleaks()
return n;
}
+<<<<<<< HEAD
+=======
// Summarise all blocks allocated and still allocated, for memory usage
// diagnostics.
void memleakfinder_report_usage_summary()
@@ -458,6 +485,7 @@ void memleakfinder_report_usage_summary()
#endif // DEBUG_LEAKS
}
+>>>>>>> 0.12
void memleakfinder_reportleaks_file(FILE *file)
{
InternalAllocGuard guard;
@@ -661,4 +689,8 @@ void operator delete(void *ptr) throw ()
internal_delete(ptr);
}
+<<<<<<< HEAD
+#endif // BOX_RELEASE_BUILD
+=======
#endif // BOX_MEMORY_LEAK_TESTING
+>>>>>>> 0.12
diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp
index 213c4f8e..c7c80ed2 100644
--- a/lib/common/ExcludeList.cpp
+++ b/lib/common/ExcludeList.cpp
@@ -101,6 +101,14 @@ std::string ExcludeList::ReplaceSlashesRegex(const std::string& input) const
output.replace(pos, 1, "\\" DIRECTORY_SEPARATOR);
}
+<<<<<<< HEAD
+ for (std::string::iterator i = output.begin(); i != output.end(); i++)
+ {
+ *i = tolower(*i);
+ }
+
+=======
+>>>>>>> 0.12
return output;
}
#endif
@@ -180,19 +188,30 @@ void ExcludeList::AddRegexEntries(const std::string &rEntries)
try
{
std::string entry = *i;
+<<<<<<< HEAD
+=======
int flags = REG_EXTENDED | REG_NOSUB;
+>>>>>>> 0.12
// Convert any forward slashes in the string
// to appropriately escaped backslashes
#ifdef WIN32
entry = ReplaceSlashesRegex(entry);
+<<<<<<< HEAD
+ #endif
+
+ // Compile
+ int errcode = ::regcomp(pregex, entry.c_str(),
+ REG_EXTENDED | REG_NOSUB);
+=======
flags |= REG_ICASE; // Windows convention
#endif
// Compile
int errcode = ::regcomp(pregex, entry.c_str(),
flags);
+>>>>>>> 0.12
if (errcode != 0)
{
@@ -235,7 +254,10 @@ bool ExcludeList::IsExcluded(const std::string &rTest) const
std::string test = rTest;
#ifdef WIN32
+<<<<<<< HEAD
+=======
// converts to lower case as well
+>>>>>>> 0.12
test = ReplaceSlashesDefinite(test);
#endif
diff --git a/lib/common/FdGetLine.cpp b/lib/common/FdGetLine.cpp
index 30409d92..2d2f7c6a 100644
--- a/lib/common/FdGetLine.cpp
+++ b/lib/common/FdGetLine.cpp
@@ -20,6 +20,16 @@
#include "MemLeakFindOn.h"
+<<<<<<< HEAD
+// utility whitespace function
+inline bool iw(int c)
+{
+ return (c == ' ' || c == '\t' || c == '\v' || c == '\f'); // \r, \n are already excluded
+}
+
+
+=======
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -29,7 +39,16 @@
//
// --------------------------------------------------------------------------
FdGetLine::FdGetLine(int fd)
+<<<<<<< HEAD
+ : mFileHandle(fd),
+ mLineNumber(0),
+ mBufferBegin(0),
+ mBytesInBuffer(0),
+ mPendingEOF(false),
+ mEOF(false)
+=======
: mFileHandle(fd)
+>>>>>>> 0.12
{
if(mFileHandle < 0) {THROW_EXCEPTION(CommonException, BadArguments)}
//printf("FdGetLine buffer size = %d\n", sizeof(mBuffer));
@@ -62,6 +81,128 @@ FdGetLine::~FdGetLine()
std::string FdGetLine::GetLine(bool Preprocess)
{
if(mFileHandle == -1) {THROW_EXCEPTION(CommonException, GetLineNoHandle)}
+<<<<<<< HEAD
+
+ // EOF?
+ if(mEOF) {THROW_EXCEPTION(CommonException, GetLineEOF)}
+
+ std::string r;
+
+ bool foundLineEnd = false;
+
+ while(!foundLineEnd && !mEOF)
+ {
+ // Use any bytes left in the buffer
+ while(mBufferBegin < mBytesInBuffer)
+ {
+ int c = mBuffer[mBufferBegin++];
+ if(c == '\r')
+ {
+ // Ignore nasty Windows line ending extra chars
+ }
+ else if(c == '\n')
+ {
+ // Line end!
+ foundLineEnd = true;
+ break;
+ }
+ else
+ {
+ // Add to string
+ r += c;
+ }
+
+ // Implicit line ending at EOF
+ if(mBufferBegin >= mBytesInBuffer && mPendingEOF)
+ {
+ foundLineEnd = true;
+ }
+ }
+
+ // Check size
+ if(r.size() > FDGETLINE_MAX_LINE_SIZE)
+ {
+ THROW_EXCEPTION(CommonException, GetLineTooLarge)
+ }
+
+ // Read more in?
+ if(!foundLineEnd && mBufferBegin >= mBytesInBuffer && !mPendingEOF)
+ {
+#ifdef WIN32
+ int bytes;
+
+ if (mFileHandle == _fileno(stdin))
+ {
+ bytes = console_read(mBuffer, sizeof(mBuffer));
+ }
+ else
+ {
+ bytes = ::read(mFileHandle, mBuffer,
+ sizeof(mBuffer));
+ }
+#else // !WIN32
+ int bytes = ::read(mFileHandle, mBuffer, sizeof(mBuffer));
+#endif // WIN32
+
+ // Error?
+ if(bytes == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ // Adjust buffer info
+ mBytesInBuffer = bytes;
+ mBufferBegin = 0;
+
+ // EOF / closed?
+ if(bytes == 0)
+ {
+ mPendingEOF = true;
+ }
+ }
+
+ // EOF?
+ if(mPendingEOF && mBufferBegin >= mBytesInBuffer)
+ {
+ // File is EOF, and now we've depleted the buffer completely, so tell caller as well.
+ mEOF = true;
+ }
+ }
+
+ if(!Preprocess)
+ {
+ return r;
+ }
+ else
+ {
+ // Check for comment char, but char before must be whitespace
+ int end = 0;
+ int size = r.size();
+ while(end < size)
+ {
+ if(r[end] == '#' && (end == 0 || (iw(r[end-1]))))
+ {
+ break;
+ }
+ end++;
+ }
+
+ // Remove whitespace
+ int begin = 0;
+ while(begin < size && iw(r[begin]))
+ {
+ begin++;
+ }
+ if(!iw(r[end])) end--;
+ while(end > begin && iw(r[end]))
+ {
+ end--;
+ }
+
+ // Return a sub string
+ return r.substr(begin, end - begin + 1);
+ }
+=======
std::string r;
bool result = GetLineInternal(r, Preprocess);
@@ -109,6 +250,7 @@ int FdGetLine::ReadMore(int Timeout)
}
return bytes;
+>>>>>>> 0.12
}
@@ -117,7 +259,11 @@ int FdGetLine::ReadMore(int Timeout)
// Function
// Name: FdGetLine::DetachFile()
// Purpose: Detaches the file handle, setting the file pointer correctly.
+<<<<<<< HEAD
+// Probably not good for sockets...
+=======
// Probably not good for sockets...
+>>>>>>> 0.12
// Created: 2003/07/24
//
// --------------------------------------------------------------------------
@@ -140,3 +286,7 @@ void FdGetLine::DetachFile()
mFileHandle = -1;
}
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
diff --git a/lib/common/FdGetLine.h b/lib/common/FdGetLine.h
index 2b9c268f..6b609fe8 100644
--- a/lib/common/FdGetLine.h
+++ b/lib/common/FdGetLine.h
@@ -12,7 +12,23 @@
#include <string>
+<<<<<<< HEAD
+#ifdef BOX_RELEASE_BUILD
+ #define FDGETLINE_BUFFER_SIZE 1024
+#elif defined WIN32
+ // need enough space for at least one unicode character
+ // in UTF-8 when calling console_read() from bbackupquery
+ #define FDGETLINE_BUFFER_SIZE 5
+#else
+ #define FDGETLINE_BUFFER_SIZE 4
+#endif
+
+// Just a very large upper bound for line size to avoid
+// people sending lots of data over sockets and causing memory problems.
+#define FDGETLINE_MAX_LINE_SIZE (1024*256)
+=======
#include "GetLine.h"
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
@@ -22,15 +38,41 @@
// Created: 2003/07/24
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+class FdGetLine
+{
+public:
+ FdGetLine(int fd);
+ ~FdGetLine();
+=======
class FdGetLine : public GetLine
{
public:
FdGetLine(int fd);
virtual ~FdGetLine();
+>>>>>>> 0.12
private:
FdGetLine(const FdGetLine &rToCopy);
public:
+<<<<<<< HEAD
+ std::string GetLine(bool Preprocess = false);
+ bool IsEOF() {return mEOF;}
+ int GetLineNumber() {return mLineNumber;}
+
+ // Call to detach, setting file pointer correctly to last bit read.
+ // Only works for lseek-able file descriptors.
+ void DetachFile();
+
+private:
+ char mBuffer[FDGETLINE_BUFFER_SIZE];
+ int mFileHandle;
+ int mLineNumber;
+ int mBufferBegin;
+ int mBytesInBuffer;
+ bool mPendingEOF;
+ bool mEOF;
+=======
virtual std::string GetLine(bool Preprocess = false);
// Call to detach, setting file pointer correctly to last bit read.
// Only works for lseek-able file descriptors.
@@ -44,6 +86,7 @@ protected:
private:
int mFileHandle;
+>>>>>>> 0.12
};
#endif // FDGETLINE__H
diff --git a/lib/common/FileModificationTime.cpp b/lib/common/FileModificationTime.cpp
index 06fc7887..bc35b7e6 100644
--- a/lib/common/FileModificationTime.cpp
+++ b/lib/common/FileModificationTime.cpp
@@ -16,7 +16,11 @@
#include "MemLeakFindOn.h"
+<<<<<<< HEAD
+box_time_t FileModificationTime(EMU_STRUCT_STAT &st)
+=======
box_time_t FileModificationTime(const EMU_STRUCT_STAT &st)
+>>>>>>> 0.12
{
#ifndef HAVE_STRUCT_STAT_ST_MTIMESPEC
box_time_t datamodified = ((int64_t)st.st_mtime) * (MICRO_SEC_IN_SEC_LL);
@@ -28,7 +32,11 @@ box_time_t FileModificationTime(const EMU_STRUCT_STAT &st)
return datamodified;
}
+<<<<<<< HEAD
+box_time_t FileAttrModificationTime(EMU_STRUCT_STAT &st)
+=======
box_time_t FileAttrModificationTime(const EMU_STRUCT_STAT &st)
+>>>>>>> 0.12
{
box_time_t statusmodified =
#ifdef HAVE_STRUCT_STAT_ST_MTIMESPEC
@@ -47,7 +55,11 @@ box_time_t FileAttrModificationTime(const EMU_STRUCT_STAT &st)
return statusmodified;
}
+<<<<<<< HEAD
+box_time_t FileModificationTimeMaxModAndAttr(EMU_STRUCT_STAT &st)
+=======
box_time_t FileModificationTimeMaxModAndAttr(const EMU_STRUCT_STAT &st)
+>>>>>>> 0.12
{
#ifndef HAVE_STRUCT_STAT_ST_MTIMESPEC
box_time_t datamodified = ((int64_t)st.st_mtime) * (MICRO_SEC_IN_SEC_LL);
diff --git a/lib/common/FileModificationTime.h b/lib/common/FileModificationTime.h
index 85424842..ffff29c7 100644
--- a/lib/common/FileModificationTime.h
+++ b/lib/common/FileModificationTime.h
@@ -14,9 +14,15 @@
#include "BoxTime.h"
+<<<<<<< HEAD
+box_time_t FileModificationTime(EMU_STRUCT_STAT &st);
+box_time_t FileAttrModificationTime(EMU_STRUCT_STAT &st);
+box_time_t FileModificationTimeMaxModAndAttr(EMU_STRUCT_STAT &st);
+=======
box_time_t FileModificationTime(const EMU_STRUCT_STAT &st);
box_time_t FileAttrModificationTime(const EMU_STRUCT_STAT &st);
box_time_t FileModificationTimeMaxModAndAttr(const EMU_STRUCT_STAT &st);
+>>>>>>> 0.12
#endif // FILEMODIFICATIONTIME__H
diff --git a/lib/common/FileStream.cpp b/lib/common/FileStream.cpp
index fc0319da..68209b15 100644
--- a/lib/common/FileStream.cpp
+++ b/lib/common/FileStream.cpp
@@ -190,6 +190,23 @@ int FileStream::Read(void *pBuffer, int NBytes, int Timeout)
}
else
{
+<<<<<<< HEAD
+ BOX_LOG_WIN_ERROR("Failed to read from file: " << mFileName);
+ r = -1;
+ }
+#else
+ int r = ::read(mOSFileHandle, pBuffer, NBytes);
+ if(r == -1)
+ {
+ BOX_LOG_SYS_ERROR("Failed to read from file: " << mFileName);
+ }
+#endif
+
+ if(r == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileReadError)
+ }
+=======
THROW_WIN_FILE_ERROR("Failed to read from file", mFileName,
CommonException, OSFileReadError);
}
@@ -206,6 +223,7 @@ int FileStream::Read(void *pBuffer, int NBytes, int Timeout)
CommonException, OSFileReadError);
}
#endif
+>>>>>>> 0.12
if(r == 0)
{
@@ -229,7 +247,11 @@ IOStream::pos_type FileStream::BytesLeftToRead()
EMU_STRUCT_STAT st;
if(EMU_FSTAT(mOSFileHandle, &st) != 0)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(CommonException, OSFileError)
+=======
BOX_LOG_SYS_ERROR(BOX_FILE_MESSAGE("Failed to stat file", mFileName));
+>>>>>>> 0.12
}
return st.st_size - GetPosition();
@@ -263,14 +285,24 @@ void FileStream::Write(const void *pBuffer, int NBytes)
if ((res == 0) || (numBytesWritten != (DWORD)NBytes))
{
+<<<<<<< HEAD
+ // DWORD err = GetLastError();
+ THROW_EXCEPTION(CommonException, OSFileWriteError)
+=======
THROW_WIN_FILE_ERROR("Failed to write to file", mFileName,
CommonException, OSFileWriteError);
+>>>>>>> 0.12
}
#else
if(::write(mOSFileHandle, pBuffer, NBytes) != NBytes)
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to write to file: " << mFileName);
+ THROW_EXCEPTION(CommonException, OSFileWriteError)
+=======
THROW_SYS_FILE_ERROR("Failed to write to file", mFileName,
CommonException, OSFileWriteError);
+>>>>>>> 0.12
}
#endif
}
@@ -293,6 +325,14 @@ IOStream::pos_type FileStream::GetPosition() const
#ifdef WIN32
LARGE_INTEGER conv;
+<<<<<<< HEAD
+
+ conv.HighPart = 0;
+ conv.LowPart = 0;
+
+ conv.LowPart = SetFilePointer(this->mOSFileHandle, 0, &conv.HighPart, FILE_CURRENT);
+
+=======
conv.HighPart = 0;
conv.LowPart = SetFilePointer(this->mOSFileHandle, 0, &conv.HighPart, FILE_CURRENT);
@@ -302,13 +342,18 @@ IOStream::pos_type FileStream::GetPosition() const
CommonException, OSFileError);
}
+>>>>>>> 0.12
return (IOStream::pos_type)conv.QuadPart;
#else // ! WIN32
off_t p = ::lseek(mOSFileHandle, 0, SEEK_CUR);
if(p == -1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(CommonException, OSFileError)
+=======
THROW_SYS_FILE_ERROR("Failed to seek in file", mFileName,
CommonException, OSFileError);
+>>>>>>> 0.12
}
return (IOStream::pos_type)p;
@@ -333,19 +378,31 @@ void FileStream::Seek(IOStream::pos_type Offset, int SeekType)
#ifdef WIN32
LARGE_INTEGER conv;
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
conv.QuadPart = Offset;
DWORD retVal = SetFilePointer(this->mOSFileHandle, conv.LowPart, &conv.HighPart, ConvertSeekTypeToOSWhence(SeekType));
if(retVal == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(CommonException, OSFileError)
+=======
THROW_WIN_FILE_ERROR("Failed to seek in file", mFileName,
CommonException, OSFileError);
+>>>>>>> 0.12
}
#else // ! WIN32
if(::lseek(mOSFileHandle, Offset, ConvertSeekTypeToOSWhence(SeekType)) == -1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(CommonException, OSFileError)
+=======
THROW_SYS_FILE_ERROR("Failed to seek in file", mFileName,
CommonException, OSFileError);
+>>>>>>> 0.12
}
#endif // WIN32
@@ -371,6 +428,14 @@ void FileStream::Close()
#ifdef WIN32
if(::CloseHandle(mOSFileHandle) == 0)
+<<<<<<< HEAD
+#else
+ if(::close(mOSFileHandle) != 0)
+#endif
+ {
+ THROW_EXCEPTION(CommonException, OSFileCloseError)
+ }
+=======
{
THROW_WIN_FILE_ERROR("Failed to close file", mFileName,
CommonException, OSFileCloseError);
@@ -382,6 +447,7 @@ void FileStream::Close()
CommonException, OSFileCloseError);
}
#endif // WIN32
+>>>>>>> 0.12
mOSFileHandle = INVALID_FILE;
mIsEOF = true;
@@ -412,7 +478,11 @@ bool FileStream::StreamDataLeft()
// --------------------------------------------------------------------------
bool FileStream::StreamClosed()
{
+<<<<<<< HEAD
+ return mIsEOF;
+=======
return (mOSFileHandle == INVALID_FILE);
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
diff --git a/lib/common/IOStreamGetLine.cpp b/lib/common/IOStreamGetLine.cpp
index ef8930b8..9a40f3eb 100644
--- a/lib/common/IOStreamGetLine.cpp
+++ b/lib/common/IOStreamGetLine.cpp
@@ -13,6 +13,16 @@
#include "MemLeakFindOn.h"
+<<<<<<< HEAD
+// utility whitespace function
+inline bool iw(int c)
+{
+ return (c == ' ' || c == '\t' || c == '\v' || c == '\f'); // \r, \n are already excluded
+}
+
+
+=======
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -22,7 +32,16 @@
//
// --------------------------------------------------------------------------
IOStreamGetLine::IOStreamGetLine(IOStream &Stream)
+<<<<<<< HEAD
+ : mrStream(Stream),
+ mLineNumber(0),
+ mBufferBegin(0),
+ mBytesInBuffer(0),
+ mPendingEOF(false),
+ mEOF(false)
+=======
: mrStream(Stream)
+>>>>>>> 0.12
{
}
@@ -54,6 +73,120 @@ IOStreamGetLine::~IOStreamGetLine()
// --------------------------------------------------------------------------
bool IOStreamGetLine::GetLine(std::string &rOutput, bool Preprocess, int Timeout)
{
+<<<<<<< HEAD
+ // EOF?
+ if(mEOF) {THROW_EXCEPTION(CommonException, GetLineEOF)}
+
+ // Initialise string to stored into
+ std::string r(mPendingString);
+ mPendingString.erase();
+
+ bool foundLineEnd = false;
+
+ while(!foundLineEnd && !mEOF)
+ {
+ // Use any bytes left in the buffer
+ while(mBufferBegin < mBytesInBuffer)
+ {
+ int c = mBuffer[mBufferBegin++];
+ if(c == '\r')
+ {
+ // Ignore nasty Windows line ending extra chars
+ }
+ else if(c == '\n')
+ {
+ // Line end!
+ foundLineEnd = true;
+ break;
+ }
+ else
+ {
+ // Add to string
+ r += c;
+ }
+
+ // Implicit line ending at EOF
+ if(mBufferBegin >= mBytesInBuffer && mPendingEOF)
+ {
+ foundLineEnd = true;
+ }
+ }
+
+ // Check size
+ if(r.size() > IOSTREAMGETLINE_MAX_LINE_SIZE)
+ {
+ THROW_EXCEPTION(CommonException, GetLineTooLarge)
+ }
+
+ // Read more in?
+ if(!foundLineEnd && mBufferBegin >= mBytesInBuffer && !mPendingEOF)
+ {
+ int bytes = mrStream.Read(mBuffer, sizeof(mBuffer), Timeout);
+
+ // Adjust buffer info
+ mBytesInBuffer = bytes;
+ mBufferBegin = 0;
+
+ // EOF / closed?
+ if(!mrStream.StreamDataLeft())
+ {
+ mPendingEOF = true;
+ }
+
+ // No data returned?
+ if(bytes == 0 && mrStream.StreamDataLeft())
+ {
+ // store string away
+ mPendingString = r;
+ // Return false;
+ return false;
+ }
+ }
+
+ // EOF?
+ if(mPendingEOF && mBufferBegin >= mBytesInBuffer)
+ {
+ // File is EOF, and now we've depleted the buffer completely, so tell caller as well.
+ mEOF = true;
+ }
+ }
+
+ if(!Preprocess)
+ {
+ rOutput = r;
+ return true;
+ }
+ else
+ {
+ // Check for comment char, but char before must be whitespace
+ int end = 0;
+ int size = r.size();
+ while(end < size)
+ {
+ if(r[end] == '#' && (end == 0 || (iw(r[end-1]))))
+ {
+ break;
+ }
+ end++;
+ }
+
+ // Remove whitespace
+ int begin = 0;
+ while(begin < size && iw(r[begin]))
+ {
+ begin++;
+ }
+ if(!iw(r[end])) end--;
+ while(end > begin && iw(r[end]))
+ {
+ end--;
+ }
+
+ // Return a sub string
+ rOutput = r.substr(begin, end - begin + 1);
+ return true;
+ }
+=======
return GetLineInternal(rOutput, Preprocess, Timeout);
}
@@ -78,6 +211,7 @@ int IOStreamGetLine::ReadMore(int Timeout)
}
return bytes;
+>>>>>>> 0.12
}
diff --git a/lib/common/IOStreamGetLine.h b/lib/common/IOStreamGetLine.h
index c4289073..1693e8ac 100644
--- a/lib/common/IOStreamGetLine.h
+++ b/lib/common/IOStreamGetLine.h
@@ -12,9 +12,24 @@
#include <string>
+<<<<<<< HEAD
+#include "IOStream.h"
+
+#ifdef BOX_RELEASE_BUILD
+ #define IOSTREAMGETLINE_BUFFER_SIZE 1024
+#else
+ #define IOSTREAMGETLINE_BUFFER_SIZE 4
+#endif
+
+// Just a very large upper bound for line size to avoid
+// people sending lots of data over sockets and causing memory problems.
+#define IOSTREAMGETLINE_MAX_LINE_SIZE (1024*256)
+
+=======
#include "GetLine.h"
#include "IOStream.h"
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Class
@@ -23,38 +38,67 @@
// Created: 2003/07/24
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+class IOStreamGetLine
+{
+public:
+ IOStreamGetLine(IOStream &Stream);
+ ~IOStreamGetLine();
+=======
class IOStreamGetLine : public GetLine
{
public:
IOStreamGetLine(IOStream &Stream);
virtual ~IOStreamGetLine();
+>>>>>>> 0.12
private:
IOStreamGetLine(const IOStreamGetLine &rToCopy);
public:
bool GetLine(std::string &rOutput, bool Preprocess = false, int Timeout = IOStream::TimeOutInfinite);
+<<<<<<< HEAD
+ bool IsEOF() {return mEOF;}
+ int GetLineNumber() {return mLineNumber;}
+=======
+>>>>>>> 0.12
// Call to detach, setting file pointer correctly to last bit read.
// Only works for lseek-able file descriptors.
void DetachFile();
+<<<<<<< HEAD
+=======
virtual bool IsStreamDataLeft()
{
return mrStream.StreamDataLeft();
}
+>>>>>>> 0.12
// For doing interesting stuff with the remaining data...
// Be careful with this!
const void *GetBufferedData() const {return mBuffer + mBufferBegin;}
int GetSizeOfBufferedData() const {return mBytesInBuffer - mBufferBegin;}
void IgnoreBufferedData(int BytesToIgnore);
IOStream &GetUnderlyingStream() {return mrStream;}
+<<<<<<< HEAD
+
+private:
+ char mBuffer[IOSTREAMGETLINE_BUFFER_SIZE];
+ IOStream &mrStream;
+ int mLineNumber;
+ int mBufferBegin;
+ int mBytesInBuffer;
+ bool mPendingEOF;
+ bool mEOF;
+ std::string mPendingString;
+=======
protected:
int ReadMore(int Timeout = IOStream::TimeOutInfinite);
private:
IOStream &mrStream;
+>>>>>>> 0.12
};
#endif // IOSTREAMGETLINE__H
diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp
index 7ce0dd3f..4a7e5e0a 100644
--- a/lib/common/Logging.cpp
+++ b/lib/common/Logging.cpp
@@ -22,9 +22,12 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+<<<<<<< HEAD
+=======
#ifdef WIN32
#include <process.h>
#endif
+>>>>>>> 0.12
#include <cstring>
#include <iomanip>
@@ -46,12 +49,15 @@ Log::Level Logging::sGlobalLevel = Log::EVERYTHING;
Logging Logging::sGlobalLogging; //automatic initialisation
std::string Logging::sProgramName;
+<<<<<<< HEAD
+=======
HideSpecificExceptionGuard::SuppressedExceptions_t
HideSpecificExceptionGuard::sSuppressedExceptions;
int Logging::Guard::sGuardCount = 0;
Log::Level Logging::Guard::sOriginalLevel = Log::INVALID;
+>>>>>>> 0.12
Logging::Logging()
{
ASSERT(!spConsole);
@@ -253,12 +259,15 @@ Logger::~Logger()
Logging::Remove(this);
}
+<<<<<<< HEAD
+=======
bool Logger::IsEnabled(Log::Level level)
{
return Logging::IsEnabled(level) &&
(int)mCurrentLevel >= (int)level;
}
+>>>>>>> 0.12
bool Console::sShowTime = false;
bool Console::sShowTimeMicros = false;
bool Console::sShowTag = false;
@@ -358,6 +367,13 @@ bool Console::Log(Log::Level level, const std::string& rFile,
#ifdef WIN32
std::string output = buf.str();
+<<<<<<< HEAD
+ ConvertUtf8ToConsole(output.c_str(), output);
+ fprintf(target, "%s\n", output.c_str());
+ #else
+ fprintf(target, "%s\n", buf.str().c_str());
+ #endif
+=======
if(ConvertUtf8ToConsole(output.c_str(), output) == false)
{
fprintf(target, "%s (and failed to convert to console encoding)\n",
@@ -372,6 +388,7 @@ bool Console::Log(Log::Level level, const std::string& rFile,
#endif
fflush(target);
+>>>>>>> 0.12
return true;
}
@@ -470,6 +487,8 @@ int Syslog::GetNamedFacility(const std::string& rFacility)
bool FileLogger::Log(Log::Level Level, const std::string& rFile,
int line, std::string& rMessage)
{
+<<<<<<< HEAD
+=======
if (mLogFile.StreamClosed())
{
/* skip this logger to allow logging failure to open
@@ -477,14 +496,19 @@ bool FileLogger::Log(Log::Level Level, const std::string& rFile,
return true;
}
+>>>>>>> 0.12
if (Level > GetLevel())
{
return true;
}
/* avoid infinite loop if this throws an exception */
+<<<<<<< HEAD
+ Logging::Remove(this);
+=======
Log::Level oldLevel = GetLevel();
Filter(Log::NOTHING);
+>>>>>>> 0.12
std::ostringstream buf;
buf << FormatTime(GetCurrentBoxTime(), true, false);
@@ -524,8 +548,12 @@ bool FileLogger::Log(Log::Level Level, const std::string& rFile,
mLogFile.Write(output.c_str(), output.length());
+<<<<<<< HEAD
+ Logging::Add(this);
+=======
// no infinite loop, reset to saved logging level
Filter(oldLevel);
+>>>>>>> 0.12
return true;
}
@@ -549,6 +577,8 @@ std::string PrintEscapedBinaryData(const std::string& rInput)
return output.str();
}
+<<<<<<< HEAD
+=======
bool HideSpecificExceptionGuard::IsHidden(int type, int subtype)
{
@@ -564,3 +594,4 @@ bool HideSpecificExceptionGuard::IsHidden(int type, int subtype)
return false;
}
+>>>>>>> 0.12
diff --git a/lib/common/Logging.h b/lib/common/Logging.h
index 1074b7c3..bc0203bb 100644
--- a/lib/common/Logging.h
+++ b/lib/common/Logging.h
@@ -10,8 +10,11 @@
#ifndef LOGGING__H
#define LOGGING__H
+<<<<<<< HEAD
+=======
#include <assert.h>
+>>>>>>> 0.12
#include <cerrno>
#include <cstring>
#include <iomanip>
@@ -43,6 +46,33 @@
if (Logging::IsEnabled(Log::TRACE)) \
{ BOX_LOG(Log::TRACE, stuff) }
+<<<<<<< HEAD
+#define BOX_SYS_ERROR(stuff) \
+ stuff << ": " << std::strerror(errno) << " (" << errno << ")"
+
+#define BOX_LOG_SYS_WARNING(stuff) \
+ BOX_WARNING(BOX_SYS_ERROR(stuff))
+#define BOX_LOG_SYS_ERROR(stuff) \
+ BOX_ERROR(BOX_SYS_ERROR(stuff))
+#define BOX_LOG_SYS_FATAL(stuff) \
+ BOX_FATAL(BOX_SYS_ERROR(stuff))
+
+#define LOG_AND_THROW_ERROR(message, filename, exception, subtype) \
+ BOX_LOG_SYS_ERROR(message << ": " << filename); \
+ THROW_EXCEPTION_MESSAGE(exception, subtype, \
+ BOX_SYS_ERROR(message << ": " << filename));
+
+inline std::string GetNativeErrorMessage()
+{
+#ifdef WIN32
+ return GetErrorMessage(GetLastError());
+#else
+ std::ostringstream _box_log_line;
+ _box_log_line << std::strerror(errno) << " (" << errno << ")";
+ return _box_log_line.str();
+#endif
+}
+=======
#define BOX_SYS_ERRNO_MESSAGE(error_number, stuff) \
stuff << ": " << std::strerror(error_number) << \
" (" << error_number << ")"
@@ -83,6 +113,7 @@
#define THROW_FILE_ERROR(message, filename, exception, subtype) \
THROW_EXCEPTION_MESSAGE(exception, subtype, \
BOX_FILE_MESSAGE(filename, message))
+>>>>>>> 0.12
#ifdef WIN32
#define BOX_LOG_WIN_ERROR(stuff) \
@@ -95,6 +126,8 @@
BOX_WARNING(stuff << ": " << GetErrorMessage(number))
#define BOX_LOG_NATIVE_ERROR(stuff) BOX_LOG_WIN_ERROR(stuff)
#define BOX_LOG_NATIVE_WARNING(stuff) BOX_LOG_WIN_WARNING(stuff)
+<<<<<<< HEAD
+=======
#define BOX_WIN_ERRNO_MESSAGE(error_number, stuff) \
stuff << ": " << GetErrorMessage(error_number)
#define THROW_WIN_ERROR_NUMBER(message, error_number, exception, subtype) \
@@ -106,11 +139,17 @@
#define THROW_WIN_FILE_ERROR(message, filename, exception, subtype) \
THROW_WIN_FILE_ERRNO(message, filename, GetLastError(), \
exception, subtype)
+>>>>>>> 0.12
#else
#define BOX_LOG_NATIVE_ERROR(stuff) BOX_LOG_SYS_ERROR(stuff)
#define BOX_LOG_NATIVE_WARNING(stuff) BOX_LOG_SYS_WARNING(stuff)
#endif
+<<<<<<< HEAD
+#define BOX_LOG_SOCKET_ERROR(_type, _name, _port, stuff) \
+ BOX_LOG_NATIVE_ERROR(stuff << " (type " << _type << ", name " << \
+ _name << ", port " << _port << ")")
+=======
#ifdef WIN32
# define BOX_LOG_SOCKET_ERROR(_type, _name, _port, stuff) \
BOX_LOG_WIN_ERROR_NUMBER(stuff << " (type " << _type << ", name " << \
@@ -120,6 +159,7 @@
BOX_LOG_NATIVE_ERROR(stuff << " (type " << _type << ", name " << \
_name << ", port " << _port << ")")
#endif
+>>>>>>> 0.12
#define BOX_FORMAT_HEX32(number) \
std::hex << \
@@ -144,12 +184,15 @@
std::setw(6) << \
timespec.tv_usec
+<<<<<<< HEAD
+=======
#define BOX_FORMAT_MICROSECONDS(t) \
(int)((t) / 1000000) << "." << \
std::setw(6) << \
std::setfill('0') << \
(int)((t) % 1000000) << " seconds"
+>>>>>>> 0.12
#undef ERROR
namespace Log
@@ -197,6 +240,10 @@ class Logger
virtual const char* GetType() = 0;
Log::Level GetLevel() { return mCurrentLevel; }
+<<<<<<< HEAD
+
+ virtual void SetProgramName(const std::string& rProgramName) = 0;
+=======
bool IsEnabled(Log::Level level);
virtual void SetProgramName(const std::string& rProgramName) = 0;
@@ -218,6 +265,7 @@ class Logger
mLogger.Filter(mOldLevel);
}
};
+>>>>>>> 0.12
};
// --------------------------------------------------------------------------
@@ -325,29 +373,42 @@ class Logging
static void SetProgramName(const std::string& rProgramName);
static std::string GetProgramName() { return sProgramName; }
static void SetFacility(int facility);
+<<<<<<< HEAD
+=======
static Console& GetConsole() { return *spConsole; }
static Syslog& GetSyslog() { return *spSyslog; }
+>>>>>>> 0.12
class Guard
{
private:
Log::Level mOldLevel;
+<<<<<<< HEAD
+=======
static int sGuardCount;
static Log::Level sOriginalLevel;
+>>>>>>> 0.12
public:
Guard(Log::Level newLevel)
{
mOldLevel = Logging::GetGlobalLevel();
+<<<<<<< HEAD
+=======
if(sGuardCount == 0)
{
sOriginalLevel = mOldLevel;
}
sGuardCount++;
+>>>>>>> 0.12
Logging::SetGlobalLevel(newLevel);
}
~Guard()
{
+<<<<<<< HEAD
+ Logging::SetGlobalLevel(mOldLevel);
+ }
+=======
sGuardCount--;
Logging::SetGlobalLevel(mOldLevel);
}
@@ -359,6 +420,7 @@ class Logging
return IsActive() &&
(int)sOriginalLevel >= (int)originalLevel;
}
+>>>>>>> 0.12
};
class Tagger
@@ -367,6 +429,11 @@ class Logging
std::string mOldTag;
public:
+<<<<<<< HEAD
+ Tagger(const std::string& rTempTag)
+ {
+ mOldTag = Logging::GetProgramName();
+=======
Tagger()
: mOldTag(Logging::GetProgramName())
{
@@ -374,17 +441,21 @@ class Logging
Tagger(const std::string& rTempTag)
: mOldTag(Logging::GetProgramName())
{
+>>>>>>> 0.12
Logging::SetProgramName(mOldTag + " " + rTempTag);
}
~Tagger()
{
Logging::SetProgramName(mOldTag);
}
+<<<<<<< HEAD
+=======
void Change(const std::string& newTempTag)
{
Logging::SetProgramName(mOldTag + " " + newTempTag);
}
+>>>>>>> 0.12
};
};
@@ -427,6 +498,8 @@ class HideExceptionMessageGuard
bool mOldHiddenState;
};
+<<<<<<< HEAD
+=======
class HideSpecificExceptionGuard
{
private:
@@ -451,6 +524,7 @@ class HideSpecificExceptionGuard
static bool IsHidden(int type, int subtype);
};
+>>>>>>> 0.12
std::string PrintEscapedBinaryData(const std::string& rInput);
#endif // LOGGING__H
diff --git a/lib/common/MainHelper.h b/lib/common/MainHelper.h
index 3c6e9ff0..453b5b5f 100644
--- a/lib/common/MainHelper.h
+++ b/lib/common/MainHelper.h
@@ -12,12 +12,16 @@
#include <stdio.h>
+<<<<<<< HEAD
+#include "BoxException.h"
+=======
#ifdef NEED_BOX_VERSION_H
# include "BoxVersion.h"
#endif
#include "BoxException.h"
#include "Logging.h"
+>>>>>>> 0.12
#define MAINHELPER_START \
if(argc == 2 && ::strcmp(argv[1], "--version") == 0) \
@@ -25,6 +29,18 @@
MEMLEAKFINDER_INIT \
MEMLEAKFINDER_START \
try {
+<<<<<<< HEAD
+#define MAINHELPER_END \
+ } catch(BoxException &e) { \
+ printf("Exception: %s (%d/%d)\n", e.what(), e.GetType(), e.GetSubType()); \
+ return 1; \
+ } catch(std::exception &e) { \
+ printf("Exception: %s\n", e.what()); \
+ return 1; \
+ } catch(...) { \
+ printf("Exception: <UNKNOWN>\n"); \
+ return 1; }
+=======
#define MAINHELPER_END \
} catch(std::exception &e) { \
@@ -34,6 +50,7 @@
BOX_FATAL("UNKNOWN"); \
return 1; \
}
+>>>>>>> 0.12
#ifdef BOX_MEMORY_LEAK_TESTING
#define MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT(file, marker) \
diff --git a/lib/common/MemBlockStream.cpp b/lib/common/MemBlockStream.cpp
index 3a43a304..554fc6ae 100644
--- a/lib/common/MemBlockStream.cpp
+++ b/lib/common/MemBlockStream.cpp
@@ -22,6 +22,8 @@
//
// Function
// Name: MemBlockStream::MemBlockStream()
+<<<<<<< HEAD
+=======
// Purpose: Constructor with no contents
// Created: 2012/11/07
//
@@ -36,6 +38,7 @@ MemBlockStream::MemBlockStream()
//
// Function
// Name: MemBlockStream::MemBlockStream()
+>>>>>>> 0.12
// Purpose: Constructor (doesn't copy block, careful with lifetimes)
// Created: 2003/09/05
//
@@ -83,6 +86,10 @@ MemBlockStream::MemBlockStream(const CollectInBufferStream &rBuffer)
ASSERT(mBytesInBuffer >= 0);
}
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
diff --git a/lib/common/MemBlockStream.h b/lib/common/MemBlockStream.h
index 5234525b..ed0bf4ff 100644
--- a/lib/common/MemBlockStream.h
+++ b/lib/common/MemBlockStream.h
@@ -27,7 +27,10 @@ class CollectInBufferStream;
class MemBlockStream : public IOStream
{
public:
+<<<<<<< HEAD
+=======
MemBlockStream();
+>>>>>>> 0.12
MemBlockStream(const void *pBuffer, int Size);
MemBlockStream(const StreamableMemBlock &rBlock);
MemBlockStream(const CollectInBufferStream &rBuffer);
@@ -42,8 +45,11 @@ public:
virtual void Seek(pos_type Offset, int SeekType);
virtual bool StreamDataLeft();
virtual bool StreamClosed();
+<<<<<<< HEAD
+=======
virtual const void* GetBuffer() const { return mpBuffer; }
virtual int GetSize() const { return mBytesInBuffer; }
+>>>>>>> 0.12
private:
const char *mpBuffer;
diff --git a/lib/common/MemLeakFinder.h b/lib/common/MemLeakFinder.h
index 1a2cf90c..e4e9a1ae 100644
--- a/lib/common/MemLeakFinder.h
+++ b/lib/common/MemLeakFinder.h
@@ -28,7 +28,10 @@ class MemLeakSuppressionGuard
extern "C"
{
void *memleakfinder_malloc(size_t size, const char *file, int line);
+<<<<<<< HEAD
+=======
void *memleakfinder_calloc(size_t blocks, size_t size, const char *file, int line);
+>>>>>>> 0.12
void *memleakfinder_realloc(void *ptr, size_t size);
void memleakfinder_free(void *ptr);
}
@@ -37,8 +40,11 @@ void memleakfinder_init();
int memleakfinder_numleaks();
+<<<<<<< HEAD
+=======
void memleakfinder_report_usage_summary();
+>>>>>>> 0.12
void memleakfinder_reportleaks();
void memleakfinder_reportleaks_appendfile(const char *filename, const char *markertext);
@@ -57,7 +63,10 @@ void *operator new[](size_t size, const char *file, int line);
// define the malloc functions now, if required
#ifdef MEMLEAKFINDER_FULL_MALLOC_MONITORING
#define malloc(X) memleakfinder_malloc(X, __FILE__, __LINE__)
+<<<<<<< HEAD
+=======
#define calloc(X, Y) memleakfinder_calloc(X, Y, __FILE__, __LINE__)
+>>>>>>> 0.12
#define realloc memleakfinder_realloc
#define free memleakfinder_free
#define MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
diff --git a/lib/common/StreamableMemBlock.cpp b/lib/common/StreamableMemBlock.cpp
index b376f037..ce2e1f98 100644
--- a/lib/common/StreamableMemBlock.cpp
+++ b/lib/common/StreamableMemBlock.cpp
@@ -3,7 +3,10 @@
// File
// Name: StreamableMemBlock.cpp
// Purpose: Memory blocks which can be loaded and saved from streams
+<<<<<<< HEAD
+=======
// with a header indicating the size of the block.
+>>>>>>> 0.12
// Created: 2003/09/05
//
// --------------------------------------------------------------------------
diff --git a/lib/common/StreamableMemBlock.h b/lib/common/StreamableMemBlock.h
index 6c1c5ab8..3fcc62b3 100644
--- a/lib/common/StreamableMemBlock.h
+++ b/lib/common/StreamableMemBlock.h
@@ -2,8 +2,12 @@
//
// File
// Name: StreamableMemBlock.h
+<<<<<<< HEAD
+// Purpose: Memory blocks which can be loaded and saved from streams
+=======
// Purpose: Memory blocks which can be loaded and saved from streams,
// with a header indicating the size of the block.
+>>>>>>> 0.12
// Created: 2003/09/05
//
// --------------------------------------------------------------------------
diff --git a/lib/common/TemporaryDirectory.h b/lib/common/TemporaryDirectory.h
new file mode 100644
index 00000000..9d52ecd9
--- /dev/null
+++ b/lib/common/TemporaryDirectory.h
@@ -0,0 +1,46 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: TemporaryDirectory.h
+// Purpose: Location of temporary directory
+// Created: 2003/10/13
+//
+// --------------------------------------------------------------------------
+
+#ifndef TEMPORARYDIRECTORY__H
+#define TEMPORARYDIRECTORY__H
+
+#include <string>
+
+#ifdef WIN32
+ #include <windows.h>
+#endif
+
+// Prefix name with Box to avoid clashing with OS API names
+std::string BoxGetTemporaryDirectoryName()
+{
+#ifdef WIN32
+ // http://msdn.microsoft.com/library/default.asp?
+ // url=/library/en-us/fileio/fs/creating_and_using_a_temporary_file.asp
+
+ DWORD dwRetVal;
+ char lpPathBuffer[1024];
+ DWORD dwBufSize = sizeof(lpPathBuffer);
+
+ // Get the temp path.
+ dwRetVal = GetTempPath(dwBufSize, // length of the buffer
+ lpPathBuffer); // buffer for path
+ if (dwRetVal > dwBufSize)
+ {
+ THROW_EXCEPTION(CommonException, TempDirPathTooLong)
+ }
+
+ return std::string(lpPathBuffer);
+#elif defined TEMP_DIRECTORY_NAME
+ return std::string(TEMP_DIRECTORY_NAME);
+#else
+ #error non-static temporary directory names not supported yet
+#endif
+}
+
+#endif // TEMPORARYDIRECTORY__H
diff --git a/lib/common/Test.cpp b/lib/common/Test.cpp
index de87c465..b627ac18 100644
--- a/lib/common/Test.cpp
+++ b/lib/common/Test.cpp
@@ -21,7 +21,10 @@
#include <unistd.h>
#endif
+<<<<<<< HEAD
+=======
#include "BoxTime.h"
+>>>>>>> 0.12
#include "Test.h"
bool TestFileExists(const char *Filename)
@@ -44,10 +47,17 @@ bool TestDirExists(const char *Filename)
}
// -1 if doesn't exist
+<<<<<<< HEAD
+int TestGetFileSize(const char *Filename)
+{
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(Filename, &st) == 0)
+=======
int TestGetFileSize(const std::string& Filename)
{
EMU_STRUCT_STAT st;
if(EMU_STAT(Filename.c_str(), &st) == 0)
+>>>>>>> 0.12
{
return st.st_size;
}
@@ -452,6 +462,40 @@ void wait_for_operation(int seconds, const char* message)
void safe_sleep(int seconds)
{
+<<<<<<< HEAD
+ BOX_TRACE("sleeping for " << seconds << " seconds");
+
+#ifdef WIN32
+ Sleep(seconds * 1000);
+#else
+ struct timespec ts;
+ memset(&ts, 0, sizeof(ts));
+ ts.tv_sec = seconds;
+ ts.tv_nsec = 0;
+ while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
+ {
+ // FIXME evil hack for OSX, where ts.tv_sec contains
+ // a negative number interpreted as unsigned 32-bit
+ // when nanosleep() returns later than expected.
+
+ int32_t secs = (int32_t) ts.tv_sec;
+ int64_t remain_ns = (secs * 1000000000) + ts.tv_nsec;
+
+ if (remain_ns < 0)
+ {
+ BOX_WARNING("nanosleep interrupted " <<
+ ((float)(0 - remain_ns) / 1000000000) <<
+ " secs late");
+ return;
+ }
+
+ BOX_TRACE("nanosleep interrupted with " <<
+ (remain_ns / 1000000000) << " secs remaining, "
+ "sleeping again");
+ }
+#endif
+=======
ShortSleep(SecondsToBoxTime(seconds), true);
+>>>>>>> 0.12
}
diff --git a/lib/common/Test.h b/lib/common/Test.h
index f318c811..a09a64af 100644
--- a/lib/common/Test.h
+++ b/lib/common/Test.h
@@ -51,6 +51,33 @@ extern std::string bbackupd_args, bbstored_args, bbackupquery_args, test_args;
#define TEST_THAT_ABORTONFAIL(condition) {if(!(condition)) TEST_ABORT_WITH_MESSAGE("Condition [" #condition "] failed")}
// NOTE: The 0- bit is to allow this to work with stuff which has negative constants for flags (eg ConnectionException)
+<<<<<<< HEAD
+#define TEST_CHECK_THROWS(statement, excepttype, subtype) \
+ { \
+ bool didthrow = false; \
+ HideExceptionMessageGuard hide; \
+ try \
+ { \
+ statement; \
+ } \
+ catch(excepttype &e) \
+ { \
+ if(e.GetSubType() != ((unsigned int)excepttype::subtype) \
+ && e.GetSubType() != (unsigned int)(0-excepttype::subtype)) \
+ { \
+ throw; \
+ } \
+ didthrow = true; \
+ } \
+ catch(...) \
+ { \
+ throw; \
+ } \
+ if(!didthrow) \
+ { \
+ TEST_FAIL_WITH_MESSAGE("Didn't throw exception " #excepttype "(" #subtype ")") \
+ } \
+=======
#define TEST_CHECK_THROWS(statement, excepttype, subtype) \
{ \
bool didthrow = false; \
@@ -78,6 +105,7 @@ extern std::string bbackupd_args, bbstored_args, bbackupquery_args, test_args;
{ \
TEST_FAIL_WITH_MESSAGE("Didn't throw exception " #excepttype "(" #subtype ")") \
} \
+>>>>>>> 0.12
}
// utility macro for comparing two strings in a line
@@ -93,7 +121,11 @@ extern std::string bbackupd_args, bbstored_args, bbackupquery_args, test_args;
\
if(_exp_str != _found_str) \
{ \
+<<<<<<< HEAD
+ BOX_WARNING("Expected <" << _exp_str << "> but found <" << \
+=======
BOX_ERROR("Expected <" << _exp_str << "> but found <" << \
+>>>>>>> 0.12
_found_str << ">"); \
\
std::ostringstream _oss3; \
@@ -129,22 +161,34 @@ extern std::string bbackupd_args, bbstored_args, bbackupquery_args, test_args;
} \
}
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
// utility macro for testing a line
#define TEST_LINE(_condition, _line) \
TEST_THAT(_condition); \
if (!(_condition)) \
{ \
+<<<<<<< HEAD
+ printf("Test failed on <%s>\n", _line.c_str()); \
+=======
std::ostringstream _ossl; \
_ossl << _line; \
std::string _line_str = _ossl.str(); \
printf("Test failed on <%s>\n", _line_str.c_str()); \
+>>>>>>> 0.12
}
bool TestFileExists(const char *Filename);
bool TestDirExists(const char *Filename);
// -1 if doesn't exist
+<<<<<<< HEAD
+int TestGetFileSize(const char *Filename);
+=======
int TestGetFileSize(const std::string& Filename);
+>>>>>>> 0.12
std::string ConvertPaths(const std::string& rOriginal);
int RunCommand(const std::string& rCommandLine);
bool ServerIsAlive(int pid);
diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp
index ad6b5e8d..390ddf8e 100644
--- a/lib/common/Timer.cpp
+++ b/lib/common/Timer.cpp
@@ -8,6 +8,14 @@
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+#ifdef WIN32
+ #define _WIN32_WINNT 0x0500
+#endif
+
+#include "Box.h"
+
+=======
#include "Box.h"
#ifdef WIN32
@@ -18,6 +26,7 @@
# endif
#endif
+>>>>>>> 0.12
#include <signal.h>
#include <cstring>
@@ -30,7 +39,11 @@ std::vector<Timer*>* Timers::spTimers = NULL;
bool Timers::sRescheduleNeeded = false;
#define TIMER_ID "timer " << mName << " (" << this << ") "
+<<<<<<< HEAD
+#define TIMER_ID_OF(t) "timer " << (t).GetName() << " (" << &(t) << ") "
+=======
#define TIMER_ID_OF(t) "timer " << (t).GetName() << " (" << &(t) << ")"
+>>>>>>> 0.12
typedef void (*sighandler_t)(int);
@@ -119,7 +132,10 @@ void Timers::Add(Timer& rTimer)
{
ASSERT(spTimers);
ASSERT(&rTimer);
+<<<<<<< HEAD
+=======
BOX_TRACE(TIMER_ID_OF(rTimer) " added to global queue, rescheduling");
+>>>>>>> 0.12
spTimers->push_back(&rTimer);
Reschedule();
}
@@ -137,7 +153,10 @@ void Timers::Remove(Timer& rTimer)
{
ASSERT(spTimers);
ASSERT(&rTimer);
+<<<<<<< HEAD
+=======
BOX_TRACE(TIMER_ID_OF(rTimer) " removed from global queue, rescheduling");
+>>>>>>> 0.12
bool restart = true;
while (restart)
@@ -172,6 +191,13 @@ void Timers::RescheduleIfNeeded()
}
}
+<<<<<<< HEAD
+#define FORMAT_MICROSECONDS(t) \
+ (int)(t / 1000000) << "." << \
+ (int)(t % 1000000) << " seconds"
+
+=======
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -234,9 +260,19 @@ void Timers::Reschedule()
if (timeToExpiry <= 0)
{
+<<<<<<< HEAD
+ /*
+ BOX_TRACE("timer " << *i << " has expired, "
+ "triggering it");
+ */
+ BOX_TRACE(TIMER_ID_OF(**i) "has expired, "
+ "triggering " <<
+ FORMAT_MICROSECONDS(-timeToExpiry) <<
+=======
BOX_TRACE(TIMER_ID_OF(**i) " has expired, "
"triggering " <<
BOX_FORMAT_MICROSECONDS(-timeToExpiry) <<
+>>>>>>> 0.12
" late");
rTimer.OnExpire();
spTimers->erase(i);
@@ -246,8 +282,13 @@ void Timers::Reschedule()
else
{
/*
+<<<<<<< HEAD
+ BOX_TRACE("timer " << *i << " has not "
+ "expired, triggering in " <<
+=======
BOX_TRACE(TIMER_ID_OF(**i) " has not expired, "
"triggering in " <<
+>>>>>>> 0.12
FORMAT_MICROSECONDS(timeToExpiry) <<
" seconds");
*/
@@ -288,8 +329,13 @@ void Timers::Reschedule()
}
else
{
+<<<<<<< HEAD
+ BOX_TRACE("timer: next event: " << nameOfNextEvent <<
+ " expires in " << FORMAT_MICROSECONDS(timeToNextEvent));
+=======
BOX_TRACE("timer: next event: " << nameOfNextEvent << " at " <<
FormatTime(timeNow + timeToNextEvent, false, true));
+>>>>>>> 0.12
}
struct itimerval timeout;
@@ -329,7 +375,11 @@ void Timers::SignalHandler(int unused)
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+// Name: Timer::Timer(size_t timeoutSecs,
+=======
// Name: Timer::Timer(size_t timeoutMillis,
+>>>>>>> 0.12
// const std::string& rName)
// Purpose: Standard timer constructor, takes a timeout in
// seconds from now, and an optional name for
@@ -338,82 +388,161 @@ void Timers::SignalHandler(int unused)
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+Timer::Timer(size_t timeoutSecs, const std::string& rName)
+: mExpires(GetCurrentBoxTime() + SecondsToBoxTime(timeoutSecs)),
+=======
Timer::Timer(size_t timeoutMillis, const std::string& rName)
: mExpires(0),
+>>>>>>> 0.12
mExpired(false),
mName(rName)
#ifdef WIN32
, mTimerHandle(INVALID_HANDLE_VALUE)
#endif
{
+<<<<<<< HEAD
+ #ifndef BOX_RELEASE_BUILD
+ if (timeoutSecs == 0)
+ {
+ BOX_TRACE(TIMER_ID "initialised for " << timeoutSecs <<
+ " secs, will not fire");
+ }
+ else
+ {
+ BOX_TRACE(TIMER_ID "initialised for " << timeoutSecs <<
+ " secs, to fire at " << FormatTime(mExpires, false, true));
+ }
+ #endif
+
+ if (timeoutSecs == 0)
+ {
+ mExpires = 0;
+ }
+ else
+ {
+ Timers::Add(*this);
+ Start(timeoutSecs * MICRO_SEC_IN_SEC_LL);
+ }
+=======
Set(timeoutMillis, true /* isInit */);
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
//
// Function
// Name: Timer::Start()
+<<<<<<< HEAD
+// Purpose: This internal function initialises an OS TimerQueue
+// timer on Windows, while on Unixes there is only a
+// single global timer, managed by the Timers class,
+// so this method does nothing.
+=======
// Purpose: This internal function recalculates the remaining
// time (timeout) from the expiry time, and then calls
// Start(timeoutMillis).
+>>>>>>> 0.12
// Created: 27/07/2008
//
// --------------------------------------------------------------------------
void Timer::Start()
{
+<<<<<<< HEAD
+#ifdef WIN32
+=======
+>>>>>>> 0.12
box_time_t timeNow = GetCurrentBoxTime();
int64_t timeToExpiry = mExpires - timeNow;
if (timeToExpiry <= 0)
{
BOX_WARNING(TIMER_ID << "fudging expiry from -" <<
+<<<<<<< HEAD
+ FORMAT_MICROSECONDS(-timeToExpiry))
+ timeToExpiry = 1;
+ }
+
+ Start(timeToExpiry);
+#endif
+=======
BOX_FORMAT_MICROSECONDS(-timeToExpiry))
timeToExpiry = 1;
}
Start(timeToExpiry / MICRO_SEC_IN_MILLI_SEC);
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+// Name: Timer::Start(int64_t delayInMicros)
+// Purpose: This internal function initialises an OS TimerQueue
+// timer on Windows, with a specified delay already
+// calculated to save us doing it again. Like
+// Timer::Start(), on Unixes it does nothing.
+=======
// Name: Timer::Start(int64_t timeoutMillis)
// Purpose: This internal function adds this timer to the global
// timer list, and on Windows it initialises an OS
// TimerQueue timer for it.
+>>>>>>> 0.12
// Created: 27/07/2008
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+void Timer::Start(int64_t delayInMicros)
+{
+=======
void Timer::Start(int64_t timeoutMillis)
{
ASSERT(mExpires != 0);
Timers::Add(*this);
+>>>>>>> 0.12
#ifdef WIN32
// only call me once!
ASSERT(mTimerHandle == INVALID_HANDLE_VALUE);
+<<<<<<< HEAD
+ int64_t delayInMillis = delayInMicros / 1000;
+
+=======
+>>>>>>> 0.12
// Windows XP always seems to fire timers up to 20 ms late,
// at least on my test laptop. Not critical in practice, but our
// tests are precise enough that they will fail if we don't
// correct for it.
+<<<<<<< HEAD
+ delayInMillis -= 20;
+
+ // Set a system timer to call our timer routine
+ if (CreateTimerQueueTimer(&mTimerHandle, NULL, TimerRoutine,
+ (PVOID)this, delayInMillis, 0, WT_EXECUTEINTIMERTHREAD)
+=======
timeoutMillis -= 20;
// Set a system timer to call our timer routine
if (CreateTimerQueueTimer(&mTimerHandle, NULL, TimerRoutine,
(PVOID)this, timeoutMillis, 0, WT_EXECUTEINTIMERTHREAD)
+>>>>>>> 0.12
== FALSE)
{
BOX_ERROR(TIMER_ID "failed to create timer: " <<
GetErrorMessage(GetLastError()));
mTimerHandle = INVALID_HANDLE_VALUE;
}
+<<<<<<< HEAD
+=======
else
{
BOX_INFO(TIMER_ID << "set for " << timeoutMillis << " ms");
}
+>>>>>>> 0.12
#endif
}
@@ -421,20 +550,29 @@ void Timer::Start(int64_t timeoutMillis)
//
// Function
// Name: Timer::Stop()
+<<<<<<< HEAD
+// Purpose: This internal function deletes the associated OS
+// TimerQueue timer on Windows, and on Unixes does
+// nothing.
+=======
// Purpose: This internal function removes us from the global
// list of timers, resets our expiry time, and on
// Windows it deletes the associated OS TimerQueue timer.
+>>>>>>> 0.12
// Created: 27/07/2008
//
// --------------------------------------------------------------------------
void Timer::Stop()
{
+<<<<<<< HEAD
+=======
if (mExpires != 0)
{
Timers::Remove(*this);
}
+>>>>>>> 0.12
#ifdef WIN32
if (mTimerHandle != INVALID_HANDLE_VALUE)
{
@@ -464,6 +602,12 @@ Timer::~Timer()
BOX_TRACE(TIMER_ID "destroyed");
#endif
+<<<<<<< HEAD
+ Timers::Remove(*this);
+ Stop();
+}
+
+=======
Stop();
}
@@ -488,6 +632,7 @@ void Timer::LogAssignment(const Timer &From)
#endif
}
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -507,10 +652,36 @@ Timer::Timer(const Timer& rToCopy)
, mTimerHandle(INVALID_HANDLE_VALUE)
#endif
{
+<<<<<<< HEAD
+ #ifndef BOX_RELEASE_BUILD
+ if (mExpired)
+ {
+ BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", "
+ "already expired, will not fire");
+ }
+ else if (mExpires == 0)
+ {
+ BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", "
+ "no expiry, will not fire");
+ }
+ else
+ {
+ BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", "
+ "to fire at " <<
+ (int)(mExpires / 1000000) << "." <<
+ (int)(mExpires % 1000000));
+ }
+ #endif
+
+ if (!mExpired && mExpires != 0)
+ {
+ Timers::Add(*this);
+=======
LogAssignment(rToCopy);
if (!mExpired && mExpires != 0)
{
+>>>>>>> 0.12
Start();
}
}
@@ -529,8 +700,32 @@ Timer::Timer(const Timer& rToCopy)
Timer& Timer::operator=(const Timer& rToCopy)
{
+<<<<<<< HEAD
+ #ifndef BOX_RELEASE_BUILD
+ if (rToCopy.mExpired)
+ {
+ BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", "
+ "already expired, will not fire");
+ }
+ else if (rToCopy.mExpires == 0)
+ {
+ BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", "
+ "no expiry, will not fire");
+ }
+ else
+ {
+ BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", "
+ "to fire at " <<
+ (int)(rToCopy.mExpires / 1000000) << "." <<
+ (int)(rToCopy.mExpires % 1000000));
+ }
+ #endif
+
+ Timers::Remove(*this);
+=======
LogAssignment(rToCopy);
+>>>>>>> 0.12
Stop();
mExpires = rToCopy.mExpires;
@@ -539,6 +734,10 @@ Timer& Timer::operator=(const Timer& rToCopy)
if (!mExpired && mExpires != 0)
{
+<<<<<<< HEAD
+ Timers::Add(*this);
+=======
+>>>>>>> 0.12
Start();
}
@@ -548,6 +747,8 @@ Timer& Timer::operator=(const Timer& rToCopy)
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+=======
// Name: Timer::Reset(size_t timeoutMillis)
// Purpose: Simple reset operation for an existing Timer. Avoids
// the need to create a temporary timer just to modify
@@ -609,6 +810,7 @@ void Timer::Set(size_t timeoutMillis, bool isInit)
// --------------------------------------------------------------------------
//
// Function
+>>>>>>> 0.12
// Name: Timer::OnExpire()
// Purpose: Method called by Timers::Reschedule (on Unixes)
// on next poll after timer expires, or from
diff --git a/lib/common/Timer.h b/lib/common/Timer.h
index 09be58fa..d3e46b2a 100644
--- a/lib/common/Timer.h
+++ b/lib/common/Timer.h
@@ -53,7 +53,11 @@ class Timers
class Timer
{
public:
+<<<<<<< HEAD
+ Timer(size_t timeoutSecs, const std::string& rName = "");
+=======
Timer(size_t timeoutMillis, const std::string& rName = "");
+>>>>>>> 0.12
virtual ~Timer();
Timer(const Timer &);
Timer &operator=(const Timer &);
@@ -67,7 +71,10 @@ public:
}
const std::string& GetName() const { return mName; }
+<<<<<<< HEAD
+=======
virtual void Reset(size_t timeoutMillis);
+>>>>>>> 0.12
private:
box_time_t mExpires;
@@ -75,10 +82,15 @@ private:
std::string mName;
void Start();
+<<<<<<< HEAD
+ void Start(int64_t delayInMicros);
+ void Stop();
+=======
void Start(int64_t timeoutMillis);
void Stop();
void LogAssignment(const Timer &From);
virtual void Set(size_t timeoutMillis, bool isReset);
+>>>>>>> 0.12
#ifdef WIN32
HANDLE mTimerHandle;
diff --git a/lib/common/UnixUser.cpp b/lib/common/UnixUser.cpp
index 32acacfa..7e69b10a 100644
--- a/lib/common/UnixUser.cpp
+++ b/lib/common/UnixUser.cpp
@@ -31,13 +31,21 @@
// Created: 21/1/04
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+UnixUser::UnixUser(const char *Username)
+=======
UnixUser::UnixUser(const std::string& Username)
+>>>>>>> 0.12
: mUID(0),
mGID(0),
mRevertOnDestruction(false)
{
// Get password info
+<<<<<<< HEAD
+ struct passwd *pwd = ::getpwnam(Username);
+=======
struct passwd *pwd = ::getpwnam(Username.c_str());
+>>>>>>> 0.12
if(pwd == 0)
{
THROW_EXCEPTION(CommonException, CouldNotLookUpUsername)
diff --git a/lib/common/UnixUser.h b/lib/common/UnixUser.h
index dafe6aa7..361971b8 100644
--- a/lib/common/UnixUser.h
+++ b/lib/common/UnixUser.h
@@ -13,7 +13,11 @@
class UnixUser
{
public:
+<<<<<<< HEAD
+ UnixUser(const char *Username);
+=======
UnixUser(const std::string& Username);
+>>>>>>> 0.12
UnixUser(uid_t UID, gid_t GID);
~UnixUser();
private:
diff --git a/lib/common/Utils.cpp b/lib/common/Utils.cpp
index decc80e8..3137d980 100644
--- a/lib/common/Utils.cpp
+++ b/lib/common/Utils.cpp
@@ -24,6 +24,11 @@
#include <cxxabi.h>
#endif
+<<<<<<< HEAD
+#include "Utils.h"
+#include "CommonException.h"
+#include "Logging.h"
+=======
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
@@ -35,6 +40,7 @@
#include "CommonException.h"
#include "Logging.h"
#include "Utils.h"
+>>>>>>> 0.12
#include "MemLeakFindOn.h"
@@ -81,6 +87,14 @@ void SplitString(const std::string &String, char SplitOn, std::vector<std::strin
}
#ifdef SHOW_BACKTRACE_ON_EXCEPTION
+<<<<<<< HEAD
+void DumpStackBacktrace()
+{
+ void *array[10];
+ size_t size = backtrace (array, 10);
+ char **strings = backtrace_symbols (array, size);
+
+=======
static std::string demangle(const std::string& mangled_name)
{
#ifdef HAVE_CXXABI_H
@@ -145,10 +159,85 @@ void DumpStackBacktrace()
{
void *array[10];
size_t size = backtrace(array, 10);
+>>>>>>> 0.12
BOX_TRACE("Obtained " << size << " stack frames.");
for(size_t i = 0; i < size; i++)
{
+<<<<<<< HEAD
+ // Demangling code copied from
+ // cctbx_sources/boost_adaptbx/meta_ext.cpp, BSD license
+
+ std::string mangled_frame = strings[i];
+ std::string output_frame = strings[i]; // default
+
+ #ifdef HAVE_CXXABI_H
+ int start = mangled_frame.find('(');
+ int end = mangled_frame.find('+', start);
+ std::string mangled_func = mangled_frame.substr(start + 1,
+ end - start - 1);
+
+ int status;
+
+#include "MemLeakFindOff.h"
+ char* result = abi::__cxa_demangle(mangled_func.c_str(),
+ NULL, NULL, &status);
+#include "MemLeakFindOn.h"
+
+ if (result == NULL)
+ {
+ if (status == 0)
+ {
+ BOX_WARNING("Demangle failed but no error: " <<
+ mangled_func);
+ }
+ else if (status == -1)
+ {
+ BOX_WARNING("Demangle failed with "
+ "memory allocation error: " <<
+ mangled_func);
+ }
+ else if (status == -2)
+ {
+ // Probably non-C++ name, don't demangle
+ /*
+ BOX_WARNING("Demangle failed with "
+ "with invalid name: " <<
+ mangled_func);
+ */
+ }
+ else if (status == -3)
+ {
+ BOX_WARNING("Demangle failed with "
+ "with invalid argument: " <<
+ mangled_func);
+ }
+ else
+ {
+ BOX_WARNING("Demangle failed with "
+ "with unknown error " << status <<
+ ": " << mangled_func);
+ }
+ }
+ else
+ {
+ output_frame = mangled_frame.substr(0, start + 1) +
+ result + mangled_frame.substr(end);
+#include "MemLeakFindOff.h"
+ std::free(result);
+#include "MemLeakFindOn.h"
+ }
+ #endif // HAVE_CXXABI_H
+
+ BOX_TRACE("Stack frame " << i << ": " << output_frame);
+ }
+
+#include "MemLeakFindOff.h"
+ std::free (strings);
+#include "MemLeakFindOn.h"
+}
+#endif
+=======
std::ostringstream output;
output << "Stack frame " << i << ": ";
@@ -181,6 +270,7 @@ void DumpStackBacktrace()
}
}
#endif // SHOW_BACKTRACE_ON_EXCEPTION
+>>>>>>> 0.12
@@ -339,6 +429,8 @@ std::string FormatUsageLineStart(const std::string& rName,
return result.str();
}
+<<<<<<< HEAD
+=======
std::string BoxGetTemporaryDirectoryName()
{
@@ -367,3 +459,4 @@ std::string BoxGetTemporaryDirectoryName()
}
+>>>>>>> 0.12
diff --git a/lib/common/Utils.h b/lib/common/Utils.h
index 3134245a..8a938981 100644
--- a/lib/common/Utils.h
+++ b/lib/common/Utils.h
@@ -39,8 +39,11 @@ std::string FormatUsageBar(int64_t Blocks, int64_t Bytes, int64_t Max,
std::string FormatUsageLineStart(const std::string& rName,
bool MachineReadable);
+<<<<<<< HEAD
+=======
std::string BoxGetTemporaryDirectoryName();
+>>>>>>> 0.12
#include "MemLeakFindOff.h"
#endif // UTILS__H
diff --git a/lib/common/ZeroStream.cpp b/lib/common/ZeroStream.cpp
index d11ed80c..26fd62cb 100644
--- a/lib/common/ZeroStream.cpp
+++ b/lib/common/ZeroStream.cpp
@@ -152,7 +152,11 @@ void ZeroStream::Close()
// --------------------------------------------------------------------------
bool ZeroStream::StreamDataLeft()
{
+<<<<<<< HEAD
+ return false;
+=======
return (BytesLeftToRead() > 0);
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
diff --git a/lib/common/makeexception.pl.in b/lib/common/makeexception.pl.in
index b1b3a8ac..593740da 100755
--- a/lib/common/makeexception.pl.in
+++ b/lib/common/makeexception.pl.in
@@ -191,7 +191,11 @@ unsigned int ${class}Exception::GetSubType() const throw()
const char *${class}Exception::what() const throw()
{
#ifdef EXCEPTION_CODENAMES_EXTENDED
+<<<<<<< HEAD
+ if(mSubType < 0 || mSubType > (sizeof(whats) / sizeof(whats[0])))
+=======
if(mSubType > (sizeof(whats) / sizeof(whats[0])))
+>>>>>>> 0.12
{
return "${class}";
}
diff --git a/lib/crypto/CipherAES.h b/lib/crypto/CipherAES.h
index d2c9ed65..dbcce9e5 100644
--- a/lib/crypto/CipherAES.h
+++ b/lib/crypto/CipherAES.h
@@ -37,6 +37,8 @@ public:
// Setup any other parameters
virtual void SetupParameters(EVP_CIPHER_CTX *pCipherContext) const;
+<<<<<<< HEAD
+=======
virtual std::string GetCipherName() const
{
std::ostringstream out;
@@ -46,6 +48,7 @@ public:
}
virtual CipherMode GetCipherMode() const { return mMode; }
+>>>>>>> 0.12
private:
CipherDescription::CipherMode mMode;
const void *mpKey;
diff --git a/lib/crypto/CipherBlowfish.h b/lib/crypto/CipherBlowfish.h
index 152a265c..27903a3e 100644
--- a/lib/crypto/CipherBlowfish.h
+++ b/lib/crypto/CipherBlowfish.h
@@ -38,6 +38,8 @@ public:
// Setup any other parameters
virtual void SetupParameters(EVP_CIPHER_CTX *pCipherContext) const;
+<<<<<<< HEAD
+=======
virtual std::string GetCipherName() const
{
std::ostringstream out;
@@ -47,6 +49,7 @@ public:
}
virtual CipherMode GetCipherMode() const { return mMode; }
+>>>>>>> 0.12
#ifdef HAVE_OLD_SSL
CipherDescription *Clone() const;
void SetIV(const void *pIV);
diff --git a/lib/crypto/CipherContext.cpp b/lib/crypto/CipherContext.cpp
index fd149395..6621f79a 100644
--- a/lib/crypto/CipherContext.cpp
+++ b/lib/crypto/CipherContext.cpp
@@ -13,7 +13,10 @@
#include "CipherContext.h"
#include "CipherDescription.h"
#include "CipherException.h"
+<<<<<<< HEAD
+=======
#include "CryptoUtils.h"
+>>>>>>> 0.12
#include "Random.h"
#include "MemLeakFindOn.h"
@@ -27,12 +30,21 @@
//
// --------------------------------------------------------------------------
CipherContext::CipherContext()
+<<<<<<< HEAD
+ : mInitialised(false),
+ mWithinTransform(false),
+ mPaddingOn(true)
+#ifdef HAVE_OLD_SSL
+ , mFunction(Decrypt),
+ mpDescription(0)
+=======
: mInitialised(false),
mWithinTransform(false),
mPaddingOn(true),
mFunction(None)
#ifdef HAVE_OLD_SSL
, mpDescription(0)
+>>>>>>> 0.12
#endif
{
}
@@ -65,6 +77,8 @@ CipherContext::~CipherContext()
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+=======
// Name: CipherContext::LogError(const std::string& operation)
// Purpose: Logs and clears any OpenSSL errors, returning the
// most recent error message for use in exception
@@ -87,6 +101,7 @@ std::string CipherContext::LogError(const std::string& operation)
// --------------------------------------------------------------------------
//
// Function
+>>>>>>> 0.12
// Name: CipherContext::Init(CipherContext::CipherFunction, const CipherDescription &)
// Purpose: Initialises the context, specifying the direction for the encryption, and a
// description of the cipher to use, it's keys, etc
@@ -105,13 +120,28 @@ void CipherContext::Init(CipherContext::CipherFunction Function, const CipherDes
THROW_EXCEPTION(CipherException, BadArguments)
}
+<<<<<<< HEAD
+=======
// Store function for later
mFunction = Function;
+>>>>>>> 0.12
// Initialise the cipher
#ifndef HAVE_OLD_SSL
EVP_CIPHER_CTX_init(&ctx); // no error return code, even though the docs says it does
+<<<<<<< HEAD
+ if(EVP_CipherInit_ex(&ctx, rDescription.GetCipher(), NULL, NULL, NULL, Function) != 1)
+#else
+ // Store function for later
+ mFunction = Function;
+
+ // Use old version of init call
+ if(EVP_CipherInit(&ctx, rDescription.GetCipher(), NULL, NULL, Function) != 1)
+#endif
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+=======
if(EVP_CipherInit_ex(&ctx, rDescription.GetCipher(), NULL, NULL, NULL,
(mFunction == Encrypt) ? 1 : 0) != 1)
#else
@@ -123,11 +153,15 @@ void CipherContext::Init(CipherContext::CipherFunction Function, const CipherDes
THROW_EXCEPTION_MESSAGE(CipherException, EVPInitFailure,
"Failed to initialise " << rDescription.GetFullName()
<< "cipher: " << LogError("initialising cipher"));
+>>>>>>> 0.12
}
try
{
+<<<<<<< HEAD
+=======
mCipherName = rDescription.GetFullName();
+>>>>>>> 0.12
#ifndef HAVE_OLD_SSL
// Let the description set up everything else
rDescription.SetupParameters(&ctx);
@@ -142,9 +176,12 @@ void CipherContext::Init(CipherContext::CipherFunction Function, const CipherDes
}
catch(...)
{
+<<<<<<< HEAD
+=======
THROW_EXCEPTION_MESSAGE(CipherException, EVPInitFailure,
"Failed to configure " << mCipherName << " cipher: " <<
LogError("configuring cipher"));
+>>>>>>> 0.12
EVP_CIPHER_CTX_cleanup(&ctx);
throw;
}
@@ -205,9 +242,13 @@ void CipherContext::Begin()
// Initialise the cipher context again
if(EVP_CipherInit(&ctx, NULL, NULL, NULL, -1) != 1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+=======
THROW_EXCEPTION_MESSAGE(CipherException, EVPInitFailure,
"Failed to reset " << mCipherName << " cipher: " <<
LogError("resetting cipher"));
+>>>>>>> 0.12
}
// Mark as being within a transform
@@ -260,9 +301,13 @@ int CipherContext::Transform(void *pOutBuffer, int OutLength, const void *pInBuf
int outLength = OutLength;
if(EVP_CipherUpdate(&ctx, (unsigned char*)pOutBuffer, &outLength, (unsigned char*)pInBuffer, InLength) != 1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(CipherException, EVPUpdateFailure)
+=======
THROW_EXCEPTION_MESSAGE(CipherException, EVPUpdateFailure,
"Failed to " << GetFunction() << " (update) " <<
mCipherName << " cipher: " << LogError(GetFunction()));
+>>>>>>> 0.12
}
return outLength;
@@ -308,12 +353,18 @@ int CipherContext::Final(void *pOutBuffer, int OutLength)
// Do the transform
int outLength = OutLength;
#ifndef HAVE_OLD_SSL
+<<<<<<< HEAD
+ if(EVP_CipherFinal_ex(&ctx, (unsigned char*)pOutBuffer, &outLength) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPFinalFailure)
+=======
if(EVP_CipherFinal(&ctx, (unsigned char*)pOutBuffer, &outLength) != 1)
{
mWithinTransform = false;
THROW_EXCEPTION_MESSAGE(CipherException, EVPFinalFailure,
"Failed to " << GetFunction() << " (final) " <<
mCipherName << " cipher: " << LogError(GetFunction()));
+>>>>>>> 0.12
}
#else
OldOpenSSLFinal((unsigned char*)pOutBuffer, outLength);
@@ -391,8 +442,12 @@ void CipherContext::OldOpenSSLFinal(unsigned char *Buffer, int &rOutLengthOut)
}
}
// Reinitialise the cipher for the next time around
+<<<<<<< HEAD
+ if(EVP_CipherInit(&ctx, mpDescription->GetCipher(), NULL, NULL, mFunction) != 1)
+=======
if(EVP_CipherInit(&ctx, mpDescription->GetCipher(), NULL, NULL,
(mFunction == Encrypt) ? 1 : 0) != 1)
+>>>>>>> 0.12
{
THROW_EXCEPTION(CipherException, EVPInitFailure)
}
@@ -490,6 +545,39 @@ int CipherContext::TransformBlock(void *pOutBuffer, int OutLength, const void *p
// Do the entire block
int outLength = 0;
+<<<<<<< HEAD
+ try
+ {
+ // Update
+ outLength = OutLength;
+ if(EVP_CipherUpdate(&ctx, (unsigned char*)pOutBuffer, &outLength, (unsigned char*)pInBuffer, InLength) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPUpdateFailure)
+ }
+ // Finalise
+ int outLength2 = OutLength - outLength;
+#ifndef HAVE_OLD_SSL
+ if(EVP_CipherFinal_ex(&ctx, ((unsigned char*)pOutBuffer) + outLength, &outLength2) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPFinalFailure)
+ }
+#else
+ OldOpenSSLFinal(((unsigned char*)pOutBuffer) + outLength, outLength2);
+#endif
+ outLength += outLength2;
+ }
+ catch(...)
+ {
+ // Finalise the context, so definately ready for the next caller
+ int outs = OutLength;
+#ifndef HAVE_OLD_SSL
+ EVP_CipherFinal_ex(&ctx, (unsigned char*)pOutBuffer, &outs);
+#else
+ OldOpenSSLFinal((unsigned char*)pOutBuffer, outs);
+#endif
+ throw;
+ }
+=======
// Update
outLength = OutLength;
@@ -513,6 +601,7 @@ int CipherContext::TransformBlock(void *pOutBuffer, int OutLength, const void *p
OldOpenSSLFinal(((unsigned char*)pOutBuffer) + outLength, outLength2);
#endif
outLength += outLength2;
+>>>>>>> 0.12
return outLength;
}
@@ -562,9 +651,13 @@ void CipherContext::SetIV(const void *pIV)
// Set IV
if(EVP_CipherInit(&ctx, NULL, NULL, (unsigned char *)pIV, -1) != 1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+=======
THROW_EXCEPTION_MESSAGE(CipherException, EVPInitFailure,
"Failed to " << GetFunction() << " (set IV) " <<
mCipherName << " cipher: " << LogError(GetFunction()));
+>>>>>>> 0.12
}
#ifdef HAVE_OLD_SSL
@@ -609,7 +702,24 @@ const void *CipherContext::SetRandomIV(int &rLengthOut)
// Generate some random data
Random::Generate(mGeneratedIV, ivLen);
+<<<<<<< HEAD
+
+ // Set IV
+ if(EVP_CipherInit(&ctx, NULL, NULL, mGeneratedIV, -1) != 1)
+ {
+ THROW_EXCEPTION(CipherException, EVPInitFailure)
+ }
+
+#ifdef HAVE_OLD_SSL
+ // Update description
+ if(mpDescription != 0)
+ {
+ mpDescription->SetIV(mGeneratedIV);
+ }
+#endif
+=======
SetIV(mGeneratedIV);
+>>>>>>> 0.12
// Return the IV and it's length
rLengthOut = ivLen;
diff --git a/lib/crypto/CipherContext.h b/lib/crypto/CipherContext.h
index 93c889d6..092c10d5 100644
--- a/lib/crypto/CipherContext.h
+++ b/lib/crypto/CipherContext.h
@@ -35,15 +35,23 @@ public:
private:
CipherContext(const CipherContext &); // no copying
CipherContext &operator=(const CipherContext &); // no assignment
+<<<<<<< HEAD
+=======
protected:
std::string LogError(const std::string& operation);
+>>>>>>> 0.12
public:
typedef enum
{
+<<<<<<< HEAD
+ Decrypt = 0,
+ Encrypt = 1
+=======
None = 0,
Decrypt,
Encrypt
+>>>>>>> 0.12
} CipherFunction;
void Init(CipherContext::CipherFunction Function, const CipherDescription &rDescription);
@@ -64,10 +72,13 @@ public:
const void *SetRandomIV(int &rLengthOut);
void UsePadding(bool Padding = true);
+<<<<<<< HEAD
+=======
const char* GetFunction() const
{
return (mFunction == Encrypt) ? "encrypt" : "decrypt";
}
+>>>>>>> 0.12
#ifdef HAVE_OLD_SSL
void OldOpenSSLFinal(unsigned char *Buffer, int &rOutLengthOut);
@@ -79,9 +90,14 @@ private:
bool mWithinTransform;
bool mPaddingOn;
uint8_t mGeneratedIV[CIPHERCONTEXT_MAX_GENERATED_IV_LENGTH];
+<<<<<<< HEAD
+#ifdef HAVE_OLD_SSL
+ CipherFunction mFunction;
+=======
CipherFunction mFunction;
std::string mCipherName;
#ifdef HAVE_OLD_SSL
+>>>>>>> 0.12
CipherDescription *mpDescription;
#endif
};
diff --git a/lib/crypto/CipherDescription.h b/lib/crypto/CipherDescription.h
index 813df2ce..15438494 100644
--- a/lib/crypto/CipherDescription.h
+++ b/lib/crypto/CipherDescription.h
@@ -34,7 +34,11 @@ public:
// Return OpenSSL cipher object
virtual const EVP_CIPHER *GetCipher() const = 0;
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
// Setup any other parameters
virtual void SetupParameters(EVP_CIPHER_CTX *pCipherContext) const = 0;
@@ -47,6 +51,8 @@ public:
Mode_OFB = 3
} CipherMode;
+<<<<<<< HEAD
+=======
virtual std::string GetCipherName() const = 0;
virtual CipherMode GetCipherMode() const = 0;
virtual std::string GetFullName() const
@@ -64,6 +70,7 @@ public:
return out.str();
}
+>>>>>>> 0.12
#ifdef HAVE_OLD_SSL
// For the old version of OpenSSL, we need to be able to store cipher descriptions.
virtual CipherDescription *Clone() const = 0;
diff --git a/lib/raidfile/RaidFileController.cpp b/lib/raidfile/RaidFileController.cpp
index cf93947f..84c2a520 100644
--- a/lib/raidfile/RaidFileController.cpp
+++ b/lib/raidfile/RaidFileController.cpp
@@ -164,18 +164,26 @@ RaidFileDiscSet &RaidFileController::GetDiscSet(unsigned int DiscSetNum)
{
if(DiscSetNum < 0 || DiscSetNum >= mSetList.size())
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, NoSuchDiscSet)
+=======
THROW_EXCEPTION_MESSAGE(RaidFileException, NoSuchDiscSet, DiscSetNum <<
" (" << mSetList.size() << " disc sets configured)")
+>>>>>>> 0.12
}
return mSetList[DiscSetNum];
}
+<<<<<<< HEAD
+
+=======
// Overload to make usable in gdb debugger.
int RaidFileDiscSet::GetSetNumForWriteFiles(const char* filename) const
{
return GetSetNumForWriteFiles(std::string(filename));
}
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
diff --git a/lib/raidfile/RaidFileController.h b/lib/raidfile/RaidFileController.h
index 601cca22..b2b8cb0d 100644
--- a/lib/raidfile/RaidFileController.h
+++ b/lib/raidfile/RaidFileController.h
@@ -49,7 +49,11 @@ public:
int GetSetID() const {return mSetID;}
int GetSetNumForWriteFiles(const std::string &rFilename) const;
+<<<<<<< HEAD
+
+=======
int GetSetNumForWriteFiles(const char* filename) const;
+>>>>>>> 0.12
unsigned int GetBlockSize() const {return mBlockSize;}
// Is this disc set a non-RAID disc set? (ie files never get transformed to raid storage)
diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp
index bcff54c6..3a7a5893 100644
--- a/lib/raidfile/RaidFileRead.cpp
+++ b/lib/raidfile/RaidFileRead.cpp
@@ -12,10 +12,14 @@
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
+<<<<<<< HEAD
+#include <unistd.h>
+=======
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
+>>>>>>> 0.12
#include <sys/stat.h>
#include <sys/types.h>
@@ -1025,8 +1029,13 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
RaidFileUtil::ExistType existance = RaidFileUtil::RaidFileExists(rdiscSet, Filename, &startDisc, &existingFiles, pRevisionID);
if(existance == RaidFileUtil::NoFile)
{
+<<<<<<< HEAD
+ BOX_ERROR("Expected raidfile " << Filename << " does not exist");
+ THROW_EXCEPTION(RaidFileException, RaidFileDoesntExist)
+=======
THROW_FILE_ERROR("Expected raidfile does not exist",
Filename, RaidFileException, RaidFileDoesntExist);
+>>>>>>> 0.12
}
else if(existance == RaidFileUtil::NonRaid)
{
@@ -1089,6 +1098,11 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
{
stripe2errno = errno;
}
+<<<<<<< HEAD
+ if(stripe1errno != 0 || stripe2errno != 0)
+ {
+ THROW_EXCEPTION(RaidFileException, ErrorOpeningFileForRead)
+=======
if(stripe1errno != 0)
{
@@ -1102,6 +1116,7 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
THROW_SYS_FILE_ERRNO("Failed to open RaidFile",
stripe2Filename, stripe2errno,
RaidFileException, ErrorOpeningFileForRead);
+>>>>>>> 0.12
}
// stat stripe 1 to find ('half' of) length...
@@ -1120,6 +1135,13 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
length += st.st_size;
// Handle errors
+<<<<<<< HEAD
+ if(stripe1errno != 0 || stripe2errno != 0)
+ {
+ THROW_EXCEPTION(RaidFileException, OSError)
+ }
+
+=======
if(stripe1errno != 0)
{
THROW_SYS_FILE_ERRNO("Failed to stat RaidFile",
@@ -1134,6 +1156,7 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
RaidFileException, OSError);
}
+>>>>>>> 0.12
// Make a nice object to represent this file
return std::auto_ptr<RaidFileRead>(new RaidFileRead_Raid(SetNumber, Filename, stripe1, stripe2, -1, length, rdiscSet.GetBlockSize(), false /* actually we don't know */));
}
@@ -1260,14 +1283,26 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
ASSERT(sizeof(FileSizeType) == 8); // compiler bug (I think) prevents from using 0 - sizeof(FileSizeType)...
if(::lseek(parity, -8 /*(0 - sizeof(FileSizeType))*/, SEEK_END) == -1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to seek "
"in parity RaidFile",
parityFilename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
// Read it in
if(::read(parity, &parityLastData, sizeof(parityLastData)) != sizeof(parityLastData))
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+ }
+ // Set back to beginning of file
+ if(::lseek(parity, 0, SEEK_SET) == -1)
+ {
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to read "
"parity RaidFile",
parityFilename,
@@ -1281,6 +1316,7 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
"in parity RaidFile",
parityFilename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
}
@@ -1303,10 +1339,14 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
// to get the size from the FileSizeType value at end of the file.
if(::fstat(stripe1, &st) != 0)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to "
"stat RaidFile stripe 1",
stripe1Filename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
pos_type stripe1Size = st.st_size;
// Is size integral?
@@ -1340,26 +1380,38 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
ASSERT(btr <= (int)sizeof(FileSizeType));
if(::lseek(stripe1, 0 - btr, SEEK_END) == -1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to "
"seek in RaidFile stripe 1",
stripe1Filename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
// Read it in
if(::read(stripe1, &stripe1LastData, btr) != btr)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to "
"read RaidFile stripe 1",
stripe1Filename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
// Set back to beginning of file
if(::lseek(stripe1, 0, SEEK_SET) == -1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to "
"seek in RaidFile stripe 1",
stripe1Filename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
}
// Lovely!
@@ -1381,10 +1433,14 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
// Get size of stripe2 file
if(::fstat(stripe2, &st) != 0)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to "
"stat RaidFile stripe 2",
stripe2Filename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
pos_type stripe2Size = st.st_size;
@@ -1453,8 +1509,12 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
}
}
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, FileIsDamagedNotRecoverable)
+=======
THROW_FILE_ERROR("Failed to recover RaidFile", Filename,
RaidFileException, FileIsDamagedNotRecoverable);
+>>>>>>> 0.12
// Avoid compiler warning -- it'll never get here...
return std::auto_ptr<RaidFileRead>();
@@ -1588,7 +1648,11 @@ bool RaidFileRead::ReadDirectoryContents(int SetNumber, const std::string &rDirN
{
// build name
std::string dn(rdiscSet[l] + DIRECTORY_SEPARATOR + rDirName);
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
// read the contents...
DIR *dirHandle = 0;
try
diff --git a/lib/raidfile/RaidFileWrite.cpp b/lib/raidfile/RaidFileWrite.cpp
index 82aeef3d..cb1f9699 100644
--- a/lib/raidfile/RaidFileWrite.cpp
+++ b/lib/raidfile/RaidFileWrite.cpp
@@ -11,6 +11,12 @@
#include <errno.h>
#include <fcntl.h>
+<<<<<<< HEAD
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/file.h>
+=======
#ifdef HAVE_UNISTD_H
# include <unistd.h>
@@ -22,6 +28,7 @@
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
+>>>>>>> 0.12
#include <stdio.h>
#include <string.h>
@@ -102,6 +109,9 @@ RaidFileWrite::~RaidFileWrite()
{
if(mOSFileHandle != -1)
{
+<<<<<<< HEAD
+ Discard();
+=======
// We must not throw exceptions from the destructor
// http://stackoverflow.com/a/130123
try
@@ -124,6 +134,7 @@ RaidFileWrite::~RaidFileWrite()
BOX_ERROR("Failed to discard RaidFile update "
"in destructor: unknown exception");
}
+>>>>>>> 0.12
}
}
@@ -154,25 +165,45 @@ void RaidFileWrite::Open(bool AllowOverwrite)
RaidFileUtil::ExistType existance = RaidFileUtil::RaidFileExists(rdiscSet, mFilename);
if(existance != RaidFileUtil::NoFile)
{
+<<<<<<< HEAD
+ BOX_ERROR("Attempted to overwrite raidfile " <<
+ mSetNumber << " " << mFilename);
+ THROW_EXCEPTION(RaidFileException, CannotOverwriteExistingFile)
+=======
THROW_FILE_ERROR("Attempted to overwrite raidfile " <<
mSetNumber, mFilename, RaidFileException,
CannotOverwriteExistingFile);
+>>>>>>> 0.12
}
}
// Get the filename for the write file
+<<<<<<< HEAD
+ std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
+ // Add on a temporary extension
+ writeFilename += 'X';
+
+ // Attempt to open
+ mOSFileHandle = ::open(writeFilename.c_str(),
+=======
mTempFilename = RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename);
// Add on a temporary extension
mTempFilename += 'X';
// Attempt to open
mOSFileHandle = ::open(mTempFilename.c_str(),
+>>>>>>> 0.12
O_WRONLY | O_CREAT | O_BINARY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(mOSFileHandle == -1)
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to open file: " << writeFilename);
+ THROW_EXCEPTION(RaidFileException, ErrorOpeningWriteFile)
+=======
THROW_SYS_FILE_ERROR("Failed to open RaidFile", mTempFilename,
RaidFileException, ErrorOpeningWriteFile);
+>>>>>>> 0.12
}
// Get a lock on the write file
@@ -192,6 +223,17 @@ void RaidFileWrite::Open(bool AllowOverwrite)
if (0)
#endif
{
+<<<<<<< HEAD
+ // Lock was not obtained.
+ bool wasLocked = (errno == errnoBlock);
+ // Close the file
+ ::close(mOSFileHandle);
+ mOSFileHandle = -1;
+ // Report an exception?
+ if(wasLocked)
+ {
+ THROW_EXCEPTION(RaidFileException, FileIsCurrentlyOpenForWriting)
+=======
int errnoSaved = errno;
// Lock was not obtained.
@@ -208,19 +250,27 @@ void RaidFileWrite::Open(bool AllowOverwrite)
"already locked", mTempFilename, errnoSaved,
RaidFileException,
FileIsCurrentlyOpenForWriting);
+>>>>>>> 0.12
}
else
{
// Random error occured
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERRNO("Failed to lock RaidFile",
mTempFilename, errnoSaved, RaidFileException,
OSError);
+>>>>>>> 0.12
}
}
// Truncate it to size zero
if(::ftruncate(mOSFileHandle, 0) != 0)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, ErrorOpeningWriteFileOnTruncate)
+=======
int errnoSaved = errno;
// Close the file
@@ -230,6 +280,7 @@ void RaidFileWrite::Open(bool AllowOverwrite)
THROW_SYS_FILE_ERRNO("Failed to truncate RaidFile",
mTempFilename, errnoSaved, RaidFileException,
ErrorOpeningWriteFileOnTruncate);
+>>>>>>> 0.12
}
// Done!
@@ -255,10 +306,16 @@ void RaidFileWrite::Write(const void *pBuffer, int Length)
int written = ::write(mOSFileHandle, pBuffer, Length);
if(written != Length)
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("RaidFileWrite failed, Length = " <<
+ Length << ", written = " << written);
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to write to RaidFile (attempted "
"to write " << Length << " bytes but managed only " <<
written << ")", mTempFilename, RaidFileException,
OSError);
+>>>>>>> 0.12
}
}
@@ -282,8 +339,12 @@ IOStream::pos_type RaidFileWrite::GetPosition() const
off_t p = ::lseek(mOSFileHandle, 0, SEEK_CUR);
if(p == -1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to get position in RaidFile",
mTempFilename, RaidFileException, OSError);
+>>>>>>> 0.12
}
return p;
@@ -308,8 +369,12 @@ void RaidFileWrite::Seek(IOStream::pos_type SeekTo, int SeekType)
// Seek...
if(::lseek(mOSFileHandle, SeekTo, ConvertSeekTypeToOSWhence(SeekType)) == -1)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to set position in RaidFile",
mTempFilename, RaidFileException, OSError);
+>>>>>>> 0.12
}
}
@@ -331,8 +396,14 @@ void RaidFileWrite::Commit(bool ConvertToRaidNow)
if (mRefCount == 0)
{
+<<<<<<< HEAD
+ BOX_ERROR("Attempted to modify object " << mFilename <<
+ ", which has no references");
+ THROW_EXCEPTION(RaidFileException,
+=======
THROW_FILE_ERROR("Attempted to modify object file with "
"no references", mTempFilename, RaidFileException,
+>>>>>>> 0.12
RequestedModifyUnreferencedFile);
}
@@ -343,8 +414,12 @@ void RaidFileWrite::Commit(bool ConvertToRaidNow)
// Close file...
if(::close(mOSFileHandle) != 0)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_WIN_FILE_ERROR("Failed to close RaidFile for rename",
mTempFilename, RaidFileException, OSError);
+>>>>>>> 0.12
}
mOSFileHandle = -1;
#endif // WIN32
@@ -358,6 +433,13 @@ void RaidFileWrite::Commit(bool ConvertToRaidNow)
#ifdef WIN32
// need to delete the target first
+<<<<<<< HEAD
+ if(::unlink(renameTo.c_str()) != 0 &&
+ GetLastError() != ERROR_FILE_NOT_FOUND)
+ {
+ BOX_LOG_WIN_ERROR("Failed to delete file: " << renameTo);
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
if(::unlink(renameTo.c_str()) != 0)
{
DWORD errorNumber = GetLastError();
@@ -366,21 +448,32 @@ void RaidFileWrite::Commit(bool ConvertToRaidNow)
THROW_WIN_FILE_ERRNO("Failed to delete file", renameTo,
errorNumber, RaidFileException, OSError);
}
+>>>>>>> 0.12
}
#endif
if(::rename(renameFrom.c_str(), renameTo.c_str()) != 0)
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to rename file: " << renameFrom <<
+ " to " << renameTo);
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_ERROR("Failed to rename file: " << renameFrom <<
" to " << renameTo, RaidFileException, OSError);
+>>>>>>> 0.12
}
#ifndef WIN32
// Close file...
if(::close(mOSFileHandle) != 0)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to close committed RaidFile",
mTempFilename, RaidFileException, OSError);
+>>>>>>> 0.12
}
mOSFileHandle = -1;
#endif // !WIN32
@@ -427,8 +520,13 @@ void RaidFileWrite::Discard()
::close(mOSFileHandle) != 0)
#endif // !WIN32
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to delete file: " << writeFilename);
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to delete file", writeFilename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
// reset file handle
@@ -729,9 +827,16 @@ void RaidFileWrite::Delete()
{
if (mRefCount != 0 && mRefCount != -1)
{
+<<<<<<< HEAD
+ BOX_ERROR("Attempted to delete object " << mFilename <<
+ " which has " << mRefCount << " references");
+ THROW_EXCEPTION(RaidFileException,
+ RequestedDeleteReferencedFile);
+=======
THROW_FILE_ERROR("Attempted to delete object with " <<
mRefCount << " references", mFilename,
RaidFileException, RequestedDeleteReferencedFile);
+>>>>>>> 0.12
}
// Get disc set
@@ -742,9 +847,13 @@ void RaidFileWrite::Delete()
RaidFileUtil::ExistType existance = RaidFileUtil::RaidFileExists(rdiscSet, mFilename);
if(existance == RaidFileUtil::NoFile)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, RaidFileDoesntExist)
+=======
THROW_FILE_ERROR("Attempted to delete object which doesn't "
"exist", mFilename, RaidFileException,
RaidFileDoesntExist);
+>>>>>>> 0.12
}
// Get the filename for the write file
@@ -783,8 +892,12 @@ void RaidFileWrite::Delete()
// Check something happened
if(!deletedSomething)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_FILE_ERROR("Failed to delete a RaidFile stripe set",
mFilename, RaidFileException, OSError);
+>>>>>>> 0.12
}
}
@@ -855,6 +968,13 @@ void RaidFileWrite::CreateDirectory(const RaidFileDiscSet &rSet, const std::stri
if(errno == EEXIST)
{
// No. Bad things.
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, FileExistsInDirectoryCreation)
+ }
+ else
+ {
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to create "
"RaidFile directory", dn,
RaidFileException,
@@ -865,6 +985,7 @@ void RaidFileWrite::CreateDirectory(const RaidFileDiscSet &rSet, const std::stri
THROW_SYS_FILE_ERROR("Failed to create "
"RaidFile directory", dn,
RaidFileException, OSError);
+>>>>>>> 0.12
}
}
}
@@ -947,8 +1068,12 @@ IOStream::pos_type RaidFileWrite::GetFileSize()
struct stat st;
if(fstat(mOSFileHandle, &st) != 0)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to stat RaidFile", mTempFilename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
return st.st_size;
@@ -977,8 +1102,12 @@ IOStream::pos_type RaidFileWrite::GetDiscUsageInBlocks()
struct stat st;
if(fstat(mOSFileHandle, &st) != 0)
{
+<<<<<<< HEAD
+ THROW_EXCEPTION(RaidFileException, OSError)
+=======
THROW_SYS_FILE_ERROR("Failed to stat RaidFile", mTempFilename,
RaidFileException, OSError);
+>>>>>>> 0.12
}
// Then return calculation
diff --git a/lib/raidfile/RaidFileWrite.h b/lib/raidfile/RaidFileWrite.h
index e2887167..52621676 100644
--- a/lib/raidfile/RaidFileWrite.h
+++ b/lib/raidfile/RaidFileWrite.h
@@ -27,6 +27,9 @@ class RaidFileDiscSet;
class RaidFileWrite : public IOStream
{
public:
+<<<<<<< HEAD
+ RaidFileWrite(int SetNumber, const std::string &Filename);
+=======
// TODO FIXME we should remove this constructor, and ensure that
// anyone who writes to a RaidFile knows what the reference count
// is before doing so. That requires supporting regenerating the
@@ -39,6 +42,7 @@ public:
// snapshots.
RaidFileWrite(int SetNumber, const std::string &Filename);
+>>>>>>> 0.12
RaidFileWrite(int SetNumber, const std::string &Filename, int refcount);
~RaidFileWrite();
private:
@@ -70,7 +74,11 @@ private:
private:
int mSetNumber;
+<<<<<<< HEAD
+ std::string mFilename;
+=======
std::string mFilename, mTempFilename;
+>>>>>>> 0.12
int mOSFileHandle;
int mRefCount;
};
diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp
index 7419f973..9b96647b 100644
--- a/lib/server/Daemon.cpp
+++ b/lib/server/Daemon.cpp
@@ -25,6 +25,19 @@
#ifdef WIN32
#include <ws2tcpip.h>
+<<<<<<< HEAD
+#endif
+
+#include <iostream>
+
+#include "Daemon.h"
+#include "Configuration.h"
+#include "ServerException.h"
+#include "Guards.h"
+#include "UnixUser.h"
+#include "FileModificationTime.h"
+#include "Logging.h"
+=======
#include <process.h>
#endif
@@ -43,6 +56,7 @@
#include "Logging.h"
#include "ServerException.h"
#include "UnixUser.h"
+>>>>>>> 0.12
#include "Utils.h"
#include "MemLeakFindOn.h"
@@ -71,7 +85,10 @@ Daemon::Daemon()
mKeepConsoleOpenAfterFork(false),
#endif
mHaveConfigFile(false),
+<<<<<<< HEAD
+=======
mLogFileLevel(Log::INVALID),
+>>>>>>> 0.12
mAppName(DaemonName())
{
// In debug builds, switch on assert failure logging to syslog
@@ -108,16 +125,25 @@ std::string Daemon::GetOptionString()
{
return "c:"
#ifndef WIN32
+<<<<<<< HEAD
+ "DFK"
+ #endif
+ "hkPqQt:TUvVW:";
+=======
"DF"
#endif
"hkKo:O:PqQt:TUvVW:";
+>>>>>>> 0.12
}
void Daemon::Usage()
{
std::cout <<
DaemonBanner() << "\n"
+<<<<<<< HEAD
+=======
"(built with QDBM " << dpversion << ")\n"
+>>>>>>> 0.12
"\n"
"Usage: " << mAppName << " [options] [config file]\n"
"\n"
@@ -130,6 +156,20 @@ void Daemon::Usage()
" -F Do not fork into background, but fork to serve multiple clients\n"
#endif
" -k Keep console open after fork, keep writing log messages to it\n"
+<<<<<<< HEAD
+#ifndef WIN32
+ " -K Stop writing log messages to console while daemon is running\n"
+ " -P Show process ID (PID) in console output\n"
+#endif
+ " -q Run more quietly, reduce verbosity level by one, can repeat\n"
+ " -Q Run at minimum verbosity, log nothing\n"
+ " -v Run more verbosely, increase verbosity level by one, can repeat\n"
+ " -V Run at maximum verbosity, log everything\n"
+ " -W <level> Set verbosity to error/warning/notice/info/trace/everything\n"
+ " -t <tag> Tag console output with specified marker\n"
+ " -T Timestamp console output\n"
+ " -U Timestamp console output with microseconds\n";
+=======
" -K Stop writing log messages to console while daemon is running\n"
" -o <file> Log to a file, defaults to maximum verbosity\n"
" -O <level> Set file log verbosity to error/warning/notice/info/trace/everything\n"
@@ -143,6 +183,7 @@ void Daemon::Usage()
" -V Run at maximum verbosity, log everything to console and system\n"
" -W <level> Set verbosity to error/warning/notice/info/trace/everything\n"
;
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -181,6 +222,8 @@ int Daemon::ProcessOption(signed int option)
break;
#endif // !WIN32
+<<<<<<< HEAD
+=======
case 'h':
{
Usage();
@@ -188,6 +231,7 @@ int Daemon::ProcessOption(signed int option)
}
break;
+>>>>>>> 0.12
case 'k':
{
mKeepConsoleOpenAfterFork = true;
@@ -200,6 +244,12 @@ int Daemon::ProcessOption(signed int option)
}
break;
+<<<<<<< HEAD
+ case 'h':
+ {
+ Usage();
+ return 2;
+=======
case 'o':
{
mLogFile = optarg;
@@ -215,6 +265,7 @@ int Daemon::ProcessOption(signed int option)
BOX_FATAL("Invalid logging level: " << optarg);
return 2;
}
+>>>>>>> 0.12
}
break;
@@ -243,6 +294,8 @@ int Daemon::ProcessOption(signed int option)
}
break;
+<<<<<<< HEAD
+=======
case 't':
{
Logging::SetProgramName(optarg);
@@ -262,6 +315,7 @@ int Daemon::ProcessOption(signed int option)
Console::SetShowTimeMicros(true);
}
break;
+>>>>>>> 0.12
case 'v':
{
@@ -287,12 +341,39 @@ int Daemon::ProcessOption(signed int option)
mLogLevel = Logging::GetNamedLevel(optarg);
if (mLogLevel == Log::INVALID)
{
+<<<<<<< HEAD
+ BOX_FATAL("Invalid logging level");
+=======
BOX_FATAL("Invalid logging level: " << optarg);
+>>>>>>> 0.12
return 2;
}
}
break;
+<<<<<<< HEAD
+ case 't':
+ {
+ Logging::SetProgramName(optarg);
+ Console::SetShowTag(true);
+ }
+ break;
+
+ case 'T':
+ {
+ Console::SetShowTime(true);
+ }
+ break;
+
+ case 'U':
+ {
+ Console::SetShowTime(true);
+ Console::SetShowTimeMicros(true);
+ }
+ break;
+
+=======
+>>>>>>> 0.12
case '?':
{
BOX_FATAL("Unknown option on command line: "
@@ -322,6 +403,18 @@ int Daemon::ProcessOption(signed int option)
// Created: 2003/07/29
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
+{
+ // Find filename of config file
+ mConfigFileName = DefaultConfigFile;
+ mAppName = argv[0];
+
+ #ifdef BOX_RELEASE_BUILD
+ mLogLevel = Log::NOTICE; // need an int to do math with
+ #else
+ mLogLevel = Log::INFO; // need an int to do math with
+=======
int Daemon::Main(const std::string& rDefaultConfigFile, int argc,
const char *argv[])
{
@@ -355,6 +448,7 @@ int Daemon::ProcessOptions(int argc, const char *argv[])
mLogLevel = Log::NOTICE;
#else
mLogLevel = Log::INFO;
+>>>>>>> 0.12
#endif
if (argc == 2 && strcmp(argv[1], "/?") == 0)
@@ -409,6 +503,9 @@ int Daemon::ProcessOptions(int argc, const char *argv[])
Logging::FilterConsole((Log::Level)mLogLevel);
Logging::FilterSyslog ((Log::Level)mLogLevel);
+<<<<<<< HEAD
+ return Main(mConfigFileName);
+=======
if (mLogFileLevel != Log::INVALID)
{
mapLogFileLogger.reset(
@@ -416,6 +513,7 @@ int Daemon::ProcessOptions(int argc, const char *argv[])
}
return 0;
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -437,7 +535,11 @@ bool Daemon::Configure(const std::string& rConfigFileName)
try
{
+<<<<<<< HEAD
+ if (!FileExists(rConfigFileName.c_str()))
+=======
if (!FileExists(rConfigFileName))
+>>>>>>> 0.12
{
BOX_FATAL("The main configuration file for " <<
DaemonName() << " was not found: " <<
@@ -1025,6 +1127,11 @@ void Daemon::SetProcessTitle(const char *format, ...)
char title[256];
::vsnprintf(title, sizeof(title), format, args);
+<<<<<<< HEAD
+ // Set process title
+ ::setproctitle("%s", title);
+
+=======
#ifdef WIN32
StringCchCatA(title, sizeof(title)," - " PACKAGE_NAME);
SetConsoleTitleA(title);
@@ -1033,6 +1140,7 @@ void Daemon::SetProcessTitle(const char *format, ...)
::setproctitle("%s", title);
#endif
+>>>>>>> 0.12
#endif // HAVE_SETPROCTITLE
}
diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h
index 2718c288..f2fa98c3 100644
--- a/lib/server/Daemon.h
+++ b/lib/server/Daemon.h
@@ -40,9 +40,14 @@ private:
Daemon(const Daemon &rToCopy);
public:
+<<<<<<< HEAD
+ virtual int Main(const char *DefaultConfigFile, int argc,
+ const char *argv[]);
+=======
virtual int Main(const std::string& rDefaultConfigFile, int argc,
const char *argv[]);
virtual int ProcessOptions(int argc, const char *argv[]);
+>>>>>>> 0.12
/* override this Main() if you want custom option processing: */
virtual int Main(const std::string &rConfigFile);
@@ -100,9 +105,12 @@ private:
bool mKeepConsoleOpenAfterFork;
bool mHaveConfigFile;
int mLogLevel; // need an int to do math with
+<<<<<<< HEAD
+=======
std::string mLogFile;
Log::Level mLogFileLevel;
std::auto_ptr<FileLogger> mapLogFileLogger;
+>>>>>>> 0.12
static Daemon *spDaemon;
std::string mAppName;
};
diff --git a/lib/server/Protocol.cpp b/lib/server/Protocol.cpp
index 382f1c37..6333b1db 100644
--- a/lib/server/Protocol.cpp
+++ b/lib/server/Protocol.cpp
@@ -11,9 +11,14 @@
#include <sys/types.h>
+<<<<<<< HEAD
+#include <stdlib.h>
+#include <string.h>
+=======
#include <cstdlib>
#include <cstring>
#include <cstdio>
+>>>>>>> 0.12
#include <new>
@@ -45,6 +50,19 @@
//
// --------------------------------------------------------------------------
Protocol::Protocol(IOStream &rStream)
+<<<<<<< HEAD
+ : mrStream(rStream),
+ mHandshakeDone(false),
+ mMaxObjectSize(PROTOCOL_DEFAULT_MAXOBJSIZE),
+ mTimeout(PROTOCOL_DEFAULT_TIMEOUT),
+ mpBuffer(0),
+ mBufferSize(0),
+ mReadOffset(-1),
+ mWriteOffset(-1),
+ mValidDataSize(-1),
+ mLastErrorType(NoError),
+ mLastErrorSubType(NoError)
+=======
: mrStream(rStream),
mHandshakeDone(false),
mMaxObjectSize(PROTOCOL_DEFAULT_MAXOBJSIZE),
@@ -56,6 +74,7 @@ Protocol::Protocol(IOStream &rStream)
mValidDataSize(-1),
mLogToSysLog(false),
mLogToFile(NULL)
+>>>>>>> 0.12
{
BOX_TRACE("Send block allocation size is " <<
PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK);
@@ -83,6 +102,37 @@ Protocol::~Protocol()
// --------------------------------------------------------------------------
//
// Function
+<<<<<<< HEAD
+// Name: Protocol::GetLastError(int &, int &)
+// Purpose: Returns true if there was an error, and type and subtype if there was.
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+bool Protocol::GetLastError(int &rTypeOut, int &rSubTypeOut)
+{
+ if(mLastErrorType == NoError)
+ {
+ // no error.
+ return false;
+ }
+
+ // Return type and subtype in args
+ rTypeOut = mLastErrorType;
+ rSubTypeOut = mLastErrorSubType;
+
+ // and unset them
+ mLastErrorType = NoError;
+ mLastErrorSubType = NoError;
+
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+=======
+>>>>>>> 0.12
// Name: Protocol::Handshake()
// Purpose: Handshake with peer (exchange ident strings)
// Created: 2003/08/20
@@ -100,7 +150,11 @@ void Protocol::Handshake()
PW_Handshake hsSend;
::memset(&hsSend, 0, sizeof(hsSend));
// Copy in ident string
+<<<<<<< HEAD
+ ::strncpy(hsSend.mIdent, GetIdentString(), sizeof(hsSend.mIdent));
+=======
::strncpy(hsSend.mIdent, GetProtocolIdentString(), sizeof(hsSend.mIdent));
+>>>>>>> 0.12
// Send it
mrStream.Write(&hsSend, sizeof(hsSend));
@@ -173,7 +227,11 @@ void Protocol::CheckAndReadHdr(void *hdr)
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+std::auto_ptr<ProtocolObject> Protocol::Receive()
+=======
std::auto_ptr<Message> Protocol::ReceiveInternal()
+>>>>>>> 0.12
{
// Get object header
PW_ObjectHeader objHeader;
@@ -193,7 +251,11 @@ std::auto_ptr<Message> Protocol::ReceiveInternal()
}
// Create a blank object
+<<<<<<< HEAD
+ std::auto_ptr<ProtocolObject> obj(MakeProtocolObject(ntohl(objHeader.mObjType)));
+=======
std::auto_ptr<Message> obj(MakeMessage(ntohl(objHeader.mObjType)));
+>>>>>>> 0.12
// Make sure memory is allocated to read it into
EnsureBufferAllocated(objSize);
@@ -245,7 +307,11 @@ std::auto_ptr<Message> Protocol::ReceiveInternal()
// Created: 2003/08/19
//
// --------------------------------------------------------------------------
+<<<<<<< HEAD
+void Protocol::Send(const ProtocolObject &rObject)
+=======
void Protocol::SendInternal(const Message &rObject)
+>>>>>>> 0.12
{
// Check usage
if(mValidDataSize != -1 || mWriteOffset != -1 || mReadOffset != -1)
@@ -688,6 +754,8 @@ void Protocol::SendStream(IOStream &rStream)
// Can't send this using the fixed size header
uncertainSize = true;
}
+<<<<<<< HEAD
+=======
if(streamSize == 0)
{
@@ -699,6 +767,7 @@ void Protocol::SendStream(IOStream &rStream)
"Sending a stream with a definite size of zero "
"is not allowed in the protocol");
}
+>>>>>>> 0.12
// Inform sub class
InformStreamSending(streamSize);
@@ -838,6 +907,9 @@ int Protocol::SendStreamSendBlock(uint8_t *Block, int BytesInBlock)
// --------------------------------------------------------------------------
void Protocol::InformStreamReceiving(u_int32_t Size)
{
+<<<<<<< HEAD
+ // Do nothing
+=======
if(GetLogToSysLog())
{
if(Size == Protocol::ProtocolStream_SizeUncertain)
@@ -858,6 +930,7 @@ void Protocol::InformStreamReceiving(u_int32_t Size)
: "Receiving stream, size %d\n", Size);
::fflush(GetLogToFile());
}
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -870,6 +943,9 @@ void Protocol::InformStreamReceiving(u_int32_t Size)
// --------------------------------------------------------------------------
void Protocol::InformStreamSending(u_int32_t Size)
{
+<<<<<<< HEAD
+ // Do nothing
+=======
if(GetLogToSysLog())
{
if(Size == Protocol::ProtocolStream_SizeUncertain)
@@ -890,6 +966,7 @@ void Protocol::InformStreamSending(u_int32_t Size)
: "Sending stream, size %d\n", Size);
::fflush(GetLogToFile());
}
+>>>>>>> 0.12
}
diff --git a/lib/server/Protocol.h b/lib/server/Protocol.h
index 42cb0ff8..dc660ad5 100644
--- a/lib/server/Protocol.h
+++ b/lib/server/Protocol.h
@@ -12,14 +12,22 @@
#include <sys/types.h>
+<<<<<<< HEAD
+class IOStream;
+#include "ProtocolObject.h"
+=======
+>>>>>>> 0.12
#include <memory>
#include <vector>
#include <string>
+<<<<<<< HEAD
+=======
#include "Message.h"
class IOStream;
+>>>>>>> 0.12
// default timeout is 15 minutes
#define PROTOCOL_DEFAULT_TIMEOUT (15*60*1000)
// 16 default maximum object size -- should be enough
@@ -42,6 +50,13 @@ public:
private:
Protocol(const Protocol &rToCopy);
+<<<<<<< HEAD
+public:
+ void Handshake();
+ std::auto_ptr<ProtocolObject> Receive();
+ void Send(const ProtocolObject &rObject);
+
+=======
protected:
// Unsafe to make public, as they may allow sending objects
// from a different protocol. The derived class prevents this.
@@ -50,6 +65,7 @@ protected:
public:
void Handshake();
+>>>>>>> 0.12
std::auto_ptr<IOStream> ReceiveStream();
void SendStream(IOStream &rStream);
@@ -59,6 +75,11 @@ public:
UnknownError = 0
};
+<<<<<<< HEAD
+ bool GetLastError(int &rTypeOut, int &rSubTypeOut);
+
+=======
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -90,7 +111,11 @@ public:
// --------------------------------------------------------------------------
void SetMaxObjectSize(unsigned int NewMaxObjSize) {mMaxObjectSize = NewMaxObjSize;}
+<<<<<<< HEAD
+ // For ProtocolObject derived classes
+=======
// For Message derived classes
+>>>>>>> 0.12
void Read(void *Buffer, int Size);
void Read(std::string &rOut, int Size);
void Read(int64_t &rOut);
@@ -171,6 +196,13 @@ public:
{
ProtocolStream_SizeUncertain = 0xffffffff
};
+<<<<<<< HEAD
+
+protected:
+ virtual std::auto_ptr<ProtocolObject> MakeProtocolObject(int ObjType) = 0;
+ virtual const char *GetIdentString() = 0;
+ void SetError(int Type, int SubType) {mLastErrorType = Type; mLastErrorSubType = SubType;}
+=======
bool GetLogToSysLog() { return mLogToSysLog; }
FILE *GetLogToFile() { return mLogToFile; }
void SetLogToSysLog(bool Log = false) {mLogToSysLog = Log;}
@@ -180,6 +212,7 @@ protected:
virtual std::auto_ptr<Message> MakeMessage(int ObjType) = 0;
virtual const char *GetProtocolIdentString() = 0;
+>>>>>>> 0.12
void CheckAndReadHdr(void *hdr); // don't use type here to avoid dependency
// Will be used for logging
@@ -190,6 +223,10 @@ private:
void EnsureBufferAllocated(int Size);
int SendStreamSendBlock(uint8_t *Block, int BytesInBlock);
+<<<<<<< HEAD
+private:
+=======
+>>>>>>> 0.12
IOStream &mrStream;
bool mHandshakeDone;
unsigned int mMaxObjectSize;
@@ -199,12 +236,17 @@ private:
int mReadOffset;
int mWriteOffset;
int mValidDataSize;
+<<<<<<< HEAD
+ int mLastErrorType;
+ int mLastErrorSubType;
+=======
bool mLogToSysLog;
FILE *mLogToFile;
};
class ProtocolContext
{
+>>>>>>> 0.12
};
#endif // PROTOCOL__H
diff --git a/lib/server/ProtocolObject.cpp b/lib/server/ProtocolObject.cpp
new file mode 100644
index 00000000..fb09f820
--- /dev/null
+++ b/lib/server/ProtocolObject.cpp
@@ -0,0 +1,125 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ProtocolObject.h
+// Purpose: Protocol object base class
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "ProtocolObject.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ProtocolObject::ProtocolObject()
+// Purpose: Default constructor
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+ProtocolObject::ProtocolObject()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ProtocolObject::ProtocolObject()
+// Purpose: Destructor
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+ProtocolObject::~ProtocolObject()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ProtocolObject::ProtocolObject()
+// Purpose: Copy constructor
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+ProtocolObject::ProtocolObject(const ProtocolObject &rToCopy)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ProtocolObject::IsError(int &, int &)
+// Purpose: Does this represent an error, and if so, what is the type and subtype?
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+bool ProtocolObject::IsError(int &rTypeOut, int &rSubTypeOut) const
+{
+ return false;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ProtocolObject::IsConversationEnd()
+// Purpose: Does this command end the conversation?
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+bool ProtocolObject::IsConversationEnd() const
+{
+ return false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ProtocolObject::GetType()
+// Purpose: Return type of the object
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+int ProtocolObject::GetType() const
+{
+ // This isn't implemented in the base class!
+ THROW_EXCEPTION(CommonException, Internal)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ProtocolObject::SetPropertiesFromStreamData(Protocol &)
+// Purpose: Set the properties of the object from the stream data ready in the Protocol object
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+void ProtocolObject::SetPropertiesFromStreamData(Protocol &rProtocol)
+{
+ // This isn't implemented in the base class!
+ THROW_EXCEPTION(CommonException, Internal)
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ProtocolObject::WritePropertiesToStreamData(Protocol &)
+// Purpose: Write the properties of the object into the stream data in the Protocol object
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+void ProtocolObject::WritePropertiesToStreamData(Protocol &rProtocol) const
+{
+ // This isn't implemented in the base class!
+ THROW_EXCEPTION(CommonException, Internal)
+}
+
+
+
diff --git a/lib/server/ProtocolObject.h b/lib/server/ProtocolObject.h
new file mode 100644
index 00000000..0a127ab5
--- /dev/null
+++ b/lib/server/ProtocolObject.h
@@ -0,0 +1,41 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ProtocolObject.h
+// Purpose: Protocol object base class
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+
+#ifndef PROTOCOLOBJECT__H
+#define PROTOCOLOBJECT__H
+
+class Protocol;
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: ProtocolObject
+// Purpose: Basic object representation of objects to pass through a Protocol session
+// Created: 2003/08/19
+//
+// --------------------------------------------------------------------------
+class ProtocolObject
+{
+public:
+ ProtocolObject();
+ virtual ~ProtocolObject();
+ ProtocolObject(const ProtocolObject &rToCopy);
+
+ // Info about this object
+ virtual int GetType() const;
+ virtual bool IsError(int &rTypeOut, int &rSubTypeOut) const;
+ virtual bool IsConversationEnd() const;
+
+ // reading and writing with Protocol objects
+ virtual void SetPropertiesFromStreamData(Protocol &rProtocol);
+ virtual void WritePropertiesToStreamData(Protocol &rProtocol) const;
+};
+
+#endif // PROTOCOLOBJECT__H
+
diff --git a/lib/server/SSLLib.cpp b/lib/server/SSLLib.cpp
index 004d2d98..6feaae4a 100644
--- a/lib/server/SSLLib.cpp
+++ b/lib/server/SSLLib.cpp
@@ -18,7 +18,10 @@
#include <wincrypt.h>
#endif
+<<<<<<< HEAD
+=======
#include "CryptoUtils.h"
+>>>>>>> 0.12
#include "SSLLib.h"
#include "ServerException.h"
@@ -40,9 +43,14 @@ void SSLLib::Initialise()
{
if(!::SSL_library_init())
{
+<<<<<<< HEAD
+ LogError("initialising OpenSSL");
+ THROW_EXCEPTION(ServerException, SSLLibraryInitialisationError)
+=======
THROW_EXCEPTION_MESSAGE(ServerException,
SSLLibraryInitialisationError,
CryptoUtils::LogError("initialising OpenSSL"));
+>>>>>>> 0.12
}
// More helpful error messages
@@ -91,3 +99,26 @@ void SSLLib::Initialise()
}
+<<<<<<< HEAD
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: SSLLib::LogError(const char *)
+// Purpose: Logs an error
+// Created: 2003/08/06
+//
+// --------------------------------------------------------------------------
+void SSLLib::LogError(const std::string& rErrorDuringAction)
+{
+ unsigned long errcode;
+ char errname[256]; // SSL docs say at least 120 bytes
+ while((errcode = ERR_get_error()) != 0)
+ {
+ ::ERR_error_string_n(errcode, errname, sizeof(errname));
+ BOX_ERROR("SSL error while " << rErrorDuringAction << ": " <<
+ errname);
+ }
+}
+
+=======
+>>>>>>> 0.12
diff --git a/lib/server/SSLLib.h b/lib/server/SSLLib.h
index d11c7804..b679d623 100644
--- a/lib/server/SSLLib.h
+++ b/lib/server/SSLLib.h
@@ -29,6 +29,10 @@
namespace SSLLib
{
void Initialise();
+<<<<<<< HEAD
+ void LogError(const std::string& rErrorDuringAction);
+=======
+>>>>>>> 0.12
};
#endif // SSLLIB__H
diff --git a/lib/server/ServerException.txt b/lib/server/ServerException.txt
index 474b4067..f8c558c6 100644
--- a/lib/server/ServerException.txt
+++ b/lib/server/ServerException.txt
@@ -13,7 +13,11 @@ SocketOpenError 10
SocketPollError 11
SocketCloseError 13
SocketNameUNIXPathTooLong 14
+<<<<<<< HEAD
+SocketBindError 16 Check the ListenAddresses directive in your config file -- must refer to local IP addresses only
+=======
SocketBindError 16 Check the ListenAddresses directive (bbstored) or CommandSocket (bbackupd) in your config file -- must refer to local IP addresses (or existing writable path) only
+>>>>>>> 0.12
SocketAcceptError 17
ServerStreamBadListenAddrs 18
ServerForkError 19
diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h
index a9b56169..8625832d 100644
--- a/lib/server/ServerStream.h
+++ b/lib/server/ServerStream.h
@@ -48,6 +48,8 @@ private:
ServerStream(const ServerStream &rToCopy)
{
}
+<<<<<<< HEAD
+=======
std::string mConnectionDetails;
@@ -57,6 +59,7 @@ protected:
return mConnectionDetails;
}
+>>>>>>> 0.12
public:
virtual const char *DaemonName() const
@@ -131,10 +134,13 @@ public:
protected:
virtual void NotifyListenerIsReady() { }
+<<<<<<< HEAD
+=======
virtual void LogConnectionDetails(std::string details)
{
BOX_NOTICE("Handling incoming connection from " << details);
}
+>>>>>>> 0.12
public:
virtual void Run2(bool &rChildExit)
@@ -250,9 +256,14 @@ public:
{
// Get the incoming connection
// (with zero wait time)
+<<<<<<< HEAD
+ std::string logMessage;
+ std::auto_ptr<StreamType> connection(psocket->Accept(0, &logMessage));
+=======
std::auto_ptr<StreamType> connection(
psocket->Accept(0,
&mConnectionDetails));
+>>>>>>> 0.12
// Was there one (there should be...)
if(connection.get())
@@ -278,7 +289,10 @@ public:
// Set up daemon
EnterChild();
SetProcessTitle("transaction");
+<<<<<<< HEAD
+=======
LogConnectionDetails(mConnectionDetails);
+>>>>>>> 0.12
// Memory leak test the forked process
#ifdef BOX_MEMORY_LEAK_TESTING
@@ -296,9 +310,13 @@ public:
}
// Log it
+<<<<<<< HEAD
+ BOX_NOTICE("Message from child process " << pid << ": " << logMessage);
+=======
BOX_TRACE("Forked child process " << pid <<
" to handle connection from " <<
mConnectionDetails);
+>>>>>>> 0.12
}
else
{
diff --git a/lib/server/Socket.cpp b/lib/server/Socket.cpp
index f2a4996b..69a11330 100644
--- a/lib/server/Socket.cpp
+++ b/lib/server/Socket.cpp
@@ -123,8 +123,32 @@ void Socket::NameLookupToSockAddr(SocketAllAddr &addr, int &sockDomain,
// --------------------------------------------------------------------------
void Socket::LogIncomingConnection(const struct sockaddr *addr, socklen_t addrlen)
{
+<<<<<<< HEAD
+ if(addr == NULL) {THROW_EXCEPTION(CommonException, BadArguments)}
+
+ switch(addr->sa_family)
+ {
+ case AF_UNIX:
+ BOX_INFO("Incoming connection from local (UNIX socket)");
+ break;
+
+ case AF_INET:
+ {
+ sockaddr_in *a = (sockaddr_in*)addr;
+ BOX_INFO("Incoming connection from " <<
+ inet_ntoa(a->sin_addr) << " port " <<
+ ntohs(a->sin_port));
+ }
+ break;
+
+ default:
+ BOX_WARNING("Incoming connection of unknown type");
+ break;
+ }
+=======
BOX_INFO("Incoming connection from " <<
IncomingConnectionLogMessage(addr, addrlen));
+>>>>>>> 0.12
}
// --------------------------------------------------------------------------
@@ -142,25 +166,40 @@ std::string Socket::IncomingConnectionLogMessage(const struct sockaddr *addr, so
switch(addr->sa_family)
{
case AF_UNIX:
+<<<<<<< HEAD
+ return std::string("Incoming connection from local (UNIX socket)");
+=======
return std::string("local (UNIX socket)");
+>>>>>>> 0.12
break;
case AF_INET:
{
+<<<<<<< HEAD
+ char msg[256]; // more than enough
+ sockaddr_in *a = (sockaddr_in*)addr;
+ sprintf(msg, "Incoming connection from %s port %d", inet_ntoa(a->sin_addr), ntohs(a->sin_port));
+ return std::string(msg);
+=======
sockaddr_in *a = (sockaddr_in*)addr;
std::ostringstream oss;
oss << inet_ntoa(a->sin_addr) << " port " <<
ntohs(a->sin_port);
return oss.str();
+>>>>>>> 0.12
}
break;
default:
+<<<<<<< HEAD
+ return std::string("Incoming connection of unknown type");
+=======
{
std::ostringstream oss;
oss << "unknown socket type " << addr->sa_family;
return oss.str();
}
+>>>>>>> 0.12
break;
}
diff --git a/lib/server/SocketListen.h b/lib/server/SocketListen.h
index 39c60ba6..635b15e8 100644
--- a/lib/server/SocketListen.h
+++ b/lib/server/SocketListen.h
@@ -87,16 +87,24 @@ public:
{
Close();
}
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
private:
SocketListen(const SocketListen &rToCopy)
{
}
+<<<<<<< HEAD
+public:
+
+=======
int mType, mPort;
std::string mName;
public:
+>>>>>>> 0.12
enum
{
MaxMultipleListenSockets = MaxMultiListenSockets
@@ -112,8 +120,13 @@ public:
if(::close(mSocketHandle) == -1)
#endif
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to close network "
+ "socket");
+=======
BOX_LOG_SOCKET_ERROR(mType, mName, mPort,
"Failed to close network socket");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException,
SocketCloseError)
}
@@ -131,10 +144,13 @@ public:
// ------------------------------------------------------------------
void Listen(Socket::Type Type, const char *Name, int Port = 0)
{
+<<<<<<< HEAD
+=======
mType = Type;
mName = Name;
mPort = Port;
+>>>>>>> 0.12
if(mSocketHandle != -1)
{
THROW_EXCEPTION(ServerException, SocketAlreadyOpen);
@@ -152,8 +168,12 @@ public:
0 /* let OS choose protocol */);
if(mSocketHandle == -1)
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to create a network socket");
+=======
BOX_LOG_SOCKET_ERROR(Type, Name, Port,
"Failed to create a network socket");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, SocketOpenError)
}
@@ -167,8 +187,12 @@ public:
&option, sizeof(option)) == -1)
#endif
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to set socket options");
+=======
BOX_LOG_SOCKET_ERROR(Type, Name, Port,
"Failed to set socket options");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, SocketOpenError)
}
@@ -176,6 +200,12 @@ public:
if(::bind(mSocketHandle, &addr.sa_generic, addrLen) == -1
|| ::listen(mSocketHandle, ListenBacklog) == -1)
{
+<<<<<<< HEAD
+ // Dispose of the socket
+ ::close(mSocketHandle);
+ mSocketHandle = -1;
+ THROW_EXCEPTION(ServerException, SocketBindError)
+=======
int err_number = errno;
BOX_LOG_SOCKET_ERROR(Type, Name, Port,
@@ -188,6 +218,7 @@ public:
THROW_SYS_FILE_ERRNO("Failed to bind or listen "
"on socket", Name, err_number,
ServerException, SocketBindError);
+>>>>>>> 0.12
}
}
@@ -240,7 +271,11 @@ public:
// signal?
if(errno == EINTR)
{
+<<<<<<< HEAD
+ BOX_ERROR("Failed to accept "
+=======
BOX_INFO("Failed to accept "
+>>>>>>> 0.12
"connection: interrupted by "
"signal");
// return nothing
@@ -248,8 +283,13 @@ public:
}
else
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to poll "
+ "connection");
+=======
BOX_LOG_SOCKET_ERROR(mType, mName, mPort,
"Failed to poll connection");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException,
SocketPollError)
}
@@ -268,8 +308,12 @@ public:
// Got socket (or error), unlock (implicit in destruction)
if(sock == -1)
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to accept connection");
+=======
BOX_LOG_SOCKET_ERROR(mType, mName, mPort,
"Failed to accept connection");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, SocketAcceptError)
}
diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp
index 6ef4b8d1..7c92ebba 100644
--- a/lib/server/SocketStream.cpp
+++ b/lib/server/SocketStream.cpp
@@ -154,16 +154,24 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port)
int sockDomain = 0;
SocketAllAddr addr;
int addrLen = 0;
+<<<<<<< HEAD
+ Socket::NameLookupToSockAddr(addr, sockDomain, Type, rName, Port, addrLen);
+=======
Socket::NameLookupToSockAddr(addr, sockDomain, Type, rName, Port,
addrLen);
+>>>>>>> 0.12
// Create the socket
mSocketHandle = ::socket(sockDomain, SOCK_STREAM,
0 /* let OS choose protocol */);
if(mSocketHandle == INVALID_SOCKET_VALUE)
{
+<<<<<<< HEAD
+ BOX_LOG_SYS_ERROR("Failed to create a network socket");
+=======
BOX_LOG_SOCKET_ERROR(Type, rName, Port,
"Failed to create a network socket");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, SocketOpenError)
}
@@ -171,11 +179,24 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port)
if(::connect(mSocketHandle, &addr.sa_generic, addrLen) == -1)
{
// Dispose of the socket
+<<<<<<< HEAD
+#ifdef WIN32
+ DWORD err = WSAGetLastError();
+ ::closesocket(mSocketHandle);
+ BOX_LOG_WIN_ERROR_NUMBER("Failed to connect to socket "
+ "(type " << Type << ", name " << rName <<
+ ", port " << Port << ")", err);
+#else // !WIN32
+ BOX_LOG_SYS_ERROR("Failed to connect to socket (type " <<
+ Type << ", name " << rName << ", port " << Port <<
+ ")");
+=======
BOX_LOG_SOCKET_ERROR(Type, rName, Port,
"Failed to connect to socket");
#ifdef WIN32
::closesocket(mSocketHandle);
#else // !WIN32
+>>>>>>> 0.12
::close(mSocketHandle);
#endif // WIN32
diff --git a/lib/server/SocketStream.h b/lib/server/SocketStream.h
index 2fb5e391..aa62e4e9 100644
--- a/lib/server/SocketStream.h
+++ b/lib/server/SocketStream.h
@@ -51,6 +51,10 @@ public:
virtual bool GetPeerCredentials(uid_t &rUidOut, gid_t &rGidOut);
protected:
+<<<<<<< HEAD
+ tOSSocketHandle GetSocketHandle();
+=======
+>>>>>>> 0.12
void MarkAsReadClosed() {mReadClosed = true;}
void MarkAsWriteClosed() {mWriteClosed = true;}
@@ -68,11 +72,14 @@ public:
off_t GetBytesWritten() const {return mBytesWritten;}
void ResetCounters() {mBytesRead = mBytesWritten = 0;}
bool IsOpened() { return mSocketHandle != INVALID_SOCKET_VALUE; }
+<<<<<<< HEAD
+=======
/**
* Only for use by NiceSocketStream!
*/
tOSSocketHandle GetSocketHandle();
+>>>>>>> 0.12
};
#endif // SOCKETSTREAM__H
diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp
index 576b53a2..6f1cc46a 100644
--- a/lib/server/SocketStreamTLS.cpp
+++ b/lib/server/SocketStreamTLS.cpp
@@ -19,12 +19,20 @@
#include <poll.h>
#endif
+<<<<<<< HEAD
+#include "SocketStreamTLS.h"
+#include "SSLLib.h"
+#include "ServerException.h"
+#include "TLSContext.h"
+#include "BoxTime.h"
+=======
#include "BoxTime.h"
#include "CryptoUtils.h"
#include "ServerException.h"
#include "SocketStreamTLS.h"
#include "SSLLib.h"
#include "TLSContext.h"
+>>>>>>> 0.12
#include "MemLeakFindOn.h"
@@ -125,7 +133,11 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
mpBIO = ::BIO_new(::BIO_s_socket());
if(mpBIO == 0)
{
+<<<<<<< HEAD
+ SSLLib::LogError("creating socket bio");
+=======
CryptoUtils::LogError("creating socket bio");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSAllocationFailed)
}
@@ -136,7 +148,11 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
mpSSL = ::SSL_new(rContext.GetRawContext());
if(mpSSL == 0)
{
+<<<<<<< HEAD
+ SSLLib::LogError("creating SSL object");
+=======
CryptoUtils::LogError("creating SSL object");
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSAllocationFailed)
}
@@ -204,12 +220,20 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
// Error occured
if(IsServer)
{
+<<<<<<< HEAD
+ SSLLib::LogError("accepting connection");
+=======
CryptoUtils::LogError("accepting connection");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSHandshakeFailed)
}
else
{
+<<<<<<< HEAD
+ SSLLib::LogError("connecting");
+=======
CryptoUtils::LogError("connecting");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSHandshakeFailed)
}
}
@@ -336,7 +360,11 @@ int SocketStreamTLS::Read(void *pBuffer, int NBytes, int Timeout)
break;
default:
+<<<<<<< HEAD
+ SSLLib::LogError("reading");
+=======
CryptoUtils::LogError("reading");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSReadFailed)
break;
}
@@ -401,7 +429,11 @@ void SocketStreamTLS::Write(const void *pBuffer, int NBytes)
break;
default:
+<<<<<<< HEAD
+ SSLLib::LogError("writing");
+=======
CryptoUtils::LogError("writing");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSWriteFailed)
break;
}
@@ -443,7 +475,11 @@ void SocketStreamTLS::Shutdown(bool Read, bool Write)
if(::SSL_shutdown(mpSSL) < 0)
{
+<<<<<<< HEAD
+ SSLLib::LogError("shutting down");
+=======
CryptoUtils::LogError("shutting down");
+>>>>>>> 0.12
THROW_EXCEPTION(ConnectionException, Conn_TLSShutdownFailed)
}
diff --git a/lib/server/TLSContext.cpp b/lib/server/TLSContext.cpp
index 341043e9..1f06d602 100644
--- a/lib/server/TLSContext.cpp
+++ b/lib/server/TLSContext.cpp
@@ -12,7 +12,11 @@
#define TLS_CLASS_IMPLEMENTATION_CPP
#include <openssl/ssl.h>
+<<<<<<< HEAD
+#include "TLSContext.h"
+=======
#include "CryptoUtils.h"
+>>>>>>> 0.12
#include "ServerException.h"
#include "SSLLib.h"
#include "TLSContext.h"
@@ -77,14 +81,22 @@ void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const c
{
std::string msg = "loading certificates from ";
msg += CertificatesFile;
+<<<<<<< HEAD
+ SSLLib::LogError(msg);
+=======
CryptoUtils::LogError(msg);
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSLoadCertificatesFailed)
}
if(::SSL_CTX_use_PrivateKey_file(mpContext, PrivateKeyFile, SSL_FILETYPE_PEM) != 1)
{
std::string msg = "loading private key from ";
msg += PrivateKeyFile;
+<<<<<<< HEAD
+ SSLLib::LogError(msg);
+=======
CryptoUtils::LogError(msg);
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSLoadPrivateKeyFailed)
}
@@ -93,7 +105,11 @@ void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const c
{
std::string msg = "loading CA cert from ";
msg += TrustedCAsFile;
+<<<<<<< HEAD
+ SSLLib::LogError(msg);
+=======
CryptoUtils::LogError(msg);
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSLoadTrustedCAsFailed)
}
@@ -105,7 +121,11 @@ void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const c
// Setup allowed ciphers
if(::SSL_CTX_set_cipher_list(mpContext, CIPHER_LIST) != 1)
{
+<<<<<<< HEAD
+ SSLLib::LogError("setting cipher list to " CIPHER_LIST);
+=======
CryptoUtils::LogError("setting cipher list to " CIPHER_LIST);
+>>>>>>> 0.12
THROW_EXCEPTION(ServerException, TLSSetCiphersFailed)
}
}
diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in
index a074b435..9caa970d 100755
--- a/lib/server/makeprotocol.pl.in
+++ b/lib/server/makeprotocol.pl.in
@@ -30,6 +30,26 @@ my %log_display_types =
'string' => ['%s', 'VAR.c_str()']
);
+<<<<<<< HEAD
+
+
+my ($type, $file) = @ARGV;
+
+if($type ne 'Server' && $type ne 'Client')
+{
+ die "Neither Server or Client is specified on command line\n";
+}
+
+open IN, $file or die "Can't open input file $file\n";
+
+print "Making $type protocol classes from $file...\n";
+
+my @extra_header_files;
+
+my $implement_syslog = 0;
+my $implement_filelog = 0;
+
+=======
if (@ARGV != 1)
{
die "Usage: $0 <protocol-txt-file>\n";
@@ -43,6 +63,7 @@ print "Making protocol classes from $file...\n";
my @extra_header_files;
+>>>>>>> 0.12
# read attributes
my %attr;
while(<IN>)
@@ -54,6 +75,43 @@ while(<IN>)
my ($k,$v) = split /\s+/,$l,2;
+<<<<<<< HEAD
+ if($k eq 'ClientType')
+ {
+ add_type($v) if $type eq 'Client';
+ }
+ elsif($k eq 'ServerType')
+ {
+ add_type($v) if $type eq 'Server';
+ }
+ elsif($k eq 'ImplementLog')
+ {
+ my ($log_if_type,$log_type) = split /\s+/,$v;
+ if($type eq $log_if_type)
+ {
+ if($log_type eq 'syslog')
+ {
+ $implement_syslog = 1;
+ }
+ elsif($log_type eq 'file')
+ {
+ $implement_filelog = 1;
+ }
+ else
+ {
+ printf("ERROR: Unknown log type for implementation: $log_type\n");
+ exit(1);
+ }
+ }
+ }
+ elsif($k eq 'LogTypeToText')
+ {
+ my ($log_if_type,$type_name,$printf_format,$arg_template) = split /\s+/,$v;
+ if($type eq $log_if_type)
+ {
+ $log_display_types{$type_name} = [$printf_format,$arg_template]
+ }
+=======
if($k eq 'AddType')
{
add_type($v);
@@ -66,6 +124,7 @@ while(<IN>)
{
my ($type_name,$printf_format,$arg_template) = split /\s+/,$v;
$log_display_types{$type_name} = [$printf_format,$arg_template]
+>>>>>>> 0.12
}
else
{
@@ -141,6 +200,11 @@ close IN;
# open files
+<<<<<<< HEAD
+my $h_filename = 'autogen_'.$protocol_name.'Protocol'.$type.'.h';
+open CPP,'>autogen_'.$protocol_name.'Protocol'.$type.'.cpp';
+open H,">$h_filename";
+=======
my $filename_base = 'autogen_'.$protocol_name.'Protocol';
print "Writing $filename_base.cpp\n";
print "Writing $filename_base.h\n";
@@ -148,6 +212,7 @@ open CPP, "> $filename_base.cpp";
open H, "> $filename_base.h";
my $guardname = uc 'AUTOGEN_'.$protocol_name.'Protocol_H';
+>>>>>>> 0.12
print CPP <<__E;
@@ -157,16 +222,41 @@ print CPP <<__E;
#include <sstream>
+<<<<<<< HEAD
+#include "$h_filename"
+#include "IOStream.h"
+
+__E
+
+if($implement_syslog)
+{
+ print H <<EOF;
+#ifndef WIN32
+#include <syslog.h>
+#endif
+EOF
+}
+
+
+my $guardname = uc 'AUTOGEN_'.$protocol_name.'Protocol'.$type.'_H';
+print H <<__E;
+
+=======
#include "$filename_base.h"
#include "IOStream.h"
__E
print H <<__E;
+>>>>>>> 0.12
// Auto-generated file -- do not edit
#ifndef $guardname
#define $guardname
+<<<<<<< HEAD
+#include "Protocol.h"
+#include "ProtocolObject.h"
+=======
#include <cstdio>
#include <list>
@@ -176,16 +266,128 @@ print H <<__E;
#include "Protocol.h"
#include "Message.h"
+>>>>>>> 0.12
#include "ServerException.h"
class IOStream;
+<<<<<<< HEAD
+__E
+
+if($implement_filelog)
+{
+ print H qq~#include <stdio.h>\n~;
+}
+=======
__E
+>>>>>>> 0.12
# extra headers
for(@extra_header_files)
{
+<<<<<<< HEAD
+ print H qq~#include "$_"\n~
+}
+print H "\n";
+
+if($type eq 'Server')
+{
+ # need utils file for the server
+ print H '#include "Utils.h"',"\n\n"
+}
+
+
+my $derive_objects_from = 'ProtocolObject';
+my $objects_extra_h = '';
+my $objects_extra_cpp = '';
+if($type eq 'Server')
+{
+ # define the context
+ print H "class $context_class;\n\n";
+ print CPP "#include \"$context_class_inc\"\n\n";
+
+ # change class we derive the objects from
+ $derive_objects_from = $protocol_name.'ProtocolObject';
+
+ $objects_extra_h = <<__E;
+ virtual std::auto_ptr<ProtocolObject> DoCommand(${protocol_name}ProtocolServer &rProtocol, $context_class &rContext);
+__E
+ $objects_extra_cpp = <<__E;
+std::auto_ptr<ProtocolObject> ${derive_objects_from}::DoCommand(${protocol_name}ProtocolServer &rProtocol, $context_class &rContext)
+{
+ THROW_EXCEPTION(ConnectionException, Conn_Protocol_TriedToExecuteReplyCommand)
+}
+__E
+}
+
+print CPP qq~#include "MemLeakFindOn.h"\n~;
+
+if($type eq 'Client' && ($implement_syslog || $implement_filelog))
+{
+ # change class we derive the objects from
+ $derive_objects_from = $protocol_name.'ProtocolObjectCl';
+}
+if($implement_syslog)
+{
+ $objects_extra_h .= <<__E;
+ virtual void LogSysLog(const char *Action) const = 0;
+__E
+}
+if($implement_filelog)
+{
+ $objects_extra_h .= <<__E;
+ virtual void LogFile(const char *Action, FILE *file) const = 0;
+__E
+}
+
+if($derive_objects_from ne 'ProtocolObject')
+{
+ # output a definition for the protocol object derived class
+ print H <<__E;
+class ${protocol_name}ProtocolServer;
+
+class $derive_objects_from : public ProtocolObject
+{
+public:
+ $derive_objects_from();
+ virtual ~$derive_objects_from();
+ $derive_objects_from(const $derive_objects_from &rToCopy);
+
+$objects_extra_h
+};
+__E
+
+ # and some cpp definitions
+ print CPP <<__E;
+${derive_objects_from}::${derive_objects_from}()
+{
+}
+${derive_objects_from}::~${derive_objects_from}()
+{
+}
+${derive_objects_from}::${derive_objects_from}(const $derive_objects_from &rToCopy)
+{
+}
+$objects_extra_cpp
+__E
+}
+
+
+
+my $classname_base = $protocol_name.'Protocol'.$type;
+
+# output the classes
+for my $cmd (@cmd_list)
+{
+ print H <<__E;
+class $classname_base$cmd : public $derive_objects_from
+{
+public:
+ $classname_base$cmd();
+ $classname_base$cmd(const $classname_base$cmd &rToCopy);
+ ~$classname_base$cmd();
+=======
print H qq@#include "$_"\n@;
}
@@ -271,13 +473,17 @@ public:
$cmd_class();
$cmd_class(const $cmd_class &rToCopy);
~$cmd_class();
+>>>>>>> 0.12
int GetType() const;
enum
{
TypeID = $cmd_id{$cmd}
};
__E
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
# constants
if(exists $cmd_constants{$cmd})
{
@@ -285,18 +491,82 @@ __E
print H join(",\n\t\t",@{$cmd_constants{$cmd}});
print H "\n\t};\n";
}
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
# flags
if(obj_is_type($cmd,'EndsConversation'))
{
print H "\tbool IsConversationEnd() const;\n";
}
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
if(obj_is_type($cmd,'IsError'))
{
print H "\tbool IsError(int &rTypeOut, int &rSubTypeOut) const;\n";
print H "\tstd::string GetMessage() const;\n";
}
+<<<<<<< HEAD
+ if($type eq 'Server' && obj_is_type($cmd, 'Command'))
+ {
+ print H "\tstd::auto_ptr<ProtocolObject> DoCommand(${protocol_name}ProtocolServer &rProtocol, $context_class &rContext); // IMPLEMENT THIS\n"
+ }
+
+ # want to be able to read from streams?
+ my $read_from_streams = (obj_is_type($cmd,'Command') && $type eq 'Server') || (obj_is_type($cmd,'Reply') && $type eq 'Client');
+ my $write_to_streams = (obj_is_type($cmd,'Command') && $type eq 'Client') || (obj_is_type($cmd,'Reply') && $type eq 'Server');
+
+ if($read_from_streams)
+ {
+ print H "\tvoid SetPropertiesFromStreamData(Protocol &rProtocol);\n";
+
+ # write Get functions
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ print H "\t".translate_type_to_arg_type($ty)." Get$nm() {return m$nm;}\n";
+ }
+ }
+ my $param_con_args = '';
+ if($write_to_streams)
+ {
+ # extra constructor?
+ if($#{$cmd_contents{$cmd}} >= 0)
+ {
+ my @a;
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ push @a,translate_type_to_arg_type($ty)." $nm";
+ }
+ $param_con_args = join(', ',@a);
+ print H "\t$classname_base$cmd(".$param_con_args.");\n";
+ }
+ print H "\tvoid WritePropertiesToStreamData(Protocol &rProtocol) const;\n";
+ # set functions
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ print H "\tvoid Set$nm(".translate_type_to_arg_type($ty)." $nm) {m$nm = $nm;}\n";
+ }
+ }
+
+ if($implement_syslog)
+ {
+ print H "\tvirtual void LogSysLog(const char *Action) const;\n";
+ }
+ if($implement_filelog)
+ {
+ print H "\tvirtual void LogFile(const char *Action, FILE *file) const;\n";
+ }
+
+=======
if(obj_is_type($cmd, 'Command'))
{
@@ -343,6 +613,7 @@ __E
print H "\tvirtual void LogSysLog(const char *Action) const;\n";
print H "\tvirtual void LogFile(const char *Action, FILE *file) const;\n";
print H "\tvirtual std::string ToString() const;\n";
+>>>>>>> 0.12
# write member variables and setup for cpp file
my @def_constructor_list;
@@ -376,6 +647,20 @@ __E
my $param_con_vars = join(",\n\t ",@param_constructor_list);
$param_con_vars = "\n\t: ".$param_con_vars if $param_con_vars ne '';
+<<<<<<< HEAD
+ my $class = "$classname_base$cmd".'::';
+ print CPP <<__E;
+$class$classname_base$cmd()$def_con_vars
+{
+}
+$class$classname_base$cmd(const $classname_base$cmd &rToCopy)$copy_con_vars
+{
+}
+$class~$classname_base$cmd()
+{
+}
+int ${class}GetType() const
+=======
print CPP <<__E;
$cmd_class\::$cmd_class()$def_con_vars
{
@@ -387,10 +672,56 @@ $cmd_class\::~$cmd_class()
{
}
int $cmd_class\::GetType() const
+>>>>>>> 0.12
{
return $cmd_id{$cmd};
}
__E
+<<<<<<< HEAD
+ if($read_from_streams)
+ {
+ print CPP "void ${class}SetPropertiesFromStreamData(Protocol &rProtocol)\n{\n";
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ if($ty =~ m/\Avector/)
+ {
+ print CPP "\trProtocol.ReadVector(m$nm);\n";
+ }
+ else
+ {
+ print CPP "\trProtocol.Read(m$nm);\n";
+ }
+ }
+ print CPP "}\n";
+ }
+ if($write_to_streams)
+ {
+ # implement extra constructor?
+ if($param_con_vars ne '')
+ {
+ print CPP "$class$classname_base$cmd($param_con_args)$param_con_vars\n{\n}\n";
+ }
+ print CPP "void ${class}WritePropertiesToStreamData(Protocol &rProtocol) const\n{\n";
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ if($ty =~ m/\Avector/)
+ {
+ print CPP "\trProtocol.WriteVector(m$nm);\n";
+ }
+ else
+ {
+ print CPP "\trProtocol.Write(m$nm);\n";
+ }
+ }
+ print CPP "}\n";
+ }
+ if(obj_is_type($cmd,'EndsConversation'))
+ {
+ print CPP "bool ${class}IsConversationEnd() const\n{\n\treturn true;\n}\n";
+ }
+=======
print CPP "void $cmd_class\::SetPropertiesFromStreamData(Protocol &rProtocol)\n{\n";
for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
{
@@ -431,18 +762,27 @@ __E
print CPP "bool $cmd_class\::IsConversationEnd() const\n{\n\treturn true;\n}\n";
}
+>>>>>>> 0.12
if(obj_is_type($cmd,'IsError'))
{
# get parameters
my ($mem_type,$mem_subtype) = split /,/,obj_get_type_params($cmd,'IsError');
print CPP <<__E;
+<<<<<<< HEAD
+bool ${class}IsError(int &rTypeOut, int &rSubTypeOut) const
+=======
bool $cmd_class\::IsError(int &rTypeOut, int &rSubTypeOut) const
+>>>>>>> 0.12
{
rTypeOut = m$mem_type;
rSubTypeOut = m$mem_subtype;
return true;
}
+<<<<<<< HEAD
+std::string ${class}GetMessage() const
+=======
std::string $cmd_class\::GetMessage() const
+>>>>>>> 0.12
{
switch(m$mem_subtype)
{
@@ -466,6 +806,149 @@ __E
__E
}
+<<<<<<< HEAD
+ if($implement_syslog)
+ {
+ my ($log) = make_log_strings_framework($cmd);
+ print CPP <<__E;
+void ${class}LogSysLog(const char *Action) const
+{
+ BOX_TRACE($log);
+}
+__E
+ }
+ if($implement_filelog)
+ {
+ my ($log) = make_log_strings_framework($cmd);
+ print CPP <<__E;
+void ${class}LogFile(const char *Action, FILE *File) const
+{
+ std::ostringstream oss;
+ oss << $log;
+ ::fprintf(File, "%s\\n", oss.str().c_str());
+ ::fflush(File);
+}
+__E
+ }
+}
+
+# finally, the protocol object itself
+print H <<__E;
+class $classname_base : public Protocol
+{
+public:
+ $classname_base(IOStream &rStream);
+ virtual ~$classname_base();
+
+ std::auto_ptr<$derive_objects_from> Receive();
+ void Send(const ${derive_objects_from} &rObject);
+__E
+if($implement_syslog)
+{
+ print H "\tvoid SetLogToSysLog(bool Log = false) {mLogToSysLog = Log;}\n";
+}
+if($implement_filelog)
+{
+ print H "\tvoid SetLogToFile(FILE *File = 0) {mLogToFile = File;}\n";
+}
+if($type eq 'Server')
+{
+ # need to put in the conversation function
+ print H "\tvoid DoServer($context_class &rContext);\n\n";
+ # and the send vector thing
+ print H "\tvoid SendStreamAfterCommand(IOStream *pStream);\n\n";
+}
+if($type eq 'Client')
+{
+ # add plain object taking query functions
+ my $with_params;
+ for my $cmd (@cmd_list)
+ {
+ if(obj_is_type($cmd,'Command'))
+ {
+ my $has_stream = obj_is_type($cmd,'StreamWithCommand');
+ my $argextra = $has_stream?', IOStream &rStream':'';
+ my $queryextra = $has_stream?', rStream':'';
+ my $reply = obj_get_type_params($cmd,'Command');
+ print H "\tstd::auto_ptr<$classname_base$reply> Query(const $classname_base$cmd &rQuery$argextra);\n";
+ my @a;
+ my @na;
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ push @a,translate_type_to_arg_type($ty)." $nm";
+ push @na,"$nm";
+ }
+ my $ar = join(', ',@a);
+ my $nar = join(', ',@na);
+ $nar = "($nar)" if $nar ne '';
+
+ $with_params .= "\tinline std::auto_ptr<$classname_base$reply> Query$cmd($ar$argextra)\n\t{\n";
+ $with_params .= "\t\t$classname_base$cmd send$nar;\n";
+ $with_params .= "\t\treturn Query(send$queryextra);\n";
+ $with_params .= "\t}\n";
+ }
+ }
+ # quick hack to correct bad argument lists for commands with zero paramters but with streams
+ $with_params =~ s/\(, /(/g;
+ print H "\n",$with_params,"\n";
+}
+print H <<__E;
+private:
+ $classname_base(const $classname_base &rToCopy);
+__E
+if($type eq 'Server')
+{
+ # need to put the streams to send vector
+ print H "\tstd::vector<IOStream*> mStreamsToSend;\n\tvoid DeleteStreamsToSend();\n";
+}
+
+if($implement_filelog || $implement_syslog)
+{
+ print H <<__E;
+ virtual void InformStreamReceiving(u_int32_t Size);
+ virtual void InformStreamSending(u_int32_t Size);
+__E
+}
+
+if($implement_syslog)
+{
+ print H "private:\n\tbool mLogToSysLog;\n";
+}
+if($implement_filelog)
+{
+ print H "private:\n\tFILE *mLogToFile;\n";
+}
+print H <<__E;
+
+protected:
+ virtual std::auto_ptr<ProtocolObject> MakeProtocolObject(int ObjType);
+ virtual const char *GetIdentString();
+};
+
+__E
+
+my $constructor_extra = '';
+$constructor_extra .= ', mLogToSysLog(false)' if $implement_syslog;
+$constructor_extra .= ', mLogToFile(0)' if $implement_filelog;
+
+my $destructor_extra = ($type eq 'Server')?"\n\tDeleteStreamsToSend();":'';
+
+my $prefix = $classname_base.'::';
+print CPP <<__E;
+$prefix$classname_base(IOStream &rStream)
+ : Protocol(rStream)$constructor_extra
+{
+}
+$prefix~$classname_base()
+{$destructor_extra
+}
+const char *${prefix}GetIdentString()
+{
+ return "$ident_string";
+}
+std::auto_ptr<ProtocolObject> ${prefix}MakeProtocolObject(int ObjType)
+=======
my ($log) = make_log_strings_framework($cmd);
print CPP <<__E;
std::string $cmd_class\::ToString() const
@@ -905,11 +1388,25 @@ __E
# write receive and send functions
print CPP <<__E;
std::auto_ptr<Message> $server_or_client_class\::MakeMessage(int ObjType)
+>>>>>>> 0.12
{
switch(ObjType)
{
__E
+<<<<<<< HEAD
+# do objects within this
+for my $cmd (@cmd_list)
+{
+ print CPP <<__E;
+ case $cmd_id{$cmd}:
+ return std::auto_ptr<ProtocolObject>(new $classname_base$cmd);
+ break;
+__E
+}
+
+print CPP <<__E;
+=======
# do objects within this
for my $cmd (@cmd_list)
{
@@ -921,11 +1418,40 @@ __E
}
print CPP <<__E;
+>>>>>>> 0.12
default:
THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnknownCommandRecieved)
}
}
__E
+<<<<<<< HEAD
+# write receive and send functions
+print CPP <<__E;
+std::auto_ptr<$derive_objects_from> ${prefix}Receive()
+{
+ std::auto_ptr<${derive_objects_from}> preply((${derive_objects_from}*)(Protocol::Receive().release()));
+
+__E
+ if($implement_syslog)
+ {
+ print CPP <<__E;
+ if(mLogToSysLog)
+ {
+ preply->LogSysLog("Receive");
+ }
+__E
+ }
+ if($implement_filelog)
+ {
+ print CPP <<__E;
+ if(mLogToFile != 0)
+ {
+ preply->LogFile("Receive", mLogToFile);
+ }
+__E
+ }
+print CPP <<__E;
+=======
if(not $writing_local)
{
@@ -944,10 +1470,45 @@ std::auto_ptr<$message_base_class> $server_or_client_class\::Receive()
{
preply->LogFile("Receive", GetLogToFile());
}
+>>>>>>> 0.12
return preply;
}
+<<<<<<< HEAD
+void ${prefix}Send(const ${derive_objects_from} &rObject)
+{
+__E
+ if($implement_syslog)
+ {
+ print CPP <<__E;
+ if(mLogToSysLog)
+ {
+ rObject.LogSysLog("Send");
+ }
+__E
+ }
+ if($implement_filelog)
+ {
+ print CPP <<__E;
+ if(mLogToFile != 0)
+ {
+ rObject.LogFile("Send", mLogToFile);
+ }
+__E
+ }
+
+print CPP <<__E;
+ Protocol::Send(rObject);
+}
+
+__E
+# write server function?
+if($type eq 'Server')
+{
+ print CPP <<__E;
+void ${prefix}DoServer($context_class &rContext)
+=======
void $server_or_client_class\::Send(const $message_base_class &rObject)
{
if(GetLogToSysLog())
@@ -971,6 +1532,7 @@ __E
{
print CPP <<__E;
void $server_or_client_class\::DoServer($context_class &rContext)
+>>>>>>> 0.12
{
// Handshake with client
Handshake();
@@ -980,6 +1542,22 @@ void $server_or_client_class\::DoServer($context_class &rContext)
while(inProgress)
{
// Get an object from the conversation
+<<<<<<< HEAD
+ std::auto_ptr<${derive_objects_from}> pobj(Receive());
+
+ // Run the command
+ std::auto_ptr<${derive_objects_from}> preply((${derive_objects_from}*)(pobj->DoCommand(*this, rContext).release()));
+
+ // Send the reply
+ Send(*(preply.get()));
+
+ // Send any streams
+ for(unsigned int s = 0; s < mStreamsToSend.size(); s++)
+ {
+ // Send the streams
+ SendStream(*mStreamsToSend[s]);
+ }
+=======
std::auto_ptr<$message_base_class> pobj = Receive();
// Run the command
@@ -996,6 +1574,7 @@ void $server_or_client_class\::DoServer($context_class &rContext)
SendStream(**i);
}
+>>>>>>> 0.12
// Delete these streams
DeleteStreamsToSend();
@@ -1007,6 +1586,122 @@ void $server_or_client_class\::DoServer($context_class &rContext)
}
}
+<<<<<<< HEAD
+void ${prefix}SendStreamAfterCommand(IOStream *pStream)
+{
+ ASSERT(pStream != NULL);
+ mStreamsToSend.push_back(pStream);
+}
+
+void ${prefix}DeleteStreamsToSend()
+{
+ for(std::vector<IOStream*>::iterator i(mStreamsToSend.begin()); i != mStreamsToSend.end(); ++i)
+ {
+ delete (*i);
+ }
+ mStreamsToSend.clear();
+}
+
+__E
+}
+
+# write logging functions?
+if($implement_filelog || $implement_syslog)
+{
+ my ($fR,$fS);
+
+ if($implement_syslog)
+ {
+ $fR .= <<__E;
+ if(mLogToSysLog)
+ {
+ if(Size==Protocol::ProtocolStream_SizeUncertain)
+ {
+ BOX_TRACE("Receiving stream, size uncertain");
+ }
+ else
+ {
+ BOX_TRACE("Receiving stream, size " << Size);
+ }
+ }
+__E
+
+ $fS .= <<__E;
+ if(mLogToSysLog)
+ {
+ if(Size==Protocol::ProtocolStream_SizeUncertain)
+ {
+ BOX_TRACE("Sending stream, size uncertain");
+ }
+ else
+ {
+ BOX_TRACE("Sending stream, size " << Size);
+ }
+ }
+__E
+ }
+
+ if($implement_filelog)
+ {
+ $fR .= <<__E;
+ if(mLogToFile)
+ {
+ ::fprintf(mLogToFile,
+ (Size==Protocol::ProtocolStream_SizeUncertain)
+ ?"Receiving stream, size uncertain\\n"
+ :"Receiving stream, size %d\\n", Size);
+ ::fflush(mLogToFile);
+ }
+__E
+ $fS .= <<__E;
+ if(mLogToFile)
+ {
+ ::fprintf(mLogToFile,
+ (Size==Protocol::ProtocolStream_SizeUncertain)
+ ?"Sending stream, size uncertain\\n"
+ :"Sending stream, size %d\\n", Size);
+ ::fflush(mLogToFile);
+ }
+__E
+ }
+
+ print CPP <<__E;
+
+void ${prefix}InformStreamReceiving(u_int32_t Size)
+{
+$fR}
+
+void ${prefix}InformStreamSending(u_int32_t Size)
+{
+$fS}
+
+__E
+}
+
+
+# write client Query functions?
+if($type eq 'Client')
+{
+ for my $cmd (@cmd_list)
+ {
+ if(obj_is_type($cmd,'Command'))
+ {
+ my $reply = obj_get_type_params($cmd,'Command');
+ my $reply_id = $cmd_id{$reply};
+ my $has_stream = obj_is_type($cmd,'StreamWithCommand');
+ my $argextra = $has_stream?', IOStream &rStream':'';
+ my $send_stream_extra = '';
+ if($has_stream)
+ {
+ $send_stream_extra = <<__E;
+
+ // Send stream after the command
+ SendStream(rStream);
+__E
+ }
+ print CPP <<__E;
+std::auto_ptr<$classname_base$reply> ${classname_base}::Query(const $classname_base$cmd &rQuery$argextra)
+=======
__E
}
@@ -1039,10 +1734,44 @@ __E
print CPP <<__E;
std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class &rQuery$argextra)
+>>>>>>> 0.12
{
// Send query
Send(rQuery);
$send_stream_extra
+<<<<<<< HEAD
+ // Wait for the reply
+ std::auto_ptr<${derive_objects_from}> preply(Receive().release());
+
+ if(preply->GetType() == $reply_id)
+ {
+ // Correct response
+ return std::auto_ptr<$classname_base$reply>(($classname_base$reply*)preply.release());
+ }
+ else
+ {
+ // Set protocol error
+ int type, subType;
+ if(preply->IsError(type, subType))
+ {
+ SetError(type, subType);
+ BOX_WARNING("$cmd command failed: received error " <<
+ ((${classname_base}Error&)*preply).GetMessage());
+ }
+ else
+ {
+ SetError(Protocol::UnknownError, Protocol::UnknownError);
+ BOX_WARNING("$cmd command failed: received "
+ "unexpected response type " <<
+ preply->GetType());
+ }
+
+ // Throw an exception
+ THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnexpectedReply)
+ }
+}
+__E
+=======
// Wait for the reply
std::auto_ptr<$message_base_class> preply = Receive();
@@ -1079,10 +1808,16 @@ std::auto_ptr<$reply_class> $server_or_client_class\::Query(const $request_class
__E
}
}
+>>>>>>> 0.12
}
}
}
+<<<<<<< HEAD
+
+
+=======
+>>>>>>> 0.12
print H <<__E;
#endif // $guardname
@@ -1092,7 +1827,12 @@ __E
close H;
close CPP;
+<<<<<<< HEAD
+
+sub obj_is_type
+=======
sub obj_is_type ($$)
+>>>>>>> 0.12
{
my ($c,$ty) = @_;
for(@{$cmd_attributes{$c}})
@@ -1146,6 +1886,43 @@ sub translate_type_to_member_type
return $typename
}
+<<<<<<< HEAD
+sub make_log_strings
+{
+ my ($cmd) = @_;
+
+ my @str;
+ my @arg;
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ if(exists $log_display_types{$ty})
+ {
+ # need to translate it
+ my ($format,$arg) = @{$log_display_types{$ty}};
+ $arg =~ s/VAR/m$nm/g;
+
+ if ($format eq "0x%llx" and $target_windows)
+ {
+ $format = "0x%I64x";
+ $arg = "(uint64_t)$arg";
+ }
+
+ push @str,$format;
+ push @arg,$arg;
+ }
+ else
+ {
+ # is opaque
+ push @str,'OPAQUE';
+ }
+ }
+ return ($cmd.'('.join(',',@str).')', join(',','',@arg));
+}
+
+=======
+>>>>>>> 0.12
sub make_log_strings_framework
{
my ($cmd) = @_;
@@ -1162,7 +1939,11 @@ sub make_log_strings_framework
my ($format,$arg) = @{$log_display_types{$ty}};
$arg =~ s/VAR/m$nm/g;
+<<<<<<< HEAD
+ if ($format eq '\\"%s\\"')
+=======
if ($format eq '"%s"')
+>>>>>>> 0.12
{
$arg = "\"\\\"\" << $arg << \"\\\"\"";
}
@@ -1189,7 +1970,11 @@ sub make_log_strings_framework
}
}
+<<<<<<< HEAD
+ my $log_cmd = "Action << \" $cmd(\" ";
+=======
my $log_cmd = '"'.$cmd.'(" ';
+>>>>>>> 0.12
foreach my $arg (@args)
{
$arg = "<< $arg ";
@@ -1199,3 +1984,7 @@ sub make_log_strings_framework
return $log_cmd;
}
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp
index ef237671..9b5159cf 100644
--- a/lib/win32/emu.cpp
+++ b/lib/win32/emu.cpp
@@ -1,5 +1,11 @@
// Box Backup Win32 native port by Nick Knight
+<<<<<<< HEAD
+// Need at least 0x0500 to use GetFileSizeEx on Cygwin/MinGW
+#define WINVER 0x0500
+
+=======
+>>>>>>> 0.12
#include "emu.h"
#ifdef WIN32
@@ -79,6 +85,12 @@ bool EnableBackupRights()
return true;
}
+<<<<<<< HEAD
+// forward declaration
+char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage);
+
+=======
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -240,7 +252,11 @@ char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage)
{
::syslog(LOG_WARNING,
"Failed to convert wide string to narrow: "
+<<<<<<< HEAD
+ "error %d", GetLastError());
+=======
"%s", GetErrorMessage(GetLastError()).c_str());
+>>>>>>> 0.12
errno = EINVAL;
return NULL;
}
@@ -272,7 +288,11 @@ char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage)
{
::syslog(LOG_WARNING,
"Failed to convert wide string to narrow: "
+<<<<<<< HEAD
+ "error %i", GetLastError());
+=======
"%s", GetErrorMessage(GetLastError()).c_str());
+>>>>>>> 0.12
errno = EACCES;
delete [] buffer;
return NULL;
@@ -281,6 +301,8 @@ char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage)
return buffer;
}
+<<<<<<< HEAD
+=======
bool ConvertFromWideString(const std::wstring& rInput,
std::string* pOutput, unsigned int codepage)
{
@@ -344,6 +366,7 @@ bool ConvertFromWideString(const std::wstring& rInput,
return true;
}
+>>>>>>> 0.12
// --------------------------------------------------------------------------
//
// Function
@@ -448,6 +471,9 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName)
return tmpStr;
}
+<<<<<<< HEAD
+ if (filename.length() > 2 && filename[0] == '\\' &&
+=======
if (filename.length() > 4 && filename[0] == '\\' &&
filename[1] == '\\' && filename[2] == '?' &&
filename[3] == '\\')
@@ -457,6 +483,7 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName)
tmpStr = "";
}
else if (filename.length() > 2 && filename[0] == '\\' &&
+>>>>>>> 0.12
filename[1] == '\\')
{
tmpStr += "UNC\\";
@@ -466,16 +493,27 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName)
}
else if (filename.length() >= 1 && filename[0] == '\\')
{
+<<<<<<< HEAD
+ // root directory of current drive.
+=======
// starts with \, i.e. root directory of current drive.
+>>>>>>> 0.12
tmpStr = wd;
tmpStr.resize(2); // drive letter and colon
}
else if (filename.length() >= 2 && filename[1] != ':')
{
+<<<<<<< HEAD
+ // Must be relative. We need to get the
+ // current directory to make it absolute.
+ tmpStr += wd;
+ if (tmpStr[tmpStr.length()] != '\\')
+=======
// Must be a relative path. We need to get the
// current directory to make it absolute.
tmpStr += wd;
if (tmpStr[tmpStr.length()-1] != '\\')
+>>>>>>> 0.12
{
tmpStr += '\\';
}
@@ -504,7 +542,11 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName)
"");
}
+<<<<<<< HEAD
+ i = lastSlash;
+=======
i = lastSlash - 1;
+>>>>>>> 0.12
}
}
@@ -719,7 +761,11 @@ int emu_fstat(HANDLE hdir, struct emu_stat * st)
{
conv.HighPart = fi.nFileSizeHigh;
conv.LowPart = fi.nFileSizeLow;
+<<<<<<< HEAD
+ st->st_size = (_off_t)conv.QuadPart;
+=======
st->st_size = conv.QuadPart;
+>>>>>>> 0.12
}
// at the mo
@@ -1053,7 +1099,11 @@ DIR *opendir(const char *name)
std::string dirName(name);
//append a '\' win32 findfirst is sensitive to this
+<<<<<<< HEAD
+ if ( dirName[dirName.size()] != '\\' || dirName[dirName.size()] != '/' )
+=======
if (dirName[dirName.size()-1] != '\\' || dirName[dirName.size()-1] != '/')
+>>>>>>> 0.12
{
dirName += '\\';
}
@@ -1077,16 +1127,26 @@ DIR *opendir(const char *name)
return NULL;
}
+<<<<<<< HEAD
+ pDir->fd = _wfindfirst((const wchar_t*)pDir->name, &(pDir->info));
+
+ if (pDir->fd == -1)
+=======
pDir->fd = FindFirstFileW(pDir->name, &pDir->info);
DWORD tmp = GetLastError();
if (pDir->fd == INVALID_HANDLE_VALUE)
+>>>>>>> 0.12
{
delete [] pDir->name;
delete pDir;
return NULL;
}
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
pDir->result.d_name = 0;
return pDir;
}
@@ -1109,6 +1169,17 @@ struct dirent *readdir(DIR *dp)
{
struct dirent *den = NULL;
+<<<<<<< HEAD
+ if (dp && dp->fd != -1)
+ {
+ if (!dp->result.d_name ||
+ _wfindnext(dp->fd, &dp->info) != -1)
+ {
+ den = &dp->result;
+ std::wstring input(dp->info.name);
+ memset(tempbuff, 0, sizeof(tempbuff));
+ WideCharToMultiByte(CP_UTF8, 0, dp->info.name,
+=======
if (dp && dp->fd != INVALID_HANDLE_VALUE)
{
// first time around, when dp->result.d_name == NULL, use
@@ -1121,10 +1192,20 @@ struct dirent *readdir(DIR *dp)
std::wstring input(dp->info.cFileName);
memset(tempbuff, 0, sizeof(tempbuff));
WideCharToMultiByte(CP_UTF8, 0, dp->info.cFileName,
+>>>>>>> 0.12
-1, &tempbuff[0], sizeof (tempbuff),
NULL, NULL);
//den->d_name = (char *)dp->info.name;
den->d_name = &tempbuff[0];
+<<<<<<< HEAD
+ if (dp->info.attrib & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ den->d_type = S_IFDIR;
+ }
+ else
+ {
+ den->d_type = S_IFREG;
+=======
den->d_type = dp->info.dwFileAttributes;
}
else // FindNextFileW failed
@@ -1140,6 +1221,7 @@ struct dirent *readdir(DIR *dp)
else
{
errno = ENOSYS;
+>>>>>>> 0.12
}
}
}
@@ -1147,7 +1229,10 @@ struct dirent *readdir(DIR *dp)
{
errno = EBADF;
}
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
return den;
}
catch (...)
@@ -1169,6 +1254,14 @@ int closedir(DIR *dp)
{
try
{
+<<<<<<< HEAD
+ int finres = -1;
+ if (dp)
+ {
+ if(dp->fd != -1)
+ {
+ finres = _findclose(dp->fd);
+=======
BOOL finres = false;
if (dp)
@@ -1176,12 +1269,21 @@ int closedir(DIR *dp)
if(dp->fd != INVALID_HANDLE_VALUE)
{
finres = FindClose(dp->fd);
+>>>>>>> 0.12
}
delete [] dp->name;
delete dp;
}
+<<<<<<< HEAD
+ if (finres == -1) // errors go to EBADF
+ {
+ errno = EBADF;
+ }
+
+ return finres;
+=======
if (finres == FALSE) // errors go to EBADF
{
winerrno = GetLastError();
@@ -1189,6 +1291,7 @@ int closedir(DIR *dp)
}
return (finres == TRUE) ? 0 : -1;
+>>>>>>> 0.12
}
catch (...)
{
diff --git a/lib/win32/emu.h b/lib/win32/emu.h
index bf408050..bc91e2ba 100644
--- a/lib/win32/emu.h
+++ b/lib/win32/emu.h
@@ -1,7 +1,10 @@
// emulates unix syscalls to win32 functions
+<<<<<<< HEAD
+=======
#include "emu_winver.h"
+>>>>>>> 0.12
#ifdef WIN32
#define EMU_STRUCT_STAT struct emu_stat
#define EMU_STAT emu_stat
@@ -17,6 +20,8 @@
#if ! defined EMU_INCLUDE && defined WIN32
#define EMU_INCLUDE
+<<<<<<< HEAD
+=======
// Need feature detection macros below
#include "../common/BoxConfig.h"
@@ -25,6 +30,7 @@
# define __MINGW_FEATURES__ 0
#endif
+>>>>>>> 0.12
// basic types, may be required by other headers since we
// don't include sys/types.h
@@ -52,6 +58,17 @@
typedef unsigned int pid_t;
#endif
+<<<<<<< HEAD
+// set up to include the necessary parts of Windows headers
+
+#define WIN32_LEAN_AND_MEAN
+
+#ifndef __MSVCRT_VERSION__
+#define __MSVCRT_VERSION__ 0x0601
+#endif
+
+=======
+>>>>>>> 0.12
// Windows headers
#include <winsock2.h>
@@ -222,15 +239,28 @@ inline int strcasecmp(const char *s1, const char *s2)
struct dirent
{
char *d_name;
+<<<<<<< HEAD
+ unsigned long d_type;
+=======
DWORD d_type; // file attributes
+>>>>>>> 0.12
};
struct DIR
{
+<<<<<<< HEAD
+ intptr_t fd; // filedescriptor
+ // struct _finddata_t info;
+ struct _wfinddata_t info;
+ // struct _finddata_t info;
+ struct dirent result; // d_name (first time null)
+ wchar_t *name; // null-terminated byte string
+=======
HANDLE fd; // the HANDLE returned by FindFirstFile
WIN32_FIND_DATAW info;
struct dirent result; // d_name (first time null)
wchar_t* name; // null-terminated byte string
+>>>>>>> 0.12
};
DIR *opendir(const char *name);
@@ -286,6 +316,11 @@ inline unsigned int sleep(unsigned int secs)
}
#define INFTIM -1
+<<<<<<< HEAD
+#define POLLIN 0x1
+#define POLLERR 0x8
+#define POLLOUT 0x4
+=======
#ifndef POLLIN
# define POLLIN 0x1
@@ -298,6 +333,7 @@ inline unsigned int sleep(unsigned int secs)
#ifndef POLLOUT
# define POLLOUT 0x4
#endif
+>>>>>>> 0.12
#define SHUT_RDWR SD_BOTH
#define SHUT_RD SD_RECEIVE
@@ -316,6 +352,14 @@ inline int ioctl(SOCKET sock, int flag, int * something)
return 0;
}
+<<<<<<< HEAD
+extern "C" inline int getpid()
+{
+ return (int)GetCurrentProcessId();
+}
+
+=======
+>>>>>>> 0.12
inline int waitpid(pid_t pid, int *status, int)
{
return 0;
@@ -355,12 +399,21 @@ int emu_chmod (const char* pName, mode_t mode);
char* emu_getcwd (char* pBuffer, int BufSize);
int emu_rename (const char* pOldName, const char* pNewName);
+<<<<<<< HEAD
+#define chdir(directory) emu_chdir (directory)
+#define mkdir(path, mode) emu_mkdir (path)
+#define unlink(file) emu_unlink (file)
+#define utimes(buffer, times) emu_utimes (buffer, times)
+#define chmod(file, mode) emu_chmod (file, mode)
+#define getcwd(buffer, size) emu_getcwd (buffer, size)
+=======
#define chdir(directory) emu_chdir (directory)
#define mkdir(path, mode) emu_mkdir (path)
#define unlink(file) emu_unlink (file)
#define utimes(buffer, times) emu_utimes (buffer, times)
#define chmod(file, mode) emu_chmod (file, mode)
#define getcwd(buffer, size) emu_getcwd (buffer, size)
+>>>>>>> 0.12
#define rename(oldname, newname) emu_rename (oldname, newname)
// Not safe to replace stat/fstat/lstat on mingw at least, as struct stat
@@ -400,10 +453,13 @@ bool ConvertFromUtf8 (const std::string& rSource, std::string& rDest,
int destCodePage);
bool ConvertUtf8ToConsole(const std::string& rSource, std::string& rDest);
bool ConvertConsoleToUtf8(const std::string& rSource, std::string& rDest);
+<<<<<<< HEAD
+=======
char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage);
bool ConvertFromWideString(const std::wstring& rInput,
std::string* pOutput, unsigned int codepage);
std::string ConvertPathToAbsoluteUnicode(const char *pFileName);
+>>>>>>> 0.12
// Utility function which returns a default config file name,
// based on the path of the current executable.
@@ -417,6 +473,8 @@ std::string GetErrorMessage(DWORD errorCode);
// relatively recent C runtime lib
int console_read(char* pBuffer, size_t BufferSize);
+<<<<<<< HEAD
+=======
// Defined thus by MinGW, but missing from MSVC
// [http://curl.haxx.se/mail/lib-2004-11/0260.html]
// note: chsize() doesn't work over 2GB:
@@ -429,6 +487,7 @@ int console_read(char* pBuffer, size_t BufferSize);
}
#endif
+>>>>>>> 0.12
#ifdef _MSC_VER
/* disable certain compiler warnings to be able to actually see the show-stopper ones */
#pragma warning(disable:4101) // unreferenced local variable
diff --git a/lib/win32/getopt_long.cpp b/lib/win32/getopt_long.cpp
index 31695aa0..a508d22a 100755
--- a/lib/win32/getopt_long.cpp
+++ b/lib/win32/getopt_long.cpp
@@ -58,7 +58,10 @@
*/
// #include "Box.h"
+<<<<<<< HEAD
+=======
#include "emu.h"
+>>>>>>> 0.12
#include <errno.h>
#include <stdarg.h>
diff --git a/modules.txt b/modules.txt
index 670f4ac4..54c29b0c 100644
--- a/modules.txt
+++ b/modules.txt
@@ -11,7 +11,11 @@
lib/raidfile
lib/crypto
+<<<<<<< HEAD
+lib/server
+=======
lib/server qdbm lib/crypto
+>>>>>>> 0.12
lib/compress
lib/intercept
@@ -25,6 +29,15 @@ test/basicserver lib/server
# Backup system
+<<<<<<< HEAD
+lib/backupclient lib/server lib/crypto lib/compress
+lib/backupstore lib/server lib/raidfile lib/backupclient
+
+bin/bbackupobjdump lib/backupclient lib/backupstore
+bin/bbstored lib/raidfile lib/server lib/backupstore lib/backupclient
+bin/bbstoreaccounts lib/raidfile lib/backupstore
+bin/bbackupd lib/server lib/backupclient
+=======
lib/backupstore lib/server lib/raidfile lib/crypto lib/compress
lib/backupclient lib/backupstore
@@ -32,12 +45,17 @@ bin/bbackupobjdump lib/backupclient lib/backupstore
bin/bbstored lib/raidfile lib/server lib/backupstore
bin/bbstoreaccounts lib/raidfile lib/backupstore
bin/bbackupd lib/server lib/backupclient qdbm
+>>>>>>> 0.12
bin/bbackupquery lib/server lib/backupclient
bin/bbackupctl lib/server lib/backupclient
test/backupstore bin/bbstored bin/bbstoreaccounts lib/server lib/backupstore lib/backupclient lib/raidfile
test/backupstorefix bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile bin/bbackupquery bin/bbackupd bin/bbackupctl
+<<<<<<< HEAD
+test/backupstorepatch bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile
+=======
test/backupstorepatch bin/bbstored bin/bbstoreaccounts lib/backupclient
+>>>>>>> 0.12
test/backupdiff lib/backupclient
test/bbackupd bin/bbackupd bin/bbstored bin/bbstoreaccounts bin/bbackupquery bin/bbackupctl lib/server lib/backupstore lib/backupclient lib/intercept
diff --git a/parcels.txt b/parcels.txt
index cbb6f7c7..396586b1 100644
--- a/parcels.txt
+++ b/parcels.txt
@@ -18,8 +18,11 @@ backup-client
html bbackupd-config
html bbackupd.conf
+<<<<<<< HEAD
+=======
subdir qdbm libqdbm.a
+>>>>>>> 0.12
EXCEPT:mingw32,mingw32msvc
man bbackupd.8
man bbackupquery.8
@@ -35,9 +38,16 @@ ONLY:mingw32,mingw32msvc
END-ONLY
ONLY:mingw32
+<<<<<<< HEAD
+ script /bin/mgwz.dll
+ script /bin/mingwm10.dll
+ script /usr/i686-pc-mingw32/bin/cygpcreposix-0.dll
+ script /usr/i686-pc-mingw32/bin/cygpcre-0.dll
+=======
script /usr/i686-pc-mingw32/sys-root/mingw/bin/libz-1.dll
script /usr/i686-pc-mingw32/sys-root/mingw/bin/mingwm10.dll
script /usr/i686-pc-mingw32/sys-root/mingw/bin/libgcc_s_dw2-1.dll
+>>>>>>> 0.12
END-ONLY
ONLY:SunOS
diff --git a/runtest.pl.in b/runtest.pl.in
index b4f59c1f..27b94763 100755
--- a/runtest.pl.in
+++ b/runtest.pl.in
@@ -99,7 +99,11 @@ sub runtest
# attempt to make this test
my $flag = ($test_mode eq 'release')?(BoxPlatform::make_flag('RELEASE')):'';
+<<<<<<< HEAD
+ my $make_res = system("cd test/$t ; $make_command $flag");
+=======
my $make_res = system("cd test/$t && $make_command $flag");
+>>>>>>> 0.12
if($make_res != 0)
{
push @results,"$t: make failed";
diff --git a/test/backupstore/Makefile.extra b/test/backupstore/Makefile.extra
index b319736c..2ce40389 100644
--- a/test/backupstore/Makefile.extra
+++ b/test/backupstore/Makefile.extra
@@ -1 +1,5 @@
+<<<<<<< HEAD
+link-extra: ../../bin/bbstored/HousekeepStoreAccount.o
+=======
link-extra: ../../lib/backupstore/HousekeepStoreAccount.o
+>>>>>>> 0.12
diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp
index 661973e0..cc708da0 100644
--- a/test/backupstore/testbackupstore.cpp
+++ b/test/backupstore/testbackupstore.cpp
@@ -12,6 +12,34 @@
#include <stdlib.h>
#include <string.h>
+<<<<<<< HEAD
+#include "Test.h"
+#include "autogen_BackupProtocolClient.h"
+#include "SSLLib.h"
+#include "TLSContext.h"
+#include "SocketStreamTLS.h"
+#include "BoxPortsAndFiles.h"
+#include "BackupStoreConstants.h"
+#include "Socket.h"
+#include "BackupStoreFilenameClear.h"
+#include "CollectInBufferStream.h"
+#include "BackupStoreDirectory.h"
+#include "BackupStoreFile.h"
+#include "FileStream.h"
+#include "RaidFileController.h"
+#include "RaidFileWrite.h"
+#include "BackupStoreInfo.h"
+#include "BackupStoreException.h"
+#include "RaidFileException.h"
+#include "MemBlockStream.h"
+#include "BackupClientFileAttributes.h"
+#include "BackupClientCryptoKeys.h"
+#include "ServerControl.h"
+#include "BackupStoreAccountDatabase.h"
+#include "BackupStoreRefCountDatabase.h"
+#include "BackupStoreAccounts.h"
+#include "HousekeepStoreAccount.h"
+=======
#include "Archive.h"
#include "BackupClientCryptoKeys.h"
#include "BackupClientFileAttributes.h"
@@ -40,6 +68,7 @@
#include "TLSContext.h"
#include "Test.h"
#include "autogen_BackupProtocol.h"
+>>>>>>> 0.12
#include "MemLeakFindOn.h"
@@ -223,6 +252,13 @@ void CheckEntries(BackupStoreDirectory &rDir, int16_t FlagsMustBeSet, int16_t Fl
int test1(int argc, const char *argv[])
{
+<<<<<<< HEAD
+ // Initialise the raid file controller
+ RaidFileController &rcontroller = RaidFileController::GetController();
+ rcontroller.Initialise("testfiles/raidfile.conf");
+
+=======
+>>>>>>> 0.12
// test some basics -- encoding and decoding filenames
{
// Make some filenames in various ways
@@ -435,6 +471,15 @@ void test_test_file(int t, IOStream &rStream)
void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
{
+<<<<<<< HEAD
+ printf("Test for del: %llx\n", DirID);
+
+ // Command
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
+ DirID,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
printf("Test for del: %llx\n", (unsigned long long)DirID);
// Command
@@ -442,6 +487,7 @@ void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
DirID,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
@@ -453,7 +499,11 @@ void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
int dirs = 0;
while((en = i.Next()) != 0)
{
+<<<<<<< HEAD
+ if(en->GetFlags() & BackupProtocolClientListDirectory::Flags_Dir)
+=======
if(en->GetFlags() & BackupProtocolListDirectory::Flags_Dir)
+>>>>>>> 0.12
{
dirs++;
// Recurse
@@ -464,7 +514,11 @@ void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
files++;
}
// Check it's deleted
+<<<<<<< HEAD
+ TEST_THAT(en->GetFlags() & BackupProtocolClientListDirectory::Flags_Deleted);
+=======
TEST_THAT(en->GetFlags() & BackupProtocolListDirectory::Flags_Deleted);
+>>>>>>> 0.12
}
// Check there were the right number of files and directories
@@ -476,7 +530,11 @@ std::vector<uint32_t> ExpectedRefCounts;
void set_refcount(int64_t ObjectID, uint32_t RefCount = 1)
{
+<<<<<<< HEAD
+ if (ExpectedRefCounts.size() <= ObjectID);
+=======
if ((int64_t)ExpectedRefCounts.size() <= ObjectID);
+>>>>>>> 0.12
{
ExpectedRefCounts.resize(ObjectID + 1, 0);
}
@@ -489,7 +547,11 @@ void create_file_in_dir(std::string name, std::string source, int64_t parentId,
BackupStoreFilenameClear name_encoded("file_One");
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(
source.c_str(), parentId, name_encoded));
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> stored(
+=======
std::auto_ptr<BackupProtocolSuccess> stored(
+>>>>>>> 0.12
protocol.QueryStoreFile(
parentId,
0x123456789abcdefLL, /* modification time */
@@ -513,14 +575,22 @@ int64_t create_test_data_subdirs(BackupProtocolClient &protocol, int64_t indir,
// Create with dummy attributes
int attrS = 0;
MemBlockStream attr(&attrS, sizeof(attrS));
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirCreate(protocol.QueryCreateDirectory(
+=======
std::auto_ptr<BackupProtocolSuccess> dirCreate(protocol.QueryCreateDirectory(
+>>>>>>> 0.12
indir,
9837429842987984LL, dirname, attr));
subdirid = dirCreate->GetObjectID();
}
+<<<<<<< HEAD
+ printf("Create subdirs, depth = %d, dirid = %llx\n", depth, subdirid);
+=======
printf("Create subdirs, depth = %d, dirid = %llx\n", depth,
(unsigned long long)subdirid);
+>>>>>>> 0.12
TEST_EQUAL(subdirid, rRefCount.GetLastObjectIDUsed());
TEST_EQUAL(1, rRefCount.GetRefCount(subdirid))
@@ -549,11 +619,19 @@ int64_t create_test_data_subdirs(BackupProtocolClient &protocol, int64_t indir,
void check_dir_after_uploads(BackupProtocolClient &protocol, const StreamableMemBlock &Attributes)
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+ TEST_THAT(dirreply->GetObjectID() == BackupProtocolClientListDirectory::RootDirectory);
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
BackupProtocolListDirectory::RootDirectory,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
TEST_THAT(dirreply->GetObjectID() == BackupProtocolListDirectory::RootDirectory);
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
@@ -574,9 +652,15 @@ void check_dir_after_uploads(BackupProtocolClient &protocol, const StreamableMem
TEST_THAT(en->GetName() == uploads[t].name);
TEST_THAT(en->GetObjectID() == uploads[t].allocated_objid);
TEST_THAT(en->GetModificationTime() == uploads[t].mod_time);
+<<<<<<< HEAD
+ int correct_flags = BackupProtocolClientListDirectory::Flags_File;
+ if(uploads[t].should_be_old_version) correct_flags |= BackupProtocolClientListDirectory::Flags_OldVersion;
+ if(uploads[t].delete_file) correct_flags |= BackupProtocolClientListDirectory::Flags_Deleted;
+=======
int correct_flags = BackupProtocolListDirectory::Flags_File;
if(uploads[t].should_be_old_version) correct_flags |= BackupProtocolListDirectory::Flags_OldVersion;
if(uploads[t].delete_file) correct_flags |= BackupProtocolListDirectory::Flags_Deleted;
+>>>>>>> 0.12
TEST_THAT(en->GetFlags() == correct_flags);
if(t == UPLOAD_ATTRS_EN)
{
@@ -605,10 +689,17 @@ typedef struct
void recursive_count_objects_r(BackupProtocolClient &protocol, int64_t id, recursive_count_objects_results &results)
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
+ id,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
id,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
@@ -648,9 +739,15 @@ void recursive_count_objects(const char *hostname, int64_t id, recursive_count_o
BackupProtocolClient protocolReadOnly(connReadOnly);
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocolReadOnly.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+ TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+ std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocolReadOnly.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly));
+=======
std::auto_ptr<BackupProtocolVersion> serverVersion(protocolReadOnly.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocolReadOnly.QueryLogin(0x01234567, BackupProtocolLogin::Flags_ReadOnly));
+>>>>>>> 0.12
}
// Count objects
@@ -757,10 +854,17 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
for(int l = 0; l < 3; ++l)
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
BackupProtocolListDirectory::RootDirectory,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
@@ -771,10 +875,17 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
// Read the dir from the readonly connection (make sure it gets in the cache)
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
BackupProtocolListDirectory::RootDirectory,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
@@ -786,7 +897,11 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
BackupStoreFilenameClear store1name("testfiles/file1");
{
FileStream out("testfiles/file1_upload1", O_WRONLY | O_CREAT | O_EXCL);
+<<<<<<< HEAD
+ std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/file1", BackupProtocolClientListDirectory::RootDirectory, store1name));
+=======
std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/file1", BackupProtocolListDirectory::RootDirectory, store1name));
+>>>>>>> 0.12
encoded->CopyStreamTo(out);
}
@@ -796,8 +911,13 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
int64_t store1objid = 0;
{
FileStream upload("testfiles/file1_upload1");
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
+ BackupProtocolClientListDirectory::RootDirectory,
+=======
std::auto_ptr<BackupProtocolSuccess> stored(protocol.QueryStoreFile(
BackupProtocolListDirectory::RootDirectory,
+>>>>>>> 0.12
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
0, /* diff from ID */
@@ -810,7 +930,11 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
// And retrieve it
{
// Retrieve as object
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getfile(protocol.QueryGetObject(store1objid));
+=======
std::auto_ptr<BackupProtocolSuccess> getfile(protocol.QueryGetObject(store1objid));
+>>>>>>> 0.12
TEST_THAT(getfile->GetObjectID() == store1objid);
// BLOCK
{
@@ -825,7 +949,11 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
}
// Retrieve as file
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getobj(protocol.QueryGetFile(BackupProtocolClientListDirectory::RootDirectory, store1objid));
+=======
std::auto_ptr<BackupProtocolSuccess> getobj(protocol.QueryGetFile(BackupProtocolListDirectory::RootDirectory, store1objid));
+>>>>>>> 0.12
TEST_THAT(getobj->GetObjectID() == store1objid);
// BLOCK
{
@@ -851,7 +979,11 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
// Retrieve the block index, by ID
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByID(store1objid));
+=======
std::auto_ptr<BackupProtocolSuccess> getblockindex(protocol.QueryGetBlockIndexByID(store1objid));
+>>>>>>> 0.12
TEST_THAT(getblockindex->GetObjectID() == store1objid);
std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
// Check against uploaded file
@@ -859,7 +991,11 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
}
// and again, by name
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByName(BackupProtocolClientListDirectory::RootDirectory, store1name));
+=======
std::auto_ptr<BackupProtocolSuccess> getblockindex(protocol.QueryGetBlockIndexByName(BackupProtocolListDirectory::RootDirectory, store1name));
+>>>>>>> 0.12
TEST_THAT(getblockindex->GetObjectID() == store1objid);
std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
// Check against uploaded file
@@ -869,10 +1005,17 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
// Get the directory again, and see if the entry is in it
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
BackupProtocolListDirectory::RootDirectory,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
@@ -895,7 +1038,11 @@ void test_server_1(BackupProtocolClient &protocol, BackupProtocolClient &protoco
// Try using GetFile on a directory
{
+<<<<<<< HEAD
+ TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientSuccess> getFile(protocol.QueryGetFile(BackupProtocolClientListDirectory::RootDirectory, BackupProtocolClientListDirectory::RootDirectory)),
+=======
TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolSuccess> getFile(protocol.QueryGetFile(BackupProtocolListDirectory::RootDirectory, BackupProtocolListDirectory::RootDirectory)),
+>>>>>>> 0.12
ConnectionException, Conn_Protocol_UnexpectedReply);
}
}
@@ -918,6 +1065,16 @@ std::auto_ptr<SocketStreamTLS> open_conn(const char *hostname,
return conn;
}
+<<<<<<< HEAD
+std::auto_ptr<BackupProtocolClient> test_server_login(SocketStreamTLS& rConn)
+{
+ // Make a protocol
+ std::auto_ptr<BackupProtocolClient> protocol(new
+ BackupProtocolClient(rConn));
+
+ // Check the version
+ std::auto_ptr<BackupProtocolClientVersion> serverVersion(
+=======
std::auto_ptr<BackupProtocolClient> test_server_login(const char *hostname,
TLSContext& rContext, std::auto_ptr<SocketStreamTLS>& rapConn)
{
@@ -929,11 +1086,16 @@ std::auto_ptr<BackupProtocolClient> test_server_login(const char *hostname,
// Check the version
std::auto_ptr<BackupProtocolVersion> serverVersion(
+>>>>>>> 0.12
protocol->QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
// Login
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(
+=======
std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(
+>>>>>>> 0.12
protocol->QueryLogin(0x01234567, 0));
return protocol;
@@ -950,6 +1112,15 @@ void run_housekeeping(BackupStoreAccountDatabase::Entry& rAccount)
housekeeping.DoHousekeeping(true /* keep trying forever */);
}
+<<<<<<< HEAD
+int test_server(const char *hostname)
+{
+ TLSContext context;
+ std::auto_ptr<SocketStreamTLS> conn = open_conn(hostname, context);
+ std::auto_ptr<BackupProtocolClient> apProtocol(
+ test_server_login(*conn));
+ BackupProtocolClient& protocol(*apProtocol);
+=======
// Run housekeeping (for which we need to disconnect ourselves) and check
// that it doesn't change the numbers of files.
//
@@ -979,6 +1150,7 @@ int test_server(const char *hostname)
std::auto_ptr<SocketStreamTLS> conn;
std::auto_ptr<BackupProtocolClient> apProtocol =
test_server_login(hostname, context, conn);
+>>>>>>> 0.12
// Make some test attributes
#define ATTR1_SIZE 245
@@ -999,7 +1171,11 @@ int test_server(const char *hostname)
// Get it logging
FILE *protocolLog = ::fopen("testfiles/protocol.log", "w");
TEST_THAT(protocolLog != 0);
+<<<<<<< HEAD
+ protocol.SetLogToFile(protocolLog);
+=======
apProtocol->SetLogToFile(protocolLog);
+>>>>>>> 0.12
#ifndef WIN32
// Check that we can't open a new connection which requests write permissions
@@ -1008,16 +1184,26 @@ int test_server(const char *hostname)
conn.Open(context, Socket::TypeINET, hostname,
BOX_PORT_BBSTORED_TEST);
BackupProtocolClient protocol(conn);
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+ TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+ TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)),
+=======
std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)),
+>>>>>>> 0.12
ConnectionException, Conn_Protocol_UnexpectedReply);
protocol.QueryFinished();
}
#endif
// Set the client store marker
+<<<<<<< HEAD
+ protocol.QuerySetClientStoreMarker(0x8732523ab23aLL);
+=======
apProtocol->QuerySetClientStoreMarker(0x8732523ab23aLL);
+>>>>>>> 0.12
#ifndef WIN32
// Open a new connection which is read only
@@ -1032,14 +1218,26 @@ int test_server(const char *hostname)
protocolReadOnly.SetLogToFile(protocolReadOnlyLog);
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocolReadOnly.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+ TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+ std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocolReadOnly.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly));
+=======
std::auto_ptr<BackupProtocolVersion> serverVersion(protocolReadOnly.QueryVersion(BACKUP_STORE_SERVER_VERSION));
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocolReadOnly.QueryLogin(0x01234567, BackupProtocolLogin::Flags_ReadOnly));
+>>>>>>> 0.12
// Check client store marker
TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL);
}
#else // WIN32
+<<<<<<< HEAD
+ BackupProtocolClient& protocolReadOnly(protocol);
+#endif
+
+ test_server_1(protocol, protocolReadOnly);
+=======
#define protocolReadOnly (*apProtocol)
#endif
@@ -1064,6 +1262,7 @@ int test_server(const char *hostname)
run_housekeeping_and_check_account(hostname, context,
conn, apProtocol);
TEST_NUM_FILES(1, 0, 0, 1);
+>>>>>>> 0.12
// sleep to ensure that the timestamp on the file will change
::safe_sleep(1);
@@ -1077,6 +1276,17 @@ int test_server(const char *hostname)
std::string filename("testfiles/test");
filename += uploads[t].fnextra;
int64_t modtime = 0;
+<<<<<<< HEAD
+
+ std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(filename.c_str(), BackupProtocolClientListDirectory::RootDirectory, uploads[t].name, &modtime));
+ TEST_THAT(modtime != 0);
+
+ std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
+ BackupProtocolClientListDirectory::RootDirectory,
+ modtime,
+ modtime, /* use it for attr hash too */
+ 0, /* diff from ID */
+=======
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(filename.c_str(), BackupProtocolListDirectory::RootDirectory, uploads[t].name, &modtime));
TEST_THAT(modtime != 0);
@@ -1086,6 +1296,7 @@ int test_server(const char *hostname)
modtime,
modtime, /* use it for attr hash too */
0, /* diff from ID */
+>>>>>>> 0.12
uploads[t].name,
*upload));
uploads[t].allocated_objid = stored->GetObjectID();
@@ -1095,28 +1306,47 @@ int test_server(const char *hostname)
BOX_TRACE("wrote file " << filename << " to server "
"as object " <<
BOX_FORMAT_OBJECTID(stored->GetObjectID()));
+<<<<<<< HEAD
+=======
TEST_NUM_FILES(t + 2, 0, 0, 1);
run_housekeeping_and_check_account(hostname, context,
conn, apProtocol);
TEST_NUM_FILES(t + 2, 0, 0, 1);
+>>>>>>> 0.12
}
// Add some attributes onto one of them
{
+<<<<<<< HEAD
+ MemBlockStream attrnew(attr3, sizeof(attr3));
+ std::auto_ptr<BackupProtocolClientSuccess> set(protocol.QuerySetReplacementFileAttributes(
+ BackupProtocolClientListDirectory::RootDirectory,
+=======
TEST_NUM_FILES(UPLOAD_NUM + 1, 0, 0, 1);
MemBlockStream attrnew(attr3, sizeof(attr3));
std::auto_ptr<BackupProtocolSuccess> set(apProtocol->QuerySetReplacementFileAttributes(
BackupProtocolListDirectory::RootDirectory,
+>>>>>>> 0.12
32498749832475LL,
uploads[UPLOAD_ATTRS_EN].name,
attrnew));
TEST_THAT(set->GetObjectID() == uploads[UPLOAD_ATTRS_EN].allocated_objid);
+<<<<<<< HEAD
+=======
TEST_NUM_FILES(UPLOAD_NUM + 1, 0, 0, 1);
+>>>>>>> 0.12
}
// Delete one of them (will implicitly delete an old version)
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> del(protocol.QueryDeleteFile(
+ BackupProtocolClientListDirectory::RootDirectory,
+ uploads[UPLOAD_DELETE_EN].name));
+ TEST_THAT(del->GetObjectID() == uploads[UPLOAD_DELETE_EN].allocated_objid);
+ }
+=======
std::auto_ptr<BackupProtocolSuccess> del(apProtocol->QueryDeleteFile(
BackupProtocolListDirectory::RootDirectory,
uploads[UPLOAD_DELETE_EN].name));
@@ -1124,11 +1354,23 @@ int test_server(const char *hostname)
TEST_NUM_FILES(UPLOAD_NUM, 0, 1, 1);
}
+>>>>>>> 0.12
// Check that the block index can be obtained by name even though it's been deleted
{
// Fetch the raw object
{
FileStream out("testfiles/downloaddelobj", O_WRONLY | O_CREAT);
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getobj(protocol.QueryGetObject(uploads[UPLOAD_DELETE_EN].allocated_objid));
+ std::auto_ptr<IOStream> objstream(protocol.ReceiveStream());
+ objstream->CopyStreamTo(out);
+ }
+ // query index and test
+ std::auto_ptr<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByName(
+ BackupProtocolClientListDirectory::RootDirectory, uploads[UPLOAD_DELETE_EN].name));
+ TEST_THAT(getblockindex->GetObjectID() == uploads[UPLOAD_DELETE_EN].allocated_objid);
+ std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
+=======
std::auto_ptr<BackupProtocolSuccess> getobj(apProtocol->QueryGetObject(uploads[UPLOAD_DELETE_EN].allocated_objid));
std::auto_ptr<IOStream> objstream(apProtocol->ReceiveStream());
objstream->CopyStreamTo(out);
@@ -1138,6 +1380,7 @@ int test_server(const char *hostname)
BackupProtocolListDirectory::RootDirectory, uploads[UPLOAD_DELETE_EN].name));
TEST_THAT(getblockindex->GetObjectID() == uploads[UPLOAD_DELETE_EN].allocated_objid);
std::auto_ptr<IOStream> blockIndexStream(apProtocol->ReceiveStream());
+>>>>>>> 0.12
TEST_THAT(check_block_index("testfiles/downloaddelobj", *blockIndexStream));
}
@@ -1145,9 +1388,15 @@ int test_server(const char *hostname)
for(int t = 0; t < UPLOAD_NUM; ++t)
{
printf("%d\n", t);
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getFile(protocol.QueryGetFile(BackupProtocolClientListDirectory::RootDirectory, uploads[t].allocated_objid));
+ TEST_THAT(getFile->GetObjectID() == uploads[t].allocated_objid);
+ std::auto_ptr<IOStream> filestream(protocol.ReceiveStream());
+=======
std::auto_ptr<BackupProtocolSuccess> getFile(apProtocol->QueryGetFile(BackupProtocolListDirectory::RootDirectory, uploads[t].allocated_objid));
TEST_THAT(getFile->GetObjectID() == uploads[t].allocated_objid);
std::auto_ptr<IOStream> filestream(apProtocol->ReceiveStream());
+>>>>>>> 0.12
test_test_file(t, *filestream);
}
@@ -1159,7 +1408,11 @@ int test_server(const char *hostname)
check_dir_after_uploads(protocolReadOnly, attrtest);
printf("done.\n\n");
// And on the read/write one
+<<<<<<< HEAD
+ check_dir_after_uploads(protocol, attrtest);
+=======
check_dir_after_uploads(*apProtocol, attrtest);
+>>>>>>> 0.12
}
// sleep to ensure that the timestamp on the file will change
@@ -1181,6 +1434,14 @@ int test_server(const char *hostname)
out.Write(buf, TEST_FILE_FOR_PATCHING_SIZE - TEST_FILE_FOR_PATCHING_PATCH_AT);
::free(buf);
}
+<<<<<<< HEAD
+ {
+ // Fetch the block index for this one
+ std::auto_ptr<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByName(
+ BackupProtocolClientListDirectory::RootDirectory, uploads[UPLOAD_PATCH_EN].name));
+ TEST_THAT(getblockindex->GetObjectID() == uploads[UPLOAD_PATCH_EN].allocated_objid);
+ std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
+=======
TEST_NUM_FILES(UPLOAD_NUM, 0, 1, 1);
@@ -1209,6 +1470,7 @@ int test_server(const char *hostname)
BackupProtocolListDirectory::RootDirectory, uploads[UPLOAD_PATCH_EN].name));
TEST_THAT(getblockindex->GetObjectID() == uploads[UPLOAD_PATCH_EN].allocated_objid);
std::auto_ptr<IOStream> blockIndexStream(apProtocol->ReceiveStream());
+>>>>>>> 0.12
// Do the patching
bool isCompletelyDifferent = false;
@@ -1216,7 +1478,11 @@ int test_server(const char *hostname)
std::auto_ptr<IOStream> patchstream(
BackupStoreFile::EncodeFileDiff(
TEST_FILE_FOR_PATCHING ".mod",
+<<<<<<< HEAD
+ BackupProtocolClientListDirectory::RootDirectory,
+=======
BackupProtocolListDirectory::RootDirectory,
+>>>>>>> 0.12
uploads[UPLOAD_PATCH_EN].name,
uploads[UPLOAD_PATCH_EN].allocated_objid,
*blockIndexStream,
@@ -1235,8 +1501,13 @@ int test_server(const char *hostname)
int64_t patchedID = 0;
{
FileStream uploadpatch(TEST_FILE_FOR_PATCHING ".patch");
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
+ BackupProtocolClientListDirectory::RootDirectory,
+=======
std::auto_ptr<BackupProtocolSuccess> stored(apProtocol->QueryStoreFile(
BackupProtocolListDirectory::RootDirectory,
+>>>>>>> 0.12
modtime,
modtime, /* use it for attr hash too */
uploads[UPLOAD_PATCH_EN].allocated_objid, /* diff from ID */
@@ -1250,6 +1521,14 @@ int test_server(const char *hostname)
set_refcount(patchedID, 1);
// Then download it to check it's OK
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getFile(protocol.QueryGetFile(BackupProtocolClientListDirectory::RootDirectory, patchedID));
+ TEST_THAT(getFile->GetObjectID() == patchedID);
+ std::auto_ptr<IOStream> filestream(protocol.ReceiveStream());
+ BackupStoreFile::DecodeFile(*filestream, TEST_FILE_FOR_PATCHING ".downloaded", IOStream::TimeOutInfinite);
+ // Check it's the same
+ TEST_THAT(check_files_same(TEST_FILE_FOR_PATCHING ".downloaded", TEST_FILE_FOR_PATCHING ".mod"));
+=======
std::auto_ptr<BackupProtocolSuccess> getFile(apProtocol->QueryGetFile(BackupProtocolListDirectory::RootDirectory, patchedID));
TEST_THAT(getFile->GetObjectID() == patchedID);
std::auto_ptr<IOStream> filestream(apProtocol->ReceiveStream());
@@ -1258,6 +1537,7 @@ int test_server(const char *hostname)
TEST_THAT(check_files_same(TEST_FILE_FOR_PATCHING ".downloaded", TEST_FILE_FOR_PATCHING ".mod"));
TEST_NUM_FILES(UPLOAD_NUM, 1, 1, 1);
+>>>>>>> 0.12
}
// Create a directory
@@ -1266,6 +1546,13 @@ int test_server(const char *hostname)
{
// Attributes
MemBlockStream attr(attr1, sizeof(attr1));
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirCreate(protocol.QueryCreateDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ 9837429842987984LL, dirname, attr));
+ subdirid = dirCreate->GetObjectID();
+ TEST_THAT(subdirid == maxID + 1);
+=======
std::auto_ptr<BackupProtocolSuccess> dirCreate(apProtocol->QueryCreateDirectory(
BackupProtocolListDirectory::RootDirectory,
9837429842987984LL, dirname, attr));
@@ -1273,6 +1560,7 @@ int test_server(const char *hostname)
TEST_THAT(subdirid == maxID + 1);
TEST_NUM_FILES(UPLOAD_NUM, 1, 1, 2);
+>>>>>>> 0.12
}
set_refcount(subdirid, 1);
@@ -1284,7 +1572,11 @@ int test_server(const char *hostname)
int64_t modtime;
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(filename.c_str(), subdirid, uploads[0].name, &modtime));
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
+=======
std::auto_ptr<BackupProtocolSuccess> stored(apProtocol->QueryStoreFile(
+>>>>>>> 0.12
subdirid,
modtime,
modtime, /* use for attr hash too */
@@ -1292,8 +1584,11 @@ int test_server(const char *hostname)
uploads[0].name,
*upload));
subdirfileid = stored->GetObjectID();
+<<<<<<< HEAD
+=======
TEST_NUM_FILES(UPLOAD_NUM + 1, 1, 1, 2);
+>>>>>>> 0.12
}
set_refcount(subdirfileid, 1);
@@ -1302,10 +1597,17 @@ int test_server(const char *hostname)
// Check the directories on the read only connection
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes! */)); // Stream
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
BackupProtocolListDirectory::RootDirectory,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes! */)); // Stream
+>>>>>>> 0.12
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
@@ -1327,17 +1629,28 @@ int test_server(const char *hostname)
}
// Does it look right?
TEST_THAT(en->GetName() == dirname);
+<<<<<<< HEAD
+ TEST_THAT(en->GetFlags() == BackupProtocolClientListDirectory::Flags_Dir);
+=======
TEST_THAT(en->GetFlags() == BackupProtocolListDirectory::Flags_Dir);
+>>>>>>> 0.12
TEST_THAT(en->GetObjectID() == subdirid);
TEST_THAT(en->GetModificationTime() == 0); // dirs don't have modification times.
}
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ subdirid,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, true /* get attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
subdirid,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, true /* get attributes */));
+>>>>>>> 0.12
TEST_THAT(dirreply->GetObjectID() == subdirid);
// Stream
BackupStoreDirectory dir;
@@ -1352,7 +1665,11 @@ int test_server(const char *hostname)
TEST_THAT(en != 0);
// Does it look right?
TEST_THAT(en->GetName() == uploads[0].name);
+<<<<<<< HEAD
+ TEST_THAT(en->GetFlags() == BackupProtocolClientListDirectory::Flags_File);
+=======
TEST_THAT(en->GetFlags() == BackupProtocolListDirectory::Flags_File);
+>>>>>>> 0.12
TEST_THAT(en->GetObjectID() == subdirfileid);
TEST_THAT(en->GetModificationTime() != 0);
@@ -1367,10 +1684,17 @@ int test_server(const char *hostname)
// Check that we don't get attributes if we don't ask for them
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ subdirid,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes! */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
subdirid,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes! */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
@@ -1384,7 +1708,11 @@ int test_server(const char *hostname)
// Change attributes on the directory
{
MemBlockStream attrnew(attr2, sizeof(attr2));
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> changereply(protocol.QueryChangeDirAttributes(
+=======
std::auto_ptr<BackupProtocolSuccess> changereply(apProtocol->QueryChangeDirAttributes(
+>>>>>>> 0.12
subdirid,
329483209443598LL,
attrnew));
@@ -1393,10 +1721,17 @@ int test_server(const char *hostname)
// Check the new attributes
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ subdirid,
+ 0, // no flags
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_EVERYTHING, true /* get attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
subdirid,
0, // no flags
BackupProtocolListDirectory::Flags_EXCLUDE_EVERYTHING, true /* get attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
@@ -1417,15 +1752,30 @@ int test_server(const char *hostname)
{
BackupStoreFilenameClear newName("moved-files");
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> rep(protocol.QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
+ BackupProtocolClientListDirectory::RootDirectory,
+ subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName));
+=======
std::auto_ptr<BackupProtocolSuccess> rep(apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
BackupProtocolListDirectory::RootDirectory,
subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName, newName));
+>>>>>>> 0.12
TEST_THAT(rep->GetObjectID() == uploads[UPLOAD_FILE_TO_MOVE].allocated_objid);
}
// Try some dodgy renames
{
BackupStoreFilenameClear newName("moved-files");
+<<<<<<< HEAD
+ TEST_CHECK_THROWS(protocol.QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
+ BackupProtocolClientListDirectory::RootDirectory,
+ subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName),
+ ConnectionException, Conn_Protocol_UnexpectedReply);
+ TEST_CHECK_THROWS(protocol.QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
+ subdirid,
+ subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName),
+=======
TEST_CHECK_THROWS(apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
BackupProtocolListDirectory::RootDirectory,
subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName, newName),
@@ -1433,24 +1783,38 @@ int test_server(const char *hostname)
TEST_CHECK_THROWS(apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
subdirid,
subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName, newName),
+>>>>>>> 0.12
ConnectionException, Conn_Protocol_UnexpectedReply);
}
// Rename within a directory
{
BackupStoreFilenameClear newName("moved-files-x");
+<<<<<<< HEAD
+ protocol.QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
+ subdirid,
+ subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName);
+=======
apProtocol->QueryMoveObject(uploads[UPLOAD_FILE_TO_MOVE].allocated_objid,
subdirid,
subdirid, BackupProtocolMoveObject::Flags_MoveAllWithSameName, newName);
+>>>>>>> 0.12
}
// Check it's all gone from the root directory...
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
BackupProtocolListDirectory::RootDirectory,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
@@ -1469,10 +1833,17 @@ int test_server(const char *hostname)
BackupStoreFilenameClear lookFor("moved-files-x");
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ subdirid,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
subdirid,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
@@ -1504,14 +1875,22 @@ int test_server(const char *hostname)
BackupStoreFilenameClear nd("sub2");
// Attributes
MemBlockStream attr(attr1, sizeof(attr1));
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirCreate(protocol.QueryCreateDirectory(
+=======
std::auto_ptr<BackupProtocolSuccess> dirCreate(apProtocol->QueryCreateDirectory(
+>>>>>>> 0.12
subdirid,
9837429842987984LL, nd, attr));
subsubdirid = dirCreate->GetObjectID();
FileStream upload("testfiles/file1_upload1");
BackupStoreFilenameClear nf("file2");
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
+=======
std::auto_ptr<BackupProtocolSuccess> stored(apProtocol->QueryStoreFile(
+>>>>>>> 0.12
subsubdirid,
0x123456789abcdefLL, /* modification time */
0x7362383249872dfLL, /* attr hash */
@@ -1526,6 +1905,21 @@ int test_server(const char *hostname)
// Query names -- test that invalid stuff returns not found OK
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(3248972347823478927LL, subsubdirid));
+ TEST_THAT(nameRep->GetNumNameElements() == 0);
+ }
+ {
+ std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(subsubfileid, 2342378424LL));
+ TEST_THAT(nameRep->GetNumNameElements() == 0);
+ }
+ {
+ std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(38947234789LL, 2342378424LL));
+ TEST_THAT(nameRep->GetNumNameElements() == 0);
+ }
+ {
+ std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(BackupProtocolClientGetObjectName::ObjectID_DirectoryOnly, 2234342378424LL));
+=======
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(3248972347823478927LL, subsubdirid));
TEST_THAT(nameRep->GetNumNameElements() == 0);
}
@@ -1539,16 +1933,25 @@ int test_server(const char *hostname)
}
{
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(BackupProtocolGetObjectName::ObjectID_DirectoryOnly, 2234342378424LL));
+>>>>>>> 0.12
TEST_THAT(nameRep->GetNumNameElements() == 0);
}
// Query names... first, get info for the file
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(subsubfileid, subsubdirid));
+ std::auto_ptr<IOStream> namestream(protocol.ReceiveStream());
+
+ TEST_THAT(nameRep->GetNumNameElements() == 3);
+ TEST_THAT(nameRep->GetFlags() == BackupProtocolClientListDirectory::Flags_File);
+=======
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(subsubfileid, subsubdirid));
std::auto_ptr<IOStream> namestream(apProtocol->ReceiveStream());
TEST_THAT(nameRep->GetNumNameElements() == 3);
TEST_THAT(nameRep->GetFlags() == BackupProtocolListDirectory::Flags_File);
+>>>>>>> 0.12
TEST_THAT(nameRep->GetModificationTime() == 0x123456789abcdefLL);
TEST_THAT(nameRep->GetAttributesHash() == 0x7362383249872dfLL);
static const char *testnames[] = {"file2","sub2","lovely_directory"};
@@ -1562,11 +1965,19 @@ int test_server(const char *hostname)
// Query names... secondly, for the directory
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(BackupProtocolClientGetObjectName::ObjectID_DirectoryOnly, subsubdirid));
+ std::auto_ptr<IOStream> namestream(protocol.ReceiveStream());
+
+ TEST_THAT(nameRep->GetNumNameElements() == 2);
+ TEST_THAT(nameRep->GetFlags() == BackupProtocolClientListDirectory::Flags_Dir);
+=======
std::auto_ptr<BackupProtocolObjectName> nameRep(apProtocol->QueryGetObjectName(BackupProtocolGetObjectName::ObjectID_DirectoryOnly, subsubdirid));
std::auto_ptr<IOStream> namestream(apProtocol->ReceiveStream());
TEST_THAT(nameRep->GetNumNameElements() == 2);
TEST_THAT(nameRep->GetFlags() == BackupProtocolListDirectory::Flags_Dir);
+>>>>>>> 0.12
static const char *testnames[] = {"sub2","lovely_directory"};
for(int l = 0; l < nameRep->GetNumNameElements(); ++l)
{
@@ -1578,18 +1989,33 @@ int test_server(const char *hostname)
//} skip:
+<<<<<<< HEAD
+ std::auto_ptr<BackupStoreAccountDatabase> apAccounts(
+ BackupStoreAccountDatabase::Read(
+ "testfiles/accounts.txt"));
+=======
+>>>>>>> 0.12
std::auto_ptr<BackupStoreRefCountDatabase> apRefCount(
BackupStoreRefCountDatabase::Load(
apAccounts->GetEntry(0x1234567), true));
// Create some nice recursive directories
+<<<<<<< HEAD
+ int64_t dirtodelete = create_test_data_subdirs(protocol,
+ BackupProtocolClientListDirectory::RootDirectory,
+=======
int64_t dirtodelete = create_test_data_subdirs(*apProtocol,
BackupProtocolListDirectory::RootDirectory,
+>>>>>>> 0.12
"test_delete", 6 /* depth */, *apRefCount);
// And delete them
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirdel(protocol.QueryDeleteDirectory(
+=======
std::auto_ptr<BackupProtocolSuccess> dirdel(apProtocol->QueryDeleteDirectory(
+>>>>>>> 0.12
dirtodelete));
TEST_THAT(dirdel->GetObjectID() == dirtodelete);
}
@@ -1597,10 +2023,17 @@ int test_server(const char *hostname)
// Get the root dir, checking for deleted items
{
// Command
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocolReadOnly.QueryListDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ BackupProtocolClientListDirectory::Flags_Dir | BackupProtocolClientListDirectory::Flags_Deleted,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocolReadOnly.QueryListDirectory(
BackupProtocolListDirectory::RootDirectory,
BackupProtocolListDirectory::Flags_Dir | BackupProtocolListDirectory::Flags_Deleted,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocolReadOnly.ReceiveStream());
@@ -1627,7 +2060,11 @@ int test_server(const char *hostname)
#ifndef WIN32
protocolReadOnly.QueryFinished();
#endif
+<<<<<<< HEAD
+ protocol.QueryFinished();
+=======
apProtocol->QueryFinished();
+>>>>>>> 0.12
// Close logs
#ifndef WIN32
@@ -1820,7 +2257,10 @@ int test3(int argc, const char *argv[])
TEST_CHECK_THROWS(info->ChangeBlocksInDeletedFiles(1), BackupStoreException, StoreInfoIsReadOnly);
TEST_CHECK_THROWS(info->RemovedDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly);
TEST_CHECK_THROWS(info->AddDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly);
+<<<<<<< HEAD
+=======
TEST_CHECK_THROWS(info->SetAccountName("hello"), BackupStoreException, StoreInfoIsReadOnly);
+>>>>>>> 0.12
}
{
std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(76, "test-info/", 0, false));
@@ -1837,7 +2277,10 @@ int test3(int argc, const char *argv[])
info->AddDeletedDirectory(3);
info->AddDeletedDirectory(4);
info->RemovedDeletedDirectory(3);
+<<<<<<< HEAD
+=======
info->SetAccountName("whee");
+>>>>>>> 0.12
TEST_CHECK_THROWS(info->RemovedDeletedDirectory(9), BackupStoreException, StoreInfoDirNotInList);
info->Save();
}
@@ -1848,7 +2291,10 @@ int test3(int argc, const char *argv[])
TEST_THAT(info->GetBlocksInDeletedFiles() == 1);
TEST_THAT(info->GetBlocksSoftLimit() == 3461231233455433LL);
TEST_THAT(info->GetBlocksHardLimit() == 2934852487LL);
+<<<<<<< HEAD
+=======
TEST_THAT(info->GetAccountName() == "whee");
+>>>>>>> 0.12
const std::vector<int64_t> &delfiles(info->GetDeletedDirectories());
TEST_THAT(delfiles.size() == 2);
TEST_THAT(delfiles[0] == 2);
@@ -1872,6 +2318,238 @@ int test3(int argc, const char *argv[])
int pid = LaunchServer(cmd.c_str(), "testfiles/bbstored.pid");
TEST_THAT(pid != -1 && pid != 0);
+<<<<<<< HEAD
+ if(pid > 0)
+ {
+ ::sleep(1);
+ TEST_THAT(ServerIsAlive(pid));
+
+ // BLOCK
+ {
+ // Open a connection to the server
+ SocketStreamTLS conn;
+ conn.Open(context, Socket::TypeINET, "localhost",
+ BOX_PORT_BBSTORED_TEST);
+
+ // Make a protocol
+ BackupProtocolClient protocol(conn);
+
+ // Check the version
+ std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+ TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+
+ // Login
+ TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)),
+ ConnectionException, Conn_Protocol_UnexpectedReply);
+
+ // Finish the connection
+ protocol.QueryFinished();
+ }
+
+ // Create an account for the test client
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf create 01234567 0 "
+ "10000B 20000B") == 0);
+
+ TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+
+ TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567"));
+ TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567"));
+ TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567"));
+ TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8);
+ // make sure something is written to it
+
+ std::auto_ptr<BackupStoreAccountDatabase> apAccounts(
+ BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
+
+ std::auto_ptr<BackupStoreRefCountDatabase> apReferences(
+ BackupStoreRefCountDatabase::Load(
+ apAccounts->GetEntry(0x1234567), true));
+ TEST_EQUAL(BACKUPSTORE_ROOT_DIRECTORY_ID,
+ apReferences->GetLastObjectIDUsed());
+ TEST_EQUAL(1, apReferences->GetRefCount(BACKUPSTORE_ROOT_DIRECTORY_ID))
+ apReferences.reset();
+
+ // Delete the refcount database and log in again,
+ // check that it is recreated automatically but with
+ // no objects in it, to ensure seamless upgrade.
+ TEST_EQUAL(0, ::unlink("testfiles/0_0/backup/01234567/refcount.db.rfw"));
+
+ TLSContext context;
+ std::auto_ptr<SocketStreamTLS> conn = open_conn("localhost",
+ context);
+ test_server_login(*conn)->QueryFinished();
+
+ BackupStoreAccountDatabase::Entry account =
+ apAccounts->GetEntry(0x1234567);
+ apReferences = BackupStoreRefCountDatabase::Load(account, true);
+ TEST_EQUAL(0, apReferences->GetLastObjectIDUsed());
+
+ TEST_THAT(ServerIsAlive(pid));
+
+ run_housekeeping(account);
+
+ // Check that housekeeping fixed the ref counts
+ TEST_EQUAL(BACKUPSTORE_ROOT_DIRECTORY_ID,
+ apReferences->GetLastObjectIDUsed());
+ TEST_EQUAL(1, apReferences->GetRefCount(BACKUPSTORE_ROOT_DIRECTORY_ID))
+
+ TEST_THAT(ServerIsAlive(pid));
+
+ set_refcount(BACKUPSTORE_ROOT_DIRECTORY_ID, 1);
+
+ TEST_THAT(test_server("localhost") == 0);
+
+ // test that all object reference counts have the
+ // expected values
+ TEST_EQUAL(ExpectedRefCounts.size() - 1,
+ apReferences->GetLastObjectIDUsed());
+ for (unsigned int i = BACKUPSTORE_ROOT_DIRECTORY_ID;
+ i < ExpectedRefCounts.size(); i++)
+ {
+ TEST_EQUAL_LINE(ExpectedRefCounts[i],
+ apReferences->GetRefCount(i),
+ "object " << BOX_FORMAT_OBJECTID(i));
+ }
+
+ // Delete the refcount database again, and let
+ // housekeeping recreate it and fix the ref counts.
+ // This could also happen after upgrade, if a housekeeping
+ // runs before the user logs in.
+ apReferences.reset();
+ TEST_EQUAL(0, ::unlink("testfiles/0_0/backup/01234567/refcount.db.rfw"));
+ run_housekeeping(account);
+ apReferences = BackupStoreRefCountDatabase::Load(account, true);
+
+ TEST_EQUAL(ExpectedRefCounts.size() - 1,
+ apReferences->GetLastObjectIDUsed());
+ for (unsigned int i = BACKUPSTORE_ROOT_DIRECTORY_ID;
+ i < ExpectedRefCounts.size(); i++)
+ {
+ TEST_EQUAL_LINE(ExpectedRefCounts[i],
+ apReferences->GetRefCount(i),
+ "object " << BOX_FORMAT_OBJECTID(i));
+ }
+
+ // Test the deletion of objects by the housekeeping system
+ // First, things as they are now.
+ recursive_count_objects_results before = {0,0,0};
+
+ recursive_count_objects("localhost", BackupProtocolClientListDirectory::RootDirectory, before);
+
+ TEST_THAT(before.objectsNotDel != 0);
+ TEST_THAT(before.deleted != 0);
+ TEST_THAT(before.old != 0);
+
+ // Kill it
+ TEST_THAT(KillServer(pid));
+ ::sleep(1);
+ TEST_THAT(!ServerIsAlive(pid));
+
+ #ifdef WIN32
+ TEST_THAT(unlink("testfiles/bbstored.pid") == 0);
+ #else
+ TestRemoteProcessMemLeaks("bbstored.memleaks");
+ #endif
+
+ // Set a new limit on the account -- leave the hard limit
+ // high to make sure the target for freeing space is the
+ // soft limit.
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf setlimit 01234567 "
+ "10B 20000B") == 0);
+ TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+
+ // Start things up
+ pid = LaunchServer(BBSTORED " testfiles/bbstored.conf",
+ "testfiles/bbstored.pid");
+
+ ::sleep(1);
+ TEST_THAT(ServerIsAlive(pid));
+
+ // wait for housekeeping to happen
+ printf("waiting for housekeeping:\n");
+ for(int l = 0; l < 30; ++l)
+ {
+ ::sleep(1);
+ printf(".");
+ fflush(stdout);
+ }
+ printf("\n");
+
+ // Count the objects again
+ recursive_count_objects_results after = {0,0,0};
+ recursive_count_objects("localhost",
+ BackupProtocolClientListDirectory::RootDirectory,
+ after);
+
+ // If these tests fail then try increasing the timeout above
+ TEST_THAT(after.objectsNotDel == before.objectsNotDel);
+ TEST_THAT(after.deleted == 0);
+ TEST_THAT(after.old == 0);
+
+ // Set a really small hard limit
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf setlimit 01234567 "
+ "10B 20B") == 0);
+ TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+
+ // Try to upload a file and create a directory, and check an error is generated
+ {
+ // Open a connection to the server
+ SocketStreamTLS conn;
+ conn.Open(context, Socket::TypeINET, "localhost",
+ BOX_PORT_BBSTORED_TEST);
+
+ // Make a protocol
+ BackupProtocolClient protocol(conn);
+
+ // Check the version
+ std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+ TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
+
+ // Login
+ std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0));
+
+ int64_t modtime = 0;
+
+ BackupStoreFilenameClear fnx("exceed-limit");
+ std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/test3", BackupProtocolClientListDirectory::RootDirectory, fnx, &modtime));
+ TEST_THAT(modtime != 0);
+
+ TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
+ BackupProtocolClientListDirectory::RootDirectory,
+ modtime,
+ modtime, /* use it for attr hash too */
+ 0, /* diff from ID */
+ fnx,
+ *upload)),
+ ConnectionException, Conn_Protocol_UnexpectedReply);
+
+ MemBlockStream attr(&modtime, sizeof(modtime));
+ BackupStoreFilenameClear fnxd("exceed-limit-dir");
+ TEST_CHECK_THROWS(std::auto_ptr<BackupProtocolClientSuccess> dirCreate(protocol.QueryCreateDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ 9837429842987984LL, fnxd, attr)),
+ ConnectionException, Conn_Protocol_UnexpectedReply);
+
+
+ // Finish the connection
+ protocol.QueryFinished();
+ }
+
+ // Kill it again
+ TEST_THAT(KillServer(pid));
+ ::sleep(1);
+ TEST_THAT(!ServerIsAlive(pid));
+
+ #ifdef WIN32
+ TEST_THAT(unlink("testfiles/bbstored.pid") == 0);
+ #else
+ TestRemoteProcessMemLeaks("bbstored.memleaks");
+ #endif
+ }
+=======
if(pid <= 0)
{
return 1;
@@ -2140,6 +2818,7 @@ int test3(int argc, const char *argv[])
#else
TestRemoteProcessMemLeaks("bbstored.memleaks");
#endif
+>>>>>>> 0.12
return 0;
}
@@ -2187,18 +2866,36 @@ int multi_server()
return 0;
}
+<<<<<<< HEAD
+#ifdef WIN32
+WCHAR* ConvertUtf8ToWideString(const char* pString);
+std::string ConvertPathToAbsoluteUnicode(const char *pFileName);
+#endif
+
+int test(int argc, const char *argv[])
+=======
void test_open_files_with_limited_win32_permissions()
+>>>>>>> 0.12
{
#ifdef WIN32
// this had better work, or bbstored will die when combining diffs
char* file = "foo";
+<<<<<<< HEAD
+ std::string abs = ConvertPathToAbsoluteUnicode(file);
+ WCHAR* wfile = ConvertUtf8ToWideString(abs.c_str());
+=======
+>>>>>>> 0.12
DWORD accessRights = FILE_READ_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_WRITE_ATTRIBUTES |
FILE_WRITE_DATA | FILE_WRITE_EA /*| FILE_ALL_ACCESS*/;
DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+<<<<<<< HEAD
+ HANDLE h1 = CreateFileW(wfile, accessRights, shareMode,
+=======
HANDLE h1 = CreateFileA(file, accessRights, shareMode,
+>>>>>>> 0.12
NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
assert(h1 != INVALID_HANDLE_VALUE);
TEST_THAT(h1 != INVALID_HANDLE_VALUE);
@@ -2206,21 +2903,36 @@ void test_open_files_with_limited_win32_permissions()
accessRights = FILE_READ_ATTRIBUTES |
FILE_LIST_DIRECTORY | FILE_READ_EA;
+<<<<<<< HEAD
+ HANDLE h2 = CreateFileW(wfile, accessRights, shareMode,
+=======
HANDLE h2 = CreateFileA(file, accessRights, shareMode,
+>>>>>>> 0.12
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
assert(h2 != INVALID_HANDLE_VALUE);
TEST_THAT(h2 != INVALID_HANDLE_VALUE);
CloseHandle(h2);
CloseHandle(h1);
+<<<<<<< HEAD
+ delete [] wfile;
+
+ h1 = openfile("foo", O_CREAT | O_RDWR, 0);
+ TEST_THAT(h1 != INVALID_HANDLE_VALUE);
+ h2 = openfile("foo", O_RDWR, 0);
+=======
h1 = openfile(file, O_CREAT | O_RDWR, 0);
TEST_THAT(h1 != INVALID_HANDLE_VALUE);
h2 = openfile(file, O_RDWR, 0);
+>>>>>>> 0.12
TEST_THAT(h2 != INVALID_HANDLE_VALUE);
CloseHandle(h2);
CloseHandle(h1);
#endif
+<<<<<<< HEAD
+
+=======
}
void compare_backupstoreinfo_values_to_expected
@@ -2512,6 +3224,7 @@ int test(int argc, const char *argv[])
return ret;
}
+>>>>>>> 0.12
// SSL library
SSLLib::Initialise();
@@ -2560,7 +3273,11 @@ int test(int argc, const char *argv[])
/* {
int64_t modtime = 0;
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("/Users/ben/temp/large.tar",
+<<<<<<< HEAD
+ BackupProtocolClientListDirectory::RootDirectory, uploads[0].name, &modtime));
+=======
BackupProtocolListDirectory::RootDirectory, uploads[0].name, &modtime));
+>>>>>>> 0.12
TEST_THAT(modtime != 0);
FileStream write("testfiles/large.enc", O_WRONLY | O_CREAT);
upload->CopyStreamTo(write);
diff --git a/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp
index bc9911f0..a93ffb8f 100644
--- a/test/backupstorefix/testbackupstorefix.cpp
+++ b/test/backupstorefix/testbackupstorefix.cpp
@@ -17,6 +17,21 @@
#include <map>
#include "Test.h"
+<<<<<<< HEAD
+#include "BackupStoreConstants.h"
+#include "BackupStoreDirectory.h"
+#include "BackupStoreFile.h"
+#include "FileStream.h"
+#include "RaidFileController.h"
+#include "RaidFileWrite.h"
+#include "RaidFileRead.h"
+#include "BackupStoreInfo.h"
+#include "BackupStoreException.h"
+#include "RaidFileException.h"
+#include "StoreStructure.h"
+#include "BackupStoreFileWire.h"
+#include "ServerControl.h"
+=======
#include "BackupClientCryptoKeys.h"
#include "BackupStoreCheck.h"
#include "BackupStoreConstants.h"
@@ -37,6 +52,7 @@
#include "ServerControl.h"
#include "StoreStructure.h"
#include "ZeroStream.h"
+>>>>>>> 0.12
#include "MemLeakFindOn.h"
@@ -76,6 +92,8 @@ std::map<int32_t, bool> objectIsDir;
::system(BBSTOREACCOUNTS " -c testfiles/bbstored.conf check 01234567"); \
::system(BBSTOREACCOUNTS " -c testfiles/bbstored.conf check 01234567 fix");
+<<<<<<< HEAD
+=======
bool check_fix_internal(int expected_num_errors)
{
BackupStoreCheck checker(storeRoot, discSetNum,
@@ -96,6 +114,7 @@ bool check_fix_internal(int expected_num_errors)
#define RUN_CHECK_INTERNAL(expected_num_errors) \
TEST_THAT(check_fix_internal(expected_num_errors))
+>>>>>>> 0.12
// Get ID of an object given a filename
int32_t getID(const char *name)
{
@@ -173,9 +192,13 @@ void check_dir(BackupStoreDirectory &dir, dir_en_check *ck)
while((en = i.Next()) != 0)
{
+<<<<<<< HEAD
+ TEST_THAT(ck->name != -1);
+=======
BackupStoreFilenameClear clear(en->GetName());
TEST_LINE(ck->name != -1, "Unexpected entry found in "
"directory: " << clear.GetClearFilename());
+>>>>>>> 0.12
if(ck->name == -1)
{
break;
@@ -207,12 +230,18 @@ void check_dir_dep(BackupStoreDirectory &dir, checkdepinfoen *ck)
{
break;
}
+<<<<<<< HEAD
+ TEST_THAT(en->GetObjectID() == ck->id);
+ TEST_THAT(en->GetDependsNewer() == ck->depNewer);
+ TEST_THAT(en->GetDependsOlder() == ck->depOlder);
+=======
TEST_EQUAL_LINE(ck->id, en->GetObjectID(), "Wrong object ID "
"for " << BOX_FORMAT_OBJECTID(ck->id));
TEST_EQUAL_LINE(ck->depNewer, en->GetDependsNewer(),
"Wrong Newer dependency for " << BOX_FORMAT_OBJECTID(ck->id));
TEST_EQUAL_LINE(ck->depOlder, en->GetDependsOlder(),
"Wrong Older dependency for " << BOX_FORMAT_OBJECTID(ck->id));
+>>>>>>> 0.12
++ck;
}
@@ -222,6 +251,13 @@ void check_dir_dep(BackupStoreDirectory &dir, checkdepinfoen *ck)
void test_dir_fixing()
{
+<<<<<<< HEAD
+ {
+ MEMLEAKFINDER_NO_LEAKS;
+ fnames[0].SetAsClearFilename("x1");
+ fnames[1].SetAsClearFilename("x2");
+ fnames[2].SetAsClearFilename("x3");
+=======
// Test that entries pointing to nonexistent entries are removed
{
BackupStoreDirectory dir;
@@ -238,10 +274,17 @@ void test_dir_fixing()
};
check_dir(dir, ck);
+>>>>>>> 0.12
}
{
BackupStoreDirectory dir;
+<<<<<<< HEAD
+ dir.AddEntry(fnames[0], 12, 2 /* id */, 1, BackupStoreDirectory::Entry::Flags_File, 2);
+ dir.AddEntry(fnames[1], 12, 2 /* id */, 1, BackupStoreDirectory::Entry::Flags_File, 2);
+ dir.AddEntry(fnames[0], 12, 3 /* id */, 1, BackupStoreDirectory::Entry::Flags_File, 2);
+ dir.AddEntry(fnames[0], 12, 5 /* id */, 1, BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_OldVersion, 2);
+=======
dir.AddEntry(fnames[0], 12, 2 /* id */, 1,
BackupStoreDirectory::Entry::Flags_File, 2);
dir.AddEntry(fnames[1], 12, 2 /* id */, 1,
@@ -251,6 +294,7 @@ void test_dir_fixing()
dir.AddEntry(fnames[0], 12, 5 /* id */, 1,
BackupStoreDirectory::Entry::Flags_File |
BackupStoreDirectory::Entry::Flags_OldVersion, 2);
+>>>>>>> 0.12
dir_en_check ck[] = {
{1, 2, BackupStoreDirectory::Entry::Flags_File},
@@ -263,7 +307,10 @@ void test_dir_fixing()
TEST_THAT(dir.CheckAndFix() == false);
check_dir(dir, ck);
}
+<<<<<<< HEAD
+=======
+>>>>>>> 0.12
{
BackupStoreDirectory dir;
dir.AddEntry(fnames[0], 12, 2 /* id */, 1, BackupStoreDirectory::Entry::Flags_File, 2);
@@ -287,6 +334,22 @@ void test_dir_fixing()
// Test dependency fixing
{
BackupStoreDirectory dir;
+<<<<<<< HEAD
+ BackupStoreDirectory::Entry *e2
+ = dir.AddEntry(fnames[0], 12, 2 /* id */, 1, BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_OldVersion, 2);
+ TEST_THAT(e2 != 0);
+ e2->SetDependsNewer(3);
+ BackupStoreDirectory::Entry *e3
+ = dir.AddEntry(fnames[0], 12, 3 /* id */, 1, BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_OldVersion, 2);
+ TEST_THAT(e3 != 0);
+ e3->SetDependsNewer(4); e3->SetDependsOlder(2);
+ BackupStoreDirectory::Entry *e4
+ = dir.AddEntry(fnames[0], 12, 4 /* id */, 1, BackupStoreDirectory::Entry::Flags_File | BackupStoreDirectory::Entry::Flags_OldVersion, 2);
+ TEST_THAT(e4 != 0);
+ e4->SetDependsNewer(5); e4->SetDependsOlder(3);
+ BackupStoreDirectory::Entry *e5
+ = dir.AddEntry(fnames[0], 12, 5 /* id */, 1, BackupStoreDirectory::Entry::Flags_File, 2);
+=======
BackupStoreDirectory::Entry *e2 = dir.AddEntry(fnames[0], 12,
2 /* id */, 1,
BackupStoreDirectory::Entry::Flags_File |
@@ -307,6 +370,7 @@ void test_dir_fixing()
e4->SetDependsNewer(5); e4->SetDependsOlder(3);
BackupStoreDirectory::Entry *e5 = dir.AddEntry(fnames[0], 12,
5 /* id */, 1, BackupStoreDirectory::Entry::Flags_File, 2);
+>>>>>>> 0.12
TEST_THAT(e5 != 0);
e5->SetDependsOlder(4);
@@ -336,6 +400,12 @@ void test_dir_fixing()
}
}
+<<<<<<< HEAD
+int test(int argc, const char *argv[])
+{
+ // Test the backupstore directory fixing
+ test_dir_fixing();
+=======
int64_t fake_upload(BackupProtocolLocal& client, const std::string& file_path,
int64_t diff_from_id)
{
@@ -450,11 +520,15 @@ int test(int argc, const char *argv[])
// Test the backupstore directory fixing
// FIXME reenable: test_dir_fixing();
+>>>>>>> 0.12
// Initialise the raidfile controller
RaidFileController &rcontroller = RaidFileController::GetController();
rcontroller.Initialise("testfiles/raidfile.conf");
+<<<<<<< HEAD
+=======
BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys");
+>>>>>>> 0.12
// Create an account
TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
@@ -462,6 +536,320 @@ int test(int argc, const char *argv[])
"create 01234567 0 10000B 20000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+<<<<<<< HEAD
+ // Start the bbstored server
+ int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf",
+ "testfiles/bbstored.pid");
+ TEST_THAT(pid != -1 && pid != 0);
+
+ if(pid > 0)
+ {
+ ::sleep(1);
+ TEST_THAT(ServerIsAlive(pid));
+
+ // Run the perl script to create the initial directories
+ TEST_THAT_ABORTONFAIL(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl init") == 0);
+
+ std::string cmd = BBACKUPD " " + bbackupd_args +
+ " testfiles/bbackupd.conf";
+ int bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
+ TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
+
+ if(bbackupd_pid > 0)
+ {
+ ::safe_sleep(1);
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+
+ // Wait 4 more seconds for the files to be old enough
+ // to upload
+ ::safe_sleep(4);
+
+ // Upload files to create a nice store directory
+ ::sync_and_wait();
+
+ // Stop bbackupd
+ #ifdef WIN32
+ terminate_bbackupd(bbackupd_pid);
+ // implicit check for memory leaks
+ #else
+ TEST_THAT(KillServer(bbackupd_pid));
+ TestRemoteProcessMemLeaks("bbackupd.memleaks");
+ #endif
+ }
+
+ // Generate a list of all the object IDs
+ TEST_THAT_ABORTONFAIL(::system(BBACKUPQUERY " -Wwarning "
+ "-c testfiles/bbackupd.conf \"list -r\" quit "
+ "> testfiles/initial-listing.txt") == 0);
+
+ // And load it in
+ {
+ FILE *f = ::fopen("testfiles/initial-listing.txt", "r");
+ TEST_THAT_ABORTONFAIL(f != 0);
+ char line[512];
+ int32_t id;
+ char flags[32];
+ char name[256];
+ while(::fgets(line, sizeof(line), f) != 0)
+ {
+ TEST_THAT(::sscanf(line, "%x %s %s", &id,
+ flags, name) == 3);
+ bool isDir = (::strcmp(flags, "-d---") == 0);
+ //TRACE3("%x,%d,%s\n", id, isDir, name);
+ MEMLEAKFINDER_NO_LEAKS;
+ nameToID[std::string(name)] = id;
+ objectIsDir[id] = isDir;
+ }
+ ::fclose(f);
+ }
+
+ // ------------------------------------------------------------------------------------------------
+ ::printf(" === Delete store info, add random file\n");
+ {
+ // Delete store info
+ RaidFileWrite del(discSetNum, storeRoot + "info");
+ del.Delete();
+ }
+ {
+ // Add a spurious file
+ RaidFileWrite random(discSetNum,
+ storeRoot + "randomfile");
+ random.Open();
+ random.Write("test", 4);
+ random.Commit(true);
+ }
+
+ // Fix it
+ RUN_CHECK
+
+ // Check everything is as it was
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 0") == 0);
+ // Check the random file doesn't exist
+ {
+ TEST_THAT(!RaidFileRead::FileExists(discSetNum,
+ storeRoot + "01/randomfile"));
+ }
+
+ // ------------------------------------------------------------------------------------------------
+ ::printf(" === Delete an entry for an object from dir, change that object to be a patch, check it's deleted\n");
+ {
+ // Open dir and find entry
+ int64_t delID = getID("Test1/cannes/ict/metegoguered/oats");
+ {
+ BackupStoreDirectory dir;
+ LoadDirectory("Test1/cannes/ict/metegoguered", dir);
+ TEST_THAT(dir.FindEntryByID(delID) != 0);
+ dir.DeleteEntry(delID);
+ SaveDirectory("Test1/cannes/ict/metegoguered", dir);
+ }
+
+ // Adjust that entry
+ //
+ // IMPORTANT NOTE: There's a special hack in testbackupstorefix.pl to make sure that
+ // the file we're modifiying has at least two blocks so we can modify it and produce a valid file
+ // which will pass the verify checks.
+ //
+ std::string fn(getObjectName(delID));
+ {
+ std::auto_ptr<RaidFileRead> file(RaidFileRead::Open(discSetNum, fn));
+ RaidFileWrite f(discSetNum, fn);
+ f.Open(true /* allow overwrite */);
+ // Make a copy of the original
+ file->CopyStreamTo(f);
+ // Move to header in both
+ file->Seek(0, IOStream::SeekType_Absolute);
+ BackupStoreFile::MoveStreamPositionToBlockIndex(*file);
+ f.Seek(file->GetPosition(), IOStream::SeekType_Absolute);
+ // Read header
+ struct
+ {
+ file_BlockIndexHeader hdr;
+ file_BlockIndexEntry e[2];
+ } h;
+ TEST_THAT(file->Read(&h, sizeof(h)) == sizeof(h));
+ file->Close();
+
+ // Modify
+ TEST_THAT(box_ntoh64(h.hdr.mOtherFileID) == 0);
+ TEST_THAT(box_ntoh64(h.hdr.mNumBlocks) >= 2);
+ h.hdr.mOtherFileID = box_hton64(2345); // don't worry about endianness
+ h.e[0].mEncodedSize = box_hton64((box_ntoh64(h.e[0].mEncodedSize)) + (box_ntoh64(h.e[1].mEncodedSize)));
+ h.e[1].mOtherBlockIndex = box_hton64(static_cast<uint64_t>(-2));
+ // Write to modified file
+ f.Write(&h, sizeof(h));
+ // Commit new version
+ f.Commit(true /* write now! */);
+ }
+
+ // Fix it
+ RUN_CHECK
+ // Check
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 1")
+ == 0);
+
+ // Check the modified file doesn't exist
+ TEST_THAT(!RaidFileRead::FileExists(discSetNum, fn));
+ }
+
+ // ------------------------------------------------------------------------------------------------
+ ::printf(" === Delete directory, change container ID of another, duplicate entry in dir, spurious file size, delete file\n");
+ {
+ BackupStoreDirectory dir;
+ LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
+ dir.SetContainerID(73773);
+ SaveDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
+ }
+ int64_t duplicatedID = 0;
+ int64_t notSpuriousFileSize = 0;
+ {
+ BackupStoreDirectory dir;
+ LoadDirectory("Test1/cannes/ict/peep", dir);
+ // Duplicate the second entry
+ {
+ BackupStoreDirectory::Iterator i(dir);
+ i.Next();
+ BackupStoreDirectory::Entry *en = i.Next();
+ TEST_THAT(en != 0);
+ duplicatedID = en->GetObjectID();
+ dir.AddEntry(*en);
+ }
+ // Adjust file size of first file
+ {
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File);
+ TEST_THAT(en != 0);
+ notSpuriousFileSize = en->GetSizeInBlocks();
+ en->SetSizeInBlocks(3473874);
+ TEST_THAT(en->GetSizeInBlocks() == 3473874);
+ }
+ SaveDirectory("Test1/cannes/ict/peep", dir);
+ }
+ // Delete a directory
+ DeleteObject("Test1/pass/cacted/ming");
+ // Delete a file
+ DeleteObject("Test1/cannes/ict/scely");
+ // Fix it
+ RUN_CHECK
+ // Check everything is as it should be
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 2") == 0);
+ {
+ BackupStoreDirectory dir;
+ LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
+ TEST_THAT(dir.GetContainerID() == getID("Test1/foreomizes/stemptinevidate"));
+ }
+ {
+ BackupStoreDirectory dir;
+ LoadDirectory("Test1/cannes/ict/peep", dir);
+ BackupStoreDirectory::Iterator i(dir);
+ // Count the number of entries with the ID which was duplicated
+ int count = 0;
+ BackupStoreDirectory::Entry *en = 0;
+ while((en = i.Next()) != 0)
+ {
+ if(en->GetObjectID() == duplicatedID)
+ {
+ ++count;
+ }
+ }
+ TEST_THAT(count == 1);
+ // Check file size has changed
+ {
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File);
+ TEST_THAT(en != 0);
+ TEST_THAT(en->GetSizeInBlocks() == notSpuriousFileSize);
+ }
+ }
+
+ // ------------------------------------------------------------------------------------------------
+ ::printf(" === Modify the obj ID of dir, delete dir with no members, add extra reference to a file\n");
+ // Set bad object ID
+ {
+ BackupStoreDirectory dir;
+ LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
+ dir.TESTONLY_SetObjectID(73773);
+ SaveDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
+ }
+ // Delete dir with no members
+ DeleteObject("Test1/dir-no-members");
+ // Add extra reference
+ {
+ BackupStoreDirectory dir;
+ LoadDirectory("Test1/divel", dir);
+ BackupStoreDirectory::Iterator i(dir);
+ BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File);
+ TEST_THAT(en != 0);
+ BackupStoreDirectory dir2;
+ LoadDirectory("Test1/divel/torsines/cruishery", dir2);
+ dir2.AddEntry(*en);
+ SaveDirectory("Test1/divel/torsines/cruishery", dir2);
+ }
+ // Fix it
+ RUN_CHECK
+ // Check everything is as it should be
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 3") == 0);
+ {
+ BackupStoreDirectory dir;
+ LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
+ TEST_THAT(dir.GetObjectID() == getID("Test1/foreomizes/stemptinevidate/ict"));
+ }
+
+ // ------------------------------------------------------------------------------------------------
+ ::printf(" === Orphan files and dirs without being recoverable\n");
+ DeleteObject("Test1/dir1");
+ DeleteObject("Test1/dir1/dir2");
+ // Fix it
+ RUN_CHECK
+ // Check everything is where it is predicted to be
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 4") == 0);
+
+ // ------------------------------------------------------------------------------------------------
+ ::printf(" === Corrupt file and dir\n");
+ // File
+ CorruptObject("Test1/foreomizes/stemptinevidate/algoughtnerge",
+ 33, "34i729834298349283479233472983sdfhasgs");
+ // Dir
+ CorruptObject("Test1/cannes/imulatrougge/foreomizes",23,
+ "dsf32489sdnadf897fd2hjkesdfmnbsdfcsfoisufio2iofe2hdfkjhsf");
+ // Fix it
+ RUN_CHECK
+ // Check everything is where it should be
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 5") == 0);
+
+ // ------------------------------------------------------------------------------------------------
+ ::printf(" === Overwrite root with a file\n");
+ {
+ std::auto_ptr<RaidFileRead> r(RaidFileRead::Open(discSetNum, getObjectName(getID("Test1/pass/shuted/brightinats/milamptimaskates"))));
+ RaidFileWrite w(discSetNum, getObjectName(1 /* root */));
+ w.Open(true /* allow overwrite */);
+ r->CopyStreamTo(w);
+ w.Commit(true /* convert now */);
+ }
+ // Fix it
+ RUN_CHECK
+ // Check everything is where it should be
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl reroot 6") == 0);
+
+
+ // ---------------------------------------------------------
+ // Stop server
+ TEST_THAT(KillServer(pid));
+
+ #ifdef WIN32
+ TEST_THAT(unlink("testfiles/bbstored.pid") == 0);
+ #else
+ TestRemoteProcessMemLeaks("bbstored.memleaks");
+ #endif
+ }
+=======
// Run the perl script to create the initial directories
TEST_THAT_ABORTONFAIL(::system(PERL_EXECUTABLE
" testfiles/testbackupstorefix.pl init") == 0);
@@ -965,6 +1353,7 @@ int test(int argc, const char *argv[])
#else
TestRemoteProcessMemLeaks("bbstored.memleaks");
#endif
+>>>>>>> 0.12
return 0;
}
diff --git a/test/backupstorefix/testfiles/testbackupstorefix.pl.in b/test/backupstorefix/testfiles/testbackupstorefix.pl.in
index 28dc439f..b58414af 100755
--- a/test/backupstorefix/testfiles/testbackupstorefix.pl.in
+++ b/test/backupstorefix/testfiles/testbackupstorefix.pl.in
@@ -104,7 +104,11 @@ elsif($ARGV[0] eq 'check')
{
print LISTING_COPY;
chomp; s/\r//;
+<<<<<<< HEAD
+ s/\[FILENAME NOT ENCRYPTED\]//;
+=======
s/ \[FILENAME NOT ENCRYPTED\]//;
+>>>>>>> 0.12
if(exists $expected{$_})
{
delete $expected{$_}
diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp
index fab56523..fe0e0531 100644
--- a/test/backupstorepatch/testbackupstorepatch.cpp
+++ b/test/backupstorepatch/testbackupstorepatch.cpp
@@ -13,7 +13,11 @@
#include <string.h>
#include <signal.h>
+<<<<<<< HEAD
+#include "autogen_BackupProtocolClient.h"
+=======
#include "autogen_BackupProtocol.h"
+>>>>>>> 0.12
#include "BackupClientCryptoKeys.h"
#include "BackupClientFileAttributes.h"
#include "BackupStoreAccountDatabase.h"
@@ -354,7 +358,11 @@ int test(int argc, const char *argv[])
// Login
{
// Check the version
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+=======
std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+>>>>>>> 0.12
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
// Login
@@ -367,9 +375,15 @@ int test(int argc, const char *argv[])
// Upload the first file
{
std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/0.test",
+<<<<<<< HEAD
+ BackupProtocolClientListDirectory::RootDirectory, storeFilename));
+ std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
+ BackupProtocolClientListDirectory::RootDirectory, ModificationTime,
+=======
BackupProtocolListDirectory::RootDirectory, storeFilename));
std::auto_ptr<BackupProtocolSuccess> stored(protocol.QueryStoreFile(
BackupProtocolListDirectory::RootDirectory, ModificationTime,
+>>>>>>> 0.12
ModificationTime, 0 /* no diff from file ID */, storeFilename, *upload));
test_files[0].IDOnServer = stored->GetObjectID();
test_files[0].IsCompletelyDifferent = true;
@@ -380,8 +394,13 @@ int test(int argc, const char *argv[])
for(unsigned int f = 1; f < NUMBER_FILES; ++f)
{
// Get an index for the previous version
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getBlockIndex(protocol.QueryGetBlockIndexByName(
+ BackupProtocolClientListDirectory::RootDirectory, storeFilename));
+=======
std::auto_ptr<BackupProtocolSuccess> getBlockIndex(protocol.QueryGetBlockIndexByName(
BackupProtocolListDirectory::RootDirectory, storeFilename));
+>>>>>>> 0.12
int64_t diffFromID = getBlockIndex->GetObjectID();
TEST_THAT(diffFromID != 0);
@@ -397,7 +416,11 @@ int test(int argc, const char *argv[])
std::auto_ptr<IOStream> patchStream(
BackupStoreFile::EncodeFileDiff(
filename,
+<<<<<<< HEAD
+ BackupProtocolClientListDirectory::RootDirectory, /* containing directory */
+=======
BackupProtocolListDirectory::RootDirectory, /* containing directory */
+>>>>>>> 0.12
storeFilename,
diffFromID,
*blockIndexStream,
@@ -407,8 +430,13 @@ int test(int argc, const char *argv[])
&isCompletelyDifferent));
// Upload the patch to the store
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(
+ BackupProtocolClientListDirectory::RootDirectory, ModificationTime,
+=======
std::auto_ptr<BackupProtocolSuccess> stored(protocol.QueryStoreFile(
BackupProtocolListDirectory::RootDirectory, ModificationTime,
+>>>>>>> 0.12
ModificationTime, isCompletelyDifferent?(0):(diffFromID), storeFilename, *patchStream));
ModificationTime += MODIFICATION_TIME_INC;
@@ -432,10 +460,17 @@ int test(int argc, const char *argv[])
// List the directory from the server, and check that no dependency info is sent -- waste of bytes
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(protocol.QueryListDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+=======
std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
BackupProtocolListDirectory::RootDirectory,
BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
+>>>>>>> 0.12
// Stream
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
@@ -531,7 +566,11 @@ int test(int argc, const char *argv[])
BOX_PORT_BBSTORED_TEST);
BackupProtocolClient protocol(conn);
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+=======
std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
+>>>>>>> 0.12
TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
protocol.QueryLogin(0x01234567, 0);
}
@@ -555,8 +594,13 @@ int test(int argc, const char *argv[])
// Fetch the file
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getobj(protocol.QueryGetFile(
+ BackupProtocolClientListDirectory::RootDirectory,
+=======
std::auto_ptr<BackupProtocolSuccess> getobj(protocol.QueryGetFile(
BackupProtocolListDirectory::RootDirectory,
+>>>>>>> 0.12
test_files[f].IDOnServer));
TEST_THAT(getobj->GetObjectID() == test_files[f].IDOnServer);
// BLOCK
@@ -572,7 +616,11 @@ int test(int argc, const char *argv[])
// Download the index, and check it looks OK
{
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientSuccess> getblockindex(protocol.QueryGetBlockIndexByID(test_files[f].IDOnServer));
+=======
std::auto_ptr<BackupProtocolSuccess> getblockindex(protocol.QueryGetBlockIndexByID(test_files[f].IDOnServer));
+>>>>>>> 0.12
TEST_THAT(getblockindex->GetObjectID() == test_files[f].IDOnServer);
std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
TEST_THAT(BackupStoreFile::CompareFileContentsAgainstBlockIndex(filename, *blockIndexStream, IOStream::TimeOutInfinite));
diff --git a/test/basicserver/Makefile.extra b/test/basicserver/Makefile.extra
index e6a4675e..cfafbdb2 100644
--- a/test/basicserver/Makefile.extra
+++ b/test/basicserver/Makefile.extra
@@ -1,6 +1,25 @@
MAKEPROTOCOL = ../../lib/server/makeprotocol.pl
+<<<<<<< HEAD
+GEN_CMD_SRV = $(MAKEPROTOCOL) Server testprotocol.txt
+GEN_CMD_CLI = $(MAKEPROTOCOL) Client testprotocol.txt
+
+# AUTOGEN SEEDING
+autogen_TestProtocolServer.cpp: $(MAKEPROTOCOL) testprotocol.txt
+ $(_PERL) $(GEN_CMD_SRV)
+
+autogen_TestProtocolServer.h: $(MAKEPROTOCOL) testprotocol.txt
+ $(_PERL) $(GEN_CMD_SRV)
+
+
+# AUTOGEN SEEDING
+autogen_TestProtocolClient.cpp: $(MAKEPROTOCOL) testprotocol.txt
+ $(_PERL) $(GEN_CMD_CLI)
+
+autogen_TestProtocolClient.h: $(MAKEPROTOCOL) testprotocol.txt
+ $(_PERL) $(GEN_CMD_CLI)
+=======
GEN_CMD = $(MAKEPROTOCOL) testprotocol.txt
# AUTOGEN SEEDING
@@ -9,4 +28,5 @@ autogen_TestProtocol.cpp: $(MAKEPROTOCOL) testprotocol.txt
autogen_TestProtocolServer.h: $(MAKEPROTOCOL) testprotocol.txt
$(_PERL) $(GEN_CMD)
+>>>>>>> 0.12
diff --git a/test/basicserver/TestCommands.cpp b/test/basicserver/TestCommands.cpp
index 5238819f..e193458e 100644
--- a/test/basicserver/TestCommands.cpp
+++ b/test/basicserver/TestCommands.cpp
@@ -5,12 +5,40 @@
#include <syslog.h>
#endif
+<<<<<<< HEAD
+#include "autogen_TestProtocolServer.h"
+=======
#include "autogen_TestProtocol.h"
+>>>>>>> 0.12
#include "CollectInBufferStream.h"
#include "MemLeakFindOn.h"
+<<<<<<< HEAD
+std::auto_ptr<ProtocolObject> TestProtocolServerHello::DoCommand(TestProtocolServer &rProtocol, TestContext &rContext)
+{
+ if(mNumber32 != 41 || mNumber16 != 87 || mNumber8 != 11 || mText != "pingu")
+ {
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerError(0, 0));
+ }
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerHello(12,89,22,std::string("Hello world!")));
+}
+
+std::auto_ptr<ProtocolObject> TestProtocolServerLists::DoCommand(TestProtocolServer &rProtocol, TestContext &rContext)
+{
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerListsReply(mLotsOfText.size()));
+}
+
+std::auto_ptr<ProtocolObject> TestProtocolServerQuit::DoCommand(TestProtocolServer &rProtocol, TestContext &rContext)
+{
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerQuit);
+}
+
+std::auto_ptr<ProtocolObject> TestProtocolServerSimple::DoCommand(TestProtocolServer &rProtocol, TestContext &rContext)
+{
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerSimpleReply(mValue+1));
+=======
std::auto_ptr<TestProtocolMessage> TestProtocolHello::DoCommand(TestProtocolReplyable &rProtocol, TestContext &rContext) const
{
if(mNumber32 != 41 || mNumber16 != 87 || mNumber8 != 11 || mText != "pingu")
@@ -33,6 +61,7 @@ std::auto_ptr<TestProtocolMessage> TestProtocolQuit::DoCommand(TestProtocolReply
std::auto_ptr<TestProtocolMessage> TestProtocolSimple::DoCommand(TestProtocolReplyable &rProtocol, TestContext &rContext) const
{
return std::auto_ptr<TestProtocolMessage>(new TestProtocolSimpleReply(mValue+1));
+>>>>>>> 0.12
}
class UncertainBufferStream : public CollectInBufferStream
@@ -45,7 +74,11 @@ public:
}
};
+<<<<<<< HEAD
+std::auto_ptr<ProtocolObject> TestProtocolServerGetStream::DoCommand(TestProtocolServer &rProtocol, TestContext &rContext)
+=======
std::auto_ptr<TestProtocolMessage> TestProtocolGetStream::DoCommand(TestProtocolReplyable &rProtocol, TestContext &rContext) const
+>>>>>>> 0.12
{
// make a new stream object
CollectInBufferStream *pstream = mUncertainSize?(new UncertainBufferStream):(new CollectInBufferStream);
@@ -68,6 +101,16 @@ std::auto_ptr<TestProtocolMessage> TestProtocolGetStream::DoCommand(TestProtocol
// Get it to be sent
rProtocol.SendStreamAfterCommand(pstream);
+<<<<<<< HEAD
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerGetStream(mStartingValue, mUncertainSize));
+}
+
+std::auto_ptr<ProtocolObject> TestProtocolServerSendStream::DoCommand(TestProtocolServer &rProtocol, TestContext &rContext)
+{
+ if(mValue != 0x73654353298ffLL)
+ {
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerError(0, 0));
+=======
return std::auto_ptr<TestProtocolMessage>(new TestProtocolGetStream(mStartingValue, mUncertainSize));
}
@@ -76,6 +119,7 @@ std::auto_ptr<TestProtocolMessage> TestProtocolSendStream::DoCommand(TestProtoco
if(mValue != 0x73654353298ffLL)
{
return std::auto_ptr<TestProtocolMessage>(new TestProtocolError(0, 0));
+>>>>>>> 0.12
}
// Get a stream
@@ -91,11 +135,20 @@ std::auto_ptr<TestProtocolMessage> TestProtocolSendStream::DoCommand(TestProtoco
}
// tell the caller how many bytes there were
+<<<<<<< HEAD
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerGetStream(bytes, uncertain));
+}
+
+std::auto_ptr<ProtocolObject> TestProtocolServerString::DoCommand(TestProtocolServer &rProtocol, TestContext &rContext)
+{
+ return std::auto_ptr<ProtocolObject>(new TestProtocolServerString(mTest));
+=======
return std::auto_ptr<TestProtocolMessage>(new TestProtocolGetStream(bytes, uncertain));
}
std::auto_ptr<TestProtocolMessage> TestProtocolString::DoCommand(TestProtocolReplyable &rProtocol, TestContext &rContext) const
{
return std::auto_ptr<TestProtocolMessage>(new TestProtocolString(mTest));
+>>>>>>> 0.12
}
diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp
index 976bdd92..ebf77979 100644
--- a/test/basicserver/testbasicserver.cpp
+++ b/test/basicserver/testbasicserver.cpp
@@ -26,7 +26,12 @@
#include "CollectInBufferStream.h"
#include "TestContext.h"
+<<<<<<< HEAD
+#include "autogen_TestProtocolClient.h"
+#include "autogen_TestProtocolServer.h"
+=======
#include "autogen_TestProtocol.h"
+>>>>>>> 0.12
#include "ServerControl.h"
#include "MemLeakFindOn.h"
@@ -330,8 +335,13 @@ void Srv2TestConversations(const std::vector<IOStream *> &conns)
bool hadTimeout = false;
while(!getline[c]->GetLine(rep, false, COMMS_READ_TIMEOUT))
hadTimeout = true;
+<<<<<<< HEAD
+ TEST_THAT(rep == recieve[q]);
+ TEST_THAT(hadTimeout)
+=======
TEST_EQUAL_LINE(rep, recieve[q], "Line " << q);
TEST_LINE(hadTimeout, "Line " << q)
+>>>>>>> 0.12
}
}
for(unsigned int c = 0; c < conns.size(); ++c)
@@ -392,7 +402,11 @@ void Srv2TestConversations(const std::vector<IOStream *> &conns)
void TestStreamReceive(TestProtocolClient &protocol, int value, bool uncertainstream)
{
+<<<<<<< HEAD
+ std::auto_ptr<TestProtocolClientGetStream> reply(protocol.QueryGetStream(value, uncertainstream));
+=======
std::auto_ptr<TestProtocolGetStream> reply(protocol.QueryGetStream(value, uncertainstream));
+>>>>>>> 0.12
TEST_THAT(reply->GetStartingValue() == value);
// Get a stream
@@ -703,11 +717,19 @@ int test(int argc, const char *argv[])
// Simple query
{
+<<<<<<< HEAD
+ std::auto_ptr<TestProtocolClientSimpleReply> reply(protocol.QuerySimple(41));
+ TEST_THAT(reply->GetValuePlusOne() == 42);
+ }
+ {
+ std::auto_ptr<TestProtocolClientSimpleReply> reply(protocol.QuerySimple(809));
+=======
std::auto_ptr<TestProtocolSimpleReply> reply(protocol.QuerySimple(41));
TEST_THAT(reply->GetValuePlusOne() == 42);
}
{
std::auto_ptr<TestProtocolSimpleReply> reply(protocol.QuerySimple(809));
+>>>>>>> 0.12
TEST_THAT(reply->GetValuePlusOne() == 810);
}
@@ -723,14 +745,22 @@ int test(int argc, const char *argv[])
char buf[1663];
s.Write(buf, sizeof(buf));
s.SetForReading();
+<<<<<<< HEAD
+ std::auto_ptr<TestProtocolClientGetStream> reply(protocol.QuerySendStream(0x73654353298ffLL, s));
+=======
std::auto_ptr<TestProtocolGetStream> reply(protocol.QuerySendStream(0x73654353298ffLL, s));
+>>>>>>> 0.12
TEST_THAT(reply->GetStartingValue() == sizeof(buf));
}
// Lots of simple queries
for(int q = 0; q < 514; q++)
{
+<<<<<<< HEAD
+ std::auto_ptr<TestProtocolClientSimpleReply> reply(protocol.QuerySimple(q));
+=======
std::auto_ptr<TestProtocolSimpleReply> reply(protocol.QuerySimple(q));
+>>>>>>> 0.12
TEST_THAT(reply->GetValuePlusOne() == (q+1));
}
// Send a list of strings to it
@@ -739,13 +769,21 @@ int test(int argc, const char *argv[])
strings.push_back(std::string("test1"));
strings.push_back(std::string("test2"));
strings.push_back(std::string("test3"));
+<<<<<<< HEAD
+ std::auto_ptr<TestProtocolClientListsReply> reply(protocol.QueryLists(strings));
+=======
std::auto_ptr<TestProtocolListsReply> reply(protocol.QueryLists(strings));
+>>>>>>> 0.12
TEST_THAT(reply->GetNumberOfStrings() == 3);
}
// And another
{
+<<<<<<< HEAD
+ std::auto_ptr<TestProtocolClientHello> reply(protocol.QueryHello(41,87,11,std::string("pingu")));
+=======
std::auto_ptr<TestProtocolHello> reply(protocol.QueryHello(41,87,11,std::string("pingu")));
+>>>>>>> 0.12
TEST_THAT(reply->GetNumber32() == 12);
TEST_THAT(reply->GetNumber16() == 89);
TEST_THAT(reply->GetNumber8() == 22);
diff --git a/test/bbackupd/Makefile.extra b/test/bbackupd/Makefile.extra
index 705345a9..1bd897bd 100644
--- a/test/bbackupd/Makefile.extra
+++ b/test/bbackupd/Makefile.extra
@@ -6,6 +6,14 @@ link-extra: ../../bin/bbackupd/autogen_ClientException.o \
../../bin/bbackupd/BackupClientInodeToIDMap.o \
../../bin/bbackupd/Win32ServiceFunctions.o \
../../bin/bbackupd/BackupDaemon.o \
+<<<<<<< HEAD
+ ../../bin/bbstored/BackupStoreContext.o \
+ ../../bin/bbstored/BBStoreDHousekeeping.o \
+ ../../bin/bbstored/HousekeepStoreAccount.o \
+ ../../bin/bbstored/autogen_BackupProtocolServer.o \
+ ../../bin/bbstored/BackupCommands.o \
+ ../../bin/bbstored/BackupStoreDaemon.o
+=======
../../bin/bbstored/BBStoreDHousekeeping.o \
../../lib/backupstore/HousekeepStoreAccount.o \
../../lib/backupstore/autogen_BackupProtocol.o \
@@ -14,3 +22,4 @@ link-extra: ../../bin/bbackupd/autogen_ClientException.o \
../../bin/bbstored/BackupStoreDaemon.o \
../../bin/bbackupquery/BackupQueries.o \
../../bin/bbackupquery/autogen_Documentation.o
+>>>>>>> 0.12
diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp
index 6cd8f27d..71778ca6 100644
--- a/test/bbackupd/testbbackupd.cpp
+++ b/test/bbackupd/testbbackupd.cpp
@@ -42,20 +42,30 @@
#include <sys/syscall.h>
#endif
+<<<<<<< HEAD
+#include "autogen_BackupProtocolServer.h"
+=======
#include "autogen_BackupProtocol.h"
+>>>>>>> 0.12
#include "BackupClientCryptoKeys.h"
#include "BackupClientFileAttributes.h"
#include "BackupClientRestore.h"
#include "BackupDaemon.h"
#include "BackupDaemonConfigVerify.h"
#include "BackupQueries.h"
+<<<<<<< HEAD
+=======
#include "BackupStoreAccounts.h"
+>>>>>>> 0.12
#include "BackupStoreConstants.h"
#include "BackupStoreContext.h"
#include "BackupStoreDaemon.h"
#include "BackupStoreDirectory.h"
#include "BackupStoreException.h"
+<<<<<<< HEAD
+=======
#include "BackupStoreConfigVerify.h"
+>>>>>>> 0.12
#include "BoxPortsAndFiles.h"
#include "BoxTime.h"
#include "BoxTimeToUnix.h"
@@ -64,10 +74,15 @@
#include "Configuration.h"
#include "FileModificationTime.h"
#include "FileStream.h"
+<<<<<<< HEAD
+#include "IOStreamGetLine.h"
+#include "LocalProcessStream.h"
+=======
#include "intercept.h"
#include "IOStreamGetLine.h"
#include "LocalProcessStream.h"
#include "RaidFileController.h"
+>>>>>>> 0.12
#include "SSLLib.h"
#include "ServerControl.h"
#include "Socket.h"
@@ -77,6 +92,13 @@
#include "Timer.h"
#include "Utils.h"
+<<<<<<< HEAD
+#include "autogen_BackupProtocolClient.h"
+#include "intercept.h"
+#include "ServerControl.h"
+
+=======
+>>>>>>> 0.12
#include "MemLeakFindOn.h"
// ENOATTR may be defined in a separate header file which we may not have
@@ -475,8 +497,13 @@ int64_t GetDirID(BackupProtocolClient &protocol, const char *name, int64_t InDir
{
protocol.QueryListDirectory(
InDirectory,
+<<<<<<< HEAD
+ BackupProtocolClientListDirectory::Flags_Dir,
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING,
+=======
BackupProtocolListDirectory::Flags_Dir,
BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
+>>>>>>> 0.12
true /* want attributes */);
// Retrieve the directory from the stream following
@@ -518,6 +545,15 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid)
22011);
BackupProtocolClient protocol(conn);
protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION);
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly));
+
+ // Test the restoration
+ TEST_THAT(BackupClientRestore(protocol, restoredirid,
+ "Test1", "testfiles/restore-interrupt",
+ true /* print progress dots */)
+ == Restore_Complete);
+=======
std::auto_ptr<BackupProtocolLoginConfirmed>
loginConf(protocol.QueryLogin(0x01234567,
BackupProtocolLogin::Flags_ReadOnly));
@@ -531,6 +567,7 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid)
false /* undelete after */,
false /* resume */,
false /* keep going */) == Restore_Complete);
+>>>>>>> 0.12
// Log out
protocol.QueryFinished();
@@ -608,7 +645,11 @@ int64_t SearchDir(BackupStoreDirectory& rDir,
if (en == 0) return 0;
int64_t id = en->GetObjectID();
TEST_THAT(id > 0);
+<<<<<<< HEAD
+ TEST_THAT(id != BackupProtocolClientListDirectory::RootDirectory);
+=======
TEST_THAT(id != BackupProtocolListDirectory::RootDirectory);
+>>>>>>> 0.12
return id;
}
@@ -621,7 +662,11 @@ std::auto_ptr<BackupProtocolClient> Connect(TLSContext& rContext)
std::auto_ptr<BackupProtocolClient> connection;
connection.reset(new BackupProtocolClient(sSocket));
connection->Handshake();
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientVersion>
+=======
std::auto_ptr<BackupProtocolVersion>
+>>>>>>> 0.12
serverVersion(connection->QueryVersion(
BACKUP_STORE_SERVER_VERSION));
if(serverVersion->GetVersion() !=
@@ -644,10 +689,17 @@ std::auto_ptr<BackupProtocolClient> ConnectAndLogin(TLSContext& rContext,
std::auto_ptr<BackupStoreDirectory> ReadDirectory
(
BackupProtocolClient& rClient,
+<<<<<<< HEAD
+ int64_t id
+)
+{
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(
+=======
int64_t id = BackupProtocolListDirectory::RootDirectory
)
{
std::auto_ptr<BackupProtocolSuccess> dirreply(
+>>>>>>> 0.12
rClient.QueryListDirectory(id, false, 0, false));
std::auto_ptr<IOStream> dirstream(rClient.ReceiveStream());
std::auto_ptr<BackupStoreDirectory> apDir(new BackupStoreDirectory());
@@ -655,8 +707,11 @@ std::auto_ptr<BackupStoreDirectory> ReadDirectory
return apDir;
}
+<<<<<<< HEAD
+=======
Daemon* spDaemon = NULL;
+>>>>>>> 0.12
int start_internal_daemon()
{
// ensure that no child processes end up running tests!
@@ -670,7 +725,10 @@ int start_internal_daemon()
};
BackupDaemon daemon;
+<<<<<<< HEAD
+=======
spDaemon = &daemon; // to propagate into child
+>>>>>>> 0.12
int result;
if (bbackupd_args.size() > 0)
@@ -681,8 +739,11 @@ int start_internal_daemon()
{
result = daemon.Main("testfiles/bbackupd.conf", 1, argv);
}
+<<<<<<< HEAD
+=======
spDaemon = NULL; // to ensure not used by parent
+>>>>>>> 0.12
TEST_EQUAL_LINE(0, result, "Daemon exit code");
@@ -720,7 +781,10 @@ int start_internal_daemon()
fflush(stdout);
TEST_THAT(pid > 0);
+<<<<<<< HEAD
+=======
spDaemon = &daemon;
+>>>>>>> 0.12
return pid;
}
@@ -761,6 +825,16 @@ extern "C" struct dirent *readdir_test_hook_1(DIR *dir)
extern "C" struct dirent *readdir_test_hook_2(DIR *dir)
{
+<<<<<<< HEAD
+ if (time(NULL) >= readdir_stop_time)
+ {
+#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ intercept_setup_readdir_hook(NULL, NULL);
+ intercept_setup_lstat_hook (NULL, NULL);
+ // we will not be called again.
+#endif
+ }
+=======
if (spDaemon->IsTerminateWanted())
{
// force daemon to crash, right now
@@ -785,6 +859,7 @@ extern "C" struct dirent *readdir_test_hook_2(DIR *dir)
BOX_TRACE("readdir hook still active at " << time_now << ", "
"waiting for " << readdir_stop_time);
}
+>>>>>>> 0.12
// fill in the struct dirent appropriately
memset(&readdir_test_dirent, 0, sizeof(readdir_test_dirent));
@@ -796,7 +871,10 @@ extern "C" struct dirent *readdir_test_hook_2(DIR *dir)
snprintf(readdir_test_dirent.d_name,
sizeof(readdir_test_dirent.d_name),
"test.%d", readdir_test_counter);
+<<<<<<< HEAD
+=======
BOX_TRACE("readdir hook returning " << readdir_test_dirent.d_name);
+>>>>>>> 0.12
// ensure that when bbackupd stats the file, it gets the
// right answer
@@ -808,9 +886,12 @@ extern "C" struct dirent *readdir_test_hook_2(DIR *dir)
intercept_setup_lstat_hook(stat_hook_filename, lstat_test_hook);
#endif
+<<<<<<< HEAD
+=======
// sleep a bit to reduce the number of dirents returned
::safe_sleep(1);
+>>>>>>> 0.12
return &readdir_test_dirent;
}
@@ -854,6 +935,8 @@ bool test_entry_deleted(BackupStoreDirectory& rDir,
return flags && BackupStoreDirectory::Entry::Flags_Deleted;
}
+<<<<<<< HEAD
+=======
bool compare_all(BackupQueries::ReturnCode::Type expected_status,
std::string config_file = "testfiles/bbackupd.conf")
{
@@ -881,6 +964,7 @@ bool compare_all(BackupQueries::ReturnCode::Type expected_status,
#define TEST_COMPARE(...) \
TEST_THAT(compare_all(BackupQueries::ReturnCode::__VA_ARGS__));
+>>>>>>> 0.12
int test_bbackupd()
{
// First, wait for a normal period to make sure the last changes
@@ -1023,11 +1107,21 @@ int test_bbackupd()
comp2.size() + 1, comp2.size());
TEST_LINE(comp2 != sub, line);
}
+<<<<<<< HEAD
+
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ Timers::Init();
+ return 1;
+ }
+=======
Timers::Init();
// stop early to make debugging easier
if (failures) return 1;
+>>>>>>> 0.12
// four-second delay on first read() of f1
// should mean that no keepalives were sent,
@@ -1035,6 +1129,25 @@ int test_bbackupd()
// before any matching blocks could be found.
intercept_setup_delay("testfiles/TestDir1/spacetest/f1",
0, 4000, SYS_read, 1);
+<<<<<<< HEAD
+ pid = start_internal_daemon();
+ intercept_clear_setup();
+
+ fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_EQUAL_LINE(sizeof(buffer),
+ write(fd, buffer, sizeof(buffer)),
+ "Buffer write");
+ TEST_THAT(close(fd) == 0);
+
+ wait_for_backup_operation("internal daemon to sync "
+ "spacetest/f1 again");
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ TEST_THAT(stop_internal_daemon(pid));
+=======
{
BackupDaemon bbackupd;
@@ -1056,6 +1169,7 @@ int test_bbackupd()
intercept_clear_setup();
Timers::Cleanup();
}
+>>>>>>> 0.12
// check that the diff was aborted, i.e. upload was not a diff
found1 = false;
@@ -1179,9 +1293,12 @@ int test_bbackupd()
TEST_LINE(comp2 != sub, line);
}
+<<<<<<< HEAD
+=======
// Check that no read error has been reported yet
TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
+>>>>>>> 0.12
if (failures > 0)
{
// stop early to make debugging easier
@@ -1201,7 +1318,11 @@ int test_bbackupd()
std::string touchfile =
"testfiles/TestDir1/spacetest/d1/touch-me";
+<<<<<<< HEAD
+ fd = open(touchfile.c_str(), O_CREAT | O_WRONLY);
+=======
fd = open(touchfile.c_str(), O_CREAT | O_WRONLY, 0700);
+>>>>>>> 0.12
TEST_THAT(fd > 0);
// write again, to update the file's timestamp
TEST_EQUAL_LINE(sizeof(buffer),
@@ -1293,7 +1414,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
if(bbackupd_pid > 0)
{
@@ -1362,7 +1486,17 @@ int test_bbackupd()
BOX_TRACE("Sync finished.");
BOX_TRACE("Compare to check that there are differences");
+<<<<<<< HEAD
+ int compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query0a.log "
+ "-Werror \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
BOX_TRACE("Compare finished.");
// Check that the notify script was run
@@ -1384,7 +1518,11 @@ int test_bbackupd()
std::auto_ptr<BackupProtocolClient> client =
ConnectAndLogin(context, 0 /* read-write */);
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientAccountUsage> usage(
+=======
std::auto_ptr<BackupProtocolAccountUsage> usage(
+>>>>>>> 0.12
client->QueryGetAccountUsage());
TEST_EQUAL_LINE(24, usage->GetBlocksUsed(),
"blocks used");
@@ -1397,7 +1535,15 @@ int test_bbackupd()
sSocket.Close();
}
+<<<<<<< HEAD
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ return 1;
+ }
+=======
if (failures) return 1;
+>>>>>>> 0.12
// ensure time is different to refresh the cache
::safe_sleep(1);
@@ -1420,6 +1566,8 @@ int test_bbackupd()
*/
BackupDaemon bbackupd;
+<<<<<<< HEAD
+=======
{
const char* argv[] = { "bbackupd",
@@ -1428,6 +1576,7 @@ int test_bbackupd()
"processing command-line options");
}
+>>>>>>> 0.12
bbackupd.Configure("testfiles/bbackupd-exclude.conf");
bbackupd.InitCrypto();
BOX_TRACE("done.");
@@ -1471,7 +1620,12 @@ int test_bbackupd()
ConnectAndLogin(context, 0 /* read-write */);
std::auto_ptr<BackupStoreDirectory> rootDir =
+<<<<<<< HEAD
+ ReadDirectory(*client,
+ BackupProtocolClientListDirectory::RootDirectory);
+=======
ReadDirectory(*client);
+>>>>>>> 0.12
int64_t testDirId = SearchDir(*rootDir, "Test1");
TEST_THAT(testDirId != 0);
@@ -1513,7 +1667,11 @@ int test_bbackupd()
ReadDirectory(*client, d4_id);
TEST_THAT(test_entry_deleted(*d4_dir, "f5"));
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientAccountUsage> usage(
+=======
std::auto_ptr<BackupProtocolAccountUsage> usage(
+>>>>>>> 0.12
client->QueryGetAccountUsage());
TEST_EQUAL_LINE(24, usage->GetBlocksUsed(),
"blocks used");
@@ -1532,7 +1690,15 @@ int test_bbackupd()
}
BOX_TRACE("done.");
+<<<<<<< HEAD
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ return 1;
+ }
+=======
if (failures) return 1;
+>>>>>>> 0.12
wait_for_operation(5, "housekeeping to remove the "
"deleted files");
@@ -1543,7 +1709,12 @@ int test_bbackupd()
ConnectAndLogin(context, 0 /* read-write */);
std::auto_ptr<BackupStoreDirectory> rootDir =
+<<<<<<< HEAD
+ ReadDirectory(*client,
+ BackupProtocolClientListDirectory::RootDirectory);
+=======
ReadDirectory(*client);
+>>>>>>> 0.12
int64_t testDirId = SearchDir(*rootDir, "Test1");
TEST_THAT(testDirId != 0);
@@ -1563,7 +1734,11 @@ int test_bbackupd()
TEST_THAT(SearchDir(*spacetest_dir, "d3") == 0);
TEST_THAT(SearchDir(*spacetest_dir, "d7") == 0);
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientAccountUsage> usage(
+=======
std::auto_ptr<BackupProtocolAccountUsage> usage(
+>>>>>>> 0.12
client->QueryGetAccountUsage());
TEST_EQUAL_LINE(16, usage->GetBlocksUsed(),
"blocks used");
@@ -1580,7 +1755,15 @@ int test_bbackupd()
sSocket.Close();
}
+<<<<<<< HEAD
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ return 1;
+ }
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Need 22 blocks free to upload everything
TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
@@ -1590,12 +1773,31 @@ int test_bbackupd()
// Run another backup, now there should be enough space
// for everything we want to upload.
+<<<<<<< HEAD
+ {
+ Logging::Guard guard(Log::ERROR);
+ bbackupd.RunSyncNow();
+ }
+=======
bbackupd.RunSyncNow();
+>>>>>>> 0.12
TEST_THAT(!bbackupd.StorageLimitExceeded());
// Check that the contents of the store are the same
// as the contents of the disc
+<<<<<<< HEAD
+ // (-a = all, -c = give result in return code)
+ BOX_TRACE("Check that all files were uploaded successfully");
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd-exclude.conf "
+ "-l testfiles/query1.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same, "testfiles/bbackupd-exclude.conf");
+>>>>>>> 0.12
BOX_TRACE("done.");
// BLOCK
@@ -1603,7 +1805,11 @@ int test_bbackupd()
std::auto_ptr<BackupProtocolClient> client =
ConnectAndLogin(context, 0 /* read-write */);
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientAccountUsage> usage(
+=======
std::auto_ptr<BackupProtocolAccountUsage> usage(
+>>>>>>> 0.12
client->QueryGetAccountUsage());
TEST_EQUAL_LINE(22, usage->GetBlocksUsed(),
"blocks used");
@@ -1618,7 +1824,15 @@ int test_bbackupd()
sSocket.Close();
}
+<<<<<<< HEAD
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ return 1;
+ }
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Put the limit back
TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
@@ -1638,7 +1852,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
BOX_TRACE("done.");
// unpack the initial files again
@@ -1656,14 +1873,33 @@ int test_bbackupd()
// as the contents of the disc
// (-a = all, -c = give result in return code)
BOX_TRACE("Check that all files were uploaded successfully");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query1.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
BOX_TRACE("done.");
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ return 1;
+ }
+=======
if (failures) return 1;
+>>>>>>> 0.12
}
// Check that no read error has been reported yet
@@ -1700,17 +1936,29 @@ int test_bbackupd()
class MyHook : public BackupStoreContext::TestHook
{
+<<<<<<< HEAD
+ virtual std::auto_ptr<ProtocolObject> StartCommand(
+ BackupProtocolObject& rCommand)
+ {
+ if (rCommand.GetType() ==
+ BackupProtocolServerStoreFile::TypeID)
+=======
virtual std::auto_ptr<BackupProtocolMessage> StartCommand(
const BackupProtocolMessage& rCommand)
{
if (rCommand.GetType() ==
BackupProtocolStoreFile::TypeID)
+>>>>>>> 0.12
{
// terminate badly
THROW_EXCEPTION(CommonException,
Internal);
}
+<<<<<<< HEAD
+ return std::auto_ptr<ProtocolObject>();
+=======
return std::auto_ptr<BackupProtocolMessage>();
+>>>>>>> 0.12
}
};
MyHook hook;
@@ -1797,7 +2045,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
}
#endif // !WIN32
@@ -1839,7 +2090,17 @@ int test_bbackupd()
sync_and_wait();
// Check that the backup was successful, i.e. no differences
+<<<<<<< HEAD
+ int compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query1.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// now stop bbackupd and update the test file,
// make the original directory unreadable
@@ -1855,6 +2116,14 @@ int test_bbackupd()
TEST_THAT(chmod(SYM_DIR, 0) == 0);
// check that we can restore it
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-Wwarning \"restore Test1 testfiles/restore-symlink\" "
+ "quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Command_OK);
+=======
{
int returnValue = ::system(BBACKUPQUERY " "
"-c testfiles/bbackupd.conf "
@@ -1863,6 +2132,7 @@ int test_bbackupd()
TEST_RETURN(returnValue,
BackupQueries::ReturnCode::Command_OK);
}
+>>>>>>> 0.12
// make it accessible again
TEST_THAT(chmod(SYM_DIR, 0755) == 0);
@@ -1927,6 +2197,27 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+ }
+ #endif // !WIN32
+
+ // Check that no read error has been reported yet
+ TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
+
+ printf("\n==== Testing that redundant locations are deleted on time\n");
+
+ // unpack the files for the redundant location test
+ TEST_THAT(::system("rm -rf testfiles/TestDir2") == 0);
+ TEST_THAT(::mkdir("testfiles/TestDir2", 0777) == 0);
+
+ #ifdef WIN32
+ TEST_THAT(::system("tar xzvf testfiles/spacetest1.tgz "
+ "-C testfiles/TestDir2") == 0);
+ #else
+ TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz "
+ "| ( cd testfiles/TestDir2 && tar xf - )") == 0);
+ #endif
+=======
if (failures) return 1;
}
#endif // !WIN32
@@ -1936,27 +2227,57 @@ int test_bbackupd()
// ensure that the directory does not exist at the start
TEST_THAT(::system("rm -rf testfiles/TestDir2") == 0);
+>>>>>>> 0.12
// BLOCK
{
// Kill the daemon
terminate_bbackupd(bbackupd_pid);
+<<<<<<< HEAD
+ // Start it with a config that has a temporary location
+ // that will be created on the server
+=======
// Delete any old result marker files
TEST_RETURN(0, system("rm -f testfiles/notifyran.*"));
// Start it with a config that has a temporary location
// whose path does not exist yet
+>>>>>>> 0.12
std::string cmd = BBACKUPD " " + bbackupd_args +
" testfiles/bbackupd-temploc.conf";
bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
+<<<<<<< HEAD
+ ::safe_sleep(1);
+=======
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+
+ sync_and_wait();
+
+ {
+ std::auto_ptr<BackupProtocolClient> client =
+ ConnectAndLogin(context,
+ BackupProtocolClientLogin::Flags_ReadOnly);
+
+ std::auto_ptr<BackupStoreDirectory> dir =
+ ReadDirectory(*client,
+ BackupProtocolClientListDirectory::RootDirectory);
+ int64_t testDirId = SearchDir(*dir, "Test2");
+ TEST_THAT(testDirId != 0);
+
+ client->QueryFinished();
+ sSocket.Close();
+ }
+
+=======
if (failures) return 1;
TEST_THAT(!TestFileExists("testfiles/notifyran.backup-start.1"));
@@ -2035,11 +2356,17 @@ int test_bbackupd()
// BLOCK
{
+>>>>>>> 0.12
// Kill the daemon
terminate_bbackupd(bbackupd_pid);
// Start it again with the normal config (no Test2)
+<<<<<<< HEAD
+ cmd = BBACKUPD " " + bbackupd_args +
+ " testfiles/bbackupd.conf";
+=======
cmd = BBACKUPD " " + bbackupd_args + " testfiles/bbackupd.conf";
+>>>>>>> 0.12
bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
@@ -2050,7 +2377,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Test2 should be deleted after 10 seconds (4 runs)
wait_for_sync_end();
@@ -2062,10 +2392,18 @@ int test_bbackupd()
{
std::auto_ptr<BackupProtocolClient> client =
ConnectAndLogin(context,
+<<<<<<< HEAD
+ BackupProtocolClientLogin::Flags_ReadOnly);
+
+ std::auto_ptr<BackupStoreDirectory> dir =
+ ReadDirectory(*client,
+ BackupProtocolClientListDirectory::RootDirectory);
+=======
BackupProtocolLogin::Flags_ReadOnly);
std::auto_ptr<BackupStoreDirectory> dir =
ReadDirectory(*client);
+>>>>>>> 0.12
int64_t testDirId = SearchDir(*dir, "Test2");
TEST_THAT(testDirId != 0);
@@ -2080,10 +2418,18 @@ int test_bbackupd()
{
std::auto_ptr<BackupProtocolClient> client =
ConnectAndLogin(context,
+<<<<<<< HEAD
+ BackupProtocolClientLogin::Flags_ReadOnly);
+
+ std::auto_ptr<BackupStoreDirectory> root_dir =
+ ReadDirectory(*client,
+ BackupProtocolClientListDirectory::RootDirectory);
+=======
BackupProtocolLogin::Flags_ReadOnly);
std::auto_ptr<BackupStoreDirectory> root_dir =
ReadDirectory(*client);
+>>>>>>> 0.12
TEST_THAT(test_entry_deleted(*root_dir, "Test2"));
@@ -2096,12 +2442,20 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+
+ if(bbackupd_pid > 0)
+ {
+ // Check that no read error has been reported yet
+ TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
+=======
if (failures) return 1;
if(bbackupd_pid > 0)
{
// Delete any old result marker files
TEST_RETURN(0, system("rm -f testfiles/notifyran.*"));
+>>>>>>> 0.12
printf("\n==== Check that read-only directories and "
"their contents can be restored.\n");
@@ -2149,6 +2503,8 @@ int test_bbackupd()
BackupQueries::ReturnCode::Compare_Same);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+<<<<<<< HEAD
+=======
// Try a restore with just the remote directory name,
// check that it uses the same name in the local
// directory.
@@ -2175,6 +2531,7 @@ int test_bbackupd()
BackupQueries::ReturnCode::Compare_Same);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+>>>>>>> 0.12
// put the permissions back to sensible values
#ifdef WIN32
TEST_THAT(::system("chmod 0755 testfiles/"
@@ -2187,6 +2544,10 @@ int test_bbackupd()
TEST_THAT(chmod("testfiles/restore1/x1",
0755) == 0);
#endif
+<<<<<<< HEAD
+
+=======
+>>>>>>> 0.12
}
#ifdef WIN32
@@ -2314,7 +2675,15 @@ int test_bbackupd()
wait_for_backup_operation("upload of file with unicode name");
// Compare to check that the file was uploaded
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " -Wwarning "
+ "-c testfiles/bbackupd.conf \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// Check that we can find it in directory listing
{
@@ -2322,7 +2691,12 @@ int test_bbackupd()
ConnectAndLogin(context, 0);
std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory(
+<<<<<<< HEAD
+ *client,
+ BackupProtocolClientListDirectory::RootDirectory);
+=======
*client);
+>>>>>>> 0.12
int64_t baseDirId = SearchDir(*dir, "Test1");
TEST_THAT(baseDirId != 0);
@@ -2496,7 +2870,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Check that SyncAllowScript is executed and can "
"pause backup\n");
@@ -2567,7 +2944,18 @@ int test_bbackupd()
long start_time = time(NULL);
// check that no backup has run (compare fails)
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-Werror "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
TEST_THAT(unlink(sync_control_file) == 0);
wait_for_sync_start();
@@ -2586,11 +2974,29 @@ int test_bbackupd()
TEST_THAT(wait_time <= 12);
wait_for_sync_end();
+<<<<<<< HEAD
+ // check that backup has run (compare succeeds)
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-Wwarning "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3a.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ return 1;
+ }
+=======
// check that backup has run (compare succeeds)
TEST_COMPARE(Compare_Same);
if (failures) return 1;
+>>>>>>> 0.12
}
// Check that no read error has been reported yet
@@ -2600,7 +3006,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Delete file and update another, "
"create symlink.\n");
@@ -2637,7 +3046,17 @@ int test_bbackupd()
sync_and_wait();
// compare to make sure that it worked
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " -Wwarning "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query2.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// Try a quick compare, just for fun
compareReturnValue = ::system(BBACKUPQUERY " "
@@ -2652,13 +3071,25 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Check that store errors are reported neatly
printf("\n==== Create store error\n");
TEST_THAT(system("rm -f testfiles/notifyran.backup-error.*")
== 0);
+<<<<<<< HEAD
+ // break the store
+ TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf",
+ "testfiles/0_0/backup/01234567/info.rf.bak") == 0);
+ TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf",
+ "testfiles/0_1/backup/01234567/info.rf.bak") == 0);
+ TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf",
+ "testfiles/0_2/backup/01234567/info.rf.bak") == 0);
+=======
// Break the store. We need a write lock on the account
// while we do this, otherwise housekeeping might be running
// and might rewrite the info files when it finishes,
@@ -2691,6 +3122,7 @@ int test_bbackupd()
TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf",
"testfiles/0_2/backup/01234567/info.rf.bak") == 0);
}
+>>>>>>> 0.12
// Create a file to trigger an upload
{
@@ -2719,7 +3151,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
sync_and_wait();
@@ -2739,7 +3174,17 @@ int test_bbackupd()
// Check that we DO get errors on compare (cannot do this
// until after we fix the store, which creates a race)
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3b.log "
+ "-Werror \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
// Test initial state
TEST_THAT(!TestFileExists("testfiles/"
@@ -2764,7 +3209,17 @@ int test_bbackupd()
"notifyran.backup-start.wait-snapshot.1"));
// Should not have backed up, should still get errors
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3b.log "
+ "-Werror \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
// wait another 10 seconds, bbackup should have run
wait_for_operation(10, "bbackupd to recover");
@@ -2772,7 +3227,17 @@ int test_bbackupd()
"notifyran.backup-start.wait-snapshot.1"));
// Check that it did get uploaded, and we have no more errors
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3b.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(::unlink("testfiles/notifyscript.tag") == 0);
@@ -2806,7 +3271,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
sync_and_wait();
@@ -2822,13 +3290,27 @@ int test_bbackupd()
// Check that we DO get errors on compare (cannot do this
// until after we fix the store, which creates a race)
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3b.log "
+ "-Werror \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
// Test initial state
TEST_THAT(!TestFileExists("testfiles/"
"notifyran.backup-start.wait-automatic.1"));
+<<<<<<< HEAD
+ // Set a tag for the notify script to distinguist from
+=======
// Set a tag for the notify script to distinguish from
+>>>>>>> 0.12
// previous runs.
{
int fd1 = open("testfiles/notifyscript.tag",
@@ -2847,7 +3329,17 @@ int test_bbackupd()
"notifyran.backup-start.wait-automatic.1"));
// Should not have backed up, should still get errors
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3b.log "
+ "-Werror \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
// wait another 10 seconds, bbackup should have run
wait_for_operation(10, "bbackupd to recover");
@@ -2855,7 +3347,17 @@ int test_bbackupd()
"notifyran.backup-start.wait-automatic.1"));
// Check that it did get uploaded, and we have no more errors
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3b.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(::unlink("testfiles/notifyscript.tag") == 0);
@@ -2863,7 +3365,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Bad case: delete a file/symlink, replace it with a directory
printf("\n==== Replace symlink with directory, "
@@ -2889,13 +3394,26 @@ int test_bbackupd()
#endif
wait_for_backup_operation("bbackupd to sync the changes");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3c.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// And the inverse, replace a directory with a file/symlink
printf("\n==== Replace directory with symlink\n");
@@ -2914,13 +3432,26 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync the changes");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3d.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// And then, put it back to how it was before.
printf("\n==== Replace symlink with directory "
@@ -2942,13 +3473,26 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync the changes");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3e.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// And finally, put it back to how it was before
// it was put back to how it was before
@@ -2970,13 +3514,26 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync the changes");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3f.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// rename an untracked file over an
// existing untracked file
@@ -3000,7 +3557,17 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync the "
"untracked files");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3g.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
#ifdef WIN32
TEST_THAT(::unlink("testfiles/TestDir1/untracked-2")
@@ -3015,13 +3582,26 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync the untracked "
"files again");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3g.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// case which went wrong: rename a tracked file over an
// existing tracked file
@@ -3050,7 +3630,17 @@ int test_bbackupd()
sync_and_wait();
// compare to make sure that it worked
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3h.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
#ifdef WIN32
TEST_THAT(::unlink("testfiles/TestDir1/tracked-2")
@@ -3065,13 +3655,26 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync the tracked "
"files again");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3i.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// case which went wrong: rename a tracked file
// over a deleted file
@@ -3082,7 +3685,17 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3j.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// Check that no read error has been reported yet
TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
@@ -3091,7 +3704,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Add files with old times, update "
"attributes of one to latest time\n");
@@ -3116,13 +3732,26 @@ int test_bbackupd()
// Wait and test
wait_for_backup_operation("bbackupd to sync old files");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3k.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Check that no read error has been reported yet
TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
@@ -3173,13 +3802,26 @@ int test_bbackupd()
wait_for_sync_end(); // files too new
wait_for_sync_end(); // should (not) be backed up this time
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3l.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Check that no read error has been reported yet
TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.1"));
@@ -3200,7 +3842,17 @@ int test_bbackupd()
wait_for_sync_end();
// compare with exclusions, should not find differences
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3m.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// compare without exclusions, should find differences
compareReturnValue = ::system(BBACKUPQUERY " "
@@ -3215,7 +3867,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// check that the excluded files did not make it
// into the store, and the included files did
@@ -3225,10 +3880,18 @@ int test_bbackupd()
{
std::auto_ptr<BackupProtocolClient> client =
ConnectAndLogin(context,
+<<<<<<< HEAD
+ BackupProtocolClientLogin::Flags_ReadOnly);
+
+ std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory(
+ *client,
+ BackupProtocolClientListDirectory::RootDirectory);
+=======
BackupProtocolLogin::Flags_ReadOnly);
std::auto_ptr<BackupStoreDirectory> dir =
ReadDirectory(*client);
+>>>>>>> 0.12
int64_t testDirId = SearchDir(*dir, "Test1");
TEST_THAT(testDirId != 0);
@@ -3259,7 +3922,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
#ifndef WIN32
// These tests only work as non-root users.
@@ -3285,9 +3951,21 @@ int test_bbackupd()
// Wait and test...
wait_for_backup_operation("bbackupd to try to sync "
"unreadable file");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3o.log "
+ "-Werror \"compare -acQ\" quit");
+
+ // should find differences
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Error);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
// should fail with an error due to unreadable file
TEST_COMPARE(Compare_Error);
+>>>>>>> 0.12
// Check that it was reported correctly
TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1"));
@@ -3308,7 +3986,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Continuously update file, "
"check isn't uploaded\n");
@@ -3374,7 +4055,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Delete directory, change attributes\n");
@@ -3387,7 +4071,17 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync deletion "
"of directory");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query4.log "
+ "-Werror \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
printf("\n==== Restore files and directories\n");
int64_t deldirid = 0;
@@ -3396,15 +4090,27 @@ int test_bbackupd()
// connect and log in
std::auto_ptr<BackupProtocolClient> client =
ConnectAndLogin(context,
+<<<<<<< HEAD
+ BackupProtocolClientLogin::Flags_ReadOnly);
+
+ // Find the ID of the Test1 directory
+ restoredirid = GetDirID(*client, "Test1",
+ BackupProtocolClientListDirectory::RootDirectory);
+=======
BackupProtocolLogin::Flags_ReadOnly);
// Find the ID of the Test1 directory
restoredirid = GetDirID(*client, "Test1",
BackupProtocolListDirectory::RootDirectory);
+>>>>>>> 0.12
TEST_THAT(restoredirid != 0);
// Test the restoration
TEST_THAT(BackupClientRestore(*client, restoredirid,
+<<<<<<< HEAD
+ "Test1", "testfiles/restore-Test1",
+ true /* print progress dots */)
+=======
"Test1" /* remote */,
"testfiles/restore-Test1" /* local */,
true /* print progress dots */,
@@ -3412,6 +4118,7 @@ int test_bbackupd()
false /* undelete after */,
false /* resume */,
false /* keep going */)
+>>>>>>> 0.12
== Restore_Complete);
// On Win32 we can't open another connection
@@ -3420,11 +4127,15 @@ int test_bbackupd()
// Make sure you can't restore a restored directory
TEST_THAT(BackupClientRestore(*client, restoredirid,
"Test1", "testfiles/restore-Test1",
+<<<<<<< HEAD
+ true /* print progress dots */)
+=======
true /* print progress dots */,
false /* restore deleted */,
false /* undelete after */,
false /* resume */,
false /* keep going */)
+>>>>>>> 0.12
== Restore_TargetExists);
// Find ID of the deleted directory
@@ -3434,12 +4145,18 @@ int test_bbackupd()
// Just check it doesn't bomb out -- will check this
// properly later (when bbackupd is stopped)
TEST_THAT(BackupClientRestore(*client, deldirid,
+<<<<<<< HEAD
+ "Test1", "testfiles/restore-Test1-x1",
+ true /* print progress dots */,
+ true /* deleted files */)
+=======
"Test1", "testfiles/restore-Test1-x1",
true /* print progress dots */,
true /* restore deleted */,
false /* undelete after */,
false /* resume */,
false /* keep going */)
+>>>>>>> 0.12
== Restore_Complete);
// Make sure you can't restore to a nonexistant path
@@ -3452,11 +4169,15 @@ int test_bbackupd()
TEST_THAT(BackupClientRestore(*client,
restoredirid, "Test1",
"testfiles/no-such-path/subdir",
+<<<<<<< HEAD
+ true /* print progress dots */)
+=======
true /* print progress dots */,
true /* restore deleted */,
false /* undelete after */,
false /* resume */,
false /* keep going */)
+>>>>>>> 0.12
== Restore_TargetPathNotFound);
}
@@ -3466,13 +4187,28 @@ int test_bbackupd()
}
// Compare the restored files
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10.log "
+ "-Wwarning "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
#ifdef WIN32
// make one of the files read-only, expect a compare failure
@@ -3480,14 +4216,37 @@ int test_bbackupd()
"testfiles\\restore-Test1\\f1.dat");
TEST_RETURN(compareReturnValue, 0);
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "-Werror "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
// set it back, expect no failures
compareReturnValue = ::system("attrib -r "
"testfiles\\restore-Test1\\f1.dat");
TEST_RETURN(compareReturnValue, 0);
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf -l testfiles/query10a.log "
+ "-Wwarning "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// change the timestamp on a file, expect a compare failure
char* testfile = "testfiles\\restore-Test1\\f1.dat";
@@ -3506,31 +4265,82 @@ int test_bbackupd()
// a compare failure
TEST_THAT(set_file_time(testfile, dummyTime, lastModTime,
lastAccessTime));
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "-Werror "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
// last access time is not backed up, so it cannot be compared
TEST_THAT(set_file_time(testfile, creationTime, lastModTime,
dummyTime));
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "-Wwarning "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// last write time is backed up, so changing it should cause
// a compare failure
TEST_THAT(set_file_time(testfile, creationTime, dummyTime,
lastAccessTime));
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "-Werror "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
// set back to original values, check that compare succeeds
TEST_THAT(set_file_time(testfile, creationTime, lastModTime,
lastAccessTime));
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "-Wwarning "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
#endif // WIN32
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Add files with current time\n");
@@ -3547,13 +4357,26 @@ int test_bbackupd()
// Wait and test
wait_for_backup_operation("bbackupd to sync new files");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query5.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Rename directory
printf("\n==== Rename directory\n");
@@ -3562,7 +4385,17 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync renamed directory");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query6.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// and again, but with quick flag
compareReturnValue = ::system(BBACKUPQUERY " "
@@ -3584,13 +4417,26 @@ int test_bbackupd()
wait_for_backup_operation("bbackupd to sync renamed files");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query6.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
// Check that modifying files with madly in the future
// timestamps still get added
@@ -3622,13 +4468,26 @@ int test_bbackupd()
// Wait and test
wait_for_backup_operation("bbackup to sync future file");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3e.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Change client store marker\n");
@@ -3646,7 +4505,11 @@ int test_bbackupd()
// Make sure the marker isn't zero,
// because that's the default, and
// it should have changed
+<<<<<<< HEAD
+ std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol->QueryLogin(0x01234567, 0));
+=======
std::auto_ptr<BackupProtocolLoginConfirmed> loginConf(protocol->QueryLogin(0x01234567, 0));
+>>>>>>> 0.12
TEST_THAT(loginConf->GetClientStoreMarker() != 0);
// Change it to something else
@@ -3671,7 +4534,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Check change of store marker pauses daemon\n");
@@ -3689,24 +4555,43 @@ int test_bbackupd()
3) / 2, "bbackupd to detect changed store marker");
// Test that there *are* differences
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query6.log "
+ "-Werror \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Different);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Different);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+
+ // 100 seconds - (12*3/2)
+ wait_for_operation(82, "bbackupd to recover");
+=======
if (failures) return 1;
wait_for_operation(100, "bbackupd to recover");
// Then check it has backed up successfully.
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
#ifndef WIN32
printf("\n==== Interrupted restore\n");
@@ -3723,34 +4608,59 @@ int test_bbackupd()
std::auto_ptr<BackupProtocolClient> client =
ConnectAndLogin(context,
+<<<<<<< HEAD
+ BackupProtocolClientLogin::Flags_ReadOnly);
+=======
BackupProtocolLogin::Flags_ReadOnly);
+>>>>>>> 0.12
// Check that the restore fn returns resume possible,
// rather than doing anything
TEST_THAT(BackupClientRestore(*client, restoredirid,
"Test1", "testfiles/restore-interrupt",
+<<<<<<< HEAD
+ true /* print progress dots */)
+=======
true /* print progress dots */,
false /* restore deleted */,
false /* undelete after */,
false /* resume */,
false /* keep going */)
+>>>>>>> 0.12
== Restore_ResumePossible);
// Then resume it
TEST_THAT(BackupClientRestore(*client, restoredirid,
"Test1", "testfiles/restore-interrupt",
true /* print progress dots */,
+<<<<<<< HEAD
+ false /* deleted files */,
+ false /* undelete server */,
+ true /* resume */)
+=======
false /* restore deleted */,
false /* undelete after */,
true /* resume */,
false /* keep going */)
+>>>>>>> 0.12
== Restore_Complete);
client->QueryFinished();
sSocket.Close();
// Then check it has restored the correct stuff
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query14.log "
+ "-Wwarning \"compare -cEQ Test1 "
+ "testfiles/restore-interrupt\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
}
#endif // !WIN32
@@ -3758,7 +4668,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
printf("\n==== Check restore deleted files\n");
@@ -3771,9 +4684,13 @@ int test_bbackupd()
"Test1", "testfiles/restore-Test1-x1-2",
true /* print progress dots */,
true /* deleted files */,
+<<<<<<< HEAD
+ true /* undelete on server */)
+=======
true /* undelete after */,
false /* resume */,
false /* keep going */)
+>>>>>>> 0.12
== Restore_Complete);
client->QueryFinished();
@@ -3799,7 +4716,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
#ifdef WIN32
printf("\n==== Testing locked file behaviour:\n");
@@ -3826,7 +4746,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
if (handle != 0)
{
@@ -3843,7 +4766,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
if (handle != 0)
{
@@ -3861,20 +4787,36 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
if (handle != 0)
{
// compare, and check that it works
// reports the correct error message (and finishes)
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query15a.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_THAT(compare_all(false));
+>>>>>>> 0.12
}
TEST_THAT(ServerIsAlive(bbackupd_pid));
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
if (handle != 0)
{
@@ -3884,7 +4826,17 @@ int test_bbackupd()
O_LOCK, 0);
TEST_THAT(handle != INVALID_HANDLE_VALUE);
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query15.log "
+ "-Werror \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Error);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Error);
+>>>>>>> 0.12
// close the file again, check that compare
// works again
@@ -3895,11 +4847,24 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+
+ if (handle != 0)
+ {
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query15a.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
if (failures) return 1;
if (handle != 0)
{
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
}
#endif
@@ -3917,7 +4882,10 @@ int test_bbackupd()
TEST_THAT(ServerIsAlive(bbstored_pid));
if (!ServerIsAlive(bbackupd_pid)) return 1;
if (!ServerIsAlive(bbstored_pid)) return 1;
+<<<<<<< HEAD
+=======
if (failures) return 1;
+>>>>>>> 0.12
if(bbackupd_pid != -1 && bbackupd_pid != 0)
{
@@ -3925,7 +4893,17 @@ int test_bbackupd()
wait_for_operation(
(TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2,
"bbackupd to sync everything");
+<<<<<<< HEAD
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query4a.log "
+ "-Wwarning \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue,
+ BackupQueries::ReturnCode::Compare_Same);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+=======
TEST_COMPARE(Compare_Same);
+>>>>>>> 0.12
// Kill it again
terminate_bbackupd(bbackupd_pid);
@@ -3952,6 +4930,8 @@ int test_bbackupd()
int test(int argc, const char *argv[])
{
+<<<<<<< HEAD
+=======
{
BackupDaemon daemon;
@@ -3965,6 +4945,7 @@ int test(int argc, const char *argv[])
TEST_EQUAL(0, daemon.GetMaxBandwidthFromSyncAllowScript());
}
+>>>>>>> 0.12
// SSL library
SSLLib::Initialise();
diff --git a/test/bbackupd/testfiles/bbackupd-temploc.conf b/test/bbackupd/testfiles/bbackupd-temploc.conf
new file mode 100644
index 00000000..07cbdcd1
--- /dev/null
+++ b/test/bbackupd/testfiles/bbackupd-temploc.conf
@@ -0,0 +1,55 @@
+
+CertificateFile = testfiles/clientCerts.pem
+PrivateKeyFile = testfiles/clientPrivKey.pem
+TrustedCAsFile = testfiles/clientTrustedCAs.pem
+
+KeysFile = testfiles/bbackupd.keys
+
+DataDirectory = testfiles/bbackupd-data
+
+StoreHostname = localhost
+StorePort = 22011
+AccountNumber = 0x01234567
+
+UpdateStoreInterval = 3
+MinimumFileAge = 4
+MaxUploadWait = 24
+
+FileTrackingSizeThreshold = 1024
+DiffingUploadSizeThreshold = 1024
+
+MaximumDiffingTime = 3
+KeepAliveTime = 1
+
+ExtendedLogging = no
+ExtendedLogFile = testfiles/bbackupd.log
+
+CommandSocket = testfiles/bbackupd.sock
+
+Server
+{
+ PidFile = testfiles/bbackupd.pid
+}
+
+BackupLocations
+{
+ Test1
+ {
+ Path = testfiles/TestDir1
+
+ ExcludeFile = testfiles/TestDir1/excluded_1
+ ExcludeFile = testfiles/TestDir1/excluded_2
+ ExcludeFilesRegex = \.excludethis$
+ ExcludeFilesRegex = EXCLUDE
+ AlwaysIncludeFile = testfiles/TestDir1/dont.excludethis
+ ExcludeDir = testfiles/TestDir1/exclude_dir
+ ExcludeDir = testfiles/TestDir1/exclude_dir_2
+ ExcludeDirsRegex = not_this_dir
+ AlwaysIncludeDirsRegex = ALWAYSINCLUDE
+ }
+ Test2
+ {
+ Path = testfiles/TestDir2
+ }
+}
+
diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp
index f47a0dba..2d4b7431 100644
--- a/test/common/testcommon.cpp
+++ b/test/common/testcommon.cpp
@@ -332,9 +332,15 @@ int test(int argc, const char *argv[])
Timers::Init();
Timer t0(0, "t0"); // should never expire
+<<<<<<< HEAD
+ Timer t1(1, "t1");
+ Timer t2(2, "t2");
+ Timer t3(3, "t3");
+=======
Timer t1(1000, "t1");
Timer t2(2000, "t2");
Timer t3(3000, "t3");
+>>>>>>> 0.12
TEST_THAT(!t0.HasExpired());
TEST_THAT(!t1.HasExpired());
@@ -352,6 +358,14 @@ int test(int argc, const char *argv[])
TEST_THAT(t1.HasExpired());
TEST_THAT(t2.HasExpired());
TEST_THAT(!t3.HasExpired());
+<<<<<<< HEAD
+
+ t1 = Timer(1, "t1a");
+ t2 = Timer(2, "t2a");
+ TEST_THAT(!t0.HasExpired());
+ TEST_THAT(!t1.HasExpired());
+ TEST_THAT(!t2.HasExpired());
+=======
// Try both ways of resetting an existing timer.
t1 = Timer(1000, "t1a");
@@ -360,6 +374,7 @@ int test(int argc, const char *argv[])
TEST_THAT(!t1.HasExpired());
TEST_THAT(!t2.HasExpired());
TEST_THAT(!t3.HasExpired());
+>>>>>>> 0.12
safe_sleep(1);
TEST_THAT(!t0.HasExpired());
@@ -367,12 +382,15 @@ int test(int argc, const char *argv[])
TEST_THAT(!t2.HasExpired());
TEST_THAT(t3.HasExpired());
+<<<<<<< HEAD
+=======
safe_sleep(1);
TEST_THAT(!t0.HasExpired());
TEST_THAT(t1.HasExpired());
TEST_THAT(t2.HasExpired());
TEST_THAT(t3.HasExpired());
+>>>>>>> 0.12
// Leave timers initialised for rest of test.
// Test main() will cleanup after test finishes.
@@ -412,10 +430,15 @@ int test(int argc, const char *argv[])
{
TEST_THAT(!getline.IsEOF());
std::string line = getline.GetLine(true);
+<<<<<<< HEAD
+ //printf("expected |%s| got |%s|\n", lines[l], line.c_str());
+ TEST_THAT(strcmp(testfilelines[l], line.c_str()) == 0);
+=======
printf("expected |%s| got |%s|\n", testfilelines[l],
line.c_str());
TEST_LINE(strcmp(testfilelines[l], line.c_str()) == 0,
line);
+>>>>>>> 0.12
l++;
}
TEST_THAT(getline.IsEOF());
@@ -465,10 +488,15 @@ int test(int argc, const char *argv[])
std::string line;
while(!getline.GetLine(line, true))
;
+<<<<<<< HEAD
+ //printf("expected |%s| got |%s|\n", lines[l], line.c_str());
+ TEST_THAT(strcmp(testfilelines[l], line.c_str()) == 0);
+=======
printf("expected |%s| got |%s|\n", testfilelines[l],
line.c_str());
TEST_LINE(strcmp(testfilelines[l], line.c_str()) == 0,
line);
+>>>>>>> 0.12
l++;
}
TEST_THAT(getline.IsEOF());
diff --git a/win32.bat b/win32.bat
index 5df3d709..f0cd6405 100644
--- a/win32.bat
+++ b/win32.bat
@@ -4,25 +4,40 @@ echo quick and dirty to get up and running by generating the required files
echo using Cygwin and Perl
copy .\infrastructure\BoxPlatform.pm.in .\infrastructure\BoxPlatform.pm
+<<<<<<< HEAD
+=======
copy .\lib\common\BoxPortsAndFiles.h.in .\lib\common\BoxPortsAndFiles.h
copy .\lib\common\BoxConfig-MSVC.h .\lib\common\BoxConfig.h
+>>>>>>> 0.12
cd .\bin\bbackupquery\ & perl ./../../bin/bbackupquery/makedocumentation.pl.in
cd ..\..\
+<<<<<<< HEAD
+cd .\lib\backupclient & perl ./../../lib/common/makeexception.pl.in BackupStoreException.txt & perl ./../../lib/server/makeprotocol.pl.in Client ./../../bin/bbstored/backupprotocol.txt
+=======
cd .\lib\backupstore & perl ./../../lib/common/makeexception.pl.in BackupStoreException.txt & perl ./../../lib/server/makeprotocol.pl.in backupprotocol.txt
+>>>>>>> 0.12
cd ..\..\
cd .\lib\compress & perl ./../../lib/common/makeexception.pl.in CompressException.txt
cd ..\..\
cd .\lib\common & perl ./../../lib/common/makeexception.pl.in CommonException.txt & perl ./../../lib/common/makeexception.pl.in ConversionException.txt
+<<<<<<< HEAD
+
+cd ..\..\
+
+cd .\bin\bbackupd & perl ./../../lib/common/makeexception.pl.in ClientException.txt
+
+=======
cd ..\..\
cd .\lib\raidfile & perl ./../../lib/common/makeexception.pl.in RaidFileException.txt
cd ..\..\
cd .\bin\bbackupd & perl ./../../lib/common/makeexception.pl.in ClientException.txt
+>>>>>>> 0.12
cd ..\..\
cd .\lib\crypto & perl ./../../lib/common/makeexception.pl.in CipherException.txt
@@ -34,6 +49,9 @@ cd .\lib\server & perl ./../../lib/common/makeexception.pl.in ServerException.tx
cd ..\..\
perl -pe 's/@PERL@/perl/' ./test/bbackupd/testfiles/bbackupd.conf.in > .\test\bbackupd\testfiles\bbackupd.conf
+<<<<<<< HEAD
+=======
echo Generating InstallJammer configuration file
perl infrastructure/msvc/fake-config.sub.pl ./contrib/windows/installer/boxbackup.mpi.in > ./contrib/windows/installer/boxbackup.mpi
+>>>>>>> 0.12