summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinhard Tartler <siretart@tauware.de>2008-01-19 15:08:54 +0100
committerReinhard Tartler <siretart@tauware.de>2008-01-19 15:08:54 +0100
commit2733267954e91e394fbb512ea3abb4c497c0752f (patch)
treed6cdebd8776bceba06a2fb5e4ed06a4744bc1b57
parent1d56581c644c53f1b9a182c6574bc2fc5243d4d1 (diff)
import version 0.11rc1
This commit has been made by 'bzr import'. I used the upstream tarball of Version 0.11rc1 for creating it. It has the md5sum: 75608d8bb72dff9a556850ccd0ae8cb9
-rw-r--r--VERSION.txt2
-rw-r--r--bin/bbackupctl/bbackupctl.cpp260
-rw-r--r--bin/bbackupd/BackupClientContext.cpp210
-rw-r--r--bin/bbackupd/BackupClientContext.h40
-rw-r--r--bin/bbackupd/BackupClientDeleteList.cpp2
-rw-r--r--bin/bbackupd/BackupClientDeleteList.h2
-rw-r--r--bin/bbackupd/BackupClientDirectoryRecord.cpp383
-rw-r--r--bin/bbackupd/BackupClientDirectoryRecord.h91
-rw-r--r--bin/bbackupd/BackupClientInodeToIDMap.cpp2
-rw-r--r--bin/bbackupd/BackupClientInodeToIDMap.h2
-rw-r--r--bin/bbackupd/BackupDaemon.cpp1421
-rw-r--r--bin/bbackupd/BackupDaemon.h268
-rw-r--r--bin/bbackupd/ClientException.txt11
-rw-r--r--bin/bbackupd/Makefile.extra7
-rw-r--r--bin/bbackupd/Win32BackupService.cpp39
-rw-r--r--bin/bbackupd/Win32BackupService.h4
-rw-r--r--bin/bbackupd/Win32ServiceFunctions.cpp241
-rw-r--r--bin/bbackupd/Win32ServiceFunctions.h8
-rwxr-xr-xbin/bbackupd/bbackupd-config140
-rwxr-xr-xbin/bbackupd/bbackupd-config.in599
-rw-r--r--bin/bbackupd/bbackupd.cpp78
-rw-r--r--bin/bbackupd/win32/NotifySysAdmin.vbs95
-rw-r--r--bin/bbackupd/win32/ReadMe.txt24
-rw-r--r--bin/bbackupd/win32/bbackupd.conf175
-rw-r--r--bin/bbackupobjdump/bbackupobjdump.cpp2
-rw-r--r--bin/bbackupquery/BackupQueries.cpp720
-rw-r--r--bin/bbackupquery/BackupQueries.h9
-rw-r--r--bin/bbackupquery/Makefile.extra2
-rw-r--r--bin/bbackupquery/bbackupquery.cpp147
-rw-r--r--bin/bbackupquery/documentation.txt3
-rwxr-xr-xbin/bbackupquery/makedocumentation.pl2
-rwxr-xr-xbin/bbackupquery/makedocumentation.pl.in75
-rw-r--r--bin/bbstoreaccounts/bbstoreaccounts.cpp87
-rw-r--r--bin/bbstored/BBStoreDHousekeeping.cpp192
-rw-r--r--bin/bbstored/BackupCommands.cpp96
-rw-r--r--bin/bbstored/BackupConstants.h2
-rw-r--r--bin/bbstored/BackupContext.cpp17
-rw-r--r--bin/bbstored/BackupContext.h2
-rw-r--r--bin/bbstored/BackupStoreDaemon.cpp93
-rw-r--r--bin/bbstored/BackupStoreDaemon.h17
-rw-r--r--bin/bbstored/HousekeepStoreAccount.cpp72
-rw-r--r--bin/bbstored/HousekeepStoreAccount.h2
-rw-r--r--bin/bbstored/Makefile.extra2
-rwxr-xr-xbin/bbstored/bbstored-certs2
-rwxr-xr-xbin/bbstored/bbstored-certs.in319
-rwxr-xr-xbin/bbstored/bbstored-config2
-rwxr-xr-xbin/bbstored/bbstored-config.in242
-rw-r--r--bin/bbstored/bbstored.cpp16
-rwxr-xr-xbootstrap2
-rwxr-xr-xconfigure1282
-rw-r--r--configure.ac140
-rwxr-xr-xcontrib/cygwin/install-cygwin-service.pl.in (renamed from contrib/cygwin/install-cygwin-service.pl)2
-rw-r--r--contrib/rpm/boxbackup.spec47
-rw-r--r--infrastructure/BoxPlatform.pm.in60
-rw-r--r--infrastructure/buildenv-testmain-template.cpp214
-rw-r--r--infrastructure/m4/ax_check_dirent_d_type.m42
-rw-r--r--infrastructure/m4/ax_config_scripts.m416
-rw-r--r--infrastructure/m4/ax_path_bdb.m427
-rwxr-xr-xinfrastructure/makebuildenv.pl.in (renamed from infrastructure/makebuildenv.pl)246
-rwxr-xr-xinfrastructure/makedistribution.pl.in351
-rwxr-xr-xinfrastructure/makeparcels.pl.in (renamed from infrastructure/makeparcels.pl)85
-rwxr-xr-xinfrastructure/mingw/configure.sh36
-rw-r--r--infrastructure/msvc/2003/bbackupctl.vcproj5
-rw-r--r--infrastructure/msvc/2003/bbackupd.vcproj11
-rw-r--r--infrastructure/msvc/2003/boxbackup.ncbbin650240 -> 0 bytes
-rw-r--r--infrastructure/msvc/2003/boxbackup.sln10
-rw-r--r--infrastructure/msvc/2003/boxbackup.suobin22528 -> 0 bytes
-rw-r--r--infrastructure/msvc/2003/boxquery.vcproj5
-rw-r--r--infrastructure/msvc/2003/common.vcproj39
-rw-r--r--infrastructure/msvc/2005/bbackupctl.vcproj15
-rw-r--r--infrastructure/msvc/2005/bbackupd.vcproj23
-rw-r--r--infrastructure/msvc/2005/boxquery.vcproj14
-rw-r--r--infrastructure/msvc/2005/common.vcproj60
-rw-r--r--infrastructure/msvc/2005/win32test.vcproj11
-rw-r--r--infrastructure/msvc/getversion.pl57
-rw-r--r--lib/backupclient/BackupClientCryptoKeys.cpp2
-rw-r--r--lib/backupclient/BackupClientCryptoKeys.h2
-rw-r--r--lib/backupclient/BackupClientFileAttributes.cpp49
-rw-r--r--lib/backupclient/BackupClientFileAttributes.h5
-rw-r--r--lib/backupclient/BackupClientMakeExcludeList.cpp2
-rw-r--r--lib/backupclient/BackupClientMakeExcludeList.h2
-rw-r--r--lib/backupclient/BackupClientRestore.cpp357
-rw-r--r--lib/backupclient/BackupClientRestore.h6
-rw-r--r--lib/backupclient/BackupDaemonConfigVerify.cpp7
-rw-r--r--lib/backupclient/BackupDaemonConfigVerify.h2
-rw-r--r--lib/backupclient/BackupStoreConstants.h11
-rw-r--r--lib/backupclient/BackupStoreDirectory.cpp7
-rw-r--r--lib/backupclient/BackupStoreDirectory.h2
-rw-r--r--lib/backupclient/BackupStoreException.h2
-rw-r--r--lib/backupclient/BackupStoreFile.cpp31
-rw-r--r--lib/backupclient/BackupStoreFile.h11
-rw-r--r--lib/backupclient/BackupStoreFileCmbDiff.cpp2
-rw-r--r--lib/backupclient/BackupStoreFileCmbIdx.cpp2
-rw-r--r--lib/backupclient/BackupStoreFileCombine.cpp2
-rw-r--r--lib/backupclient/BackupStoreFileCryptVar.cpp2
-rw-r--r--lib/backupclient/BackupStoreFileCryptVar.h2
-rw-r--r--lib/backupclient/BackupStoreFileDiff.cpp111
-rw-r--r--lib/backupclient/BackupStoreFileEncodeStream.cpp21
-rw-r--r--lib/backupclient/BackupStoreFileEncodeStream.h4
-rw-r--r--lib/backupclient/BackupStoreFileRevDiff.cpp2
-rw-r--r--lib/backupclient/BackupStoreFileWire.h2
-rw-r--r--lib/backupclient/BackupStoreFilename.cpp2
-rw-r--r--lib/backupclient/BackupStoreFilename.h2
-rw-r--r--lib/backupclient/BackupStoreFilenameClear.cpp9
-rw-r--r--lib/backupclient/BackupStoreFilenameClear.h2
-rw-r--r--lib/backupclient/BackupStoreObjectDump.cpp10
-rw-r--r--lib/backupclient/BackupStoreObjectMagic.h2
-rw-r--r--lib/backupclient/Makefile.extra4
-rw-r--r--lib/backupstore/BackupStoreAccountDatabase.cpp2
-rw-r--r--lib/backupstore/BackupStoreAccountDatabase.h2
-rw-r--r--lib/backupstore/BackupStoreAccounts.cpp7
-rw-r--r--lib/backupstore/BackupStoreAccounts.h2
-rw-r--r--lib/backupstore/BackupStoreCheck.cpp100
-rw-r--r--lib/backupstore/BackupStoreCheck.h2
-rw-r--r--lib/backupstore/BackupStoreCheck2.cpp28
-rw-r--r--lib/backupstore/BackupStoreCheckData.cpp2
-rw-r--r--lib/backupstore/BackupStoreConfigVerify.cpp10
-rw-r--r--lib/backupstore/BackupStoreConfigVerify.h2
-rw-r--r--lib/backupstore/BackupStoreInfo.cpp5
-rw-r--r--lib/backupstore/BackupStoreInfo.h4
-rw-r--r--lib/backupstore/StoreStructure.cpp2
-rw-r--r--lib/backupstore/StoreStructure.h2
-rw-r--r--lib/common/Archive.h2
-rw-r--r--lib/common/BannerText.h4
-rw-r--r--lib/common/BeginStructPackForWire.h2
-rw-r--r--lib/common/Box.h24
-rw-r--r--lib/common/BoxConfig-MSVC.h (renamed from lib/win32/config.h.win32)50
-rw-r--r--lib/common/BoxConfig.h469
-rw-r--r--lib/common/BoxConfig.h.in47
-rw-r--r--lib/common/BoxException.cpp2
-rw-r--r--lib/common/BoxException.h2
-rw-r--r--lib/common/BoxPlatform.h34
-rw-r--r--lib/common/BoxPortsAndFiles.h28
-rw-r--r--lib/common/BoxTime.cpp33
-rw-r--r--lib/common/BoxTime.h7
-rw-r--r--lib/common/BoxTimeToText.cpp40
-rw-r--r--lib/common/BoxTimeToText.h4
-rw-r--r--lib/common/BoxTimeToUnix.h2
-rw-r--r--lib/common/BufferedStream.cpp245
-rw-r--r--lib/common/BufferedStream.h81
-rw-r--r--lib/common/CollectInBufferStream.cpp2
-rw-r--r--lib/common/CollectInBufferStream.h2
-rw-r--r--lib/common/CommonException.h2
-rw-r--r--lib/common/CommonException.txt1
-rw-r--r--lib/common/Configuration.cpp16
-rw-r--r--lib/common/Configuration.h13
-rw-r--r--lib/common/Conversion.h2
-rw-r--r--lib/common/ConversionString.cpp4
-rw-r--r--lib/common/DebugAssertFailed.cpp2
-rw-r--r--lib/common/DebugMemLeakFinder.cpp183
-rw-r--r--lib/common/DebugPrintf.cpp2
-rw-r--r--lib/common/EndStructPackForWire.h2
-rw-r--r--lib/common/EventWatchFilesystemObject.cpp7
-rw-r--r--lib/common/EventWatchFilesystemObject.h2
-rw-r--r--lib/common/ExcludeList.cpp117
-rw-r--r--lib/common/ExcludeList.h11
-rw-r--r--lib/common/FdGetLine.cpp2
-rw-r--r--lib/common/FdGetLine.h6
-rw-r--r--lib/common/FileModificationTime.h2
-rw-r--r--lib/common/FileStream.cpp55
-rw-r--r--lib/common/FileStream.h4
-rw-r--r--lib/common/Guards.h14
-rw-r--r--lib/common/IOStream.cpp2
-rw-r--r--lib/common/IOStream.h2
-rw-r--r--lib/common/IOStreamGetLine.cpp2
-rw-r--r--lib/common/IOStreamGetLine.h2
-rw-r--r--lib/common/InvisibleTempFileStream.cpp77
-rw-r--r--lib/common/InvisibleTempFileStream.h73
-rw-r--r--lib/common/Logging.cpp386
-rw-r--r--lib/common/Logging.h241
-rw-r--r--lib/common/MainHelper.h3
-rw-r--r--lib/common/Makefile.extra4
-rw-r--r--lib/common/MemBlockStream.cpp2
-rw-r--r--lib/common/MemBlockStream.h2
-rw-r--r--lib/common/MemLeakFindOff.h2
-rw-r--r--lib/common/MemLeakFindOn.h2
-rw-r--r--lib/common/MemLeakFinder.h19
-rw-r--r--lib/common/NamedLock.cpp5
-rw-r--r--lib/common/NamedLock.h2
-rw-r--r--lib/common/PartialReadStream.cpp12
-rw-r--r--lib/common/PartialReadStream.h6
-rw-r--r--lib/common/PathUtils.cpp72
-rw-r--r--lib/common/PathUtils.h64
-rw-r--r--lib/common/ReadGatherStream.cpp11
-rw-r--r--lib/common/ReadGatherStream.h2
-rw-r--r--lib/common/ReadLoggingStream.cpp245
-rw-r--r--lib/common/ReadLoggingStream.h81
-rw-r--r--lib/common/StreamableMemBlock.cpp2
-rw-r--r--lib/common/StreamableMemBlock.h2
-rw-r--r--lib/common/TemporaryDirectory.h2
-rw-r--r--lib/common/Test.h434
-rw-r--r--lib/common/Timer.cpp432
-rw-r--r--lib/common/Timer.h125
-rw-r--r--lib/common/UnixUser.cpp13
-rw-r--r--lib/common/UnixUser.h2
-rw-r--r--lib/common/Utils.cpp21
-rw-r--r--lib/common/Utils.h4
-rw-r--r--lib/common/WaitForEvent.cpp2
-rw-r--r--lib/common/WaitForEvent.h2
-rw-r--r--lib/common/ZeroStream.cpp208
-rw-r--r--lib/common/ZeroStream.h77
-rwxr-xr-xlib/common/makeexception.pl2
-rwxr-xr-xlib/common/makeexception.pl.in277
-rw-r--r--lib/compress/Compress.h6
-rw-r--r--lib/compress/CompressException.h2
-rw-r--r--lib/compress/CompressStream.cpp2
-rw-r--r--lib/compress/CompressStream.h2
-rw-r--r--lib/compress/Makefile.extra2
-rw-r--r--lib/crypto/CipherAES.cpp2
-rw-r--r--lib/crypto/CipherAES.h2
-rw-r--r--lib/crypto/CipherBlowfish.cpp2
-rw-r--r--lib/crypto/CipherBlowfish.h2
-rw-r--r--lib/crypto/CipherContext.cpp2
-rw-r--r--lib/crypto/CipherContext.h2
-rw-r--r--lib/crypto/CipherDescription.cpp2
-rw-r--r--lib/crypto/CipherDescription.h2
-rw-r--r--lib/crypto/CipherException.h2
-rw-r--r--lib/crypto/MD5Digest.cpp2
-rw-r--r--lib/crypto/MD5Digest.h2
-rw-r--r--lib/crypto/Makefile.extra2
-rw-r--r--lib/crypto/Random.cpp5
-rw-r--r--lib/crypto/Random.h2
-rw-r--r--lib/crypto/RollingChecksum.cpp2
-rw-r--r--lib/crypto/RollingChecksum.h2
-rw-r--r--lib/intercept/intercept.cpp (renamed from test/raidfile/intercept.cpp)353
-rw-r--r--lib/intercept/intercept.h85
-rw-r--r--lib/raidfile/Makefile.extra2
-rw-r--r--lib/raidfile/RaidFileController.cpp13
-rw-r--r--lib/raidfile/RaidFileController.h5
-rw-r--r--lib/raidfile/RaidFileException.h2
-rw-r--r--lib/raidfile/RaidFileException.txt2
-rw-r--r--lib/raidfile/RaidFileRead.cpp85
-rw-r--r--lib/raidfile/RaidFileRead.h2
-rw-r--r--lib/raidfile/RaidFileUtil.cpp2
-rw-r--r--lib/raidfile/RaidFileUtil.h2
-rw-r--r--lib/raidfile/RaidFileWrite.cpp74
-rw-r--r--lib/raidfile/RaidFileWrite.h2
-rwxr-xr-xlib/raidfile/raidfile-config2
-rwxr-xr-xlib/raidfile/raidfile-config.in97
-rw-r--r--lib/server/ConnectionException.txt2
-rw-r--r--lib/server/Daemon.cpp450
-rw-r--r--lib/server/Daemon.h18
-rw-r--r--lib/server/LocalProcessStream.cpp82
-rw-r--r--lib/server/LocalProcessStream.h2
-rw-r--r--lib/server/Makefile.extra4
-rw-r--r--lib/server/Protocol.cpp6
-rw-r--r--lib/server/Protocol.h2
-rw-r--r--lib/server/ProtocolObject.cpp2
-rw-r--r--lib/server/ProtocolObject.h2
-rw-r--r--lib/server/ProtocolUncertainStream.cpp2
-rw-r--r--lib/server/ProtocolUncertainStream.h6
-rw-r--r--lib/server/ProtocolWire.h2
-rw-r--r--lib/server/SSLLib.cpp18
-rw-r--r--lib/server/SSLLib.h2
-rw-r--r--lib/server/ServerControl.h228
-rw-r--r--lib/server/ServerException.h2
-rw-r--r--lib/server/ServerStream.h87
-rw-r--r--lib/server/ServerTLS.h2
-rw-r--r--lib/server/Socket.cpp11
-rw-r--r--lib/server/Socket.h2
-rw-r--r--lib/server/SocketListen.h2
-rw-r--r--lib/server/SocketStream.cpp66
-rw-r--r--lib/server/SocketStream.h5
-rw-r--r--lib/server/SocketStreamTLS.cpp43
-rw-r--r--lib/server/SocketStreamTLS.h2
-rw-r--r--lib/server/TLSContext.cpp7
-rw-r--r--lib/server/TLSContext.h2
-rw-r--r--lib/server/WinNamedPipeStream.cpp629
-rw-r--r--lib/server/WinNamedPipeStream.h (renamed from lib/win32/WinNamedPipeStream.h)16
-rwxr-xr-xlib/server/makeprotocol.pl63
-rwxr-xr-xlib/server/makeprotocol.pl.in1048
-rwxr-xr-xlib/win32/MSG00001.binbin0 -> 32 bytes
-rw-r--r--lib/win32/WinNamedPipeStream.cpp350
-rw-r--r--lib/win32/emu.cpp1035
-rw-r--r--lib/win32/emu.h348
-rwxr-xr-xlib/win32/getopt.h136
-rwxr-xr-xlib/win32/getopt_long.cxx550
-rwxr-xr-xlib/win32/messages.h95
-rw-r--r--lib/win32/messages.mc22
-rwxr-xr-xlib/win32/messages.rc2
-rw-r--r--modules.txt42
-rw-r--r--notes/win32_build_on_cygwin_using_mingw.txt27
-rw-r--r--notes/win32_build_on_linux_using_mingw.txt37
-rw-r--r--parcels.txt13
-rwxr-xr-xruntest.pl.in123
-rw-r--r--test/backupdiff/difftestfiles.cpp2
-rw-r--r--test/backupdiff/testbackupdiff.cpp79
-rw-r--r--test/backupdiff/testextra2
-rw-r--r--test/backupstore/testbackupstore.cpp148
-rw-r--r--test/backupstore/testextra2
-rw-r--r--test/backupstorefix/testbackupstorefix.cpp135
-rw-r--r--test/backupstorefix/testextra2
-rwxr-xr-xtest/backupstorefix/testfiles/testbackupstorefix.pl6
-rwxr-xr-xtest/backupstorefix/testfiles/testbackupstorefix.pl.in213
-rw-r--r--test/backupstorepatch/testbackupstorepatch.cpp34
-rw-r--r--test/backupstorepatch/testextra2
-rw-r--r--test/basicserver/Makefile.extra8
-rw-r--r--test/basicserver/TestCommands.cpp4
-rw-r--r--test/basicserver/TestContext.cpp2
-rw-r--r--test/basicserver/TestContext.h2
-rw-r--r--test/basicserver/testbasicserver.cpp265
-rw-r--r--test/basicserver/testfiles/srv4.conf2
-rw-r--r--test/bbackupd/Makefile.extra1
-rw-r--r--test/bbackupd/testbbackupd.cpp2543
-rw-r--r--test/bbackupd/testextra2
-rw-r--r--test/bbackupd/testfiles/bbackupd-temploc.conf54
-rwxr-xr-x[-rw-r--r--]test/bbackupd/testfiles/bbackupd.conf10
-rw-r--r--test/bbackupd/testfiles/bbackupd.conf.in54
-rwxr-xr-xtest/bbackupd/testfiles/extcheck1.pl21
-rwxr-xr-xtest/bbackupd/testfiles/extcheck1.pl.in44
-rwxr-xr-xtest/bbackupd/testfiles/extcheck2.pl22
-rwxr-xr-xtest/bbackupd/testfiles/extcheck2.pl.in41
-rwxr-xr-xtest/bbackupd/testfiles/notifyscript.pl2
-rwxr-xr-xtest/bbackupd/testfiles/notifyscript.pl.in15
-rwxr-xr-xtest/bbackupd/testfiles/syncallowscript.pl (renamed from runtest.pl)109
-rwxr-xr-xtest/bbackupd/testfiles/syncallowscript.pl.in33
-rw-r--r--test/common/testcommon.cpp326
-rw-r--r--test/compress/testcompress.cpp2
-rw-r--r--test/crypto/testcrypto.cpp2
-rw-r--r--test/raidfile/testextra2
-rw-r--r--test/raidfile/testraidfile.cpp128
-rw-r--r--test/win32/testlibwin32.cpp281
-rw-r--r--test/win32/timezone.cpp2
323 files changed, 21071 insertions, 4190 deletions
diff --git a/VERSION.txt b/VERSION.txt
index 79378a7d..3832471a 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1,2 +1,2 @@
-0.10
+0.11rc1
boxbackup
diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp
index 5b09b4b5..28c43b0d 100644
--- a/bin/bbackupctl/bbackupctl.cpp
+++ b/bin/bbackupctl/bbackupctl.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -66,16 +66,26 @@
#include "MemLeakFindOn.h"
+enum Command
+{
+ Default,
+ WaitForSyncStart,
+ WaitForSyncEnd,
+ SyncAndWaitForEnd,
+};
+
void PrintUsageAndExit()
{
printf("Usage: bbackupctl [-q] [-c config_file] <command>\n"
"Commands are:\n"
- " sync -- start a syncronisation run now\n"
- " force-sync -- force the start of a syncronisation run, "
+ " sync -- start a synchronisation (backup) run now\n"
+ " force-sync -- force the start of a synchronisation run, "
"even if SyncAllowScript says no\n"
" reload -- reload daemon configuration\n"
" terminate -- terminate daemon now\n"
" wait-for-sync -- wait until the next sync starts, then exit\n"
+ " wait-for-end -- wait until the next sync finishes, then exit\n"
+ " sync-and-wait -- start sync, wait until it finishes, then exit\n"
);
exit(1);
}
@@ -84,17 +94,23 @@ int main(int argc, const char *argv[])
{
int returnCode = 0;
-#if defined WIN32 && ! defined NDEBUG
- ::openlog("Box Backup (bbackupctl)", 0, 0);
-#endif
-
MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupctl.memleaks",
"bbackupctl")
MAINHELPER_START
- // Filename for configuraiton file?
- const char *configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG;
+#if defined WIN32 && ! defined NDEBUG
+ ::openlog("Box Backup (bbackupctl)", 0, 0);
+#endif
+
+ // Filename for configuration file?
+ std::string configFilename;
+
+ #ifdef WIN32
+ configFilename = BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE;
+ #else
+ configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG;
+ #endif
// Quiet?
bool quiet = false;
@@ -131,12 +147,16 @@ int main(int argc, const char *argv[])
}
// Read in the configuration file
- if(!quiet) printf("Using configuration file %s\n", configFilename);
+ if(!quiet) BOX_NOTICE("Using configuration file " << configFilename);
+
std::string errs;
- std::auto_ptr<Configuration> config(Configuration::LoadAndVerify(configFilename, &BackupDaemonConfigVerify, errs));
+ std::auto_ptr<Configuration> config(
+ Configuration::LoadAndVerify
+ (configFilename, &BackupDaemonConfigVerify, errs));
+
if(config.get() == 0 || !errs.empty())
{
- printf("Invalid configuration file:\n%s", errs.c_str());
+ BOX_ERROR("Invalid configuration file: " << errs);
return 1;
}
// Easier coding
@@ -145,7 +165,10 @@ int main(int argc, const char *argv[])
// Check there's a socket defined in the config file
if(!conf.KeyExists("CommandSocket"))
{
- printf("Daemon isn't using a control socket, could not execute command.\nAdd a CommandSocket declaration to the bbackupd.conf file.\n");
+ BOX_ERROR("Daemon isn't using a control socket, "
+ "could not execute command.\n"
+ "Add a CommandSocket declaration to the "
+ "bbackupd.conf file.");
return 1;
}
@@ -160,25 +183,22 @@ int main(int argc, const char *argv[])
try
{
#ifdef WIN32
- connection.Connect(BOX_NAMED_PIPE_NAME);
+ std::string socket = conf.GetKeyValue("CommandSocket");
+ connection.Connect(socket);
#else
connection.Open(Socket::TypeUNIX, conf.GetKeyValue("CommandSocket").c_str());
#endif
}
catch(...)
{
- printf("Failed to connect to daemon control socket.\n"
+ BOX_ERROR("Failed to connect to daemon control socket.\n"
"Possible causes:\n"
" * Daemon not running\n"
" * Daemon busy syncing with store server\n"
" * Another bbackupctl process is communicating with the daemon\n"
- " * Daemon is waiting to recover from an error\n"
+ " * Daemon is waiting to recover from an error"
);
-#if defined WIN32 && ! defined NDEBUG
- syslog(LOG_ERR,"Failed to connect to the command socket");
-#endif
-
return 1;
}
@@ -189,29 +209,16 @@ int main(int argc, const char *argv[])
std::string configSummary;
if(!getLine.GetLine(configSummary))
{
-#if defined WIN32 && ! defined NDEBUG
- syslog(LOG_ERR, "Failed to receive configuration summary "
+ BOX_ERROR("Failed to receive configuration summary "
"from daemon");
-#else
- printf("Failed to receive configuration summary from daemon\n");
-#endif
-
return 1;
}
// Was the connection rejected by the server?
if(getLine.IsEOF())
{
-#if defined WIN32 && ! defined NDEBUG
- syslog(LOG_ERR, "Server rejected the connection. "
- "Are you running bbackupctl as the same user "
- "as the daemon?");
-#else
- printf("Server rejected the connection. "
- "Are you running bbackupctl as the same user "
- "as the daemon?\n");
-#endif
-
+ BOX_ERROR("Server rejected the connection. Are you running "
+ "bbackupctl as the same user as the daemon?");
return 1;
}
@@ -220,74 +227,163 @@ int main(int argc, const char *argv[])
if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", &autoBackup,
&updateStoreInterval, &minimumFileAge, &maxUploadWait) != 4)
{
- printf("Config summary didn't decode\n");
+ BOX_ERROR("Config summary didn't decode.");
return 1;
}
// Print summary?
if(!quiet)
{
- printf("Daemon configuration summary:\n" \
- " AutomaticBackup = %s\n" \
- " UpdateStoreInterval = %d seconds\n" \
- " MinimumFileAge = %d seconds\n" \
- " MaxUploadWait = %d seconds\n",
- autoBackup?"true":"false", updateStoreInterval, minimumFileAge, maxUploadWait);
+ BOX_INFO("Daemon configuration summary:\n"
+ " AutomaticBackup = " <<
+ (autoBackup?"true":"false") << "\n"
+ " UpdateStoreInterval = " << updateStoreInterval <<
+ " seconds\n"
+ " MinimumFileAge = " << minimumFileAge << " seconds\n"
+ " MaxUploadWait = " << maxUploadWait << " seconds");
}
- // Is the command the "wait for sync to start" command?
- bool areWaitingForSync = false;
- if(::strcmp(argv[0], "wait-for-sync") == 0)
+ std::string stateLine;
+ if(!getLine.GetLine(stateLine) || getLine.IsEOF())
{
- // Check that it's not in non-automatic mode, because then it'll never start
- if(!autoBackup)
- {
- printf("ERROR: Daemon is not in automatic mode -- sync will never start!\n");
- return 1;
- }
-
- // Yes... set the flag so we know what we're waiting for a sync to start
- areWaitingForSync = true;
+ BOX_ERROR("Failed to receive state line from daemon");
+ return 1;
+ }
+
+ // Decode it
+ int currentState;
+ if(::sscanf(stateLine.c_str(), "state %d", &currentState) != 1)
+ {
+ BOX_ERROR("Received invalid state line from daemon");
+ return 1;
+ }
+
+ Command command = Default;
+ std::string commandName(argv[0]);
+
+ if (commandName == "wait-for-sync")
+ {
+ command = WaitForSyncStart;
}
- else
+ else if (commandName == "wait-for-end")
{
- // No? Just send the command given plus a quit command.
- std::string cmd(argv[0]);
- cmd += "\nquit\n";
- connection.Write(cmd.c_str(), cmd.size());
+ command = WaitForSyncEnd;
+ }
+ else if (commandName == "sync-and-wait")
+ {
+ command = SyncAndWaitForEnd;
+ }
+
+ switch (command)
+ {
+ case WaitForSyncStart:
+ case WaitForSyncEnd:
+ {
+ // Check that it's in automatic mode,
+ // because otherwise it'll never start
+
+ if(!autoBackup)
+ {
+ BOX_ERROR("Daemon is not in automatic mode, "
+ "sync will never start!");
+ return 1;
+ }
+
+ }
+ break;
+
+ case SyncAndWaitForEnd:
+ {
+ // send a sync command
+ std::string cmd("force-sync\n");
+ connection.Write(cmd.c_str(), cmd.size());
+ connection.WriteAllBuffered();
+
+ if (currentState != 0)
+ {
+ BOX_INFO("Waiting for current sync/error state "
+ "to finish...");
+ }
+ }
+ break;
+
+ default:
+ {
+ // Normal case, just send the command given
+ // plus a quit command.
+ std::string cmd = commandName;
+ cmd += "\nquit\n";
+ connection.Write(cmd.c_str(), cmd.size());
+ }
}
// Read the response
std::string line;
- while(!getLine.IsEOF() && getLine.GetLine(line))
+ bool syncIsRunning = false;
+ bool finished = false;
+
+ while(!finished && !getLine.IsEOF() && getLine.GetLine(line))
{
- if(areWaitingForSync)
+ switch (command)
{
- // Need to wait for the state change...
- if(line == "start-sync")
+ case WaitForSyncStart:
{
- // Send a quit command to finish nicely
- connection.Write("quit\n", 5);
-
- // And we're done
- break;
- }
- }
- else
- {
- // Is this an OK or error line?
- if(line == "ok")
+ // Need to wait for the state change...
+ if(line == "start-sync")
+ {
+ // Send a quit command to finish nicely
+ connection.Write("quit\n", 5);
+
+ // And we're done
+ finished = true;
+ }
+ }
+ break;
+
+ case WaitForSyncEnd:
+ case SyncAndWaitForEnd:
{
- if(!quiet)
+ if(line == "start-sync")
+ {
+ if (!quiet) BOX_INFO("Sync started...");
+ syncIsRunning = true;
+ }
+ else if(line == "finish-sync")
{
- printf("Succeeded.\n");
+ if (syncIsRunning)
+ {
+ if (!quiet) BOX_INFO("Sync finished.");
+ // Send a quit command to finish nicely
+ connection.Write("quit\n", 5);
+
+ // And we're done
+ finished = true;
+ }
+ else
+ {
+ if (!quiet) BOX_INFO("Previous sync finished.");
+ }
+ // daemon must still be busy
}
- break;
}
- else if(line == "error")
+ break;
+
+ default:
{
- printf("ERROR. (Check command spelling)\n");
- returnCode = 1;
- break;
+ // Is this an OK or error line?
+ if(line == "ok")
+ {
+ if(!quiet)
+ {
+ BOX_INFO("Succeeded.");
+ }
+ finished = true;
+ }
+ else if(line == "error")
+ {
+ BOX_ERROR("Check command spelling");
+ returnCode = 1;
+ finished = true;
+ }
}
}
}
diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp
index 2445b077..ee8ffdd7 100644
--- a/bin/bbackupd/BackupClientContext.cpp
+++ b/bin/bbackupd/BackupClientContext.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -47,12 +47,10 @@
#include "Box.h"
-#ifdef HAVE_SYSLOG_H
- #include <syslog.h>
-#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
+
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -67,19 +65,28 @@
#include "BackupDaemon.h"
#include "autogen_BackupProtocolClient.h"
#include "BackupStoreFile.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupClientContext::BackupClientContext(BackupDaemon &, TLSContext &, const std::string &, int32_t, bool)
+// Name: BackupClientContext::BackupClientContext(BackupDaemon &, TLSContext &, const std::string &, int32_t, bool, bool, std::string)
// Purpose: Constructor
// Created: 2003/10/08
//
// --------------------------------------------------------------------------
-BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLSContext, const std::string &rHostname,
- int32_t AccountNumber, bool ExtendedLogging)
+BackupClientContext::BackupClientContext
+(
+ BackupDaemon &rDaemon,
+ TLSContext &rTLSContext,
+ const std::string &rHostname,
+ int32_t AccountNumber,
+ bool ExtendedLogging,
+ bool ExtendedLogToFile,
+ std::string ExtendedLogFile
+)
: mrDaemon(rDaemon),
mrTLSContext(rTLSContext),
mHostname(rHostname),
@@ -87,6 +94,9 @@ BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLS
mpSocket(0),
mpConnection(0),
mExtendedLogging(ExtendedLogging),
+ mExtendedLogToFile(ExtendedLogToFile),
+ mExtendedLogFile(ExtendedLogFile),
+ mpExtendedLogFileHandle(NULL),
mClientStoreMarker(ClientStoreMarker_NotKnown),
mpDeleteList(0),
mpCurrentIDMap(0),
@@ -94,8 +104,8 @@ BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLS
mStorageLimitExceeded(false),
mpExcludeFiles(0),
mpExcludeDirs(0),
- mbIsManaged(false),
- mTimeMgmtEpoch(0)
+ mKeepAliveTimer(0),
+ mbIsManaged(false)
{
}
@@ -153,7 +163,8 @@ BackupProtocolClient &BackupClientContext::GetConnection()
}
// Log intention
- ::syslog(LOG_INFO, "Opening connection to server %s...", mHostname.c_str());
+ BOX_INFO("Opening connection to server '" <<
+ mHostname << "'...");
// Connect!
mpSocket->Open(mrTLSContext, Socket::TypeINET, mHostname.c_str(), BOX_PORT_BBSTORED);
@@ -164,6 +175,24 @@ BackupProtocolClient &BackupClientContext::GetConnection()
// Set logging option
mpConnection->SetLogToSysLog(mExtendedLogging);
+ if (mExtendedLogToFile)
+ {
+ ASSERT(mpExtendedLogFileHandle == NULL);
+
+ mpExtendedLogFileHandle = fopen(
+ mExtendedLogFile.c_str(), "a+");
+
+ if (!mpExtendedLogFileHandle)
+ {
+ BOX_ERROR("Failed to open extended log "
+ "file: " << strerror(errno));
+ }
+ else
+ {
+ mpConnection->SetLogToFile(mpExtendedLogFileHandle);
+ }
+ }
+
// Handshake
mpConnection->Handshake();
@@ -202,19 +231,16 @@ BackupProtocolClient &BackupClientContext::GetConnection()
}
// Log success
- ::syslog(LOG_INFO, "Connection made, login successful");
+ BOX_INFO("Connection made, login successful");
// Check to see if there is any space available on the server
- int64_t softLimit = loginConf->GetBlocksSoftLimit();
- int64_t hardLimit = loginConf->GetBlocksHardLimit();
- // Threshold for uploading new stuff
- int64_t stopUploadThreshold = softLimit + ((hardLimit - softLimit) / 3);
- if(loginConf->GetBlocksUsed() > stopUploadThreshold)
+ if(loginConf->GetBlocksUsed() >= loginConf->GetBlocksHardLimit())
{
// no -- flag so only things like deletions happen
mStorageLimitExceeded = true;
// Log
- ::syslog(LOG_INFO, "Exceeded storage limits on server -- not uploading changes to files");
+ BOX_WARNING("Exceeded storage hard-limit on server, "
+ "not uploading changes to files");
}
}
catch(...)
@@ -294,6 +320,12 @@ void BackupClientContext::CloseAnyOpenConnection()
delete mpDeleteList;
mpDeleteList = 0;
}
+
+ if (mpExtendedLogFileHandle != NULL)
+ {
+ fclose(mpExtendedLogFileHandle);
+ mpExtendedLogFileHandle = NULL;
+ }
}
@@ -341,8 +373,8 @@ BackupClientDeleteList &BackupClientContext::GetDeleteList()
// --------------------------------------------------------------------------
//
// Function
-// Name:
-// Purpose:
+// Name: BackupClientContext::PerformDeletions()
+// Purpose: Perform any pending file deletions.
// Created: 10/11/03
//
// --------------------------------------------------------------------------
@@ -499,35 +531,18 @@ bool BackupClientContext::FindFilename(int64_t ObjectID, int64_t ContainingDirec
return true;
}
-
-// maximum time to spend diffing
-static int sMaximumDiffTime = 600;
-// maximum time of SSL inactivity (keep-alive interval)
-static int sKeepAliveTime = 0;
-
void BackupClientContext::SetMaximumDiffingTime(int iSeconds)
{
- sMaximumDiffTime = iSeconds < 0 ? 0 : iSeconds;
- TRACE1("Set maximum diffing time to %d seconds\n", sMaximumDiffTime);
+ mMaximumDiffingTime = iSeconds < 0 ? 0 : iSeconds;
+ BOX_TRACE("Set maximum diffing time to " << mMaximumDiffingTime <<
+ " seconds");
}
void BackupClientContext::SetKeepAliveTime(int iSeconds)
{
- sKeepAliveTime = iSeconds < 0 ? 0 : iSeconds;
- TRACE1("Set keep-alive time to %d seconds\n", sKeepAliveTime);
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: static TimerSigHandler(int)
-// Purpose: Signal handler
-// Created: 19/3/04
-//
-// --------------------------------------------------------------------------
-static void TimerSigHandler(int iUnused)
-{
- BackupStoreFile::DiffTimerExpired();
+ mKeepAliveTime = iSeconds < 0 ? 0 : iSeconds;
+ BOX_TRACE("Set keep-alive time to " << mKeepAliveTime << " seconds");
+ mKeepAliveTimer = Timer(mKeepAliveTime);
}
// --------------------------------------------------------------------------
@@ -540,59 +555,8 @@ static void TimerSigHandler(int iUnused)
// --------------------------------------------------------------------------
void BackupClientContext::ManageDiffProcess()
{
- if (mbIsManaged || !mpConnection)
- return;
-
- ASSERT(mTimeMgmtEpoch == 0);
-
-#ifdef PLATFORM_CYGWIN
- ::signal(SIGALRM, TimerSigHandler);
-#elif defined WIN32
- // no support for SIGVTALRM
- SetTimerHandler(TimerSigHandler);
-#else
- ::signal(SIGVTALRM, TimerSigHandler);
-#endif // PLATFORM_CYGWIN
-
- struct itimerval timeout;
- memset(&timeout, 0, sizeof(timeout));
-
- //
- //
- //
- if (sMaximumDiffTime <= 0 && sKeepAliveTime <= 0)
- {
- TRACE0("Diff control not requested - letting things run wild\n");
- return;
- }
- else if (sMaximumDiffTime > 0 && sKeepAliveTime > 0)
- {
- timeout.it_value.tv_sec = sKeepAliveTime < sMaximumDiffTime ? sKeepAliveTime : sMaximumDiffTime;
- timeout.it_interval.tv_sec = sKeepAliveTime < sMaximumDiffTime ? sKeepAliveTime : sMaximumDiffTime;
- }
- else
- {
- timeout.it_value.tv_sec = sKeepAliveTime > 0 ? sKeepAliveTime : sMaximumDiffTime;
- timeout.it_interval.tv_sec = sKeepAliveTime > 0 ? sKeepAliveTime : sMaximumDiffTime;
- }
-
- // avoid race
- mTimeMgmtEpoch = time(NULL);
-
-#ifdef PLATFORM_CYGWIN
- if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0)
-#else
- if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0)
-#endif // PLATFORM_CYGWIN
- {
- mTimeMgmtEpoch = 0;
-
- TRACE0("WARNING: couldn't set file diff control timeout\n");
- THROW_EXCEPTION(BackupStoreException, Internal)
- }
-
+ ASSERT(!mbIsManaged);
mbIsManaged = true;
- TRACE0("Initiated timer for file diff control\n");
}
// --------------------------------------------------------------------------
@@ -605,33 +569,16 @@ void BackupClientContext::ManageDiffProcess()
// --------------------------------------------------------------------------
void BackupClientContext::UnManageDiffProcess()
{
- if (!mbIsManaged /* don't test for active connection, just do it */)
- return;
-
- struct itimerval timeout;
- memset(&timeout, 0, sizeof(timeout));
-
-#ifdef PLATFORM_CYGWIN
- if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0)
-#else
- if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0)
-#endif // PLATFORM_CYGWIN
- {
- TRACE0("WARNING: couldn't clear file diff control timeout\n");
- THROW_EXCEPTION(BackupStoreException, Internal)
- }
-
+ // ASSERT(mbIsManaged);
mbIsManaged = false;
- mTimeMgmtEpoch = 0;
-
- TRACE0("Suspended timer for file diff control\n");
}
// --------------------------------------------------------------------------
//
// Function
// Name: BackupClientContext::DoKeepAlive()
-// Purpose: Does something inconsequential over the SSL link to keep it up
+// Purpose: Check whether it's time to send a KeepAlive
+// message over the SSL link, and if so, send it.
// Created: 04/19/2005
//
// --------------------------------------------------------------------------
@@ -639,33 +586,26 @@ void BackupClientContext::DoKeepAlive()
{
if (!mpConnection)
{
- ::syslog(LOG_ERR, "DoKeepAlive() called with no connection!");
+ return;
+ }
+
+ if (mKeepAliveTime == 0)
+ {
return;
}
+ if (!mKeepAliveTimer.HasExpired())
+ {
+ return;
+ }
+
+ BOX_TRACE("KeepAliveTime reached, sending keep-alive message");
mpConnection->QueryGetIsAlive();
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupClientContext::GetTimeMgmtEpoch()
-// Purpose: Returns the unix time when the diff was started, or zero
-// if the diff process is unmanaged.
-// Created: 04/19/2005
-//
-// --------------------------------------------------------------------------
-time_t BackupClientContext::GetTimeMgmtEpoch()
-{
- return mTimeMgmtEpoch;
+
+ mKeepAliveTimer = Timer(mKeepAliveTime);
}
int BackupClientContext::GetMaximumDiffingTime()
{
- return sMaximumDiffTime;
-}
-
-int BackupClientContext::GetKeepaliveTime()
-{
- return sKeepAliveTime;
+ return mMaximumDiffingTime;
}
diff --git a/bin/bbackupd/BackupClientContext.h b/bin/bbackupd/BackupClientContext.h
index d41dc78a..7d42a93e 100644
--- a/bin/bbackupd/BackupClientContext.h
+++ b/bin/bbackupd/BackupClientContext.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -52,6 +52,7 @@
#include "BackupClientDeleteList.h"
#include "BackupStoreFile.h"
#include "ExcludeList.h"
+#include "Timer.h"
class TLSContext;
class BackupProtocolClient;
@@ -73,8 +74,16 @@ class BackupStoreFilenameClear;
class BackupClientContext : public DiffTimer
{
public:
- BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLSContext, const std::string &rHostname,
- int32_t AccountNumber, bool ExtendedLogging);
+ BackupClientContext
+ (
+ BackupDaemon &rDaemon,
+ TLSContext &rTLSContext,
+ const std::string &rHostname,
+ int32_t AccountNumber,
+ bool ExtendedLogging,
+ bool ExtendedLogToFile,
+ std::string ExtendedLogFile
+ );
virtual ~BackupClientContext();
private:
BackupClientContext(const BackupClientContext &);
@@ -181,7 +190,7 @@ public:
// Created: 04/19/2005
//
// --------------------------------------------------------------------------
- static void SetMaximumDiffingTime(int iSeconds);
+ void SetMaximumDiffingTime(int iSeconds);
// --------------------------------------------------------------------------
//
@@ -191,7 +200,7 @@ public:
// Created: 04/19/2005
//
// --------------------------------------------------------------------------
- static void SetKeepAliveTime(int iSeconds);
+ void SetKeepAliveTime(int iSeconds);
// --------------------------------------------------------------------------
//
@@ -213,19 +222,18 @@ public:
// --------------------------------------------------------------------------
void UnManageDiffProcess();
- // --------------------------------------------------------------------------
+ // -------------------------------------------------------------------
//
// Function
// Name: BackupClientContext::DoKeepAlive()
- // Purpose: Does something inconsequential over the SSL link to
- // keep it up, implements DiffTimer interface
+ // Purpose: Check whether it's time to send a KeepAlive
+ // message over the SSL link, and if so, send it.
// Created: 04/19/2005
//
- // --------------------------------------------------------------------------
+ // -------------------------------------------------------------------
virtual void DoKeepAlive();
- virtual time_t GetTimeMgmtEpoch();
virtual int GetMaximumDiffingTime();
- virtual int GetKeepaliveTime();
+ virtual bool IsManaged() { return mbIsManaged; }
private:
BackupDaemon &mrDaemon;
@@ -235,6 +243,9 @@ private:
SocketStreamTLS *mpSocket;
BackupProtocolClient *mpConnection;
bool mExtendedLogging;
+ bool mExtendedLogToFile;
+ std::string mExtendedLogFile;
+ FILE* mpExtendedLogFileHandle;
int64_t mClientStoreMarker;
BackupClientDeleteList *mpDeleteList;
const BackupClientInodeToIDMap *mpCurrentIDMap;
@@ -242,11 +253,10 @@ private:
bool mStorageLimitExceeded;
ExcludeList *mpExcludeFiles;
ExcludeList *mpExcludeDirs;
-
+ Timer mKeepAliveTimer;
bool mbIsManaged;
- // unix time when diff was started
- time_t mTimeMgmtEpoch;
+ int mKeepAliveTime;
+ int mMaximumDiffingTime;
};
-
#endif // BACKUPCLIENTCONTEXT__H
diff --git a/bin/bbackupd/BackupClientDeleteList.cpp b/bin/bbackupd/BackupClientDeleteList.cpp
index 30f8ab47..2e154b50 100644
--- a/bin/bbackupd/BackupClientDeleteList.cpp
+++ b/bin/bbackupd/BackupClientDeleteList.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbackupd/BackupClientDeleteList.h b/bin/bbackupd/BackupClientDeleteList.h
index 5a6fc212..71a668a5 100644
--- a/bin/bbackupd/BackupClientDeleteList.h
+++ b/bin/bbackupd/BackupClientDeleteList.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp
index cccf2f9b..0d3300cb 100644
--- a/bin/bbackupd/BackupClientDirectoryRecord.cpp
+++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -67,6 +67,9 @@
#include "BackupDaemon.h"
#include "BackupStoreException.h"
#include "Archive.h"
+#include "PathUtils.h"
+#include "Logging.h"
+#include "ReadLoggingStream.h"
#include "MemLeakFindOn.h"
@@ -175,8 +178,8 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
{
// The directory has probably been deleted, so just ignore this error.
// In a future scan, this deletion will be noticed, deleted from server, and this object deleted.
- TRACE1("Stat failed for '%s' (directory)\n",
- rLocalPath.c_str());
+ rParams.GetProgressNotifier().NotifyDirStatFailed(
+ this, rLocalPath, strerror(errno));
return;
}
// Store inode number in map so directories are tracked in case they're renamed
@@ -204,15 +207,48 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
std::vector<std::string> dirs;
std::vector<std::string> files;
bool downloadDirectoryRecordBecauseOfFutureFiles = false;
+
+ struct stat dir_st;
+ if(::lstat(rLocalPath.c_str(), &dir_st) != 0)
+ {
+ // Report the error (logs and
+ // eventual email to administrator)
+ rParams.GetProgressNotifier().NotifyFileStatFailed(this,
+ rLocalPath, strerror(errno));
+
+ // FIXME move to NotifyFileStatFailed()
+ SetErrorWhenReadingFilesystemObject(rParams,
+ rLocalPath.c_str());
+
+ // This shouldn't happen, so we'd better not continue
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
// BLOCK
{
// read the contents...
DIR *dirHandle = 0;
try
{
+ rParams.GetProgressNotifier().NotifyScanDirectory(
+ this, rLocalPath);
+
dirHandle = ::opendir(rLocalPath.c_str());
if(dirHandle == 0)
{
+ // Report the error (logs and
+ // eventual email to administrator)
+ if (errno == EACCES)
+ {
+ rParams.GetProgressNotifier().NotifyDirListFailed(
+ this, rLocalPath, "Access denied");
+ }
+ else
+ {
+ rParams.GetProgressNotifier().NotifyDirListFailed(this,
+ rLocalPath, strerror(errno));
+ }
+
// Report the error (logs and eventual email to administrator)
SetErrorWhenReadingFilesystemObject(rParams, rLocalPath.c_str());
// Ignore this directory for now.
@@ -234,6 +270,8 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
std::string filename;
while((en = ::readdir(dirHandle)) != 0)
{
+ rParams.mrContext.DoKeepAlive();
+
// Don't need to use LinuxWorkaround_FinishDirentStruct(en, rLocalPath.c_str());
// on Linux, as a stat is performed to get all this info
@@ -245,13 +283,28 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
}
// Stat file to get info
- filename = rLocalPath + DIRECTORY_SEPARATOR +
- en->d_name;
+ filename = MakeFullPath(rLocalPath, en->d_name);
+ #ifdef WIN32
+ // Don't stat the file just yet, to ensure
+ // that users can exclude unreadable files
+ // to suppress warnings that they are
+ // not accessible.
+ //
+ // Our emulated readdir() abuses en->d_type,
+ // which would normally contain DT_REG,
+ // DT_DIR, etc, but we only use it here and
+ // prefer S_IFREG, S_IFDIR...
+ int type = en->d_type;
+ #else
if(::lstat(filename.c_str(), &st) != 0)
{
// Report the error (logs and
// eventual email to administrator)
+ rParams.GetProgressNotifier().NotifyFileStatFailed(this,
+ filename, strerror(errno));
+
+ // FIXME move to NotifyFileStatFailed()
SetErrorWhenReadingFilesystemObject(
rParams, filename.c_str());
@@ -259,7 +312,17 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
continue;
}
+ if(st.st_dev != dir_st.st_dev)
+ {
+ rParams.GetProgressNotifier()
+ .NotifyMountPointSkipped(this,
+ filename);
+ continue;
+ }
+
int type = st.st_mode & S_IFMT;
+ #endif
+
if(type == S_IFREG || type == S_IFLNK)
{
// File or symbolic link
@@ -267,6 +330,11 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
// Exclude it?
if(rParams.mrContext.ExcludeFile(filename))
{
+ rParams.GetProgressNotifier()
+ .NotifyFileExcluded(
+ this,
+ filename);
+
// Next item!
continue;
}
@@ -281,6 +349,11 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
// Exclude it?
if(rParams.mrContext.ExcludeDir(filename))
{
+ rParams.GetProgressNotifier()
+ .NotifyDirExcluded(
+ this,
+ filename);
+
// Next item!
continue;
}
@@ -290,11 +363,56 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
}
else
{
+ if(rParams.mrContext.ExcludeFile(filename))
+ {
+ rParams.GetProgressNotifier()
+ .NotifyFileExcluded(
+ this,
+ filename);
+ }
+ else
+ {
+ rParams.GetProgressNotifier()
+ .NotifyUnsupportedFileType(
+ this, filename);
+ SetErrorWhenReadingFilesystemObject(
+ rParams, filename.c_str());
+ }
+
continue;
}
// Here if the object is something to back up (file, symlink or dir, not excluded)
// So make the information for adding to the checksum
+
+ #ifdef WIN32
+ // We didn't stat the file before,
+ // but now we need the information.
+ if(::lstat(filename.c_str(), &st) != 0)
+ {
+ rParams.GetProgressNotifier()
+ .NotifyFileStatFailed(this,
+ filename,
+ strerror(errno));
+
+ // Report the error (logs and
+ // eventual email to administrator)
+ SetErrorWhenReadingFilesystemObject(
+ rParams, filename.c_str());
+
+ // Ignore this entry for now.
+ continue;
+ }
+
+ if(st.st_dev != dir_st.st_dev)
+ {
+ rParams.GetProgressNotifier()
+ .NotifyMountPointSkipped(this,
+ filename);
+ continue;
+ }
+ #endif
+
checksum_info.mModificationTime = FileModificationTime(st);
checksum_info.mAttributeModificationTime = FileAttrModificationTime(st);
checksum_info.mSize = st.st_size;
@@ -310,8 +428,8 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn
// Log that this has happened
if(!rParams.mHaveLoggedWarningAboutFutureFileTimes)
{
- ::syslog(LOG_ERR, "Some files have modification times excessively in the future. Check clock syncronisation.\n");
- ::syslog(LOG_ERR, "Example file (only one shown) : %s\n", filename.c_str());
+ rParams.GetProgressNotifier().NotifyFileModifiedInFuture(
+ this, filename);
rParams.mHaveLoggedWarningAboutFutureFileTimes = true;
}
}
@@ -549,8 +667,11 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
for(std::vector<std::string>::const_iterator f = rFiles.begin();
f != rFiles.end(); ++f)
{
+ // Send keep-alive message if needed
+ rParams.mrContext.DoKeepAlive();
+
// Filename of this file
- std::string filename(rLocalPath + DIRECTORY_SEPARATOR + *f);
+ std::string filename(MakeFullPath(rLocalPath, *f));
// Get relevant info about file
box_time_t modTime = 0;
@@ -564,7 +685,16 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
struct stat st;
if(::lstat(filename.c_str(), &st) != 0)
{
- THROW_EXCEPTION(CommonException, OSFileError)
+ rParams.GetProgressNotifier().NotifyFileStatFailed(this,
+ filename, strerror(errno));
+
+ // Report the error (logs and
+ // eventual email to administrator)
+ SetErrorWhenReadingFilesystemObject(rParams,
+ filename.c_str());
+
+ // Ignore this entry for now.
+ continue;
}
// Extract required data
@@ -683,34 +813,94 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
// Need to update?
//
// Condition for upload:
- // modifiction time within sync period
+ // modification time within sync period
// if it's been seen before but not uploaded, is the time from this first sight longer than the MaxUploadWait
// and if we know about it from a directory listing, that it hasn't got the same upload time as on the store
- if(
- (
- // Check the file modified within the acceptable time period we're checking
- // If the file isn't on the server, the acceptable time starts at zero.
- // Check pDirOnStore and en, because if we didn't download a directory listing,
- // pDirOnStore will be zero, but we know it's on the server.
- ( ((pDirOnStore != 0 && en == 0) || (modTime >= rParams.mSyncPeriodStart)) && modTime < rParams.mSyncPeriodEnd)
-
- // However, just in case things are continually modified, we check the first seen time.
- // The two compares of syncPeriodEnd and pendingFirstSeenTime are because the values are unsigned.
- || (pendingFirstSeenTime != 0 &&
- (rParams.mSyncPeriodEnd > pendingFirstSeenTime)
- && ((rParams.mSyncPeriodEnd - pendingFirstSeenTime) > rParams.mMaxUploadWait))
-
- // Then make sure that if files are added with a time less than the sync period start
- // (which can easily happen on file server), it gets uploaded. The directory contents checksum
- // will pick up the fact it has been added, so the store listing will be available when this happens.
- || ((modTime <= rParams.mSyncPeriodStart) && (en != 0) && (en->GetModificationTime() != modTime))
-
- // And just to catch really badly off clocks in the future for file server clients,
- // just upload the file if it's madly in the future.
- || (modTime > rParams.mUploadAfterThisTimeInTheFuture)
- )
- // But even then, only upload it if the mod time locally is different to that on the server.
- && (en == 0 || en->GetModificationTime() != modTime))
+
+ bool doUpload = false;
+
+ // Only upload a file if the mod time locally is
+ // different to that on the server.
+
+ if (en == 0 || en->GetModificationTime() != modTime)
+ {
+ // Check the file modified within the acceptable time period we're checking
+ // If the file isn't on the server, the acceptable time starts at zero.
+ // Check pDirOnStore and en, because if we didn't download a directory listing,
+ // pDirOnStore will be zero, but we know it's on the server.
+ if (modTime < rParams.mSyncPeriodEnd)
+ {
+ if (pDirOnStore != 0 && en == 0)
+ {
+ doUpload = true;
+ BOX_TRACE(filename << ": will upload "
+ "(not on server)");
+ }
+ else if (modTime >= rParams.mSyncPeriodStart)
+ {
+ doUpload = true;
+ BOX_TRACE(filename << ": will upload "
+ "(modified since last sync)");
+ }
+ }
+
+ // However, just in case things are continually
+ // modified, we check the first seen time.
+ // The two compares of syncPeriodEnd and
+ // pendingFirstSeenTime are because the values
+ // are unsigned.
+
+ if (!doUpload &&
+ pendingFirstSeenTime != 0 &&
+ rParams.mSyncPeriodEnd > pendingFirstSeenTime &&
+ (rParams.mSyncPeriodEnd - pendingFirstSeenTime)
+ > rParams.mMaxUploadWait)
+ {
+ doUpload = true;
+ BOX_TRACE(filename << ": will upload "
+ "(continually modified)");
+ }
+
+ // Then make sure that if files are added with a
+ // time less than the sync period start
+ // (which can easily happen on file server), it
+ // gets uploaded. The directory contents checksum
+ // will pick up the fact it has been added, so the
+ // store listing will be available when this happens.
+
+ if (!doUpload &&
+ modTime <= rParams.mSyncPeriodStart &&
+ en != 0 &&
+ en->GetModificationTime() != modTime)
+ {
+ doUpload = true;
+ BOX_TRACE(filename << ": will upload "
+ "(mod time changed)");
+ }
+
+ // And just to catch really badly off clocks in
+ // the future for file server clients,
+ // just upload the file if it's madly in the future.
+
+ if (!doUpload && modTime >
+ rParams.mUploadAfterThisTimeInTheFuture)
+ {
+ doUpload = true;
+ BOX_TRACE(filename << ": will upload "
+ "(mod time in the future)");
+ }
+ }
+
+ if (!doUpload)
+ {
+ BOX_TRACE(filename << ": will not upload "
+ "(no reason to upload, mod time is "
+ << modTime << " versus sync period "
+ << rParams.mSyncPeriodStart << " to "
+ << rParams.mSyncPeriodEnd << ")");
+ }
+
+ if (doUpload)
{
// Make sure we're connected -- must connect here so we know whether
// the storage limit has been exceeded, and hence whether or not
@@ -735,6 +925,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
{
// Connection errors should just be passed on to the main handler, retries
// would probably just cause more problems.
+ rParams.GetProgressNotifier()
+ .NotifyFileUploadException(
+ this, filename, e);
throw;
}
catch(BoxException &e)
@@ -743,8 +936,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
allUpdatedSuccessfully = false;
// Log it.
SetErrorWhenReadingFilesystemObject(rParams, filename.c_str());
- // Log error.
- ::syslog(LOG_ERR, "Error code when uploading was (%d/%d), %s", e.GetType(), e.GetSubType(), e.what());
+ rParams.GetProgressNotifier()
+ .NotifyFileUploadException(
+ this, filename, e);
}
// Update structures if the file was uploaded successfully.
@@ -757,6 +951,11 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
}
}
}
+ else
+ {
+ rParams.GetProgressNotifier().NotifyFileSkippedServerFull(this,
+ filename);
+ }
}
else if(en != 0 && en->GetAttributesHash() != attributesHash)
{
@@ -838,6 +1037,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
}
}
}
+
+ rParams.GetProgressNotifier().NotifyFileSynchronised(this,
+ filename, fileSize);
}
// Erase contents of files to save space when recursing
@@ -855,8 +1057,11 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
for(std::vector<std::string>::const_iterator d = rDirs.begin();
d != rDirs.end(); ++d)
{
+ // Send keep-alive message if needed
+ rParams.mrContext.DoKeepAlive();
+
// Get the local filename
- std::string dirname(rLocalPath + DIRECTORY_SEPARATOR + *d);
+ std::string dirname(MakeFullPath(rLocalPath, *d));
// See if it's in the listing (if we have one)
BackupStoreFilenameClear storeFilename(*d);
@@ -893,11 +1098,15 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
// In the list, just use this pointer
psubDirRecord = e->second;
}
- else if(!rParams.mrContext.StorageLimitExceeded()) // know we've got a connection if we get this far, as dir will have been modified.
+ else
{
- // Note: only think about adding directory records if there's space left on the server.
- // If there isn't, this step will be repeated when there is some available.
-
+ // Note: if we have exceeded our storage limit, then
+ // we should not upload any more data, nor create any
+ // DirectoryRecord representing data that would have
+ // been uploaded. This step will be repeated when
+ // there is some space available.
+ bool doCreateDirectoryRecord = true;
+
// Need to create the record. But do we need to create the directory on the server?
int64_t subDirObjectID = 0;
if(en != 0)
@@ -905,6 +1114,12 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
// No. Exists on the server, and we know about it from the listing.
subDirObjectID = en->GetObjectID();
}
+ else if(rParams.mrContext.StorageLimitExceeded())
+ // know we've got a connection if we get this far,
+ // as dir will have been modified.
+ {
+ doCreateDirectoryRecord = false;
+ }
else
{
// Yes, creation required!
@@ -987,20 +1202,23 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
haveJustCreatedDirOnServer = true;
}
}
-
- // New an object for this
- psubDirRecord = new BackupClientDirectoryRecord(subDirObjectID, *d);
-
- // Store in list
- try
- {
- mSubDirectories[*d] = psubDirRecord;
- }
- catch(...)
- {
- delete psubDirRecord;
- psubDirRecord = 0;
- throw;
+
+ if (doCreateDirectoryRecord)
+ {
+ // New an object for this
+ psubDirRecord = new BackupClientDirectoryRecord(subDirObjectID, *d);
+
+ // Store in list
+ try
+ {
+ mSubDirectories[*d] = psubDirRecord;
+ }
+ catch(...)
+ {
+ delete psubDirRecord;
+ psubDirRecord = 0;
+ throw;
+ }
}
}
@@ -1060,7 +1278,13 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP
BackupClientDirectoryRecord *rec = e->second;
mSubDirectories.erase(e);
delete rec;
- TRACE2("Deleted directory record for %s/%s\n", rLocalPath.c_str(), dirname.GetClearFilename().c_str());
+
+ std::string name = MakeFullPath(
+ rLocalPath,
+ dirname.GetClearFilename());
+
+ TRACE1("Deleted directory record for "
+ "%s\n", name.c_str());
}
}
}
@@ -1132,7 +1356,11 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn
if(diffFromID != 0)
{
- // Found an old version -- get the index
+ // Found an old version
+ rParams.GetProgressNotifier().NotifyFileUploadingPatch(this,
+ rFilename);
+
+ // Get the index
std::auto_ptr<IOStream> blockIndexStream(connection.ReceiveStream());
//
@@ -1168,9 +1396,13 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn
if(doNormalUpload)
{
// below threshold or nothing to diff from, so upload whole
+ rParams.GetProgressNotifier().NotifyFileUploading(this,
+ rFilename);
// Prepare to upload, getting a stream which will encode the file as we go along
- std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile(rFilename.c_str(), mObjectID, rStoreFilename));
+ std::auto_ptr<IOStream> upload(
+ BackupStoreFile::EncodeFile(rFilename.c_str(),
+ mObjectID, rStoreFilename));
// Send to store
std::auto_ptr<BackupProtocolClientSuccess> stored(
@@ -1190,14 +1422,20 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn
if(e.GetType() == ConnectionException::ExceptionType && e.GetSubType() == ConnectionException::Protocol_UnexpectedReply)
{
- // Check and see what error the protocol has -- as it might be an error...
+ // Check and see what error the protocol has,
+ // this is more useful to users than the exception.
int type, subtype;
- if(connection.GetLastError(type, subtype)
- && type == BackupProtocolClientError::ErrorType
- && subtype == BackupProtocolClientError::Err_StorageLimitExceeded)
+ if(connection.GetLastError(type, subtype))
{
- // The hard limit was exceeded on the server, notify!
- rParams.mrDaemon.NotifySysadmin(BackupDaemon::NotifyEvent_StoreFull);
+ if(type == BackupProtocolClientError::ErrorType
+ && subtype == BackupProtocolClientError::Err_StorageLimitExceeded)
+ {
+ // The hard limit was exceeded on the server, notify!
+ rParams.mrDaemon.NotifySysadmin(BackupDaemon::NotifyEvent_StoreFull);
+ }
+ rParams.GetProgressNotifier()
+ .NotifyFileUploadServerError(
+ this, rFilename, type, subtype);
}
}
@@ -1205,6 +1443,8 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn
throw;
}
+ rParams.GetProgressNotifier().NotifyFileUploaded(this, rFilename, FileSize);
+
// Return the new object ID of this file
return objID;
}
@@ -1224,8 +1464,11 @@ void BackupClientDirectoryRecord::SetErrorWhenReadingFilesystemObject(BackupClie
// Zero hash, so it gets synced properly next time round.
::memset(mStateChecksum, 0, sizeof(mStateChecksum));
- // Log the error
- ::syslog(LOG_ERR, "Backup object failed, error when reading %s", Filename);
+ // Log the error - already done by caller
+ /*
+ rParams.GetProgressNotifier().NotifyFileReadFailed(this,
+ Filename, strerror(errno));
+ */
// Mark that an error occured in the parameters object
rParams.mReadErrorsOnFilesystemObjects = true;
@@ -1241,8 +1484,10 @@ void BackupClientDirectoryRecord::SetErrorWhenReadingFilesystemObject(BackupClie
// Created: 8/3/04
//
// --------------------------------------------------------------------------
-BackupClientDirectoryRecord::SyncParams::SyncParams(BackupDaemon &rDaemon, BackupClientContext &rContext)
- : mSyncPeriodStart(0),
+BackupClientDirectoryRecord::SyncParams::SyncParams(BackupDaemon &rDaemon,
+ ProgressNotifier &rProgressNotifier, BackupClientContext &rContext)
+ : mrProgressNotifier(rProgressNotifier),
+ mSyncPeriodStart(0),
mSyncPeriodEnd(0),
mMaxUploadWait(0),
mMaxFileTimeInFuture(99999999999999999LL),
diff --git a/bin/bbackupd/BackupClientDirectoryRecord.h b/bin/bbackupd/BackupClientDirectoryRecord.h
index 2e192a96..3a33ed95 100644
--- a/bin/bbackupd/BackupClientDirectoryRecord.h
+++ b/bin/bbackupd/BackupClientDirectoryRecord.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -63,6 +63,82 @@ class BackupDaemon;
// --------------------------------------------------------------------------
//
// Class
+// Name: ProgressNotifier
+// Purpose: Provides methods for the backup library to inform the user
+// interface about its progress with the backup
+// Created: 2005/11/20
+//
+// --------------------------------------------------------------------------
+class BackupClientDirectoryRecord;
+
+class ProgressNotifier
+{
+ public:
+ virtual ~ProgressNotifier() { }
+ virtual void NotifyScanDirectory(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyDirStatFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg) = 0;
+ virtual void NotifyFileStatFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg) = 0;
+ virtual void NotifyDirListFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg) = 0;
+ virtual void NotifyMountPointSkipped(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileExcluded(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyDirExcluded(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyUnsupportedFileType(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileReadFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg) = 0;
+ virtual void NotifyFileModifiedInFuture(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileSkippedServerFull(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileUploadException(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const BoxException& rException) = 0;
+ virtual void NotifyFileUploadServerError(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int type, int subtype) = 0;
+ virtual void NotifyFileUploading(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileUploadingPatch(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileUploaded(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int64_t FileSize) = 0;
+ virtual void NotifyFileSynchronised(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int64_t FileSize) = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
// Name: BackupClientDirectoryRecord
// Purpose: Implementation of record about directory for backup client
// Created: 2003/10/08
@@ -97,14 +173,18 @@ public:
class SyncParams
{
public:
- SyncParams(BackupDaemon &rDaemon, BackupClientContext &rContext);
+ SyncParams(
+ BackupDaemon &rDaemon,
+ ProgressNotifier &rProgressNotifier,
+ BackupClientContext &rContext);
~SyncParams();
private:
// No copying
SyncParams(const SyncParams&);
SyncParams &operator=(const SyncParams&);
+ ProgressNotifier &mrProgressNotifier;
+
public:
-
// Data members are public, as accessors are not justified here
box_time_t mSyncPeriodStart;
box_time_t mSyncPeriodEnd;
@@ -119,6 +199,11 @@ public:
// Member variables modified by syncing process
box_time_t mUploadAfterThisTimeInTheFuture;
bool mHaveLoggedWarningAboutFutureFileTimes;
+
+ ProgressNotifier& GetProgressNotifier() const
+ {
+ return mrProgressNotifier;
+ }
};
void SyncDirectory(SyncParams &rParams, int64_t ContainingDirectoryID, const std::string &rLocalPath,
diff --git a/bin/bbackupd/BackupClientInodeToIDMap.cpp b/bin/bbackupd/BackupClientInodeToIDMap.cpp
index 5ffe98f9..eb2842b1 100644
--- a/bin/bbackupd/BackupClientInodeToIDMap.cpp
+++ b/bin/bbackupd/BackupClientInodeToIDMap.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbackupd/BackupClientInodeToIDMap.h b/bin/bbackupd/BackupClientInodeToIDMap.h
index fdf77cba..806bf964 100644
--- a/bin/bbackupd/BackupClientInodeToIDMap.h
+++ b/bin/bbackupd/BackupClientInodeToIDMap.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp
index 5db7cb8b..24fa0a24 100644
--- a/bin/bbackupd/BackupDaemon.cpp
+++ b/bin/bbackupd/BackupDaemon.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -56,9 +56,6 @@
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
-#ifdef HAVE_SYSLOG_H
- #include <syslog.h>
-#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
@@ -79,6 +76,8 @@
#include <process.h>
#endif
+#include <iostream>
+
#include "Configuration.h"
#include "IOStream.h"
#include "MemBlockStream.h"
@@ -97,6 +96,7 @@
#include "BackupStoreFilenameClear.h"
#include "BackupClientInodeToIDMap.h"
#include "autogen_BackupProtocolClient.h"
+#include "autogen_ConversionException.h"
#include "BackupClientCryptoKeys.h"
#include "BannerText.h"
#include "BackupStoreFile.h"
@@ -112,6 +112,16 @@
#include "IOStreamGetLine.h"
#include "Conversion.h"
#include "Archive.h"
+#include "Timer.h"
+#include "Logging.h"
+#include "autogen_ClientException.h"
+
+#ifdef WIN32
+ #include "Win32ServiceFunctions.h"
+ #include "Win32BackupService.h"
+
+ extern Win32BackupService* gpDaemonService;
+#endif
#include "MemLeakFindOn.h"
@@ -151,30 +161,51 @@ unsigned int WINAPI HelperThread(LPVOID lpParam)
BackupDaemon::BackupDaemon()
: mState(BackupDaemon::State_Initialising),
mpCommandSocketInfo(0),
- mDeleteUnusedRootDirEntriesAfter(0)
+ mDeleteUnusedRootDirEntriesAfter(0),
+ mLogAllFileAccess(false)
+ #ifdef WIN32
+ , mInstallService(false),
+ mRemoveService(false),
+ mRunAsService(false),
+ mServiceName("bbackupd")
+ #endif
{
// Only ever one instance of a daemon
SSLLib::Initialise();
- // Initialise notifcation sent status
- for(int l = 0; l <= NotifyEvent__MAX; ++l)
+ // Initialise notification sent status
+ for(int l = 0; l < NotifyEvent__MAX; ++l)
{
mNotificationsSent[l] = false;
}
-#ifdef WIN32
- // Create a thread to handle the named pipe
- HANDLE hThread;
- unsigned int dwThreadId;
-
- hThread = (HANDLE) _beginthreadex(
- NULL, // default security attributes
- 0, // use default stack size
- HelperThread, // thread function
- this, // argument to thread function
- 0, // use default creation flags
- &dwThreadId); // returns the thread identifier
-#endif
+ #ifdef WIN32
+ // Create the event object to signal from main thread to
+ // worker when new messages are queued to be sent to the
+ // command socket.
+
+ mhMessageToSendEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if(mhMessageToSendEvent == INVALID_HANDLE_VALUE)
+ {
+ BOX_ERROR("Failed to create event object: error " <<
+ GetLastError());
+ exit(1);
+ }
+
+ // Create the event object to signal from worker to main thread
+ // when a command has been received on the command socket.
+
+ mhCommandReceivedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if(mhCommandReceivedEvent == INVALID_HANDLE_VALUE)
+ {
+ BOX_ERROR("Failed to create event object: error " <<
+ GetLastError());
+ exit(1);
+ }
+
+ // Create the critical section to protect the message queue
+ InitializeCriticalSection(&mMessageQueueLock);
+ #endif
}
// --------------------------------------------------------------------------
@@ -219,13 +250,21 @@ const char *BackupDaemon::DaemonName() const
// Created: 1/1/04
//
// --------------------------------------------------------------------------
-const char *BackupDaemon::DaemonBanner() const
+std::string BackupDaemon::DaemonBanner() const
{
-#ifndef NDEBUG
- // Don't display banner in debug builds
- return 0;
-#else
return BANNER_TEXT("Backup Client");
+}
+
+void BackupDaemon::Usage()
+{
+ this->Daemon::Usage();
+
+#ifdef WIN32
+ std::cout <<
+ " -s Run as a Windows Service, for internal use only\n"
+ " -i Install Windows Service (you may want to specify a config file)\n"
+ " -r Remove Windows Service\n"
+ " -S <name> Service name for -i and -r options\n";
#endif
}
@@ -260,7 +299,7 @@ void BackupDaemon::SetupInInitialProcess()
// Print a warning on this platform if the CommandSocket is used.
if(GetConfiguration().KeyExists("CommandSocket"))
{
- printf(
+ BOX_WARNING(
"==============================================================================\n"
"SECURITY WARNING: This platform cannot check the credentials of connections to\n"
"the command socket. This is a potential DoS security problem.\n"
@@ -298,26 +337,133 @@ void BackupDaemon::DeleteAllLocations()
}
#ifdef WIN32
+std::string BackupDaemon::GetOptionString()
+{
+ std::string oldOpts = this->Daemon::GetOptionString();
+ ASSERT(oldOpts.find("s") == std::string::npos);
+ ASSERT(oldOpts.find("S") == std::string::npos);
+ ASSERT(oldOpts.find("i") == std::string::npos);
+ ASSERT(oldOpts.find("r") == std::string::npos);
+ return oldOpts + "sS:ir";
+}
+
+int BackupDaemon::ProcessOption(signed int option)
+{
+ switch(option)
+ {
+ case 's':
+ {
+ mRunAsService = true;
+ return 0;
+ }
+
+ case 'S':
+ {
+ mServiceName = optarg;
+ return 0;
+ }
+
+ case 'i':
+ {
+ mInstallService = true;
+ return 0;
+ }
+
+ case 'r':
+ {
+ mRemoveService = true;
+ return 0;
+ }
+
+ default:
+ {
+ return this->Daemon::ProcessOption(option);
+ }
+ }
+}
+
+int BackupDaemon::Main(const std::string &rConfigFileName)
+{
+ if (mInstallService)
+ {
+ return InstallService(rConfigFileName.c_str(), mServiceName);
+ }
+
+ if (mRemoveService)
+ {
+ return RemoveService(mServiceName);
+ }
+
+ Logging::SetProgramName("Box Backup (" + mServiceName + ")");
+
+ int returnCode;
+
+ if (mRunAsService)
+ {
+ // We will be called reentrantly by the Service Control
+ // Manager, and we had better not call OurService again!
+ mRunAsService = false;
+
+ BOX_INFO("Box Backup service starting");
+ returnCode = OurService(rConfigFileName.c_str());
+ BOX_INFO("Box Backup service shut down");
+ }
+ else
+ {
+ returnCode = this->Daemon::Main(rConfigFileName);
+ }
+
+ return returnCode;
+}
+
void BackupDaemon::RunHelperThread(void)
{
+ const Configuration &conf(GetConfiguration());
mpCommandSocketInfo = new CommandSocketInfo;
- this->mReceivedCommandConn = false;
+ WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket);
- // loop until the parent process exits
- while (TRUE)
+ // loop until the parent process exits, or we decide
+ // to kill the thread ourselves
+ while (!IsTerminateWanted())
{
try
{
- mpCommandSocketInfo->mListeningSocket.Accept(
- BOX_NAMED_PIPE_NAME);
+ std::string socket = conf.GetKeyValue("CommandSocket");
+ rSocket.Accept(socket);
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to open command socket: " <<
+ e.what());
+ SetTerminateWanted();
+ break; // this is fatal to listening thread
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to open command socket: " <<
+ e.what());
+ SetTerminateWanted();
+ break; // this is fatal to listening thread
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to open command socket: "
+ "unknown error");
+ SetTerminateWanted();
+ break; // this is fatal to listening thread
+ }
+
+ try
+ {
+ // Errors here do not kill the thread,
+ // only the current connection.
// This next section comes from Ben's original function
// Log
- ::syslog(LOG_INFO, "Connection from command socket");
+ BOX_INFO("Connection from command socket");
// Send a header line summarising the configuration
// and current state
- const Configuration &conf(GetConfiguration());
char summary[256];
size_t summarySize = sprintf(summary,
"bbackupd: %d %d %d %d\nstate %d\n",
@@ -327,17 +473,76 @@ void BackupDaemon::RunHelperThread(void)
conf.GetKeyValueInt("MaxUploadWait"),
mState);
- mpCommandSocketInfo->mListeningSocket.Write(summary, summarySize);
- mpCommandSocketInfo->mListeningSocket.Write("ping\n", 5);
+ rSocket.Write(summary, summarySize);
+ rSocket.Write("ping\n", 5);
+
+ // old queued messages are not useful
+ EnterCriticalSection(&mMessageQueueLock);
+ mMessageList.clear();
+ ResetEvent(mhMessageToSendEvent);
+ LeaveCriticalSection(&mMessageQueueLock);
- IOStreamGetLine readLine(mpCommandSocketInfo->mListeningSocket);
+ IOStreamGetLine readLine(rSocket);
std::string command;
- while (mpCommandSocketInfo->mListeningSocket.IsConnected() &&
- readLine.GetLine(command) )
+ while (rSocket.IsConnected() && !IsTerminateWanted())
{
- TRACE1("Receiving command '%s' over "
- "command socket\n", command.c_str());
+ HANDLE handles[2];
+ handles[0] = mhMessageToSendEvent;
+ handles[1] = rSocket.GetReadableEvent();
+
+ BOX_TRACE("Received command '" << command
+ << "' over command socket");
+
+ DWORD result = WaitForMultipleObjects(
+ sizeof(handles)/sizeof(*handles),
+ handles, FALSE, 1000);
+
+ if(result == 0)
+ {
+ ResetEvent(mhMessageToSendEvent);
+
+ EnterCriticalSection(&mMessageQueueLock);
+ try
+ {
+ while (mMessageList.size() > 0)
+ {
+ std::string message = *(mMessageList.begin());
+ mMessageList.erase(mMessageList.begin());
+ printf("Sending '%s' to waiting client... ", message.c_str());
+ message += "\n";
+ rSocket.Write(message.c_str(),
+ message.length());
+
+ printf("done.\n");
+ }
+ }
+ catch (...)
+ {
+ LeaveCriticalSection(&mMessageQueueLock);
+ throw;
+ }
+ LeaveCriticalSection(&mMessageQueueLock);
+ continue;
+ }
+ else if(result == WAIT_TIMEOUT)
+ {
+ continue;
+ }
+ else if(result != 1)
+ {
+ BOX_ERROR("WaitForMultipleObjects returned invalid result " << result);
+ continue;
+ }
+
+ if(!readLine.GetLine(command))
+ {
+ BOX_ERROR("Failed to read line");
+ continue;
+ }
+
+ BOX_INFO("Received command " << command <<
+ " from client");
bool sendOK = false;
bool sendResponse = true;
@@ -356,6 +561,7 @@ void BackupDaemon::RunHelperThread(void)
this->mDoSyncFlagOut = true;
this->mSyncIsForcedOut = false;
sendOK = true;
+ SetEvent(mhCommandReceivedEvent);
}
else if(command == "force-sync")
{
@@ -363,48 +569,65 @@ void BackupDaemon::RunHelperThread(void)
this->mDoSyncFlagOut = true;
this->mSyncIsForcedOut = true;
sendOK = true;
+ SetEvent(mhCommandReceivedEvent);
}
else if(command == "reload")
{
// Reload the configuration
SetReloadConfigWanted();
sendOK = true;
+ SetEvent(mhCommandReceivedEvent);
}
else if(command == "terminate")
{
// Terminate the daemon cleanly
SetTerminateWanted();
sendOK = true;
+ SetEvent(mhCommandReceivedEvent);
+ }
+ else
+ {
+ BOX_ERROR("Received unknown command "
+ "'" << command << "' "
+ "from client");
+ sendResponse = true;
+ sendOK = false;
}
// Send a response back?
- if (sendResponse)
+ if(sendResponse)
{
const char* response = sendOK ? "ok\n" : "error\n";
- mpCommandSocketInfo->mListeningSocket.Write(
+ rSocket.Write(
response, strlen(response));
}
- if (disconnect)
+ if(disconnect)
{
break;
}
-
- this->mReceivedCommandConn = true;
}
- mpCommandSocketInfo->mListeningSocket.Close();
+ rSocket.Close();
}
- catch (BoxException &e)
+ catch(BoxException &e)
+ {
+ BOX_ERROR("Communication error with "
+ "control client: " << e.what());
+ }
+ catch(std::exception &e)
{
- ::syslog(LOG_ERR, "Communication error with "
- "control client: %s", e.what());
+ BOX_ERROR("Internal error in command socket "
+ "thread: " << e.what());
}
- catch (...)
+ catch(...)
{
- ::syslog(LOG_ERR, "Communication error with control client");
+ BOX_ERROR("Communication error with control client");
}
}
+
+ CloseHandle(mhCommandReceivedEvent);
+ CloseHandle(mhMessageToSendEvent);
}
#endif
@@ -418,35 +641,39 @@ void BackupDaemon::RunHelperThread(void)
// --------------------------------------------------------------------------
void BackupDaemon::Run()
{
-#ifdef WIN32
- // init our own timer for file diff timeouts
- InitTimer();
-
- try
- {
- Run2();
- }
- catch(...)
- {
- FiniTimer();
- throw;
- }
-
- FiniTimer();
-#else // ! WIN32
- // Ignore SIGPIPE (so that if a command connection is broken, the daemon doesn't terminate)
- ::signal(SIGPIPE, SIG_IGN);
-
- // Create a command socket?
- const Configuration &conf(GetConfiguration());
- if(conf.KeyExists("CommandSocket"))
- {
- // Yes, create a local UNIX socket
- mpCommandSocketInfo = new CommandSocketInfo;
- const char *socketName = conf.GetKeyValue("CommandSocket").c_str();
- ::unlink(socketName);
- mpCommandSocketInfo->mListeningSocket.Listen(Socket::TypeUNIX, socketName);
- }
+ // initialise global timer mechanism
+ Timers::Init();
+
+ #ifdef WIN32
+ // Create a thread to handle the named pipe
+ HANDLE hThread;
+ unsigned int dwThreadId;
+
+ hThread = (HANDLE) _beginthreadex(
+ NULL, // default security attributes
+ 0, // use default stack size
+ HelperThread, // thread function
+ this, // argument to thread function
+ 0, // use default creation flags
+ &dwThreadId); // returns the thread identifier
+ #else
+ // Ignore SIGPIPE so that if a command connection is broken,
+ // the daemon doesn't terminate.
+ ::signal(SIGPIPE, SIG_IGN);
+
+ // Create a command socket?
+ const Configuration &conf(GetConfiguration());
+ if(conf.KeyExists("CommandSocket"))
+ {
+ // Yes, create a local UNIX socket
+ mpCommandSocketInfo = new CommandSocketInfo;
+ const char *socketName =
+ conf.GetKeyValue("CommandSocket").c_str();
+ ::unlink(socketName);
+ mpCommandSocketInfo->mListeningSocket.Listen(
+ Socket::TypeUNIX, socketName);
+ }
+ #endif // !WIN32
// Handle things nicely on exceptions
try
@@ -455,31 +682,47 @@ void BackupDaemon::Run()
}
catch(...)
{
+ #ifdef WIN32
+ // Don't delete the socket, as the helper thread
+ // is probably still using it. Let Windows clean
+ // up after us.
+ #else
if(mpCommandSocketInfo != 0)
{
try
{
delete mpCommandSocketInfo;
}
+ catch(std::exception &e)
+ {
+ BOX_WARNING("Internal error while "
+ "closing command socket after "
+ "another exception: " << e.what());
+ }
catch(...)
{
- ::syslog(LOG_WARNING,
- "Error closing command socket "
+ BOX_WARNING("Error closing command socket "
"after exception, ignored.");
}
mpCommandSocketInfo = 0;
}
+ #endif // WIN32
+ Timers::Cleanup();
+
throw;
}
- // Clean up
- if(mpCommandSocketInfo != 0)
- {
- delete mpCommandSocketInfo;
- mpCommandSocketInfo = 0;
- }
-#endif
+ #ifndef WIN32
+ // Clean up
+ if(mpCommandSocketInfo != 0)
+ {
+ delete mpCommandSocketInfo;
+ mpCommandSocketInfo = 0;
+ }
+ #endif
+
+ Timers::Cleanup();
}
// --------------------------------------------------------------------------
@@ -503,18 +746,20 @@ void BackupDaemon::Run2()
// Set up the keys for various things
BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile").c_str());
+ // Setup various timings
+ int maximumDiffingTime = 600;
+ int keepAliveTime = 60;
+
// max diffing time, keep-alive time
if(conf.KeyExists("MaximumDiffingTime"))
{
- BackupClientContext::SetMaximumDiffingTime(conf.GetKeyValueInt("MaximumDiffingTime"));
+ maximumDiffingTime = conf.GetKeyValueInt("MaximumDiffingTime");
}
if(conf.KeyExists("KeepAliveTime"))
{
- BackupClientContext::SetKeepAliveTime(conf.GetKeyValueInt("KeepAliveTime"));
+ keepAliveTime = conf.GetKeyValueInt("KeepAliveTime");
}
- // Setup various timings
-
// How often to connect to the store (approximate)
box_time_t updateStoreInterval = SecondsToBoxTime(conf.GetKeyValueInt("UpdateStoreInterval"));
@@ -542,8 +787,8 @@ void BackupDaemon::Run2()
BackupClientContext::ClientStoreMarker_NotKnown;
// haven't contacted the store yet
- bool deserialised = DeserializeStoreObjectInfo(clientStoreMarker,
- lastSyncTime, nextSyncTime);
+ bool deleteStoreObjectInfoFile = DeserializeStoreObjectInfo(
+ clientStoreMarker, lastSyncTime, nextSyncTime);
// --------------------------------------------------------------------------------------------
@@ -564,38 +809,64 @@ void BackupDaemon::Run2()
box_time_t currentTime;
do
{
- // Need to check the stop run thing here too, so this loop isn't run if we should be stopping
+ // Check whether we should be stopping,
+ // and don't run a sync if so.
if(StopRun()) break;
currentTime = GetCurrentBoxTime();
- // Pause a while, but no more than MAX_SLEEP_TIME seconds (use the conditional because times are unsigned)
- box_time_t requiredDelay = (nextSyncTime < currentTime)?(0):(nextSyncTime - currentTime);
- // If there isn't automatic backup happening, set a long delay. And limit delays at the same time.
- if(!automaticBackup || requiredDelay > SecondsToBoxTime(MAX_SLEEP_TIME))
- requiredDelay = SecondsToBoxTime(MAX_SLEEP_TIME);
+ // Pause a while, but no more than
+ // MAX_SLEEP_TIME seconds (use the conditional
+ // because times are unsigned)
+ box_time_t requiredDelay =
+ (nextSyncTime < currentTime)
+ ? (0)
+ : (nextSyncTime - currentTime);
+
+ // If there isn't automatic backup happening,
+ // set a long delay. And limit delays at the
+ // same time.
+ if(!automaticBackup || requiredDelay >
+ SecondsToBoxTime(MAX_SLEEP_TIME))
+ {
+ requiredDelay = SecondsToBoxTime(
+ MAX_SLEEP_TIME);
+ }
- // Only do the delay if there is a delay required
+ // Only delay if necessary
if(requiredDelay > 0)
{
- // Sleep somehow. There are choices on how this should be done, depending on the state of the control connection
+ // Sleep somehow. There are choices
+ // on how this should be done,
+ // depending on the state of the
+ // control connection
if(mpCommandSocketInfo != 0)
{
- // A command socket exists, so sleep by handling connections with it
- WaitOnCommandSocket(requiredDelay, doSync, doSyncForcedByCommand);
+ // A command socket exists,
+ // so sleep by waiting on it
+ WaitOnCommandSocket(
+ requiredDelay, doSync,
+ doSyncForcedByCommand);
}
else
{
- // No command socket or connection, just do a normal sleep
- time_t sleepSeconds = BoxTimeToSeconds(requiredDelay);
- ::sleep((sleepSeconds <= 0)?1:sleepSeconds);
+ // No command socket or
+ // connection, just do a
+ // normal sleep
+ time_t sleepSeconds =
+ BoxTimeToSeconds(
+ requiredDelay);
+ ::sleep((sleepSeconds <= 0)
+ ? 1
+ : sleepSeconds);
}
}
} while((!automaticBackup || (currentTime < nextSyncTime)) && !doSync && !StopRun());
}
- // Time of sync start, and if it's time for another sync (and we're doing automatic syncs), set the flag
+ // Time of sync start, and if it's time for another sync
+ // (and we're doing automatic syncs), set the flag
box_time_t currentSyncStartTime = GetCurrentBoxTime();
if(automaticBackup && currentSyncStartTime >= nextSyncTime)
{
@@ -609,12 +880,14 @@ void BackupDaemon::Run2()
if(d > 0)
{
// Script has asked for a delay
- nextSyncTime = GetCurrentBoxTime() + SecondsToBoxTime(d);
+ nextSyncTime = GetCurrentBoxTime() +
+ SecondsToBoxTime(d);
doSync = false;
}
}
- // Ready to sync? (but only if we're not supposed to be stopping)
+ // Ready to sync? (but only if we're not supposed
+ // to be stopping)
if(doSync && !StopRun())
{
// Touch a file to record times in filesystem
@@ -628,34 +901,70 @@ void BackupDaemon::Run2()
// Calculate the sync period of files to examine
box_time_t syncPeriodStart = lastSyncTime;
- box_time_t syncPeriodEnd = currentSyncStartTime - minimumFileAge;
+ box_time_t syncPeriodEnd = currentSyncStartTime -
+ minimumFileAge;
+
+ if(syncPeriodStart >= syncPeriodEnd &&
+ syncPeriodStart - syncPeriodEnd < minimumFileAge)
+ {
+ // This can happen if we receive a force-sync
+ // command less than minimumFileAge after
+ // the last sync. Deal with it by moving back
+ // syncPeriodStart, which should not do any
+ // damage.
+ syncPeriodStart = syncPeriodEnd -
+ SecondsToBoxTime(1);
+ }
+
+ if(syncPeriodStart >= syncPeriodEnd)
+ {
+ BOX_ERROR("Invalid (negative) sync period: "
+ "perhaps your clock is going "
+ "backwards (" << syncPeriodStart <<
+ " to " << syncPeriodEnd << ")");
+ THROW_EXCEPTION(ClientException,
+ ClockWentBackwards);
+ }
+
// Check logic
ASSERT(syncPeriodEnd > syncPeriodStart);
// Paranoid check on sync times
if(syncPeriodStart >= syncPeriodEnd) continue;
- // Adjust syncPeriodEnd to emulate snapshot behaviour properly
+ // Adjust syncPeriodEnd to emulate snapshot
+ // behaviour properly
box_time_t syncPeriodEndExtended = syncPeriodEnd;
// Using zero min file age?
if(minimumFileAge == 0)
{
- // Add a year on to the end of the end time, to make sure we sync
- // files which are modified after the scan run started.
- // Of course, they may be eligable to be synced again the next time round,
- // but this should be OK, because the changes only upload should upload no data.
- syncPeriodEndExtended += SecondsToBoxTime((time_t)(356*24*3600));
+ // Add a year on to the end of the end time,
+ // to make sure we sync files which are
+ // modified after the scan run started.
+ // Of course, they may be eligible to be
+ // synced again the next time round,
+ // but this should be OK, because the changes
+ // only upload should upload no data.
+ syncPeriodEndExtended += SecondsToBoxTime(
+ (time_t)(356*24*3600));
}
// Delete the serialised store object file,
// so that we don't try to reload it after a
// partially completed backup
- if(deserialised && !DeleteStoreObjectInfo())
+ if(deleteStoreObjectInfoFile &&
+ !DeleteStoreObjectInfo())
{
- ::syslog(LOG_ERR, "Failed to delete the "
+ BOX_ERROR("Failed to delete the "
"StoreObjectInfoFile, backup cannot "
"continue safely.");
- continue;
+ THROW_EXCEPTION(ClientException,
+ FailedToDeleteStoreObjectInfoFile);
}
+
+ // In case the backup throws an exception,
+ // we should not try to delete the store info
+ // object file again.
+ deleteStoreObjectInfoFile = false;
// Do sync
bool errorOccurred = false;
@@ -666,30 +975,73 @@ void BackupDaemon::Run2()
{
// Set state and log start
SetState(State_Connected);
- ::syslog(LOG_INFO, "Beginning scan of local files");
+ BOX_NOTICE("Beginning scan of local files");
- // Then create a client context object (don't just connect, as this may be unnecessary)
- BackupClientContext clientContext(*this, tlsContext, conf.GetKeyValue("StoreHostname"),
- conf.GetKeyValueInt("AccountNumber"), conf.GetKeyValueBool("ExtendedLogging"));
+ std::string extendedLogFile;
+ if (conf.KeyExists("ExtendedLogFile"))
+ {
+ extendedLogFile = conf.GetKeyValue(
+ "ExtendedLogFile");
+ }
+
+ if (conf.KeyExists("LogAllFileAccess"))
+ {
+ mLogAllFileAccess =
+ conf.GetKeyValueBool(
+ "LogAllFileAccess");
+ }
+
+ // Then create a client context object (don't
+ // just connect, as this may be unnecessary)
+ BackupClientContext clientContext
+ (
+ *this,
+ tlsContext,
+ conf.GetKeyValue("StoreHostname"),
+ conf.GetKeyValueInt("AccountNumber"),
+ conf.GetKeyValueBool("ExtendedLogging"),
+ conf.KeyExists("ExtendedLogFile"),
+ extendedLogFile
+ );
// Set up the sync parameters
- BackupClientDirectoryRecord::SyncParams params(*this, clientContext);
+ BackupClientDirectoryRecord::SyncParams params(
+ *this, *this, clientContext);
params.mSyncPeriodStart = syncPeriodStart;
- params.mSyncPeriodEnd = syncPeriodEndExtended; // use potentially extended end time
+ params.mSyncPeriodEnd = syncPeriodEndExtended;
+ // use potentially extended end time
params.mMaxUploadWait = maxUploadWait;
- params.mFileTrackingSizeThreshold = conf.GetKeyValueInt("FileTrackingSizeThreshold");
- params.mDiffingUploadSizeThreshold = conf.GetKeyValueInt("DiffingUploadSizeThreshold");
- params.mMaxFileTimeInFuture = SecondsToBoxTime(conf.GetKeyValueInt("MaxFileTimeInFuture"));
+ params.mFileTrackingSizeThreshold =
+ conf.GetKeyValueInt(
+ "FileTrackingSizeThreshold");
+ params.mDiffingUploadSizeThreshold =
+ conf.GetKeyValueInt(
+ "DiffingUploadSizeThreshold");
+ params.mMaxFileTimeInFuture =
+ SecondsToBoxTime(
+ conf.GetKeyValueInt(
+ "MaxFileTimeInFuture"));
+ mDeleteRedundantLocationsAfter =
+ conf.GetKeyValueInt(
+ "DeleteRedundantLocationsAfter");
+
+ clientContext.SetMaximumDiffingTime(maximumDiffingTime);
+ clientContext.SetKeepAliveTime(keepAliveTime);
// Set store marker
clientContext.SetClientStoreMarker(clientStoreMarker);
- // Set up the locations, if necessary -- need to do it here so we have a (potential) connection to use
+ // Set up the locations, if necessary --
+ // need to do it here so we have a
+ // (potential) connection to use
if(mLocations.empty())
{
- const Configuration &locations(conf.GetSubConfiguration("BackupLocations"));
+ const Configuration &locations(
+ conf.GetSubConfiguration(
+ "BackupLocations"));
- // Make sure all the directory records are set up
+ // Make sure all the directory records
+ // are set up
SetupLocations(clientContext, locations);
}
@@ -699,17 +1051,29 @@ void BackupDaemon::Run2()
// Delete any unused directories?
DeleteUnusedRootDirEntries(clientContext);
+ // Notify administrator
+ NotifySysadmin(NotifyEvent_BackupStart);
+
// Go through the records, syncing them
- for(std::vector<Location *>::const_iterator i(mLocations.begin()); i != mLocations.end(); ++i)
+ for(std::vector<Location *>::const_iterator
+ i(mLocations.begin());
+ i != mLocations.end(); ++i)
{
- // Set current and new ID map pointers in the context
+ // Set current and new ID map pointers
+ // in the context
clientContext.SetIDMaps(mCurrentIDMaps[(*i)->mIDMapIndex], mNewIDMaps[(*i)->mIDMapIndex]);
- // Set exclude lists (context doesn't take ownership)
- clientContext.SetExcludeLists((*i)->mpExcludeFiles, (*i)->mpExcludeDirs);
+ // Set exclude lists (context doesn't
+ // take ownership)
+ clientContext.SetExcludeLists(
+ (*i)->mpExcludeFiles,
+ (*i)->mpExcludeDirs);
// Sync the directory
- (*i)->mpDirectoryRecord->SyncDirectory(params, BackupProtocolClientListDirectory::RootDirectory, (*i)->mPath);
+ (*i)->mpDirectoryRecord->SyncDirectory(
+ params,
+ BackupProtocolClientListDirectory::RootDirectory,
+ (*i)->mPath);
// Unset exclude lists (just in case)
clientContext.SetExcludeLists(0, 0);
@@ -723,13 +1087,14 @@ void BackupDaemon::Run2()
}
else
{
- // Unset the read error flag, so the error is
- // reported again in the future
+ // Unset the read error flag, so the // error is reported again if it
+ // happens again
mNotificationsSent[NotifyEvent_ReadError] = false;
}
- // Perform any deletions required -- these are delayed until the end
- // to allow renaming to happen neatly.
+ // Perform any deletions required -- these are
+ // delayed until the end to allow renaming to
+ // happen neatly.
clientContext.PerformDeletions();
// Close any open connection
@@ -746,26 +1111,45 @@ void BackupDaemon::Run2()
}
else
{
- // The start time of the next run is the end time of this run
- // This is only done if the storage limit wasn't exceeded (as things won't have been done properly if it was)
+ // The start time of the next run is
+ // the end time of this run.
+ // This is only done if the storage
+ // limit wasn't exceeded (as things
+ // won't have been done properly if
+ // it was)
lastSyncTime = syncPeriodEnd;
- // unflag the storage full notify flag so that next time the store is full, and alert will be sent
+
+ // unflag the storage full notify flag
+ // so that next time the store is full,
+ // an alert will be sent
mNotificationsSent[NotifyEvent_StoreFull] = false;
}
// Calculate when the next sync run should be
- nextSyncTime = currentSyncStartTime + updateStoreInterval + Random::RandomInt(updateStoreInterval >> SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY);
+ nextSyncTime = currentSyncStartTime +
+ updateStoreInterval +
+ Random::RandomInt(updateStoreInterval >>
+ SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY);
// Commit the ID Maps
CommitIDMapsAfterSync();
// Log
- ::syslog(LOG_INFO, "Finished scan of local files");
+ BOX_NOTICE("Finished scan of local files");
+
+ // Notify administrator
+ NotifySysadmin(NotifyEvent_BackupFinish);
// --------------------------------------------------------------------------------------------
- // We had a successful backup, save the store info
- SerializeStoreObjectInfo(clientStoreMarker, lastSyncTime, nextSyncTime);
+ // We had a successful backup, save the store
+ // info. If we save successfully, we must
+ // delete the file next time we start a backup
+
+ deleteStoreObjectInfoFile =
+ SerializeStoreObjectInfo(
+ clientStoreMarker,
+ lastSyncTime, nextSyncTime);
// --------------------------------------------------------------------------------------------
}
@@ -776,17 +1160,31 @@ void BackupDaemon::Run2()
errorCode = e.GetType();
errorSubCode = e.GetSubType();
}
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Internal error during "
+ "backup run: " << e.what());
+ errorOccurred = true;
+ errorString = e.what();
+ }
catch(...)
{
- // TODO: better handling of exceptions here... need to be very careful
+ // TODO: better handling of exceptions here...
+ // need to be very careful
errorOccurred = true;
}
if(errorOccurred)
{
// Is it a berkely db failure?
- bool isBerkelyDbFailure = (errorCode == BackupStoreException::ExceptionType
- && errorSubCode == BackupStoreException::BerkelyDBFailure);
+ bool isBerkelyDbFailure = false;
+
+ if (errorCode == BackupStoreException::ExceptionType
+ && errorSubCode == BackupStoreException::BerkelyDBFailure)
+ {
+ isBerkelyDbFailure = true;
+ }
+
if(isBerkelyDbFailure)
{
// Delete corrupt files
@@ -794,7 +1192,8 @@ void BackupDaemon::Run2()
}
// Clear state data
- syncPeriodStart = 0; // go back to beginning of time
+ syncPeriodStart = 0;
+ // go back to beginning of time
clientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown; // no store marker, so download everything
DeleteAllLocations();
DeleteAllIDMaps();
@@ -802,26 +1201,30 @@ void BackupDaemon::Run2()
// Handle restart?
if(StopRun())
{
- ::syslog(LOG_INFO, "Exception (%d/%d) due to signal", errorCode, errorSubCode);
+ BOX_NOTICE("Exception (" << errorCode
+ << "/" << errorSubCode
+ << ") due to signal");
return;
}
// If the Berkely db files get corrupted, delete them and try again immediately
if(isBerkelyDbFailure)
{
- ::syslog(LOG_ERR, "Berkely db inode map files corrupted, deleting and restarting scan. Renamed files and directories will not be tracked until after this scan.\n");
+ BOX_ERROR("Berkely db inode map files corrupted, deleting and restarting scan. Renamed files and directories will not be tracked until after this scan.");
::sleep(1);
}
else
{
// Not restart/terminate, pause and retry
+ // Notify administrator
+ NotifySysadmin(NotifyEvent_BackupError);
SetState(State_Error);
- ::syslog(LOG_ERR,
- "Exception caught (%s %d/%d), "
- "reset state and waiting "
- "to retry...",
- errorString, errorCode,
- errorSubCode);
+ BOX_ERROR("Exception caught ("
+ << errorString
+ << " " << errorCode
+ << "/" << errorSubCode
+ << "), reset state and "
+ "waiting to retry...");
::sleep(10);
nextSyncTime = currentSyncStartTime +
SecondsToBoxTime(90) +
@@ -832,9 +1235,12 @@ void BackupDaemon::Run2()
}
// Log the stats
- ::syslog(LOG_INFO, "File statistics: total file size uploaded %lld, bytes already on server %lld, encoded size %lld",
- BackupStoreFile::msStats.mBytesInEncodedFiles, BackupStoreFile::msStats.mBytesAlreadyOnServer,
- BackupStoreFile::msStats.mTotalFileStreamSize);
+ BOX_NOTICE("File statistics: total file size uploaded "
+ << BackupStoreFile::msStats.mBytesInEncodedFiles
+ << ", bytes already on server "
+ << BackupStoreFile::msStats.mBytesAlreadyOnServer
+ << ", encoded size "
+ << BackupStoreFile::msStats.mTotalFileStreamSize);
BackupStoreFile::ResetStats();
// Tell anything connected to the command socket
@@ -889,7 +1295,7 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed()
std::string line;
if(getLine.GetLine(line, true, 30000)) // 30 seconds should be enough
{
- // Got a string, intepret
+ // Got a string, interpret
if(line == "now")
{
// Script says do it now. Obey.
@@ -897,27 +1303,46 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed()
}
else
{
- // How many seconds to wait?
- waitInSeconds = BoxConvert::Convert<int32_t, const std::string&>(line);
- ::syslog(LOG_INFO, "Delaying sync by %d seconds (SyncAllowScript '%s')", waitInSeconds, conf.GetKeyValue("SyncAllowScript").c_str());
+ try
+ {
+ // How many seconds to wait?
+ waitInSeconds = BoxConvert::Convert<int32_t, const std::string&>(line);
+ }
+ catch(ConversionException &e)
+ {
+ BOX_ERROR("Invalid output "
+ "from SyncAllowScript '"
+ << conf.GetKeyValue("SyncAllowScript")
+ << "': '" << line << "'");
+ throw;
+ }
+
+ BOX_NOTICE("Delaying sync by " << waitInSeconds
+ << " seconds (SyncAllowScript '"
+ << conf.GetKeyValue("SyncAllowScript")
+ << "')");
}
}
- // Wait and then cleanup child process
- int status = 0;
- ::waitpid(pid, &status, 0);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Internal error running SyncAllowScript: "
+ << e.what());
}
catch(...)
{
// Ignore any exceptions
// Log that something bad happened
- ::syslog(LOG_ERR, "Error running SyncAllowScript '%s'", conf.GetKeyValue("SyncAllowScript").c_str());
- // Clean up though
- if(pid != 0)
- {
- int status = 0;
- ::waitpid(pid, &status, 0);
- }
+ BOX_ERROR("Error running SyncAllowScript '"
+ << conf.GetKeyValue("SyncAllowScript") << "'");
+ }
+
+ // Wait and then cleanup child process, if any
+ if(pid != 0)
+ {
+ int status = 0;
+ ::waitpid(pid, &status, 0);
}
return waitInSeconds;
@@ -937,32 +1362,34 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed()
void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut)
{
#ifdef WIN32
- // Really could use some interprocess protection, mutex etc
- // any side effect should be too bad???? :)
- DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay);
+ DWORD requiredDelayMs = BoxTimeToMilliSeconds(RequiredDelay);
- while ( this->mReceivedCommandConn == false )
- {
- Sleep(1);
+ DWORD result = WaitForSingleObject(mhCommandReceivedEvent,
+ (DWORD)requiredDelayMs);
- if ( timeout == 0 )
- {
- DoSyncFlagOut = false;
- SyncIsForcedOut = false;
- return;
- }
- timeout--;
+ if(result == WAIT_OBJECT_0)
+ {
+ DoSyncFlagOut = this->mDoSyncFlagOut;
+ SyncIsForcedOut = this->mSyncIsForcedOut;
+ ResetEvent(mhCommandReceivedEvent);
+ }
+ else if(result == WAIT_TIMEOUT)
+ {
+ DoSyncFlagOut = false;
+ SyncIsForcedOut = false;
+ }
+ else
+ {
+ BOX_ERROR("Unexpected result from WaitForSingleObject: "
+ "error " << GetLastError());
}
- this->mReceivedCommandConn = false;
- DoSyncFlagOut = this->mDoSyncFlagOut;
- SyncIsForcedOut = this->mSyncIsForcedOut;
return;
#else // ! WIN32
ASSERT(mpCommandSocketInfo != 0);
if(mpCommandSocketInfo == 0) {::sleep(1); return;} // failure case isn't too bad
- TRACE1("Wait on command socket, delay = %lld\n", RequiredDelay);
+ BOX_TRACE("Wait on command socket, delay = " << RequiredDelay);
try
{
@@ -988,7 +1415,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla
{
#ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
bool uidOK = true;
- ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)");
+ BOX_WARNING("On this platform, no security check can be made on the credentials of peers connecting to the command socket. (bbackupctl)");
#else
// Security check -- does the process connecting to this socket have
// the same UID as this process?
@@ -1013,14 +1440,14 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla
if(!uidOK)
{
// Dump the connection
- ::syslog(LOG_ERR, "Incoming command connection from peer had different user ID than this process, or security check could not be completed.");
+ BOX_ERROR("Incoming command connection from peer had different user ID than this process, or security check could not be completed.");
mpCommandSocketInfo->mpConnectedSocket.reset();
return;
}
else
{
// Log
- ::syslog(LOG_INFO, "Connection from command socket");
+ BOX_INFO("Connection from command socket");
// Send a header line summarising the configuration and current state
const Configuration &conf(GetConfiguration());
@@ -1058,7 +1485,8 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla
while(mpCommandSocketInfo->mpGetLine != 0 && !mpCommandSocketInfo->mpGetLine->IsEOF()
&& mpCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout))
{
- TRACE1("Receiving command '%s' over command socket\n", command.c_str());
+ BOX_TRACE("Receiving command '" << command
+ << "' over command socket");
bool sendOK = false;
bool sendResponse = true;
@@ -1113,13 +1541,29 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla
CloseCommandConnection();
}
}
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Internal error in command socket thread: "
+ << e.what());
+ // If an error occurs, and there is a connection active, just close that
+ // connection and continue. Otherwise, let the error propagate.
+ if(mpCommandSocketInfo->mpConnectedSocket.get() == 0)
+ {
+ throw; // thread will die
+ }
+ else
+ {
+ // Close socket and ignore error
+ CloseCommandConnection();
+ }
+ }
catch(...)
{
// If an error occurs, and there is a connection active, just close that
// connection and continue. Otherwise, let the error propagate.
if(mpCommandSocketInfo->mpConnectedSocket.get() == 0)
{
- throw;
+ throw; // thread will die
}
else
{
@@ -1144,7 +1588,7 @@ void BackupDaemon::CloseCommandConnection()
#ifndef WIN32
try
{
- TRACE0("Closing command connection\n");
+ BOX_TRACE("Closing command connection");
if(mpCommandSocketInfo->mpGetLine)
{
@@ -1153,6 +1597,11 @@ void BackupDaemon::CloseCommandConnection()
}
mpCommandSocketInfo->mpConnectedSocket.reset();
}
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Internal error while closing command "
+ "socket: " << e.what());
+ }
catch(...)
{
// Ignore any errors
@@ -1172,14 +1621,10 @@ void BackupDaemon::CloseCommandConnection()
// --------------------------------------------------------------------------
void BackupDaemon::SendSyncStartOrFinish(bool SendStart)
{
- // The bbackupctl program can't rely on a state change, because it may never
- // change if the server doesn't need to be contacted.
+ // The bbackupctl program can't rely on a state change, because it
+ // may never change if the server doesn't need to be contacted.
-#ifdef __MINGW32__
-#warning race condition: what happens if socket is closed?
-#endif
-
- if (mpCommandSocketInfo != NULL &&
+ if(mpCommandSocketInfo != NULL &&
#ifdef WIN32
mpCommandSocketInfo->mListeningSocket.IsConnected()
#else
@@ -1187,17 +1632,26 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart)
#endif
)
{
- const char* message = SendStart ? "start-sync\n" : "finish-sync\n";
+ std::string message = SendStart ? "start-sync" : "finish-sync";
try
{
#ifdef WIN32
- mpCommandSocketInfo->mListeningSocket.Write(message,
- (int)strlen(message));
+ EnterCriticalSection(&mMessageQueueLock);
+ mMessageList.push_back(message);
+ SetEvent(mhMessageToSendEvent);
+ LeaveCriticalSection(&mMessageQueueLock);
#else
- mpCommandSocketInfo->mpConnectedSocket->Write(message,
- strlen(message));
+ message += "\n";
+ mpCommandSocketInfo->mpConnectedSocket->Write(
+ message.c_str(), message.size());
#endif
}
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Internal error while sending to "
+ "command socket client: " << e.what());
+ CloseCommandConnection();
+ }
catch(...)
{
CloseCommandConnection();
@@ -1298,7 +1752,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con
struct mntent *entry = 0;
while((entry = ::getmntent(mountPointsFile)) != 0)
{
- TRACE1("Found mount point at %s\n", entry->mnt_dir);
+ BOX_TRACE("Found mount point at " << entry->mnt_dir);
mountPoints.insert(std::string(entry->mnt_dir));
}
@@ -1307,7 +1761,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con
}
catch(...)
{
- ::endmntent(mountPointsFile);
+ ::endmntent(mountPointsFile);
throw;
}
#else // ! HAVE_STRUCT_MNTENT_MNT_DIR
@@ -1320,12 +1774,11 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con
try
{
-
// Read all the entries, and put them in the set
struct mnttab entry;
while(getmntent(mountPointsFile, &entry) == 0)
{
- TRACE1("Found mount point at %s\n", entry.mnt_mountp);
+ BOX_TRACE("Found mount point at " << entry.mnt_mountp);
mountPoints.insert(std::string(entry.mnt_mountp));
}
@@ -1354,19 +1807,37 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con
for(std::list<std::pair<std::string, Configuration> >::const_iterator i = rLocationsConf.mSubConfigurations.begin();
i != rLocationsConf.mSubConfigurations.end(); ++i)
{
-TRACE0("new location\n");
+ BOX_TRACE("new location: " << i->first);
// Create a record for it
- Location *ploc = new Location;
+ std::auto_ptr<Location> apLoc(new Location);
+
try
{
// Setup names in the location record
- ploc->mName = i->first;
- ploc->mPath = i->second.GetKeyValue("Path");
+ apLoc->mName = i->first;
+ apLoc->mPath = i->second.GetKeyValue("Path");
// Read the exclude lists from the Configuration
- ploc->mpExcludeFiles = BackupClientMakeExcludeList_Files(i->second);
- ploc->mpExcludeDirs = BackupClientMakeExcludeList_Dirs(i->second);
-
+ apLoc->mpExcludeFiles = BackupClientMakeExcludeList_Files(i->second);
+ apLoc->mpExcludeDirs = BackupClientMakeExcludeList_Dirs(i->second);
+
+ // Does this exist on the server?
+ // Remove from dir object early, so that if we fail
+ // to stat the local directory, we still don't
+ // consider to remote one for deletion.
+ BackupStoreDirectory::Iterator iter(dir);
+ BackupStoreFilenameClear dirname(apLoc->mName); // generate the filename
+ BackupStoreDirectory::Entry *en = iter.FindMatchingClearName(dirname);
+ int64_t oid = 0;
+ if(en != 0)
+ {
+ oid = en->GetObjectID();
+
+ // Delete the entry from the directory, so we get a list of
+ // unused root directories at the end of this.
+ dir.DeleteEntry(oid);
+ }
+
// Do a fsstat on the pathname to find out which mount it's on
{
@@ -1375,13 +1846,18 @@ TRACE0("new location\n");
// BSD style statfs -- includes mount point, which is nice.
#ifdef HAVE_STRUCT_STATVFS_F_MNTONNAME
struct statvfs s;
- if(::statvfs(ploc->mPath.c_str(), &s) != 0)
+ if(::statvfs(apLoc->mPath.c_str(), &s) != 0)
#else // HAVE_STRUCT_STATVFS_F_MNTONNAME
struct statfs s;
- if(::statfs(ploc->mPath.c_str(), &s) != 0)
+ if(::statfs(apLoc->mPath.c_str(), &s) != 0)
#endif // HAVE_STRUCT_STATVFS_F_MNTONNAME
{
- THROW_EXCEPTION(CommonException, OSFileError)
+ BOX_WARNING("Failed to stat location "
+ "path '" << apLoc->mPath <<
+ "' (" << strerror(errno) <<
+ "), skipping location '" <<
+ apLoc->mName << "'");
+ continue;
}
// Where the filesystem is mounted
@@ -1390,29 +1866,34 @@ TRACE0("new location\n");
#else // !HAVE_STRUCT_STATFS_F_MNTONNAME && !WIN32
// Warn in logs if the directory isn't absolute
- if(ploc->mPath[0] != '/')
+ if(apLoc->mPath[0] != '/')
{
- ::syslog(LOG_ERR, "Location path '%s' isn't absolute", ploc->mPath.c_str());
+ BOX_WARNING("Location path '"
+ << apLoc->mPath
+ << "' is not absolute");
}
// Go through the mount points found, and find a suitable one
std::string mountName("/");
{
std::set<std::string, mntLenCompare>::const_iterator i(mountPoints.begin());
- TRACE1("%d potential mount points\n", mountPoints.size());
+ BOX_TRACE(mountPoints.size()
+ << " potential mount points");
for(; i != mountPoints.end(); ++i)
{
// Compare first n characters with the filename
// If it matches, the file belongs in that mount point
// (sorting order ensures this)
- TRACE1("checking against mount point %s\n", i->c_str());
- if(::strncmp(i->c_str(), ploc->mPath.c_str(), i->size()) == 0)
+ BOX_TRACE("checking against mount point " << *i);
+ if(::strncmp(i->c_str(), apLoc->mPath.c_str(), i->size()) == 0)
{
// Match
mountName = *i;
break;
}
}
- TRACE2("mount point chosen for %s is %s\n", ploc->mPath.c_str(), mountName.c_str());
+ BOX_TRACE("mount point chosen for "
+ << apLoc->mPath << " is "
+ << mountName);
}
#endif
@@ -1422,12 +1903,12 @@ TRACE0("new location\n");
if(f != mounts.end())
{
// Yes -- store the index
- ploc->mIDMapIndex = f->second;
+ apLoc->mIDMapIndex = f->second;
}
else
{
// No -- new index
- ploc->mIDMapIndex = numIDMaps;
+ apLoc->mIDMapIndex = numIDMaps;
mounts[mountName] = numIDMaps;
// Store the mount name
@@ -1439,49 +1920,73 @@ TRACE0("new location\n");
}
// Does this exist on the server?
- BackupStoreDirectory::Iterator iter(dir);
- BackupStoreFilenameClear dirname(ploc->mName); // generate the filename
- BackupStoreDirectory::Entry *en = iter.FindMatchingClearName(dirname);
- int64_t oid = 0;
- if(en != 0)
- {
- oid = en->GetObjectID();
-
- // Delete the entry from the directory, so we get a list of
- // unused root directories at the end of this.
- dir.DeleteEntry(oid);
- }
- else
+ if(en == 0)
{
// Doesn't exist, so it has to be created on the server. Let's go!
// First, get the directory's attributes and modification time
box_time_t attrModTime = 0;
BackupClientFileAttributes attr;
- attr.ReadAttributes(ploc->mPath.c_str(), true /* directories have zero mod times */,
- 0 /* not interested in mod time */, &attrModTime /* get the attribute modification time */);
+ try
+ {
+ attr.ReadAttributes(apLoc->mPath.c_str(),
+ true /* directories have zero mod times */,
+ 0 /* not interested in mod time */,
+ &attrModTime /* get the attribute modification time */);
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to get attributes "
+ "for path '" << apLoc->mPath
+ << "', skipping location '" <<
+ apLoc->mName << "'");
+ continue;
+ }
// Execute create directory command
- MemBlockStream attrStream(attr);
- std::auto_ptr<BackupProtocolClientSuccess> dirCreate(connection.QueryCreateDirectory(
- BackupProtocolClientListDirectory::RootDirectory,
- attrModTime, dirname, attrStream));
-
- // Object ID for later creation
- oid = dirCreate->GetObjectID();
+ try
+ {
+ MemBlockStream attrStream(attr);
+ std::auto_ptr<BackupProtocolClientSuccess>
+ dirCreate(connection.QueryCreateDirectory(
+ BackupProtocolClientListDirectory::RootDirectory,
+ attrModTime, dirname, attrStream));
+
+ // Object ID for later creation
+ oid = dirCreate->GetObjectID();
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to create remote "
+ "directory '/" << apLoc->mName <<
+ "', skipping location '" <<
+ apLoc->mName << "'");
+ continue;
+ }
+
}
// Create and store the directory object for the root of this location
ASSERT(oid != 0);
BackupClientDirectoryRecord *precord = new BackupClientDirectoryRecord(oid, i->first);
- ploc->mpDirectoryRecord.reset(precord);
+ apLoc->mpDirectoryRecord.reset(precord);
// Push it back on the vector of locations
- mLocations.push_back(ploc);
+ mLocations.push_back(apLoc.release());
+ }
+ catch (std::exception &e)
+ {
+ BOX_ERROR("Failed to configure location '"
+ << apLoc->mName << "' path '"
+ << apLoc->mPath << "': " << e.what() <<
+ ": please check for previous errors");
+ throw;
}
catch(...)
{
- delete ploc;
- ploc = 0;
+ BOX_ERROR("Failed to configure location '"
+ << apLoc->mName << "' path '"
+ << apLoc->mPath << "': please check for "
+ "previous errors");
throw;
}
}
@@ -1489,8 +1994,26 @@ TRACE0("new location\n");
// Any entries in the root directory which need deleting?
if(dir.GetNumberOfEntries() > 0)
{
- ::syslog(LOG_INFO, "%d redundant locations in root directory found, will delete from store after %d seconds.",
- dir.GetNumberOfEntries(), BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER);
+ box_time_t now = GetCurrentBoxTime();
+
+ // This should reset the timer if the list of unused
+ // locations changes, but it will not if the number of
+ // unused locations does not change, but the locations
+ // do change, e.g. one mysteriously appears and another
+ // mysteriously appears. (FIXME)
+ if (dir.GetNumberOfEntries() != mUnusedRootDirEntries.size() ||
+ mDeleteUnusedRootDirEntriesAfter == 0)
+ {
+ mDeleteUnusedRootDirEntriesAfter = now +
+ SecondsToBoxTime(mDeleteRedundantLocationsAfter);
+ }
+
+ int secs = BoxTimeToSeconds(mDeleteUnusedRootDirEntriesAfter
+ - now);
+
+ BOX_NOTICE(dir.GetNumberOfEntries() << " redundant locations "
+ "in root directory found, will delete from store "
+ "after " << secs << " seconds.");
// Store directories in list of things to delete
mUnusedRootDirEntries.clear();
@@ -1501,14 +2024,13 @@ TRACE0("new location\n");
// Add name to list
BackupStoreFilenameClear clear(en->GetName());
const std::string &name(clear.GetClearFilename());
- mUnusedRootDirEntries.push_back(std::pair<int64_t,std::string>(en->GetObjectID(), name));
+ mUnusedRootDirEntries.push_back(
+ std::pair<int64_t,std::string>
+ (en->GetObjectID(), name));
// Log this
- ::syslog(LOG_INFO, "Unused location in root: %s", name.c_str());
+ BOX_INFO("Unused location in root: " << name);
}
ASSERT(mUnusedRootDirEntries.size() > 0);
- // Time to delete them
- mDeleteUnusedRootDirEntriesAfter =
- GetCurrentBoxTime() + SecondsToBoxTime(BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER);
}
}
@@ -1620,14 +2142,14 @@ void BackupDaemon::DeleteCorruptBerkelyDbFiles()
MakeMapBaseName(l, filename);
// Delete the file
- TRACE1("Deleting %s\n", filename.c_str());
+ BOX_TRACE("Deleting " << filename);
::unlink(filename.c_str());
// Add a suffix for the new map
filename += ".n";
// Delete that too
- TRACE1("Deleting %s\n", filename.c_str());
+ BOX_TRACE("Deleting " << filename);
::unlink(filename.c_str());
}
}
@@ -1707,6 +2229,9 @@ void BackupDaemon::CommitIDMapsAfterSync()
#endif
if(::rename(newmap.c_str(), target.c_str()) != 0)
{
+ BOX_ERROR("failed to rename ID map: " << newmap
+ << " to " << target << ": "
+ << strerror(errno));
THROW_EXCEPTION(CommonException, OSFileError)
}
}
@@ -1791,39 +2316,44 @@ void BackupDaemon::SetState(int State)
// command socket if there's an error
char newState[64];
- char newStateSize = sprintf(newState, "state %d\n", State);
+ sprintf(newState, "state %d", State);
+ std::string message = newState;
#ifdef WIN32
- #ifndef _MSC_VER
- #warning FIX ME: race condition
- #endif
+ EnterCriticalSection(&mMessageQueueLock);
+ mMessageList.push_back(newState);
+ SetEvent(mhMessageToSendEvent);
+ LeaveCriticalSection(&mMessageQueueLock);
+#else
+ message += "\n";
- // what happens if the socket is closed by the other thread before
- // we can write to it? Null pointer deref at best.
- if (mpCommandSocketInfo &&
- mpCommandSocketInfo->mListeningSocket.IsConnected())
+ if(mpCommandSocketInfo == 0)
{
- try
- {
- mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize);
- }
- catch(...)
- {
- CloseCommandConnection();
- }
+ return;
}
-#else
- if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0)
+
+ if(mpCommandSocketInfo->mpConnectedSocket.get() == 0)
{
- // Something connected to the command socket, tell it about the new state
- try
- {
- mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize);
- }
- catch(...)
- {
- CloseCommandConnection();
- }
+ return;
+ }
+
+ // Something connected to the command socket, tell it about the new state
+ try
+ {
+ mpCommandSocketInfo->mpConnectedSocket->Write(message.c_str(),
+ message.length());
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Internal error while writing state "
+ "to command socket: " << e.what());
+ CloseCommandConnection();
+ }
+ catch(...)
+ {
+ BOX_ERROR("Internal error while writing state "
+ "to command socket: unknown error");
+ CloseCommandConnection();
}
#endif
}
@@ -1854,49 +2384,80 @@ void BackupDaemon::TouchFileInWorkingDir(const char *Filename)
//
// Function
// Name: BackupDaemon::NotifySysadmin(int)
-// Purpose: Run the script to tell the sysadmin about events which need attention.
+// Purpose: Run the script to tell the sysadmin about events
+// which need attention.
// Created: 25/2/04
//
// --------------------------------------------------------------------------
void BackupDaemon::NotifySysadmin(int Event)
{
- static const char *sEventNames[] = {"store-full", "read-error", 0};
+ static const char *sEventNames[] =
+ {
+ "store-full",
+ "read-error",
+ "backup-error",
+ "backup-start",
+ "backup-finish",
+ 0
+ };
+
+ BOX_TRACE("sizeof(sEventNames) == " << sizeof(sEventNames));
+ BOX_TRACE("sizeof(*sEventNames) == " << sizeof(*sEventNames));
+ BOX_TRACE("NotifyEvent__MAX == " << NotifyEvent__MAX);
+ ASSERT((sizeof(sEventNames)/sizeof(*sEventNames)) == NotifyEvent__MAX + 1);
- TRACE1("BackupDaemon::NotifySysadmin() called, event = %d\n", Event);
+ BOX_TRACE("BackupDaemon::NotifySysadmin() called, event = " <<
+ sEventNames[Event]);
- if(Event < 0 || Event > NotifyEvent__MAX)
+ if(Event < 0 || Event >= NotifyEvent__MAX)
{
- THROW_EXCEPTION(BackupStoreException, BadNotifySysadminEventCode);
+ THROW_EXCEPTION(BackupStoreException,
+ BadNotifySysadminEventCode);
}
// Don't send lots of repeated messages
- if(mNotificationsSent[Event])
+ if(mNotificationsSent[Event] &&
+ Event != NotifyEvent_BackupStart &&
+ Event != NotifyEvent_BackupFinish)
{
+ BOX_WARNING("Suppressing duplicate notification about " <<
+ sEventNames[Event]);
return;
}
- // Is there a notifation script?
+ // Is there a notification script?
const Configuration &conf(GetConfiguration());
if(!conf.KeyExists("NotifyScript"))
{
// Log, and then return
- ::syslog(LOG_ERR, "Not notifying administrator about event %s -- set NotifyScript to do this in future", sEventNames[Event]);
+ if(Event != NotifyEvent_BackupStart &&
+ Event != NotifyEvent_BackupFinish)
+ {
+ BOX_ERROR("Not notifying administrator about event "
+ << sEventNames[Event] << " -- set NotifyScript "
+ "to do this in future");
+ }
return;
}
// Script to run
- std::string script(conf.GetKeyValue("NotifyScript") + ' ' + sEventNames[Event]);
+ std::string script(conf.GetKeyValue("NotifyScript") + ' ' +
+ sEventNames[Event]);
// Log what we're about to do
- ::syslog(LOG_INFO, "About to notify administrator about event %s, running script '%s'", sEventNames[Event], script.c_str());
+ BOX_NOTICE("About to notify administrator about event "
+ << sEventNames[Event] << ", running script '"
+ << script << "'");
// Then do it
if(::system(script.c_str()) != 0)
{
- ::syslog(LOG_ERR, "Notify script returned an error code. ('%s')", script.c_str());
+ BOX_ERROR("Notify script returned an error code. ('"
+ << script << "')");
}
- // Flag that this is done so the administrator isn't constantly bombarded with lots of errors
+ // Flag that this is done so the administrator isn't constantly
+ // bombarded with lots of errors
mNotificationsSent[Event] = true;
}
@@ -1911,28 +2472,40 @@ void BackupDaemon::NotifySysadmin(int Event)
// --------------------------------------------------------------------------
void BackupDaemon::DeleteUnusedRootDirEntries(BackupClientContext &rContext)
{
- if(mUnusedRootDirEntries.empty() || mDeleteUnusedRootDirEntriesAfter == 0)
+ if(mUnusedRootDirEntries.empty())
{
- // Nothing to do.
+ BOX_INFO("Not deleting unused entries - none in list");
return;
}
+ if(mDeleteUnusedRootDirEntriesAfter == 0)
+ {
+ BOX_INFO("Not deleting unused entries - "
+ "zero delete time (bad)");
+ return;
+ }
+
// Check time
- if(GetCurrentBoxTime() < mDeleteUnusedRootDirEntriesAfter)
+ box_time_t now = GetCurrentBoxTime();
+ if(now < mDeleteUnusedRootDirEntriesAfter)
{
- // Too early to delete files
+ int secs = BoxTimeToSeconds(mDeleteUnusedRootDirEntriesAfter
+ - now);
+ BOX_INFO("Not deleting unused entries - too early ("
+ << secs << " seconds remaining)");
return;
}
// Entries to delete, and it's the right time to do so...
- ::syslog(LOG_INFO, "Deleting unused locations from store root...");
+ BOX_NOTICE("Deleting unused locations from store root...");
BackupProtocolClient &connection(rContext.GetConnection());
for(std::vector<std::pair<int64_t,std::string> >::iterator i(mUnusedRootDirEntries.begin()); i != mUnusedRootDirEntries.end(); ++i)
{
connection.QueryDeleteDirectory(i->first);
// Log this
- ::syslog(LOG_INFO, "Deleted %s (ID %08llx) from store root", i->second.c_str(), i->first);
+ BOX_NOTICE("Deleted " << i->second << " (ID " << i->first
+ << ") from store root");
}
// Reset state
@@ -2006,12 +2579,12 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive)
//
//
mpDirectoryRecord.reset(NULL);
- if (mpExcludeFiles)
+ if(mpExcludeFiles)
{
delete mpExcludeFiles;
mpExcludeFiles = NULL;
}
- if (mpExcludeDirs)
+ if(mpExcludeDirs)
{
delete mpExcludeDirs;
mpExcludeDirs = NULL;
@@ -2030,15 +2603,17 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive)
int64_t aMagicMarker = 0;
rArchive.Read(aMagicMarker);
- if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
+ if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
{
// NOOP
}
- else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
+ else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
{
BackupClientDirectoryRecord *pSubRecord = new BackupClientDirectoryRecord(0, "");
- if (!pSubRecord)
+ if(!pSubRecord)
+ {
throw std::bad_alloc();
+ }
mpDirectoryRecord.reset(pSubRecord);
mpDirectoryRecord->Deserialize(rArchive);
@@ -2046,7 +2621,7 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive)
else
{
// there is something going on here
- THROW_EXCEPTION(CommonException, Internal)
+ THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile);
}
//
@@ -2054,22 +2629,24 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive)
//
rArchive.Read(aMagicMarker);
- if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
+ if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
{
// NOOP
}
- else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
+ else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
{
mpExcludeFiles = new ExcludeList;
- if (!mpExcludeFiles)
+ if(!mpExcludeFiles)
+ {
throw std::bad_alloc();
+ }
mpExcludeFiles->Deserialize(rArchive);
}
else
{
// there is something going on here
- THROW_EXCEPTION(CommonException, Internal)
+ THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile);
}
//
@@ -2077,22 +2654,24 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive)
//
rArchive.Read(aMagicMarker);
- if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
+ if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP)
{
// NOOP
}
- else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
+ else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE)
{
mpExcludeDirs = new ExcludeList;
- if (!mpExcludeDirs)
+ if(!mpExcludeDirs)
+ {
throw std::bad_alloc();
+ }
mpExcludeDirs->Deserialize(rArchive);
}
else
{
// there is something going on here
- THROW_EXCEPTION(CommonException, Internal)
+ THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile);
}
}
@@ -2117,7 +2696,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const
//
//
//
- if (mpDirectoryRecord.get() == NULL)
+ if(mpDirectoryRecord.get() == NULL)
{
int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
rArchive.Write(aMagicMarker);
@@ -2133,7 +2712,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const
//
//
//
- if (!mpExcludeFiles)
+ if(!mpExcludeFiles)
{
int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
rArchive.Write(aMagicMarker);
@@ -2149,7 +2728,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const
//
//
//
- if (!mpExcludeDirs)
+ if(!mpExcludeDirs)
{
int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP;
rArchive.Write(aMagicMarker);
@@ -2206,27 +2785,31 @@ BackupDaemon::CommandSocketInfo::~CommandSocketInfo()
static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F;
static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE";
-static const int STOREOBJECTINFO_VERSION = 1;
+static const int STOREOBJECTINFO_VERSION = 2;
-void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const
+bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const
{
if(!GetConfiguration().KeyExists("StoreObjectInfoFile"))
{
- return;
+ return false;
}
std::string StoreObjectInfoFile =
GetConfiguration().GetKeyValue("StoreObjectInfoFile");
- if (StoreObjectInfoFile.size() <= 0)
+ if(StoreObjectInfoFile.size() <= 0)
{
- return;
+ return false;
}
+ bool created = false;
+
try
{
FileStream aFile(StoreObjectInfoFile.c_str(),
O_WRONLY | O_CREAT | O_TRUNC);
+ created = true;
+
Archive anArchive(aFile, 0);
anArchive.Write(STOREOBJECTINFO_MAGIC_ID_VALUE);
@@ -2243,7 +2826,7 @@ void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time
int64_t iCount = mLocations.size();
anArchive.Write(iCount);
- for (int v = 0; v < iCount; v++)
+ for(int v = 0; v < iCount; v++)
{
ASSERT(mLocations[v]);
mLocations[v]->Serialize(anArchive);
@@ -2255,22 +2838,48 @@ void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time
iCount = mIDMapMounts.size();
anArchive.Write(iCount);
- for (int v = 0; v < iCount; v++)
+ for(int v = 0; v < iCount; v++)
anArchive.Write(mIDMapMounts[v]);
//
//
//
+ iCount = mUnusedRootDirEntries.size();
+ anArchive.Write(iCount);
+
+ for(int v = 0; v < iCount; v++)
+ {
+ anArchive.Write(mUnusedRootDirEntries[v].first);
+ anArchive.Write(mUnusedRootDirEntries[v].second);
+ }
+
+ if (iCount > 0)
+ {
+ anArchive.Write(mDeleteUnusedRootDirEntriesAfter);
+ }
+
+ //
+ //
+ //
aFile.Close();
- ::syslog(LOG_INFO, "Saved store object info file '%s'",
- StoreObjectInfoFile.c_str());
+ BOX_INFO("Saved store object info file version " <<
+ STOREOBJECTINFO_VERSION << " (" <<
+ StoreObjectInfoFile << ")");
}
- catch (...)
+ catch(std::exception &e)
{
- ::syslog(LOG_WARNING, "Requested store object info file '%s' "
- "not accessible or could not be created",
- StoreObjectInfoFile.c_str());
+ BOX_ERROR("Internal error writing store object "
+ "info file (" << StoreObjectInfoFile << "): "
+ << e.what());
}
+ catch(...)
+ {
+ BOX_ERROR("Internal error writing store object "
+ "info file (" << StoreObjectInfoFile << "): "
+ "unknown error");
+ }
+
+ return created;
}
// --------------------------------------------------------------------------
@@ -2300,7 +2909,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
std::string StoreObjectInfoFile =
GetConfiguration().GetKeyValue("StoreObjectInfoFile");
- if (StoreObjectInfoFile.size() <= 0)
+ if(StoreObjectInfoFile.size() <= 0)
{
return false;
}
@@ -2316,12 +2925,12 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
int iMagicValue = 0;
anArchive.Read(iMagicValue);
- if (iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE)
+ if(iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE)
{
- ::syslog(LOG_WARNING, "Store object info file '%s' "
+ BOX_WARNING("Store object info file "
"is not a valid or compatible serialised "
- "archive. Will re-cache from store.",
- StoreObjectInfoFile.c_str());
+ "archive. Will re-cache from store. "
+ "(" << StoreObjectInfoFile << ")");
return false;
}
@@ -2331,12 +2940,12 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
std::string strMagicValue;
anArchive.Read(strMagicValue);
- if (strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING)
+ if(strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING)
{
- ::syslog(LOG_WARNING, "Store object info file '%s' "
+ BOX_WARNING("Store object info file "
"is not a valid or compatible serialised "
- "archive. Will re-cache from store.",
- StoreObjectInfoFile.c_str());
+ "archive. Will re-cache from store. "
+ "(" << StoreObjectInfoFile << ")");
return false;
}
@@ -2347,13 +2956,12 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
int iVersion = 0;
anArchive.Read(iVersion);
- if (iVersion != STOREOBJECTINFO_VERSION)
+ if(iVersion != STOREOBJECTINFO_VERSION)
{
- ::syslog(LOG_WARNING, "Store object info file '%s' "
- "version %d unsupported. "
- "Will re-cache from store.",
- StoreObjectInfoFile.c_str(),
- iVersion);
+ BOX_WARNING("Store object info file "
+ "version " << iVersion << " unsupported. "
+ "Will re-cache from store. "
+ "(" << StoreObjectInfoFile << ")");
return false;
}
@@ -2364,11 +2972,11 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
box_time_t lastKnownConfigModTime;
anArchive.Read(lastKnownConfigModTime);
- if (lastKnownConfigModTime != GetLoadedConfigModifiedTime())
+ if(lastKnownConfigModTime != GetLoadedConfigModifiedTime())
{
- ::syslog(LOG_WARNING, "Store object info file '%s' "
- "out of date. Will re-cache from store",
- StoreObjectInfoFile.c_str());
+ BOX_WARNING("Store object info file "
+ "out of date. Will re-cache from store. "
+ "(" << StoreObjectInfoFile << ")");
return false;
}
@@ -2385,11 +2993,13 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
int64_t iCount = 0;
anArchive.Read(iCount);
- for (int v = 0; v < iCount; v++)
+ for(int v = 0; v < iCount; v++)
{
Location* pLocation = new Location;
- if (!pLocation)
+ if(!pLocation)
+ {
throw std::bad_alloc();
+ }
pLocation->Deserialize(anArchive);
mLocations.push_back(pLocation);
@@ -2401,7 +3011,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
iCount = 0;
anArchive.Read(iCount);
- for (int v = 0; v < iCount; v++)
+ for(int v = 0; v < iCount; v++)
{
std::string strItem;
anArchive.Read(strItem);
@@ -2412,28 +3022,53 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
//
//
//
- aFile.Close();
- ::syslog(LOG_INFO, "Loaded store object info file '%s', "
- "version [%d]", StoreObjectInfoFile.c_str(),
- iVersion);
+ iCount = 0;
+ anArchive.Read(iCount);
+
+ for(int v = 0; v < iCount; v++)
+ {
+ int64_t anId;
+ anArchive.Read(anId);
+ std::string aName;
+ anArchive.Read(aName);
+
+ mUnusedRootDirEntries.push_back(std::pair<int64_t, std::string>(anId, aName));
+ }
+
+ if (iCount > 0)
+ anArchive.Read(mDeleteUnusedRootDirEntriesAfter);
+
+ //
+ //
+ //
+ aFile.Close();
+ BOX_INFO("Loaded store object info file version " << iVersion
+ << " (" << StoreObjectInfoFile << ")");
+
return true;
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Internal error reading store object info file: "
+ << StoreObjectInfoFile << ": " << e.what());
}
- catch (...)
+ catch(...)
{
- DeleteAllLocations();
+ BOX_ERROR("Internal error reading store object info file: "
+ << StoreObjectInfoFile << ": unknown error");
+ }
- aClientStoreMarker =
- BackupClientContext::ClientStoreMarker_NotKnown;
- theLastSyncTime = 0;
- theNextSyncTime = 0;
+ DeleteAllLocations();
- ::syslog(LOG_WARNING, "Requested store object info file '%s' "
- "does not exist, not accessible, or inconsistent. "
- "Will re-cache from store.",
- StoreObjectInfoFile.c_str());
- }
+ aClientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown;
+ theLastSyncTime = 0;
+ theNextSyncTime = 0;
+ BOX_WARNING("Store object info file is missing, not accessible, "
+ "or inconsistent. Will re-cache from store. "
+ "(" << StoreObjectInfoFile << ")");
+
return false;
}
@@ -2455,14 +3090,24 @@ bool BackupDaemon::DeleteStoreObjectInfo() const
return false;
}
- std::string StoreObjectInfoFile =
- GetConfiguration().GetKeyValue("StoreObjectInfoFile");
+ std::string storeObjectInfoFile(GetConfiguration().GetKeyValue("StoreObjectInfoFile"));
+
+ // Check to see if the file exists
+ if(!FileExists(storeObjectInfoFile.c_str()))
+ {
+ // File doesn't exist -- so can't be deleted. But something isn't quite right, so log a message
+ BOX_WARNING("Store object info file did not exist when it "
+ "was supposed to. (" << storeObjectInfoFile << ")");
+
+ // Return true to stop things going around in a loop
+ return true;
+ }
- if (::unlink(StoreObjectInfoFile.c_str()) != 0)
+ // Actually delete it
+ if(::unlink(storeObjectInfoFile.c_str()) != 0)
{
- ::syslog(LOG_ERR, "Failed to delete the old "
- "store object info file '%s': %s",
- StoreObjectInfoFile.c_str(), strerror(errno));
+ BOX_ERROR("Failed to delete the old store object info file: "
+ << storeObjectInfoFile << ": "<< strerror(errno));
return false;
}
diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h
index 3b63ae3d..e2d7846f 100644
--- a/bin/bbackupd/BackupDaemon.h
+++ b/bin/bbackupd/BackupDaemon.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -54,9 +54,13 @@
#include "BoxTime.h"
#include "Daemon.h"
+#include "BackupClientDirectoryRecord.h"
#include "Socket.h"
#include "SocketListen.h"
#include "SocketStream.h"
+#include "Logging.h"
+#include "autogen_BackupProtocolClient.h"
+
#ifdef WIN32
#include "WinNamedPipeStream.h"
#endif
@@ -77,23 +81,34 @@ class Archive;
// Created: 2003/10/08
//
// --------------------------------------------------------------------------
-class BackupDaemon : public Daemon
+class BackupDaemon : public Daemon, ProgressNotifier
{
public:
BackupDaemon();
~BackupDaemon();
private:
- // methods below do partial (specialized) serialization of client state only
- void SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const;
- bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime);
+ // methods below do partial (specialized) serialization of
+ // client state only
+ bool SerializeStoreObjectInfo(int64_t aClientStoreMarker,
+ box_time_t theLastSyncTime, box_time_t theNextSyncTime) const;
+ bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker,
+ box_time_t & theLastSyncTime, box_time_t & theNextSyncTime);
bool DeleteStoreObjectInfo() const;
BackupDaemon(const BackupDaemon &);
+
public:
+ #ifdef WIN32
+ // add command-line options to handle Windows services
+ std::string GetOptionString();
+ int ProcessOption(signed int option);
+ int Main(const std::string &rConfigFileName);
+ #endif
void Run();
virtual const char *DaemonName() const;
- virtual const char *DaemonBanner() const;
+ virtual std::string DaemonBanner() const;
+ virtual void Usage();
const ConfigurationVerify *GetConfigVerify() const;
bool FindLocationPathName(const std::string &rLocationName, std::string &rPathOut) const;
@@ -114,8 +129,11 @@ public:
enum
{
NotifyEvent_StoreFull = 0,
- NotifyEvent_ReadError = 1,
- NotifyEvent__MAX = 1
+ NotifyEvent_ReadError,
+ NotifyEvent_BackupError,
+ NotifyEvent_BackupStart,
+ NotifyEvent_BackupFinish,
+ NotifyEvent__MAX
// When adding notifications, remember to add strings to NotifySysadmin()
};
void NotifySysadmin(int Event);
@@ -186,6 +204,8 @@ private:
std::vector<BackupClientInodeToIDMap *> mCurrentIDMaps;
std::vector<BackupClientInodeToIDMap *> mNewIDMaps;
+ int mDeleteRedundantLocationsAfter;
+
// For the command socket
class CommandSocketInfo
{
@@ -209,18 +229,246 @@ private:
CommandSocketInfo *mpCommandSocketInfo;
// Stop notifications being repeated.
- bool mNotificationsSent[NotifyEvent__MAX + 1];
+ bool mNotificationsSent[NotifyEvent__MAX];
// Unused entries in the root directory wait a while before being deleted
box_time_t mDeleteUnusedRootDirEntriesAfter; // time to delete them
std::vector<std::pair<int64_t,std::string> > mUnusedRootDirEntries;
+public:
+ bool StopRun() { return this->Daemon::StopRun(); }
+
+private:
+ bool mLogAllFileAccess;
+
+ /* ProgressNotifier implementation */
+public:
+ virtual void NotifyScanDirectory(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ if (mLogAllFileAccess)
+ {
+ BOX_INFO("Scanning directory: " << rLocalPath);
+ }
+ }
+ virtual void NotifyDirStatFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg)
+ {
+ BOX_WARNING("Failed to access directory: " << rLocalPath
+ << ": " << rErrorMsg);
+ }
+ virtual void NotifyFileStatFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg)
+ {
+ BOX_WARNING("Failed to access file: " << rLocalPath
+ << ": " << rErrorMsg);
+ }
+ virtual void NotifyDirListFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg)
+ {
+ BOX_WARNING("Failed to list directory: " << rLocalPath
+ << ": " << rErrorMsg);
+ }
+ virtual void NotifyMountPointSkipped(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ #ifdef WIN32
+ BOX_WARNING("Ignored directory: " << rLocalPath <<
+ ": is an NTFS junction/reparse point; create "
+ "a new location if you want to back it up");
+ #else
+ BOX_WARNING("Ignored directory: " << rLocalPath <<
+ ": is a mount point; create a new location "
+ "if you want to back it up");
+ #endif
+ }
+ virtual void NotifyFileExcluded(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ if (mLogAllFileAccess)
+ {
+ BOX_INFO("Skipping excluded file: " << rLocalPath);
+ }
+ }
+ virtual void NotifyDirExcluded(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ if (mLogAllFileAccess)
+ {
+ BOX_INFO("Skipping excluded directory: " << rLocalPath);
+ }
+ }
+ virtual void NotifyUnsupportedFileType(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ BOX_WARNING("Ignoring file of unknown type: " << rLocalPath);
+ }
+ virtual void NotifyFileReadFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg)
+ {
+ BOX_WARNING("Error reading file: " << rLocalPath
+ << ": " << rErrorMsg);
+ }
+ virtual void NotifyFileModifiedInFuture(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ BOX_WARNING("Some files have modification times excessively "
+ "in the future. Check clock synchronisation. "
+ "Example file (only one shown): " << rLocalPath);
+ }
+ virtual void NotifyFileSkippedServerFull(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ BOX_WARNING("Skipped file: server is full: " << rLocalPath);
+ }
+ virtual void NotifyFileUploadException(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const BoxException& rException)
+ {
+ if (rException.GetType() == CommonException::ExceptionType &&
+ rException.GetSubType() == CommonException::AccessDenied)
+ {
+ BOX_ERROR("Failed to upload file: " << rLocalPath
+ << ": Access denied");
+ }
+ else
+ {
+ BOX_ERROR("Failed to upload file: " << rLocalPath
+ << ": caught exception: " << rException.what()
+ << " (" << rException.GetType()
+ << "/" << rException.GetSubType() << ")");
+ }
+ }
+ virtual void NotifyFileUploadServerError(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int type, int subtype)
+ {
+ std::ostringstream msgs;
+ if (type != BackupProtocolClientError::ErrorType)
+ {
+ msgs << "unknown error type " << type;
+ }
+ else
+ {
+ switch(subtype)
+ {
+ case BackupProtocolClientError::Err_WrongVersion:
+ msgs << "WrongVersion";
+ break;
+ case BackupProtocolClientError::Err_NotInRightProtocolPhase:
+ msgs << "NotInRightProtocolPhase";
+ break;
+ case BackupProtocolClientError::Err_BadLogin:
+ msgs << "BadLogin";
+ break;
+ case BackupProtocolClientError::Err_CannotLockStoreForWriting:
+ msgs << "CannotLockStoreForWriting";
+ break;
+ case BackupProtocolClientError::Err_SessionReadOnly:
+ msgs << "SessionReadOnly";
+ break;
+ case BackupProtocolClientError::Err_FileDoesNotVerify:
+ msgs << "FileDoesNotVerify";
+ break;
+ case BackupProtocolClientError::Err_DoesNotExist:
+ msgs << "DoesNotExist";
+ break;
+ case BackupProtocolClientError::Err_DirectoryAlreadyExists:
+ msgs << "DirectoryAlreadyExists";
+ break;
+ case BackupProtocolClientError::Err_CannotDeleteRoot:
+ msgs << "CannotDeleteRoot";
+ break;
+ case BackupProtocolClientError::Err_TargetNameExists:
+ msgs << "TargetNameExists";
+ break;
+ case BackupProtocolClientError::Err_StorageLimitExceeded:
+ msgs << "StorageLimitExceeded";
+ break;
+ case BackupProtocolClientError::Err_DiffFromFileDoesNotExist:
+ msgs << "DiffFromFileDoesNotExist";
+ break;
+ case BackupProtocolClientError::Err_DoesNotExistInDirectory:
+ msgs << "DoesNotExistInDirectory";
+ break;
+ case BackupProtocolClientError::Err_PatchConsistencyError:
+ msgs << "PatchConsistencyError";
+ break;
+ default:
+ msgs << "unknown error subtype " << subtype;
+ }
+ }
+
+ BOX_ERROR("Failed to upload file: " << rLocalPath
+ << ": server error: " << msgs.str());
+ }
+ virtual void NotifyFileUploading(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ if (mLogAllFileAccess)
+ {
+ BOX_INFO("Uploading complete file: " << rLocalPath);
+ }
+ }
+ virtual void NotifyFileUploadingPatch(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ if (mLogAllFileAccess)
+ {
+ BOX_INFO("Uploading patch to file: " << rLocalPath);
+ }
+ }
+ virtual void NotifyFileUploaded(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int64_t FileSize)
+ {
+ if (mLogAllFileAccess)
+ {
+ BOX_INFO("Uploaded file: " << rLocalPath);
+ }
+ }
+ virtual void NotifyFileSynchronised(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int64_t FileSize)
+ {
+ if (mLogAllFileAccess)
+ {
+ BOX_INFO("Synchronised file: " << rLocalPath);
+ }
+ }
+
#ifdef WIN32
public:
void RunHelperThread(void);
private:
- bool mDoSyncFlagOut, mSyncIsForcedOut, mReceivedCommandConn;
+ bool mDoSyncFlagOut, mSyncIsForcedOut;
+ bool mInstallService, mRemoveService, mRunAsService;
+ std::string mServiceName;
+ HANDLE mhMessageToSendEvent, mhCommandReceivedEvent;
+ CRITICAL_SECTION mMessageQueueLock;
+ std::vector<std::string> mMessageList;
#endif
};
diff --git a/bin/bbackupd/ClientException.txt b/bin/bbackupd/ClientException.txt
new file mode 100644
index 00000000..04f88620
--- /dev/null
+++ b/bin/bbackupd/ClientException.txt
@@ -0,0 +1,11 @@
+
+# NOTE: Exception descriptions are for public distributions of Box Backup only -- do not rely for other applications.
+
+
+EXCEPTION Client 13
+
+Internal 0
+AssertFailed 1
+ClockWentBackwards 2 Invalid (negative) sync period: perhaps your clock is going backwards?
+FailedToDeleteStoreObjectInfoFile 3 Failed to delete the StoreObjectInfoFile, backup cannot continue safely.
+CorruptStoreObjectInfoFile 4 The store object info file contained an invalid value and is probably corrupt. Try deleting it.
diff --git a/bin/bbackupd/Makefile.extra b/bin/bbackupd/Makefile.extra
new file mode 100644
index 00000000..52e21366
--- /dev/null
+++ b/bin/bbackupd/Makefile.extra
@@ -0,0 +1,7 @@
+
+MAKEEXCEPTION = ../../lib/common/makeexception.pl
+
+# AUTOGEN SEEDING
+autogen_ClientException.h autogen_ClientException.cpp: $(MAKEEXCEPTION) ClientException.txt
+ $(PERL) $(MAKEEXCEPTION) ClientException.txt
+
diff --git a/bin/bbackupd/Win32BackupService.cpp b/bin/bbackupd/Win32BackupService.cpp
index 96f2b057..d275c891 100644
--- a/bin/bbackupd/Win32BackupService.cpp
+++ b/bin/bbackupd/Win32BackupService.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -50,40 +50,37 @@
#include "Win32BackupService.h"
-Win32BackupService gDaemonService;
+Win32BackupService* gpDaemonService = NULL;
extern HANDLE gStopServiceEvent;
+extern DWORD gServiceReturnCode;
unsigned int WINAPI RunService(LPVOID lpParameter)
{
- DWORD retVal = gDaemonService.WinService();
- SetEvent( gStopServiceEvent );
+ DWORD retVal = gpDaemonService->WinService((const char*) lpParameter);
+ gServiceReturnCode = retVal;
+ SetEvent(gStopServiceEvent);
return retVal;
}
void TerminateService(void)
{
- gDaemonService.SetTerminateWanted();
+ gpDaemonService->SetTerminateWanted();
}
-DWORD Win32BackupService::WinService(void)
+DWORD Win32BackupService::WinService(const char* pConfigFileName)
{
- int argc = 2;
- //first off get the path name for the default
- char buf[MAX_PATH];
-
- GetModuleFileName(NULL, buf, sizeof(buf));
- std::string buffer(buf);
- std::string conf( "-c");
- std::string cfile(buffer.substr(0,(buffer.find("bbackupd.exe")))
- + "bbackupd.conf");
+ DWORD ret;
- const char *argv[] = {conf.c_str(), cfile.c_str()};
+ if (pConfigFileName != NULL)
+ {
+ ret = this->Main(pConfigFileName);
+ }
+ else
+ {
+ ret = this->Main(BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE);
+ }
- MAINHELPER_START
-
- return this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv);
-
- MAINHELPER_END
+ return ret;
}
#endif // WIN32
diff --git a/bin/bbackupd/Win32BackupService.h b/bin/bbackupd/Win32BackupService.h
index 980e5d6c..e71c93c5 100644
--- a/bin/bbackupd/Win32BackupService.h
+++ b/bin/bbackupd/Win32BackupService.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -50,7 +50,7 @@ class BackupDaemon;
class Win32BackupService : public BackupDaemon
{
public:
- DWORD WinService(void);
+ DWORD WinService(const char* pConfigFileName);
};
#endif // WIN32
diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp
index 07791af3..276d004f 100644
--- a/bin/bbackupd/Win32ServiceFunctions.cpp
+++ b/bin/bbackupd/Win32ServiceFunctions.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -68,6 +68,7 @@ TCHAR* gServiceName = TEXT("Box Backup Service");
SERVICE_STATUS gServiceStatus;
SERVICE_STATUS_HANDLE gServiceStatusHandle = 0;
HANDLE gStopServiceEvent = 0;
+DWORD gServiceReturnCode = 0;
#define SERVICE_NAME "boxbackup"
@@ -81,8 +82,9 @@ void ErrorHandler(char *s, DWORD err)
{
char buf[256];
memset(buf, 0, sizeof(buf));
- _snprintf(buf, sizeof(buf)-1, "%s (%d)", s, err);
- ::syslog(LOG_ERR, "%s", buf);
+ _snprintf(buf, sizeof(buf)-1, "%s: %s", s,
+ GetErrorMessage(err).c_str());
+ BOX_ERROR(buf);
MessageBox(0, buf, "Error",
MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY);
ExitProcess(err);
@@ -131,28 +133,30 @@ void WINAPI ServiceControlHandler( DWORD controlCode )
// It also returns on any error because the
// service cannot start if there is an eror.
+static char* spConfigFileName;
+
VOID ServiceMain(DWORD argc, LPTSTR *argv)
{
- // initialise service status
- gServiceStatus.dwServiceType = SERVICE_WIN32;
- gServiceStatus.dwCurrentState = SERVICE_STOPPED;
- gServiceStatus.dwControlsAccepted = 0;
- gServiceStatus.dwWin32ExitCode = NO_ERROR;
- gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
- gServiceStatus.dwCheckPoint = 0;
- gServiceStatus.dwWaitHint = 0;
-
- gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName,
- ServiceControlHandler);
-
- if (gServiceStatusHandle)
- {
- // service is starting
- gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
- SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
-
- // do initialisation here
- gStopServiceEvent = CreateEvent( 0, TRUE, FALSE, 0 );
+ // initialise service status
+ gServiceStatus.dwServiceType = SERVICE_WIN32;
+ gServiceStatus.dwCurrentState = SERVICE_STOPPED;
+ gServiceStatus.dwControlsAccepted = 0;
+ gServiceStatus.dwWin32ExitCode = NO_ERROR;
+ gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
+ gServiceStatus.dwCheckPoint = 0;
+ gServiceStatus.dwWaitHint = 0;
+
+ gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName,
+ ServiceControlHandler);
+
+ if (gServiceStatusHandle)
+ {
+ // service is starting
+ gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+ SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
+
+ // do initialisation here
+ gStopServiceEvent = CreateEvent(0, TRUE, FALSE, 0);
if (!gStopServiceEvent)
{
gServiceStatus.dwControlsAccepted &=
@@ -167,7 +171,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv)
NULL,
0,
RunService,
- 0,
+ spConfigFileName,
CREATE_SUSPENDED,
NULL);
@@ -176,7 +180,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv)
// we are now running so tell the SCM
gServiceStatus.dwControlsAccepted |=
- (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
+ (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
gServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
@@ -192,13 +196,23 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv)
// service is now stopped
gServiceStatus.dwControlsAccepted &=
~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
+
gServiceStatus.dwCurrentState = SERVICE_STOPPED;
+
+ if (gServiceReturnCode != 0)
+ {
+ gServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+ gServiceStatus.dwServiceSpecificExitCode = gServiceReturnCode;
+ }
+
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
- }
+ }
}
-void OurService(void)
+int OurService(const char* pConfigFileName)
{
+ spConfigFileName = strdup(pConfigFileName);
+
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain },
@@ -209,54 +223,119 @@ void OurService(void)
// Register with the SCM
success = StartServiceCtrlDispatcher(serviceTable);
+ free(spConfigFileName);
+ spConfigFileName = NULL;
+
if (!success)
{
ErrorHandler("Failed to start service. Did you start "
"Box Backup from the Service Control Manager? "
"(StartServiceCtrlDispatcher)", GetLastError());
+ return 1;
}
+
+ return 0;
}
-void InstallService(void)
+int InstallService(const char* pConfigFileName, const std::string& rServiceName)
{
- SC_HANDLE newService, scm;
+ if (pConfigFileName != NULL)
+ {
+ struct stat st;
- scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
+ if (emu_stat(pConfigFileName, &st) != 0)
+ {
+ BOX_ERROR("Failed to open configuration file '" <<
+ pConfigFileName << "': " << strerror(errno));
+ return 1;
+ }
+
+ if (!(st.st_mode & S_IFREG))
+ {
+
+ BOX_ERROR("Failed to open configuration file '" <<
+ pConfigFileName << "': not a file");
+ return 1;
+ }
+ }
+
+ SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
if (!scm)
{
- syslog(LOG_ERR, "Failed to open service control manager: "
- "error %d", GetLastError());
- return;
+ BOX_ERROR("Failed to open service control manager: " <<
+ GetErrorMessage(GetLastError()));
+ return 1;
}
char cmd[MAX_PATH];
GetModuleFileName(NULL, cmd, sizeof(cmd)-1);
cmd[sizeof(cmd)-1] = 0;
- char cmd_args[MAX_PATH];
- _snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd);
- cmd_args[sizeof(cmd_args)-1] = 0;
+ std::string cmdWithArgs(cmd);
+ cmdWithArgs += " -s -S \"" + rServiceName + "\"";
- newService = CreateService(
+ if (pConfigFileName != NULL)
+ {
+ cmdWithArgs += " \"";
+ cmdWithArgs += pConfigFileName;
+ cmdWithArgs += "\"";
+ }
+
+ std::string serviceDesc = "Box Backup (" + rServiceName + ")";
+
+ SC_HANDLE newService = CreateService(
scm,
- SERVICE_NAME,
- "Box Backup",
+ rServiceName.c_str(),
+ serviceDesc.c_str(),
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
- cmd_args,
+ cmdWithArgs.c_str(),
0,0,0,0,0);
+ DWORD err = GetLastError();
+ CloseServiceHandle(scm);
+
if (!newService)
{
- ::syslog(LOG_ERR, "Failed to create Box Backup service: "
- "error %d", GetLastError());
- return;
+ switch (err)
+ {
+ case ERROR_SERVICE_EXISTS:
+ {
+ BOX_ERROR("Failed to create Box Backup "
+ "service: it already exists");
+ }
+ break;
+
+ case ERROR_SERVICE_MARKED_FOR_DELETE:
+ {
+ BOX_ERROR("Failed to create Box Backup "
+ "service: it is waiting to be deleted");
+ }
+ break;
+
+ case ERROR_DUPLICATE_SERVICE_NAME:
+ {
+ BOX_ERROR("Failed to create Box Backup "
+ "service: a service with this name "
+ "already exists");
+ }
+ break;
+
+ default:
+ {
+ BOX_ERROR("Failed to create Box Backup "
+ "service: error " <<
+ GetErrorMessage(GetLastError()));
+ }
+ }
+
+ return 1;
}
- ::syslog(LOG_INFO, "Created Box Backup service");
+ BOX_INFO("Created Box Backup service");
SERVICE_DESCRIPTION desc;
desc.lpDescription = "Backs up your data files over the Internet";
@@ -264,50 +343,80 @@ void InstallService(void)
if (!ChangeServiceConfig2(newService, SERVICE_CONFIG_DESCRIPTION,
&desc))
{
- ::syslog(LOG_WARNING, "Failed to set description for "
- "Box Backup service: error %d", GetLastError());
+ BOX_WARNING("Failed to set description for Box Backup "
+ "service: " << GetErrorMessage(GetLastError()));
}
CloseServiceHandle(newService);
- CloseServiceHandle(scm);
+
+ return 0;
}
-void RemoveService(void)
+int RemoveService(const std::string& rServiceName)
{
- SC_HANDLE service, scm;
- SERVICE_STATUS status;
-
- scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
+ SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
if (!scm)
{
- syslog(LOG_ERR, "Failed to open service control manager: "
- "error %d", GetLastError());
- return;
+ BOX_ERROR("Failed to open service control manager: " <<
+ GetErrorMessage(GetLastError()));
+ return 1;
}
- service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE);
- ControlService(service, SERVICE_CONTROL_STOP, &status);
+ SC_HANDLE service = OpenService(scm, rServiceName.c_str(),
+ SERVICE_ALL_ACCESS|DELETE);
+ DWORD err = GetLastError();
+ CloseServiceHandle(scm);
if (!service)
{
- syslog(LOG_ERR, "Failed to open Box Backup service: "
- "error %d", GetLastError());
- return;
+ if (err == ERROR_SERVICE_DOES_NOT_EXIST ||
+ err == ERROR_IO_PENDING)
+ // hello microsoft? anyone home?
+ {
+ BOX_ERROR("Failed to open Box Backup service: "
+ "not installed or not found");
+ }
+ else
+ {
+ BOX_ERROR("Failed to open Box Backup service: " <<
+ GetErrorMessage(err));
+ }
+ return 1;
+ }
+
+ SERVICE_STATUS status;
+ if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
+ {
+ err = GetLastError();
+ if (err != ERROR_SERVICE_NOT_ACTIVE)
+ {
+ BOX_WARNING("Failed to stop Box Backup service: " <<
+ GetErrorMessage(err));
+ }
}
- if (DeleteService(service))
+ BOOL deleted = DeleteService(service);
+ err = GetLastError();
+ CloseServiceHandle(service);
+
+ if (deleted)
{
- syslog(LOG_INFO, "Box Backup service deleted");
+ BOX_INFO("Box Backup service deleted");
+ return 0;
+ }
+ else if (err == ERROR_SERVICE_MARKED_FOR_DELETE)
+ {
+ BOX_ERROR("Failed to remove Box Backup service: "
+ "it is already being deleted");
}
else
{
- syslog(LOG_ERR, "Failed to remove Box Backup service: "
- "error %d", GetLastError());
+ BOX_ERROR("Failed to remove Box Backup service: " <<
+ GetErrorMessage(err));
}
- CloseServiceHandle(service);
- CloseServiceHandle(scm);
+ return 1;
}
#endif // WIN32
diff --git a/bin/bbackupd/Win32ServiceFunctions.h b/bin/bbackupd/Win32ServiceFunctions.h
index 98856ca1..f85929b8 100644
--- a/bin/bbackupd/Win32ServiceFunctions.h
+++ b/bin/bbackupd/Win32ServiceFunctions.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -50,8 +50,8 @@
#ifndef WIN32SERVICEFUNCTIONS_H
#define WIN32SERVICEFUNCTIONS_H
-void RemoveService(void);
-void InstallService(void);
-void OurService(void);
+int RemoveService (const std::string& rServiceName);
+int InstallService (const char* pConfigFilePath, const std::string& rServiceName);
+int OurService (const char* pConfigFileName);
#endif
diff --git a/bin/bbackupd/bbackupd-config b/bin/bbackupd/bbackupd-config
index fb73e8d3..880f2e97 100755
--- a/bin/bbackupd/bbackupd-config
+++ b/bin/bbackupd/bbackupd-config
@@ -1,5 +1,5 @@
#!/usr/bin/perl
-# distribution boxbackup-0.10 (svn version: 494)
+# distribution boxbackup-0.11rc1 (svn version: 2023_2024)
#
# Copyright (c) 2003 - 2006
# Ben Summers and contributors. All rights reserved.
@@ -161,9 +161,9 @@ __E
print ' ',$_,"\n" for(@tobackup);
print <<__E;
-Note: If other file systems are mounted inside these directories, then problems may occur
-with files on the store server being renamed incorrectly. This will cause efficiency
-problems, but not affect the integrity of the backups.
+Note: If other file systems are mounted inside these directories, then
+they will NOT be backed up. You will have to create separate locations for
+any mounted filesystems inside your backup locations.
WARNING: Directories not checked against mountpoints. Check mounted filesystems manually.
@@ -249,12 +249,24 @@ $sendmail = 'sendmail' if $sendmail !~ m/\S/;
print NOTIFY <<__EOS;
#!/bin/sh
+# This script is run whenever bbackupd changes state or 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.
+# 3) A backup run starts or finishes.
+#
+# The default script emails the system administrator, except for backups
+# starting and stopping, where it does nothing.
+
SUBJECT="BACKUP PROBLEM on host $hostname"
SENDTO="$current_username"
-if [ \$1 = store-full ]
-then
-$sendmail \$SENDTO <<EOM
+if [ "\$1" = "" ]; then
+ echo "Usage: $0 <store-full|read-error|backup-error|backup-start|backup-finish>" >&2
+ exit 2
+elif [ "\$1" = store-full ]; then
+ $sendmail \$SENDTO <<EOM
Subject: \$SUBJECT (store full)
To: \$SENDTO
@@ -268,8 +280,7 @@ FILES ARE NOT BEING BACKED UP
Please adjust the limits on account $account_num on server $server.
EOM
-elif [ \$1 = read-error ]
-then
+elif [ "\$1" = read-error ]; then
$sendmail \$SENDTO <<EOM
Subject: \$SUBJECT (read errors)
To: \$SENDTO
@@ -282,11 +293,14 @@ THESE FILES ARE NOT BEING BACKED UP
===================================
Check the logs on $hostname for the files and directories which caused
-these errors, and take appropraite action.
+these errors, and take appropriate action.
Other files are being backed up.
EOM
+elif [ "\$1" = backup-start -o "\$1" = backup-finish ]; then
+ # do nothing by default
+ true
else
$sendmail \$SENDTO <<EOM
Subject: \$SUBJECT (unknown)
@@ -325,11 +339,15 @@ TrustedCAsFile = $ca_root_cert
DataDirectory = $working_dir
-# This script is run whenever bbackupd encounters a problem which requires
-# the system administrator to assist:
+# This script is run whenever bbackupd changes state or 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.
+# 3) A backup run starts or finishes.
+#
+# The default script emails the system administrator, except for backups
+# starting and stopping, where it does nothing.
NotifyScript = $notify_script
@@ -340,24 +358,46 @@ if($backup_mode eq 'lazy')
# lazy mode configuration
print CONFIG <<__E;
-# 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
+# The number of seconds between backup runs under normal conditions. To avoid
+# cycles of load on the server, this time is randomly adjusted by a small
# percentage as the daemon runs.
UpdateStoreInterval = 3600
-# A file must have been modified at least 6 hours ago before it will be uploaded.
+# The minimum age of a file, in seconds, that will be uploaded. Avoids
+# repeated uploads of a file which is constantly being modified.
MinimumFileAge = 21600
-# 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)
+# If a file is modified repeated, it won't be uploaded immediately in case
+# it's modified again, due to the MinimumFileAge specified above. However, it
+# should be uploaded eventually even if it is being modified repeatedly. This
+# is how long we should wait, in seconds, after first noticing a change.
+# (86400 seconds = 1 day)
MaxUploadWait = 86400
+# If the connection is idle for some time (e.g. over 10 minutes or 600
+# seconds, not sure exactly how long) then the server will give up and
+# disconnect the client, resulting in Connection Protocol_Timeout errors
+# on the server and TLSReadFailed or TLSWriteFailed errors on the client.
+# Also, some firewalls and NAT gateways will kill idle connections after
+# similar lengths of time.
+#
+# This can happen for example when most files are backed up already and
+# don't need to be sent to the store again, while scanning a large
+# directory, or while calculating diffs of a large file. To avoid this,
+# KeepAliveTime specifies that special keep-alive messages should be sent
+# when the connection is otherwise idle for a certain length of time,
+# specified here in seconds.
+#
+# The default is that these messages are never sent, equivalent to setting
+# this option to zero, but we recommend that all users enable this.
+
+KeepAliveTime = 120
+
__E
}
else
@@ -390,13 +430,17 @@ FileTrackingSizeThreshold = 65535
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.
+# The limit on how much time is spent diffing files, in seconds. 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.
+#
+# * Increase if you have large files, and think the upload of changes is too
+# large and you want bbackupd to spend more time searching for unchanged
+# blocks.
-MaximumDiffingTime = 20
+MaximumDiffingTime = 120
# Uncomment this line to see exactly what the daemon is going when it's connected to the server.
@@ -404,14 +448,20 @@ MaximumDiffingTime = 20
# 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.
+# 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 must output (print) 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
+# no backup will happen for that number of seconds (bbackupd will pause) and
+# then the script will be run again.
+#
+# Use this to temporarily stop bbackupd from syncronising or connecting to the
+# store. For example, you could use this on a laptop to only backup when on a
+# specific network, or when it has a working Internet connection.
# SyncAllowScript = /path/to/intepreter/or/exe script-name parameters etc
@@ -434,7 +484,7 @@ Server
PidFile = /var/run/bbackupd.pid
}
-#
+
# BackupLocations specifies which locations on disc should be backed up. Each
# directory is in the format
#
@@ -456,22 +506,38 @@ Server
# For example:
#
# ExcludeDir = /home/guest-user
-# ExcludeFilesRegex = *.(mp3|MP3)\$
+# 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.
+# explicitly mentioned in a AlwaysInclude directive. However, Box Backup
+# does NOT scan inside excluded directories and will never back up an
+# AlwaysIncluded file or directory inside an excluded directory or any
+# subdirectory thereof.
+#
+# To back up a directory inside an excluded directory, use a configuration
+# like this, to ensure that each directory in the path to the important
+# files is included, but none of their contents will be backed up except
+# the directories further down that path to the important one.
+#
+# ExcludeDirsRegex = ^/home/user/bigfiles/
+# ExcludeFilesRegex = ^/home/user/bigfiles/
+# AlwaysIncludeDir = /home/user/bigfiles/path
+# AlwaysIncludeDir = /home/user/bigfiles/path/to
+# AlwaysIncludeDir = /home/user/bigfiles/path/important
+# AlwaysIncludeDir = /home/user/bigfiles/path/important/files
+# AlwaysIncludeDirsRegex = ^/home/user/bigfiles/path/important/files/
+# AlwaysIncludeFilesRegex = ^/home/user/bigfiles/path/important/files/
#
-# If a directive ends in Regex, then it is a regular expression rather than a
+# 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
{
diff --git a/bin/bbackupd/bbackupd-config.in b/bin/bbackupd/bbackupd-config.in
new file mode 100755
index 00000000..adb5d5e6
--- /dev/null
+++ b/bin/bbackupd/bbackupd-config.in
@@ -0,0 +1,599 @@
+#!@PERL@
+use strict;
+
+# should be running as root
+if($> != 0)
+{
+ printf "\nWARNING: this should be run as root\n\n"
+}
+
+sub error_print_usage
+{
+ print <<__E;
+
+Setup bbackupd config utility.
+
+Bad command line parameters.
+Usage:
+ bbackupd-config config-dir backup-mode account-num server-hostname working-dir backup-dir [more backup directories]
+
+config-dir usually /etc/box
+backup-mode is lazy or snapshot
+ lazy mode runs continously, uploading files over a specified age
+ snapshot mode uploads a snapshot of the filesystem when instructed explicitly
+account-num (hexdecimal) and server-hostname as supplied from the server administrator
+working-dir usually /var/bbackupd
+backup-dir, list of directories to back up
+
+__E
+ print "=========\nERROR:\n",$_[0],"\n\n" if $_[0] ne '';
+ exit(1);
+}
+
+# check and get command line parameters
+if($#ARGV < 4)
+{
+ error_print_usage();
+}
+
+# check for OPENSSL_CONF environment var being set
+if(exists $ENV{'OPENSSL_CONF'})
+{
+ print <<__E;
+
+---------------------------------------
+
+WARNING:
+ You have the OPENSSL_CONF environment variable set.
+ Use of non-standard openssl configs may cause problems.
+
+---------------------------------------
+
+__E
+}
+
+# default locations
+my $default_config_location = '/etc/box/bbackupd.conf';
+
+# command line parameters
+my ($config_dir,$backup_mode,$account_num,$server,$working_dir,@tobackup) = @ARGV;
+
+# check backup mode is valid
+if($backup_mode ne 'lazy' && $backup_mode ne 'snapshot')
+{
+ error_print_usage("ERROR: backup mode must be 'lazy' or 'snapshot'");
+}
+
+# check server exists
+{
+ my @r = gethostbyname($server);
+ if($#r < 0)
+ {
+ error_print_usage("Backup server specified as '$server', but it could not found.\n(A test DNS lookup failed -- check arguments)");
+ }
+}
+
+if($working_dir !~ m~\A/~)
+{
+ error_print_usage("Working directory $working_dir is not specified as an absolute path");
+}
+
+# ssl stuff
+my $private_key = "$config_dir/bbackupd/$account_num-key.pem";
+my $certificate_request = "$config_dir/bbackupd/$account_num-csr.pem";
+my $certificate = "$config_dir/bbackupd/$account_num-cert.pem";
+my $ca_root_cert = "$config_dir/bbackupd/serverCA.pem";
+
+# encryption keys
+my $enc_key_file = "$config_dir/bbackupd/$account_num-FileEncKeys.raw";
+
+# other files
+my $config_file = "$config_dir/bbackupd.conf";
+my $notify_script = "$config_dir/bbackupd/NotifySysadmin.sh";
+
+# check that the directories are allowable
+for(@tobackup)
+{
+ if($_ eq '/')
+ {
+ die "It is not recommended that you backup the root directory of your disc";
+ }
+ if($_ !~ m/\A\//)
+ {
+ die "Directory $_ is not specified as an absolute path";
+ }
+ if(!-d $_)
+ {
+ die "$_ is not a directory";
+ }
+}
+
+# summarise configuration
+
+print <<__E;
+
+Setup bbackupd config utility.
+
+Configuration:
+ Writing configuration file: $config_file
+ Account: $account_num
+ Server hostname: $server
+ Directories to back up:
+__E
+print ' ',$_,"\n" for(@tobackup);
+print <<__E;
+
+Note: If other file systems are mounted inside these directories, then
+they will NOT be backed up. You will have to create separate locations for
+any mounted filesystems inside your backup locations.
+
+WARNING: Directories not checked against mountpoints. Check mounted filesystems manually.
+
+__E
+
+# create directories
+if(!-d $config_dir)
+{
+ printf "Creating $config_dir...\n";
+ mkdir $config_dir,0755 or die "Can't create $config_dir";
+}
+
+if(!-d "$config_dir/bbackupd")
+{
+ printf "Creating $config_dir/bbackupd\n";
+ mkdir "$config_dir/bbackupd",0700 or die "Can't create $config_dir/bbackupd";
+}
+
+if(!-d "$working_dir")
+{
+ printf "Creating $working_dir\n";
+ if(!mkdir($working_dir,0700))
+ {
+ die "Couldn't create $working_dir -- create this manually and try again\n";
+ }
+}
+
+# generate the private key for the server
+if(!-f $private_key)
+{
+ print "Generating private key...\n";
+ if(system("openssl genrsa -out $private_key 2048") != 0)
+ {
+ die "Couldn't generate private key."
+ }
+}
+
+# generate a certificate request
+if(!-f $certificate_request)
+{
+ die "Couldn't run openssl for CSR generation" unless
+ open(CSR,"|openssl req -new -key $private_key -sha1 -out $certificate_request");
+ print CSR <<__E;
+.
+.
+.
+.
+.
+BACKUP-$account_num
+.
+.
+.
+
+__E
+ close CSR;
+ print "\n\n";
+ die "Certificate request wasn't created.\n" unless -f $certificate_request
+}
+
+# generate the key material for the file
+if(!-f $enc_key_file)
+{
+ print "Generating keys for file backup\n";
+ if(system("openssl rand -out $enc_key_file 1024") != 0)
+ {
+ die "Couldn't generate file backup keys."
+ }
+}
+
+# write the notify when store full script
+print "Writing notify script $notify_script\n";
+open NOTIFY,">$notify_script" or die "Can't open for writing";
+
+my $hostname = `hostname`; chomp $hostname;
+my $current_username = `whoami`; chomp $current_username;
+my $sendmail = `whereis sendmail`; chomp $sendmail;
+$sendmail =~ s/\n.\Z//s;
+# for Linux style whereis
+$sendmail = $1 if $sendmail =~ /^sendmail:\s+([\S]+)/;
+# last ditch guess
+$sendmail = 'sendmail' if $sendmail !~ m/\S/;
+
+print NOTIFY <<__EOS;
+#!/bin/sh
+
+# This script is run whenever bbackupd changes state or 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.
+# 3) A backup run starts or finishes.
+#
+# The default script emails the system administrator, except for backups
+# starting and stopping, where it does nothing.
+
+SUBJECT="BACKUP PROBLEM on host $hostname"
+SENDTO="$current_username"
+
+if [ "\$1" = "" ]; then
+ echo "Usage: $0 <store-full|read-error|backup-error|backup-start|backup-finish>" >&2
+ exit 2
+elif [ "\$1" = store-full ]; then
+ $sendmail \$SENDTO <<EOM
+Subject: \$SUBJECT (store full)
+To: \$SENDTO
+
+
+The store account for $hostname 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 $hostname.
+
+===================================
+THESE FILES ARE NOT BEING BACKED UP
+===================================
+
+Check the logs on $hostname for the files and directories which caused
+these errors, and take appropriate action.
+
+Other files are being backed up.
+
+EOM
+elif [ "\$1" = backup-start -o "\$1" = backup-finish ]; then
+ # do nothing by default
+ true
+else
+$sendmail \$SENDTO <<EOM
+Subject: \$SUBJECT (unknown)
+To: \$SENDTO
+
+
+The backup daemon on $hostname reported an unknown error.
+
+==========================
+FILES MAY NOT BE BACKED UP
+==========================
+
+Please check the logs on $hostname.
+
+EOM
+fi
+__EOS
+
+close NOTIFY;
+chmod 0700,$notify_script or die "Can't chmod $notify_script";
+
+
+# write the configuration file
+print "Writing configuration file $config_file\n";
+open CONFIG,">$config_file" or die "Can't open config file for writing";
+print CONFIG <<__E;
+
+StoreHostname = $server
+AccountNumber = 0x$account_num
+KeysFile = $enc_key_file
+
+CertificateFile = $certificate
+PrivateKeyFile = $private_key
+TrustedCAsFile = $ca_root_cert
+
+DataDirectory = $working_dir
+
+
+# This script is run whenever bbackupd changes state or 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.
+# 3) A backup run starts or finishes.
+#
+# The default script emails the system administrator, except for backups
+# starting and stopping, where it does nothing.
+
+NotifyScript = $notify_script
+
+__E
+
+if($backup_mode eq 'lazy')
+{
+ # lazy mode configuration
+ print CONFIG <<__E;
+
+# The number of seconds between backup runs under normal conditions. To avoid
+# cycles of load on the server, this time is randomly adjusted by a small
+# percentage as the daemon runs.
+
+UpdateStoreInterval = 3600
+
+
+# The minimum age of a file, in seconds, that will be uploaded. Avoids
+# repeated uploads of a file which is constantly being modified.
+
+MinimumFileAge = 21600
+
+
+# If a file is modified repeated, it won't be uploaded immediately in case
+# it's modified again, due to the MinimumFileAge specified above. However, it
+# should be uploaded eventually even if it is being modified repeatedly. This
+# is how long we should wait, in seconds, after first noticing a change.
+# (86400 seconds = 1 day)
+
+MaxUploadWait = 86400
+
+# If the connection is idle for some time (e.g. over 10 minutes or 600
+# seconds, not sure exactly how long) then the server will give up and
+# disconnect the client, resulting in Connection Protocol_Timeout errors
+# on the server and TLSReadFailed or TLSWriteFailed errors on the client.
+# Also, some firewalls and NAT gateways will kill idle connections after
+# similar lengths of time.
+#
+# This can happen for example when most files are backed up already and
+# don't need to be sent to the store again, while scanning a large
+# directory, or while calculating diffs of a large file. To avoid this,
+# KeepAliveTime specifies that special keep-alive messages should be sent
+# when the connection is otherwise idle for a certain length of time,
+# specified here in seconds.
+#
+# The default is that these messages are never sent, equivalent to setting
+# this option to zero, but we recommend that all users enable this.
+
+KeepAliveTime = 120
+
+__E
+}
+else
+{
+ # snapshot configuration
+ print CONFIG <<__E;
+
+# This configuration file is written for snapshot mode.
+# You will need to run bbackupctl to instruct the daemon to upload files.
+
+AutomaticBackup = no
+UpdateStoreInterval = 0
+MinimumFileAge = 0
+MaxUploadWait = 0
+
+__E
+}
+
+print CONFIG <<__E;
+
+# 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, in seconds. 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 you want bbackupd to spend more time searching for unchanged
+# blocks.
+
+MaximumDiffingTime = 120
+
+
+# Uncomment this line to see exactly what the daemon is going when it's connected to the server.
+
+# ExtendedLogging = yes
+
+
+# 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 must output (print) 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
+# no backup will happen for that number of seconds (bbackupd will pause) and
+# then the script will be run again.
+#
+# Use this to temporarily stop bbackupd from syncronising or connecting to the
+# store. For example, you could use this on a laptop to only backup when on a
+# specific network, or when it has a working Internet connection.
+
+# SyncAllowScript = /path/to/intepreter/or/exe script-name parameters etc
+
+
+# Where the command socket is created in the filesystem.
+
+CommandSocket = /var/run/bbackupd.sock
+
+# Uncomment the StoreObjectInfoFile to enable the experimental archiving
+# of the daemon's state (including client store marker and configuration)
+# between backup runs. This saves time and increases efficiency when
+# bbackupd is frequently stopped and started, since it removes the need
+# to rescan all directories on the remote server. However, it is new and
+# not yet heavily tested, so use with caution.
+
+# StoreObjectInfoFile = $working_dir/bbackupd.state
+
+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. However, Box Backup
+# does NOT scan inside excluded directories and will never back up an
+# AlwaysIncluded file or directory inside an excluded directory or any
+# subdirectory thereof.
+#
+# To back up a directory inside an excluded directory, use a configuration
+# like this, to ensure that each directory in the path to the important
+# files is included, but none of their contents will be backed up except
+# the directories further down that path to the important one.
+#
+# ExcludeDirsRegex = ^/home/user/bigfiles/
+# ExcludeFilesRegex = ^/home/user/bigfiles/
+# AlwaysIncludeDir = /home/user/bigfiles/path
+# AlwaysIncludeDir = /home/user/bigfiles/path/to
+# AlwaysIncludeDir = /home/user/bigfiles/path/important
+# AlwaysIncludeDir = /home/user/bigfiles/path/important/files
+# AlwaysIncludeDirsRegex = ^/home/user/bigfiles/path/important/files/
+# AlwaysIncludeFilesRegex = ^/home/user/bigfiles/path/important/files/
+#
+# 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
+{
+__E
+
+# write the dirs to backup
+for my $d (@tobackup)
+{
+ $d =~ m/\A.(.+)\Z/;
+ my $n = $1;
+ $n =~ tr`/`-`;
+
+ my $excludekeys = '';
+ if(substr($enc_key_file, 0, length($d)+1) eq $d.'/')
+ {
+ $excludekeys = "\t\tExcludeFile = $enc_key_file\n";
+ print <<__E;
+
+NOTE: Keys file has been explicitly excluded from the backup.
+
+__E
+ }
+
+ print CONFIG <<__E
+ $n
+ {
+ Path = $d
+$excludekeys }
+__E
+}
+
+print CONFIG "}\n\n";
+close CONFIG;
+
+# explain to the user what they need to do next
+my $daemon_args = ($config_file eq $default_config_location)?'':" $config_file";
+my $ctl_daemon_args = ($config_file eq $default_config_location)?'':" -c $config_file";
+
+print <<__E;
+
+===================================================================
+
+bbackupd basic configuration complete.
+
+What you need to do now...
+
+1) Make a backup of $enc_key_file
+ This should be a secure offsite backup.
+ Without it, you cannot restore backups. Everything else can
+ be replaced. But this cannot.
+ KEEP IT IN A SAFE PLACE, OTHERWISE YOUR BACKUPS ARE USELESS.
+
+2) Send $certificate_request
+ to the administrator of the backup server, and ask for it to
+ be signed.
+
+3) The administrator will send you two files. Install them as
+ $certificate
+ $ca_root_cert
+ after checking their authenticity.
+
+4) You may wish to read the configuration file
+ $config_file
+ and adjust as appropraite.
+
+ There are some notes in it on excluding files you do not
+ wish to be backed up.
+
+5) Review the script
+ $notify_script
+ and check that it will email the right person when the store
+ becomes full. This is important -- when the store is full, no
+ more files will be backed up. You want to know about this.
+
+6) Start the backup daemon with the command
+ /usr/local/bin/bbackupd$daemon_args
+ in /etc/rc.local, or your local equivalent.
+ Note that bbackupd must run as root.
+__E
+if($backup_mode eq 'snapshot')
+{
+ print <<__E;
+
+7) Set up a cron job to run whenever you want a snapshot of the
+ file system to be taken. Run the command
+ /usr/local/bin/bbackupctl -q$ctl_daemon_args sync
+__E
+}
+print <<__E;
+
+===================================================================
+
+Remember to make a secure, offsite backup of your backup keys,
+as described in step 1 above. If you do not, you have no backups.
+
+__E
+
diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp
index 1ccfc7f8..c8320454 100644
--- a/bin/bbackupd/bbackupd.cpp
+++ b/bin/bbackupd/bbackupd.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -50,6 +50,7 @@
#include "MainHelper.h"
#include "BoxPortsAndFiles.h"
#include "BackupStoreException.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -57,82 +58,37 @@
#include "Win32ServiceFunctions.h"
#include "Win32BackupService.h"
- extern Win32BackupService gDaemonService;
+ extern Win32BackupService* gpDaemonService;
#endif
int main(int argc, const char *argv[])
{
- MAINHELPER_START
-
-#ifdef WIN32
-
- ::openlog("Box Backup (bbackupd)", 0, 0);
+ int ExitCode = 0;
- if(argc == 2 &&
- (::strcmp(argv[1], "--help") == 0 ||
- ::strcmp(argv[1], "-h") == 0))
- {
- printf("-h help, -i install service, -r remove service,\n"
- "-c <config file> start daemon now");
- return 2;
- }
- if(argc == 2 && ::strcmp(argv[1], "-r") == 0)
- {
- RemoveService();
- return 0;
- }
- if(argc == 2 && ::strcmp(argv[1], "-i") == 0)
- {
- InstallService();
- return 0;
- }
+ MAINHELPER_START
- bool runAsWin32Service = false;
- if (argc == 2 && ::strcmp(argv[1], "--service") == 0)
- {
- runAsWin32Service = true;
- }
+ Logging::SetProgramName("Box Backup (bbackupd)");
+ Logging::ToConsole(true);
+ Logging::ToSyslog (true);
- // Under win32 we must initialise the Winsock library
- // before using sockets
-
- WSADATA info;
-
- if (WSAStartup(0x0101, &info) == SOCKET_ERROR)
- {
- // box backup will not run without sockets
- ::syslog(LOG_ERR, "Failed to initialise Windows Sockets");
- THROW_EXCEPTION(BackupStoreException, Internal)
- }
+#ifdef WIN32
EnableBackupRights();
- int ExitCode = 0;
-
- if (runAsWin32Service)
- {
- syslog(LOG_INFO,"Starting Box Backup Service");
- OurService();
- }
- else
- {
- ExitCode = gDaemonService.Main(
- BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv);
- }
-
- // Clean up our sockets
- WSACleanup();
-
- ::closelog();
-
- return ExitCode;
+ gpDaemonService = new Win32BackupService();
+ ExitCode = gpDaemonService->Daemon::Main(
+ BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE,
+ argc, argv);
+ delete gpDaemonService;
#else // !WIN32
BackupDaemon daemon;
- return daemon.Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv);
+ ExitCode = daemon.Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv);
#endif // WIN32
MAINHELPER_END
+
+ return ExitCode;
}
diff --git a/bin/bbackupd/win32/NotifySysAdmin.vbs b/bin/bbackupd/win32/NotifySysAdmin.vbs
new file mode 100644
index 00000000..49082887
--- /dev/null
+++ b/bin/bbackupd/win32/NotifySysAdmin.vbs
@@ -0,0 +1,95 @@
+Dim hostname
+Dim account
+Dim from
+Dim sendto
+Dim subjtmpl
+Dim subject
+Dim body
+Dim smtpserver
+
+Set WshNet = CreateObject("WScript.Network")
+hostname = WshNet.ComputerName
+
+account = "0a1"
+from = "boxbackup@" & hostname
+sendto = "admin@example.com"
+subjtmpl = "BACKUP PROBLEM on host " & hostname
+smtpserver = "smtp.example.com"
+
+Set args = WScript.Arguments
+
+If args(0) = "store-full" Then
+ subject = subjtmpl & " (store full)"
+ body = "The store account for "&hostname&" is full." & vbCrLf & vbCrLf & _
+ "=============================" & vbCrLf & _
+ "FILES ARE NOT BEING BACKED UP" & vbCrLf & _
+ "=============================" & vbCrLf & vbCrLf & _
+ "Please adjust the limits on account "&account&" on server "&hostname&"." _
+ & vbCrLf
+ SendMail from,sendto,subject,body
+ElseIf args(0) = "read-error" Then
+ subject = subjtmpl & " (read errors)"
+ body = "Errors occured reading some files or directories for backup on "&hostname&"." _
+ & vbCrLf & vbCrLf & _
+ "===================================" & vbCrLf & _
+ "THESE FILES ARE NOT BEING BACKED UP" & vbCrLf & _
+ "===================================" & vbCrLf & vbCrLf & _
+ "Check the logs on "&hostname&" for the files and directories which caused" & _
+ "these errors, and take appropraite action." & vbCrLf & vbCrLf & _
+ "Other files are being backed up." & vbCrLf
+ SendMail from,sendto,subject,body
+ElseIf args(0) = "backup-start" Or args(0) = "backup-finish" Then
+ ' do nothing for these messages by default
+Else
+ subject = subjtmpl & " (unknown)"
+ body = "The backup daemon on "&hostname&" reported an unknown error." _
+ & vbCrLf & vbCrLf & _
+ "==========================" & vbCrLf & _
+ "FILES MAY NOT BE BACKED UP" & vbCrLf & _
+ "==========================" & vbCrLf & vbCrLf & _
+ "Please check the logs on "&hostname&"." & vbCrLf
+ SendMail from,sendto,subject,body
+End If
+
+Function CheckSMTPSvc()
+ Set objWMISvc = GetObject("winmgmts:" _
+ & "{impersonationLevel=impersonate}!\\.\root\cimv2")
+ Set colSMTPSvc = objWMISvc.ExecQuery("Select * From Win32_Service " _
+ & "Where Name='SMTPSVC'")
+ If colSMTPSvc.Count > 0 Then
+ CheckSMTPSvc = True
+ Else
+ CheckSMTPSvc = False
+ End If
+End Function
+
+Sub SendMail(from,sendto,subject,body)
+ Set objEmail = CreateObject("CDO.Message")
+ Set WshShell = CreateObject("WScript.Shell")
+ Dim cdoschema
+ cdoschema = "http://schemas.microsoft.com/cdo/configuration/"
+
+ With objEmail
+ .From = from
+ .To = sendto
+ .Subject = subject
+ .TextBody = body
+ If CheckSMTPSvc = False Then
+ .Configuration.Fields.Item(cdoschema & "sendusing") = 2
+ .Configuration.Fields.Item(cdoschema & "smtpserver") = smtpserver
+ .Configuration.Fields.Item(cdoschema & "smtpserverport") = 25
+ .Configuration.Fields.Update
+ End If
+ End With
+ On Error Resume Next
+ rc = objEmail.Send
+ If rc Then
+ WshShell.Exec "eventcreate /L Application /ID 201 /T WARNING " _
+ & "/SO ""Box Backup"" /D """ & args(0) _
+ & " notification sent to " & sendto & "."""
+ Else
+ WshShell.Exec "eventcreate /L Application /ID 202 /T ERROR " _
+ & "/SO ""Box Backup"" /D ""Failed to send " & args(0) _
+ & " notification to " & sendto & "."""
+ End If
+End Sub
diff --git a/bin/bbackupd/win32/ReadMe.txt b/bin/bbackupd/win32/ReadMe.txt
deleted file mode 100644
index 3d260750..00000000
--- a/bin/bbackupd/win32/ReadMe.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Upgrade instructions
-
-Version 0.09g to 0.09h
-
-This version included patches to the server as well. The server for this
-upgrade can be found at http://home.earthlink.net/~gniemcew/ but hopefully
-will be merged into the core in the next release.
-
-New values in the bbackupd.conf can now be added:
-
-StoreObjectInfoFile = C:\Program Files\Box Backup\bbackupd\bbackupd.dat
-
-This stores the state when a backup daemon is shutdown.
-
-KeepAliveTime = 250
-
-This is imperative if MaximumDiffingTime is larger than 300, this stops the ssl
-layer timing out when a diff is performed. It is wise to set MaximumDiffingTime
-long enough for the largest file you may have. If you do not wish to upgrade your
-server then make KeepAliveTime greater than MaximumDiffingTime.
-
-Have fun
-
-Nick
diff --git a/bin/bbackupd/win32/bbackupd.conf b/bin/bbackupd/win32/bbackupd.conf
index 85915520..6c987f7d 100644
--- a/bin/bbackupd/win32/bbackupd.conf
+++ b/bin/bbackupd/win32/bbackupd.conf
@@ -12,34 +12,69 @@ DataDirectory = C:\Program Files\Box Backup\bbackupd
# If you do not install it in the default location - also do not forget to
# change the pid file location (below)
-
-# This script is run whenever bbackupd encounters a problem which requires
-# the system administrator to assist:
+# This script is run whenever bbackupd changes state or 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.
+# 3) A backup run starts or finishes.
+#
+# The default script emails the system administrator, except for backups
+# starting and stopping, where it does nothing.
+#
+# NOTE: You need to edit the following variables in the script before
+# enabling it:
+#
+# account = "accountnumber"
+# sendto = "your@email.address"
+# smtpserver = "your.smtp.server"
+#
+# You do not need to set smtpserver if the client has the SMTP Service
+# installed, the script will connect directly to the SMTP service.
-# NotifyScript = NotifySysadmin.sh
+NotifyScript = cscript "C:\Program Files\Box Backup\NotifySysAdmin.vbs"
-# 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
+# The number of seconds between backup runs under normal conditions. To avoid
+# cycles of load on the server, this time is randomly adjusted by a small
# percentage as the daemon runs.
UpdateStoreInterval = 3600
-# A file must have been modified at least 6 hours ago before it will be uploaded.
+# The minimum age of a file, in seconds, that will be uploaded. Avoids
+# repeated uploads of a file which is constantly being modified.
MinimumFileAge = 21600
-# 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)
+# If a file is modified repeated, it won't be uploaded immediately in case
+# it's modified again, due to the MinimumFileAge specified above. However, it
+# should be uploaded eventually even if it is being modified repeatedly. This
+# is how long we should wait, in seconds, after first noticing a change.
+# (86400 seconds = 1 day)
MaxUploadWait = 86400
+# If the connection is idle for some time (e.g. over 10 minutes or 600
+# seconds, not sure exactly how long) then the server will give up and
+# disconnect the client, resulting in Connection Protocol_Timeout errors
+# on the server and TLSReadFailed or TLSWriteFailed errors on the client.
+# Also, some firewalls and NAT gateways will kill idle connections after
+# similar lengths of time.
+#
+# This can happen for example when most files are backed up already and
+# don't need to be sent to the store again, while scanning a large
+# directory, or while calculating diffs of a large file. To avoid this,
+# KeepAliveTime specifies that special keep-alive messages should be sent
+# when the connection is otherwise idle for a certain length of time,
+# specified here in seconds.
+#
+# The default is that these messages are never sent, equivalent to setting
+# this option to zero, but we recommend that all users enable this.
+
+KeepAliveTime = 120
+
# 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)
@@ -53,30 +88,38 @@ FileTrackingSizeThreshold = 65535
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.
+# The limit on how much time is spent diffing files, in seconds. 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.
+#
+# * Increase if you have large files, and think the upload of changes is too
+# large and you want bbackupd to spend more time searching for unchanged
+# blocks.
-MaximumDiffingTime = 20
+MaximumDiffingTime = 120
-# KeepAliveTime requires Gary's SSL KeepAlive patches
-# KeepAliveTime = 250
# 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.
+# 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 must output (print) 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
+# no backup will happen for that number of seconds (bbackupd will pause) and
+# then the script will be run again.
+#
+# Use this to temporarily stop bbackupd from syncronising or connecting to the
+# store. For example, you could use this on a laptop to only backup when on a
+# specific network, or when it has a working Internet connection.
# SyncAllowScript = /path/to/intepreter/or/exe script-name parameters etc
@@ -85,16 +128,21 @@ MaximumDiffingTime = 20
CommandSocket = pipe
+# Uncomment the StoreObjectInfoFile to enable the experimental archiving
+# of the daemon's state (including client store marker and configuration)
+# between backup runs. This saves time and increases efficiency when
+# bbackupd is frequently stopped and started, since it removes the need
+# to rescan all directories on the remote server. However, it is new and
+# not yet heavily tested, so use with caution.
+
+StoreObjectInfoFile = C:\Program Files\Box Backup\bbackupd\bbackupd.state
Server
{
PidFile = C:\Program Files\Box Backup\bbackupd\bbackupd.pid
}
-# StoreObjectInfoFile requires Gary's client marker serialisation patch
-# StoreObjectInfoFile = C:\Program Files\Box Backup\bbackupd\bbackupd.dat
-#
# BackupLocations specifies which locations on disc should be backed up. Each
# directory is in the format
#
@@ -116,22 +164,69 @@ Server
# For example:
#
# ExcludeDir = /home/guest-user
-# ExcludeFilesRegex = *.(mp3|MP3)$
+# 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.
-#
+# explicit full pathname. See:
+#
+# http://bbdev.fluffy.co.uk/trac/wiki/Win32Regex
+#
+# for more information about regular expressions on Windows.
+#
+# In general, Exclude excludes a file or directory, unless the directory is
+# explicitly mentioned in a AlwaysInclude directive. However, Box Backup
+# does NOT scan inside excluded directories and will never back up an
+# AlwaysIncluded file or directory inside an excluded directory or any
+# subdirectory thereof.
+#
+# To back up a directory inside an excluded directory, use a configuration
+# like this, to ensure that each directory in the path to the important
+# files is included, but none of their contents will be backed up except
+# the directories further down that path to the important one.
+#
+# ExcludeDirsRegex = ^/home/user/bigfiles/
+# ExcludeFilesRegex = ^/home/user/bigfiles/
+# AlwaysIncludeDir = /home/user/bigfiles/path
+# AlwaysIncludeDir = /home/user/bigfiles/path/to
+# AlwaysIncludeDir = /home/user/bigfiles/path/important
+# AlwaysIncludeDir = /home/user/bigfiles/path/important/files
+# AlwaysIncludeDirsRegex = ^/home/user/bigfiles/path/important/files/
+# AlwaysIncludeFilesRegex = ^/home/user/bigfiles/path/important/files/
+#
+# Here are some more examples of possible regular expressions for Windows:
+#
+# ExcludeDir = C:\Documents and Settings\Owner
+# ExcludeFilesRegex = \.(mp3|MP3)$
+# AlwaysIncludeFile = C:\Documents and Settings\Owner\My Documents\My Music\veryimportant.mp3
+# ExcludeFilesRegex = \.pst$
+# AlwaysIncludeFilesRegex = \.*backup.*\.pst$
+# ExcludeFilesRegex = \.avi$
+# ExcludeDirsRegex = \\Temporary Internet Files$
+# ExcludeFilesRegex = \\pagefile\.sys$
+# ExcludeDirsRegex = \\pagefile\.sys$
+# ExcludeFilesRegex = \\boot\.ini$
+# ExcludeFilesRegex = \\NTDETECT\.COM$
+# ExcludeFilesRegex = \\UsrClass\.dat\.LOG$
+# ExcludeDirsRegex = \\System Volume Information$
+# ExcludeFilesRegex = \\ntldr$
+# ExcludeDirsRegex = \\Local Settings\\.*\\Cache$
+# ExcludeFilesRegex = \\thumbs\.db$
+# ExcludeFilesRegex = \\~.*
+# ExcludeFilesRegex = \\Perflib.*
+# ExcludeDirsRegex = \\Application Data$
+# ExcludeFilesRegex = \.bk[~!0-9]$
+# ExcludeFilesRegex = \.iso$
+# ExcludeFilesRegex = \.mpe?[2345g]$
+# ExcludeFilesRegex = \.qbw$
+# AlwaysIncludeFilesRegex = \.qbb$
+# ExcludeFilesRegex = \.tif[f]$
+# ExcludeFilesRegex = \.wmv$
+# ExcludeFilesRegex = \.avi$
+# ExcludeFilesRegex = \.(avi|iso|mp(e)?[g345]|bk[~!1-9]|[mt]bk)$
BackupLocations
{
diff --git a/bin/bbackupobjdump/bbackupobjdump.cpp b/bin/bbackupobjdump/bbackupobjdump.cpp
index 3b2b86a0..41acaf38 100644
--- a/bin/bbackupobjdump/bbackupobjdump.cpp
+++ b/bin/bbackupobjdump/bbackupobjdump.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp
index d254ba9c..ee650b9c 100644
--- a/bin/bbackupquery/BackupQueries.cpp
+++ b/bin/bbackupquery/BackupQueries.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -64,6 +64,7 @@
#endif
#include <set>
+#include <limits>
#include "BackupQueries.h"
#include "Utils.h"
@@ -83,13 +84,19 @@
#include "BackupStoreException.h"
#include "ExcludeList.h"
#include "BackupClientMakeExcludeList.h"
+#include "PathUtils.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
-#define COMPARE_RETURN_SAME 1
+// min() and max() macros from stdlib.h break numeric_limits<>::min(), etc.
+#undef min
+#undef max
+
+#define COMPARE_RETURN_SAME 1
#define COMPARE_RETURN_DIFFERENT 2
#define COMPARE_RETURN_ERROR 3
-
+#define COMMAND_RETURN_ERROR 4
// --------------------------------------------------------------------------
//
@@ -107,7 +114,11 @@ BackupQueries::BackupQueries(BackupProtocolClient &rConnection, const Configurat
mWarnedAboutOwnerAttributes(false),
mReturnCode(0) // default return code
{
+ #ifdef WIN32
+ mRunningAsRoot = TRUE;
+ #else
mRunningAsRoot = (::geteuid() == 0);
+ #endif
}
// --------------------------------------------------------------------------
@@ -122,15 +133,21 @@ BackupQueries::~BackupQueries()
{
}
+typedef struct
+{
+ const char* name;
+ const char* opts;
+} QueryCommandSpecification;
+
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupQueries::DoCommand(const char *)
+// Name: BackupQueries::DoCommand(const char *, bool)
// Purpose: Perform a command
// Created: 2003/10/10
//
// --------------------------------------------------------------------------
-void BackupQueries::DoCommand(const char *Command)
+void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
{
// is the command a shell command?
if(Command[0] == 's' && Command[1] == 'h' && Command[2] == ' ' && Command[3] != '\0')
@@ -191,6 +208,25 @@ void BackupQueries::DoCommand(const char *Command)
if(!s.empty()) cmdElements.push_back(s);
}
+ #ifdef WIN32
+ if (isFromCommandLine)
+ {
+ for (std::vector<std::string>::iterator
+ i = cmdElements.begin();
+ i != cmdElements.end(); i++)
+ {
+ std::string converted;
+ if (!ConvertEncoding(*i, CP_ACP, converted,
+ GetConsoleCP()))
+ {
+ BOX_ERROR("Failed to convert encoding");
+ return;
+ }
+ *i = converted;
+ }
+ }
+ #endif
+
// Check...
if(cmdElements.size() < 1)
{
@@ -199,8 +235,24 @@ void BackupQueries::DoCommand(const char *Command)
}
// Data about commands
- static const char *commandNames[] = {"quit", "exit", "list", "pwd", "cd", "lcd", "sh", "getobject", "get", "compare", "restore", "help", "usage", "undelete", 0};
- static const char *validOptions[] = {"", "", "rodIFtsh", "", "od", "", "", "", "i", "alcqE", "dri", "", "", "", 0};
+ static QueryCommandSpecification commands[] =
+ {
+ { "quit", "" },
+ { "exit", "" },
+ { "list", "rodIFtTsh", },
+ { "pwd", "" },
+ { "cd", "od" },
+ { "lcd", "" },
+ { "sh", "" },
+ { "getobject", "" },
+ { "get", "i" },
+ { "compare", "alcqAEQ" },
+ { "restore", "dri" },
+ { "help", "" },
+ { "usage", "" },
+ { "undelete", "" },
+ { NULL, NULL }
+ };
#define COMMAND_Quit 0
#define COMMAND_Exit 1
#define COMMAND_List 2
@@ -220,11 +272,11 @@ void BackupQueries::DoCommand(const char *Command)
// Work out which command it is...
int cmd = 0;
- while(commandNames[cmd] != 0 && ::strcmp(cmdElements[0].c_str(), commandNames[cmd]) != 0)
+ while(commands[cmd].name != 0 && ::strcmp(cmdElements[0].c_str(), commands[cmd].name) != 0)
{
cmd++;
}
- if(commandNames[cmd] == 0)
+ if(commands[cmd].name == 0)
{
// Check for aliases
int a;
@@ -241,7 +293,7 @@ void BackupQueries::DoCommand(const char *Command)
// No such command
if(alias[a] == 0)
{
- printf("Unrecognised command: %s\n", Command);
+ BOX_ERROR("Unrecognised command: " << Command);
return;
}
}
@@ -259,9 +311,10 @@ void BackupQueries::DoCommand(const char *Command)
while(*c != 0)
{
// Valid option?
- if(::strchr(validOptions[cmd], *c) == NULL)
+ if(::strchr(commands[cmd].opts, *c) == NULL)
{
- printf("Invalid option '%c' for command %s\n", *c, commandNames[cmd]);
+ BOX_ERROR("Invalid option '" << *c << "' for "
+ "command " << commands[cmd].name);
return;
}
opts[(int)*c] = true;
@@ -290,9 +343,8 @@ void BackupQueries::DoCommand(const char *Command)
case COMMAND_pwd:
{
// Simple implementation, so do it here
- printf("%s (%08llx)\n",
- GetCurrentDirectoryName().c_str(),
- (long long)GetCurrentDirectoryID());
+ BOX_INFO(GetCurrentDirectoryName() << " (" <<
+ BOX_FORMAT_OBJECTID(GetCurrentDirectoryID()));
}
break;
@@ -305,7 +357,7 @@ void BackupQueries::DoCommand(const char *Command)
break;
case COMMAND_sh:
- printf("The command to run must be specified as an argument.\n");
+ BOX_ERROR("The command to run must be specified as an argument.");
break;
case COMMAND_GetObject:
@@ -356,8 +408,9 @@ void BackupQueries::CommandList(const std::vector<std::string> &args, const bool
#define LIST_OPTION_ALLOWOLD 'o'
#define LIST_OPTION_ALLOWDELETED 'd'
#define LIST_OPTION_NOOBJECTID 'I'
- #define LIST_OPTION_NOFLAGS 'F'
- #define LIST_OPTION_TIMES 't'
+ #define LIST_OPTION_NOFLAGS 'F'
+ #define LIST_OPTION_TIMES_LOCAL 't'
+ #define LIST_OPTION_TIMES_UTC 'T'
#define LIST_OPTION_SIZEINBLOCKS 's'
#define LIST_OPTION_DISPLAY_HASH 'h'
@@ -385,8 +438,8 @@ void BackupQueries::CommandList(const std::vector<std::string> &args, const bool
if(rootDir == 0)
{
- printf("Directory '%s' not found on store\n",
- args[0].c_str());
+ BOX_ERROR("Directory '" << args[0] << "' not found "
+ "on store.");
return;
}
}
@@ -399,7 +452,7 @@ void BackupQueries::CommandList(const std::vector<std::string> &args, const bool
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupQueries::CommandList2(int64_t, const std::string &, const bool *)
+// Name: BackupQueries::List(int64_t, const std::string &, const bool *, bool)
// Purpose: Do the actual listing of directories and files
// Created: 2003/10/10
//
@@ -474,11 +527,19 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
}
}
- if(opts[LIST_OPTION_TIMES])
+ if(opts[LIST_OPTION_TIMES_UTC])
+ {
+ // Show UTC times...
+ std::string time = BoxTimeToISO8601String(
+ en->GetModificationTime(), false);
+ printf("%s ", time.c_str());
+ }
+
+ if(opts[LIST_OPTION_TIMES_LOCAL])
{
- // Show times...
+ // Show local times...
std::string time = BoxTimeToISO8601String(
- en->GetModificationTime());
+ en->GetModificationTime(), true);
printf("%s ", time.c_str());
}
@@ -723,7 +784,7 @@ void BackupQueries::CommandChangeDir(const std::vector<std::string> &args, const
{
if(args.size() != 1 || args[0].size() == 0)
{
- printf("Incorrect usage.\ncd [-o] [-d] <directory>\n");
+ BOX_ERROR("Incorrect usage. cd [-o] [-d] <directory>");
return;
}
@@ -740,7 +801,7 @@ void BackupQueries::CommandChangeDir(const std::vector<std::string> &args, const
if(id == 0)
{
- printf("Directory '%s' not found\n", args[0].c_str());
+ BOX_ERROR("Directory '" << args[0] << "' not found.");
return;
}
@@ -761,22 +822,37 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
{
if(args.size() != 1 || args[0].size() == 0)
{
- printf("Incorrect usage.\nlcd <local-directory>\n");
+ BOX_ERROR("Incorrect usage. lcd <local-directory>");
+ SetReturnCode(COMMAND_RETURN_ERROR);
return;
}
// Try changing directory
#ifdef WIN32
std::string dirName;
- if(!ConvertConsoleToUtf8(args[0].c_str(), dirName)) return;
+ if(!ConvertConsoleToUtf8(args[0].c_str(), dirName))
+ {
+ BOX_ERROR("Failed to convert path from console encoding.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ return;
+ }
int result = ::chdir(dirName.c_str());
#else
int result = ::chdir(args[0].c_str());
#endif
if(result != 0)
{
- printf((errno == ENOENT || errno == ENOTDIR)?"Directory '%s' does not exist\n":"Error changing dir to '%s'\n",
- args[0].c_str());
+ if(errno == ENOENT || errno == ENOTDIR)
+ {
+ BOX_ERROR("Directory '" << args[0] << "' does not exist.");
+ }
+ else
+ {
+ BOX_ERROR("Error changing to directory '" <<
+ args[0] << ": " << strerror(errno));
+ }
+
+ SetReturnCode(COMMAND_RETURN_ERROR);
return;
}
@@ -784,15 +860,22 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
char wd[PATH_MAX];
if(::getcwd(wd, PATH_MAX) == 0)
{
- printf("Error getting current directory\n");
+ BOX_ERROR("Error getting current directory: " <<
+ strerror(errno));
+ SetReturnCode(COMMAND_RETURN_ERROR);
return;
}
#ifdef WIN32
- if(!ConvertUtf8ToConsole(wd, dirName)) return;
- printf("Local current directory is now '%s'\n", dirName.c_str());
+ if(!ConvertUtf8ToConsole(wd, dirName))
+ {
+ BOX_ERROR("Failed to convert new path from console encoding.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ return;
+ }
+ BOX_INFO("Local current directory is now '" << dirName << "'.");
#else
- printf("Local current directory is now '%s'\n", wd);
+ BOX_INFO("Local current directory is now '" << wd << "'.");
#endif
}
@@ -810,14 +893,15 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
// Check args
if(args.size() != 2)
{
- printf("Incorrect usage.\ngetobject <object-id> <local-filename>\n");
+ BOX_ERROR("Incorrect usage. getobject <object-id> "
+ "<local-filename>");
return;
}
int64_t id = ::strtoll(args[0].c_str(), 0, 16);
- if(id == LLONG_MIN || id == LLONG_MAX || id == 0)
+ if(id == std::numeric_limits<long long>::min() || id == std::numeric_limits<long long>::max() || id == 0)
{
- printf("Not a valid object ID (specified in hex)\n");
+ BOX_ERROR("Not a valid object ID (specified in hex).");
return;
}
@@ -825,7 +909,7 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
struct stat st;
if(::stat(args[1].c_str(), &st) == 0 || errno != ENOENT)
{
- printf("The local file %s already exists\n", args[1].c_str());
+ BOX_ERROR("The local file '" << args[1] << " already exists.");
return;
}
@@ -843,18 +927,20 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
std::auto_ptr<IOStream> objectStream(mrConnection.ReceiveStream());
objectStream->CopyStreamTo(out);
- printf("Object ID %08llx fetched successfully.\n", id);
+ BOX_INFO("Object ID " << BOX_FORMAT_OBJECTID(id) <<
+ " fetched successfully.");
}
else
{
- printf("Object does not exist on store.\n");
+ BOX_ERROR("Object ID " << BOX_FORMAT_OBJECTID(id) <<
+ " does not exist on store.");
::unlink(args[1].c_str());
}
}
catch(...)
{
::unlink(args[1].c_str());
- printf("Error occured fetching object.\n");
+ BOX_ERROR("Error occured fetching object.");
}
}
@@ -868,26 +954,65 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
// Created: 2003/10/12
//
// --------------------------------------------------------------------------
-void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool *opts)
+void BackupQueries::CommandGet(std::vector<std::string> args, const bool *opts)
{
// At least one argument?
// Check args
if(args.size() < 1 || (opts['i'] && args.size() != 2) || args.size() > 2)
{
- printf("Incorrect usage.\n"
+ BOX_ERROR("Incorrect usage.\n"
"get <remote-filename> [<local-filename>] or\n"
- "get -i <object-id> <local-filename>\n");
+ "get -i <object-id> <local-filename>");
return;
}
// Find object ID somehow
- int64_t id;
+ int64_t fileId;
+ int64_t dirId = GetCurrentDirectoryID();
std::string localName;
+
// BLOCK
{
+#ifdef WIN32
+ for (std::vector<std::string>::iterator
+ i = args.begin(); i != args.end(); i++)
+ {
+ std::string out;
+ if(!ConvertConsoleToUtf8(i->c_str(), out))
+ {
+ BOX_ERROR("Failed to convert encoding.");
+ return;
+ }
+ *i = out;
+ }
+#endif
+
+ std::string fileName(args[0]);
+
+ if(!opts['i'])
+ {
+ // does this remote filename include a path?
+ std::string::size_type index = fileName.rfind('/');
+ if(index != std::string::npos)
+ {
+ std::string dirName(fileName.substr(0, index));
+ fileName = fileName.substr(index + 1);
+
+ dirId = FindDirectoryObjectID(dirName);
+ if(dirId == 0)
+ {
+ BOX_ERROR("Directory '" << dirName <<
+ "' not found.");
+ return;
+ }
+ }
+ }
+
+ BackupStoreFilenameClear fn(fileName);
+
// Need to look it up in the current directory
mrConnection.QueryListDirectory(
- GetCurrentDirectoryID(),
+ dirId,
BackupProtocolClientListDirectory::Flags_File, // just files
(opts['i'])?(BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING):(BackupProtocolClientListDirectory::Flags_OldVersion | BackupProtocolClientListDirectory::Flags_Deleted), // only current versions
false /* don't want attributes */);
@@ -900,17 +1025,24 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
if(opts['i'])
{
// Specified as ID.
- id = ::strtoll(args[0].c_str(), 0, 16);
- if(id == LLONG_MIN || id == LLONG_MAX || id == 0)
+ fileId = ::strtoll(args[0].c_str(), 0, 16);
+ if(fileId == std::numeric_limits<long long>::min() ||
+ fileId == std::numeric_limits<long long>::max() ||
+ fileId == 0)
{
- printf("Not a valid object ID (specified in hex)\n");
+ BOX_ERROR("Not a valid object ID (specified in hex).");
return;
}
// Check that the item is actually in the directory
- if(dir.FindEntryByID(id) == 0)
+ if(dir.FindEntryByID(fileId) == 0)
{
- printf("ID '%08llx' not found in current directory on store.\n(You can only download objects by ID from the current directory.)\n", id);
+ BOX_ERROR("File ID " <<
+ BOX_FORMAT_OBJECTID(fileId) <<
+ " not found in current "
+ "directory on store.\n"
+ "(You can only download files by ID "
+ "from the current directory.)");
return;
}
@@ -921,26 +1053,23 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
{
// Specified by name, find the object in the directory to get the ID
BackupStoreDirectory::Iterator i(dir);
-#ifdef WIN32
- std::string fileName;
- if(!ConvertConsoleToUtf8(args[0].c_str(), fileName))
- return;
- BackupStoreFilenameClear fn(fileName);
-#else
- BackupStoreFilenameClear fn(args[0]);
-#endif
BackupStoreDirectory::Entry *en = i.FindMatchingClearName(fn);
if(en == 0)
{
- printf("Filename '%s' not found in current directory on store.\n(Subdirectories in path not searched.)\n", args[0].c_str());
+ BOX_ERROR("Filename '" << args[0] << "' "
+ "not found in current "
+ "directory on store.\n"
+ "(Subdirectories in path not "
+ "searched.)");
return;
}
- id = en->GetObjectID();
+ fileId = en->GetObjectID();
- // Local name is the last argument, which is either the looked up filename, or
- // a filename specified by the user.
+ // Local name is the last argument, which is either
+ // the looked up filename, or a filename specified
+ // by the user.
localName = args[args.size() - 1];
}
}
@@ -949,7 +1078,9 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
struct stat st;
if(::stat(localName.c_str(), &st) == 0 || errno != ENOENT)
{
- printf("The local file %s already exists, will not overwrite it.\n", localName.c_str());
+ BOX_ERROR("The local file " << localName << " already exists, "
+ "will not overwrite it.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
return;
}
@@ -957,7 +1088,7 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
try
{
// Request object
- mrConnection.QueryGetFile(GetCurrentDirectoryID(), id);
+ mrConnection.QueryGetFile(dirId, fileId);
// Stream containing encoded file
std::auto_ptr<IOStream> objectStream(mrConnection.ReceiveStream());
@@ -966,12 +1097,25 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
BackupStoreFile::DecodeFile(*objectStream, localName.c_str(), mrConnection.GetTimeout());
// Done.
- printf("Object ID %08llx fetched sucessfully.\n", id);
+ BOX_INFO("Object ID " << BOX_FORMAT_OBJECTID(fileId) <<
+ " fetched successfully.");
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to fetch file: " <<
+ e.what());
+ ::unlink(localName.c_str());
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to fetch file: " <<
+ e.what());
+ ::unlink(localName.c_str());
}
catch(...)
{
+ BOX_ERROR("Failed to fetch file: unknown error");
::unlink(localName.c_str());
- printf("Error occured fetching file.\n");
}
}
@@ -987,8 +1131,10 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
BackupQueries::CompareParams::CompareParams()
: mQuickCompare(false),
mIgnoreExcludes(false),
+ mIgnoreAttributes(false),
mDifferences(0),
mDifferencesExplainedByModTime(0),
+ mUncheckedFiles(0),
mExcludedDirs(0),
mExcludedFiles(0),
mpExcludeFiles(0),
@@ -1048,7 +1194,9 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
// Parameters, including count of differences
BackupQueries::CompareParams params;
params.mQuickCompare = opts['q'];
+ params.mQuietCompare = opts['Q'];
params.mIgnoreExcludes = opts['E'];
+ params.mIgnoreAttributes = opts['A'];
// Try and work out the time before which all files should be on the server
{
@@ -1064,14 +1212,16 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
}
else
{
- printf("Warning: couldn't determine the time of the last synchronisation -- checks not performed.\n");
+ BOX_WARNING("Failed to determine the time of the last "
+ "synchronisation -- checks not performed.");
}
}
// Quick compare?
if(params.mQuickCompare)
{
- printf("WARNING: Quick compare used -- file attributes are not checked.\n");
+ BOX_WARNING("Quick compare used -- file attributes are not "
+ "checked.");
}
if(!opts['l'] && opts['a'] && args.size() == 0)
@@ -1096,7 +1246,7 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
// Can't be bothered to do all the hard work to work out which location it's on, and hence which exclude list
if(!params.mIgnoreExcludes)
{
- printf("Cannot use excludes on directory to directory comparison -- use -E flag to specify ignored excludes\n");
+ BOX_ERROR("Cannot use excludes on directory to directory comparison -- use -E flag to specify ignored excludes.");
return;
}
else
@@ -1107,17 +1257,38 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
}
else
{
- printf("Incorrect usage.\ncompare -a\n or compare -l <location-name>\n or compare <store-dir-name> <local-dir-name>\n");
+ BOX_ERROR("Incorrect usage.\ncompare -a\n or compare -l <location-name>\n or compare <store-dir-name> <local-dir-name>");
return;
}
-
- printf("\n[ %d (of %d) differences probably due to file modifications after the last upload ]\nDifferences: %d (%d dirs excluded, %d files excluded)\n",
- params.mDifferencesExplainedByModTime, params.mDifferences, params.mDifferences, params.mExcludedDirs, params.mExcludedFiles);
+
+ if (!params.mQuietCompare)
+ {
+ BOX_INFO("[ " <<
+ params.mDifferencesExplainedByModTime << " (of " <<
+ params.mDifferences << ") differences probably "
+ "due to file modifications after the last upload ]");
+ }
+
+ BOX_INFO("Differences: " << params.mDifferences << " (" <<
+ params.mExcludedDirs << " dirs excluded, " <<
+ params.mExcludedFiles << " files excluded, " <<
+ params.mUncheckedFiles << " files not checked)");
// Set return code?
if(opts['c'])
{
- SetReturnCode((params.mDifferences == 0)?COMPARE_RETURN_SAME:COMPARE_RETURN_DIFFERENT);
+ if (params.mUncheckedFiles != 0)
+ {
+ SetReturnCode(COMPARE_RETURN_ERROR);
+ }
+ else if (params.mDifferences != 0)
+ {
+ SetReturnCode(COMPARE_RETURN_DIFFERENT);
+ }
+ else
+ {
+ SetReturnCode(COMPARE_RETURN_SAME);
+ }
}
}
@@ -1136,10 +1307,23 @@ void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries:
const Configuration &locations(mrConfiguration.GetSubConfiguration("BackupLocations"));
if(!locations.SubConfigurationExists(rLocation.c_str()))
{
- printf("Location %s does not exist.\n", rLocation.c_str());
+ BOX_ERROR("Location " << rLocation << " does not exist.");
return;
}
const Configuration &loc(locations.GetSubConfiguration(rLocation.c_str()));
+
+ #ifdef WIN32
+ {
+ std::string path = loc.GetKeyValue("Path");
+ if (path.size() > 0 && path[path.size()-1] ==
+ DIRECTORY_SEPARATOR_ASCHAR)
+ {
+ BOX_WARNING("Location '" << rLocation << "' path ends "
+ "with '" DIRECTORY_SEPARATOR "', "
+ "compare may fail!");
+ }
+ }
+ #endif
try
{
@@ -1189,9 +1373,9 @@ void BackupQueries::Compare(const std::string &rStoreDir, const std::string &rLo
// Found?
if(dirID == 0)
{
- printf("Local directory '%s' exists, but "
- "server directory '%s' does not exist\n",
- rLocalDir.c_str(), rStoreDir.c_str());
+ BOX_WARNING("Local directory '" << rLocalDir << "' exists, "
+ "but server directory '" << rStoreDir << "' does not "
+ "exist.");
rParams.mDifferences ++;
return;
}
@@ -1222,14 +1406,14 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
#ifdef WIN32
// By this point, rStoreDir and rLocalDir should be in UTF-8 encoding
- std::string localName;
- std::string storeName;
+ std::string localDirDisplay;
+ std::string storeDirDisplay;
- if(!ConvertUtf8ToConsole(rLocalDir.c_str(), localName)) return;
- if(!ConvertUtf8ToConsole(rStoreDir.c_str(), storeName)) return;
+ if(!ConvertUtf8ToConsole(rLocalDir.c_str(), localDirDisplay)) return;
+ if(!ConvertUtf8ToConsole(rStoreDir.c_str(), storeDirDisplay)) return;
#else
- const std::string& localName(rLocalDir);
- const std::string& storeName(rStoreDir);
+ const std::string& localDirDisplay(rLocalDir);
+ const std::string& storeDirDisplay(rStoreDir);
#endif
// Get info on the local directory
@@ -1239,21 +1423,24 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// What kind of error?
if(errno == ENOTDIR)
{
- printf("Local object '%s' is a file, "
- "server object '%s' is a directory\n",
- localName.c_str(), storeName.c_str());
+ BOX_WARNING("Local object '" << localDirDisplay << "' "
+ "is a file, server object '" <<
+ storeDirDisplay << "' is a directory.");
rParams.mDifferences ++;
}
else if(errno == ENOENT)
{
- printf("Local directory '%s' does not exist "
- "(compared to server directory '%s')\n",
- localName.c_str(), storeName.c_str());
+ BOX_WARNING("Local directory '" << localDirDisplay <<
+ "' does not exist (compared to server "
+ "directory '" << storeDirDisplay << "').");
+ rParams.mDifferences ++;
}
else
{
- printf("ERROR: stat on local dir '%s'\n",
- localName.c_str());
+ BOX_WARNING("Failed to access local directory '" <<
+ localDirDisplay << ": " << strerror(errno) <<
+ "'.");
+ rParams.mUncheckedFiles ++;
}
return;
}
@@ -1273,8 +1460,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Test out the attributes
if(!dir.HasAttributes())
{
- printf("Store directory '%s' doesn't have attributes.\n",
- storeName.c_str());
+ BOX_WARNING("Store directory '" << storeDirDisplay << "' "
+ "doesn't have attributes.");
}
else
{
@@ -1289,9 +1476,9 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
if(!(attr.Compare(localAttr, true, true /* ignore modification times */)))
{
- printf("Local directory '%s' has different attributes "
- "to store directory '%s'.\n",
- localName.c_str(), storeName.c_str());
+ BOX_WARNING("Local directory '" << localDirDisplay <<
+ "' has different attributes to store "
+ "directory '" << storeDirDisplay << "'.");
rParams.mDifferences ++;
}
}
@@ -1300,7 +1487,9 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
DIR *dirhandle = ::opendir(rLocalDir.c_str());
if(dirhandle == 0)
{
- printf("ERROR: opendir on local dir '%s'\n", localName.c_str());
+ BOX_WARNING("Failed to open local directory '" <<
+ localDirDisplay << "': " << strerror(errno));
+ rParams.mUncheckedFiles ++;
return;
}
try
@@ -1316,13 +1505,23 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
(localDirEn->d_name[1] == '\0' || (localDirEn->d_name[1] == '.' && localDirEn->d_name[2] == '\0')))
{
// ignore, it's . or ..
+
+#ifdef HAVE_VALID_DIRENT_D_TYPE
+ if (localDirEn->d_type != DT_DIR)
+ {
+ BOX_ERROR("d_type does not really "
+ "work on your platform. "
+ "Reconfigure Box!");
+ return;
+ }
+#endif
+
continue;
}
#ifndef HAVE_VALID_DIRENT_D_TYPE
- std::string fn(rLocalDir);
- fn += DIRECTORY_SEPARATOR_ASCHAR;
- fn += localDirEn->d_name;
+ std::string fn(MakeFullPath
+ (rLocalDir, localDirEn->d_name));
struct stat st;
if(::lstat(fn.c_str(), &st) != 0)
{
@@ -1339,7 +1538,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
{
// Directory
localDirs.insert(std::string(localDirEn->d_name));
- }
+ }
#else
// Entry -- file or dir?
if(localDirEn->d_type == DT_REG || localDirEn->d_type == DT_LNK)
@@ -1357,8 +1556,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Close directory
if(::closedir(dirhandle) != 0)
{
- printf("ERROR: closedir on local dir '%s'\n",
- localName.c_str());
+ BOX_ERROR("Failed to close local directory '" <<
+ localDirDisplay << "': " << strerror(errno));
}
dirhandle = 0;
@@ -1395,25 +1594,39 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Now compare files.
for(std::set<std::pair<std::string, BackupStoreDirectory::Entry *> >::const_iterator i = storeFiles.begin(); i != storeFiles.end(); ++i)
{
+ const std::string& fileName(i->first);
+#ifdef WIN32
+ // File name is also in UTF-8 encoding,
+ // need to convert to console
+ std::string fileNameDisplay;
+ if(!ConvertUtf8ToConsole(i->first.c_str(),
+ fileNameDisplay)) return;
+#else
+ const std::string& fileNameDisplay(i->first);
+#endif
+
+ std::string localPath(MakeFullPath
+ (rLocalDir, fileName));
+ std::string localPathDisplay(MakeFullPath
+ (localDirDisplay, fileNameDisplay));
+ std::string storePathDisplay
+ (storeDirDisplay + "/" + fileNameDisplay);
+
// Does the file exist locally?
- string_set_iter_t local(localFiles.find(i->first));
+ string_set_iter_t local(localFiles.find(fileName));
if(local == localFiles.end())
{
// Not found -- report
- printf("Local file '%s" DIRECTORY_SEPARATOR
- "%s' does not exist, "
- "but store file '%s/%s' does.\n",
- localName.c_str(), i->first.c_str(),
- storeName.c_str(), i->first.c_str());
+ BOX_WARNING("Local file '" <<
+ localPathDisplay << "' does not exist, "
+ "but store file '" <<
+ storePathDisplay << "' does.");
rParams.mDifferences ++;
}
else
{
try
{
- // make local name of file for comparison
- std::string localName(rLocalDir + DIRECTORY_SEPARATOR + i->first);
-
// Files the same flag?
bool equal = true;
@@ -1429,7 +1642,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
std::auto_ptr<IOStream> blockIndexStream(mrConnection.ReceiveStream());
// Compare
- equal = BackupStoreFile::CompareFileContentsAgainstBlockIndex(localName.c_str(), *blockIndexStream, mrConnection.GetTimeout());
+ equal = BackupStoreFile::CompareFileContentsAgainstBlockIndex(localPath.c_str(), *blockIndexStream, mrConnection.GetTimeout());
}
else
{
@@ -1441,7 +1654,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Decode it
std::auto_ptr<BackupStoreFile::DecodedStream> fileOnServerStream;
- // Got additional attibutes?
+ // Got additional attributes?
if(i->second->HasAttributes())
{
// Use these attributes
@@ -1464,26 +1677,39 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Compare attributes
BackupClientFileAttributes localAttr;
box_time_t fileModTime = 0;
- localAttr.ReadAttributes(localName.c_str(), false /* don't zero mod times */, &fileModTime);
+ localAttr.ReadAttributes(localPath.c_str(), false /* don't zero mod times */, &fileModTime);
modifiedAfterLastSync = (fileModTime > rParams.mLatestFileUploadTime);
- if(!localAttr.Compare(fileOnServerStream->GetAttributes(),
- true /* ignore attr mod time */,
+ bool ignoreAttrModTime = true;
+
+ #ifdef WIN32
+ // attr mod time is really
+ // creation time, so check it
+ ignoreAttrModTime = false;
+ #endif
+
+ if(!rParams.mIgnoreAttributes &&
+ #ifdef PLATFORM_DISABLE_SYMLINK_ATTRIB_COMPARE
+ !fileOnServerStream->IsSymLink() &&
+ #endif
+ !localAttr.Compare(fileOnServerStream->GetAttributes(),
+ ignoreAttrModTime,
fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */))
{
- printf("Local file '%s"
- DIRECTORY_SEPARATOR
- "%s' has different attributes "
- "to store file '%s/%s'.\n",
- localName.c_str(), i->first.c_str(), storeName.c_str(), i->first.c_str());
+ BOX_WARNING("Local file '" <<
+ localPathDisplay <<
+ "' has different attributes "
+ "to store file '" <<
+ storePathDisplay <<
+ "'.");
rParams.mDifferences ++;
if(modifiedAfterLastSync)
{
rParams.mDifferencesExplainedByModTime ++;
- printf("(the file above was modified after the last sync time -- might be reason for difference)\n");
+ BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
}
else if(i->second->HasAttributes())
{
- printf("(the file above has had new attributes applied)\n");
+ BOX_INFO("(the file above has had new attributes applied)\n");
}
}
@@ -1492,7 +1718,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
if(!fileOnServerStream->IsSymLink())
{
// Open the local file
- FileStream l(localName.c_str());
+ FileStream l(localPath.c_str());
// Size
IOStream::pos_type fileSizeLocal = l.BytesLeftToRead();
@@ -1522,7 +1748,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
equal = false;
}
- // Must always read the entire decoded string, if it's not a symlink
+ // Must always read the entire decoded stream, if it's not a symlink
if(fileOnServerStream->StreamDataLeft())
{
// Absorb all the data remaining
@@ -1532,40 +1758,65 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
fileOnServerStream->Read(buffer, sizeof(buffer), mrConnection.GetTimeout());
}
}
+
+ // Must always read the entire encoded stream
+ if(objectStream->StreamDataLeft())
+ {
+ // Absorb all the data remaining
+ char buffer[2048];
+ while(objectStream->StreamDataLeft())
+ {
+ objectStream->Read(buffer, sizeof(buffer), mrConnection.GetTimeout());
+ }
+ }
}
}
// Report if not equal.
if(!equal)
{
- printf("Local file '%s"
- DIRECTORY_SEPARATOR
- "%s' has different contents "
- "to store file '%s/%s'.\n",
- localName.c_str(), i->first.c_str(), storeName.c_str(), i->first.c_str());
+ BOX_WARNING("Local file '" <<
+ localPathDisplay << "' "
+ "has different contents "
+ "to store file '" <<
+ storePathDisplay <<
+ "'.");
rParams.mDifferences ++;
if(modifiedAfterLastSync)
{
rParams.mDifferencesExplainedByModTime ++;
- printf("(the file above was modified after the last sync time -- might be reason for difference)\n");
+ BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
}
else if(i->second->HasAttributes())
{
- printf("(the file above has had new attributes applied)\n");
+ BOX_INFO("(the file above has had new attributes applied)\n");
}
}
}
catch(BoxException &e)
{
- printf("ERROR: (%d/%d) during file fetch and comparsion for '%s/%s'\n",
- e.GetType(),
- e.GetSubType(),
- storeName.c_str(),
- i->first.c_str());
+ BOX_ERROR("Failed to fetch and compare "
+ "'" <<
+ storePathDisplay.c_str() <<
+ "': error " << e.what() <<
+ " (" << e.GetType() <<
+ "/" << e.GetSubType() << ")");
+ rParams.mUncheckedFiles ++;
}
- catch(...)
+ catch(std::exception &e)
{
- printf("ERROR: (unknown) during file fetch and comparsion for '%s/%s'\n", storeName.c_str(), i->first.c_str());
+ BOX_ERROR("Failed to fetch and compare "
+ "'" <<
+ storePathDisplay.c_str() <<
+ "': " << e.what());
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to fetch and compare "
+ "'" <<
+ storePathDisplay.c_str() <<
+ "': unknown error");
+ rParams.mUncheckedFiles ++;
}
// Remove from set so that we know it's been compared
@@ -1576,28 +1827,43 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Report any files which exist on the locally, but not on the store
for(string_set_iter_t i = localFiles.begin(); i != localFiles.end(); ++i)
{
- std::string localFileName(rLocalDir +
- DIRECTORY_SEPARATOR + *i);
+#ifdef WIN32
+ // File name is also in UTF-8 encoding,
+ // need to convert to console
+ std::string fileNameDisplay;
+ if(!ConvertUtf8ToConsole(i->c_str(), fileNameDisplay))
+ return;
+#else
+ const std::string& fileNameDisplay(*i);
+#endif
+
+ std::string localPath(MakeFullPath
+ (rLocalDir, *i));
+ std::string localPathDisplay(MakeFullPath
+ (localDirDisplay, fileNameDisplay));
+ std::string storePathDisplay
+ (storeDirDisplay + "/" + fileNameDisplay);
+
// Should this be ignored (ie is excluded)?
if(rParams.mpExcludeFiles == 0 ||
- !(rParams.mpExcludeFiles->IsExcluded(localFileName)))
+ !(rParams.mpExcludeFiles->IsExcluded(localPath)))
{
- printf("Local file '%s" DIRECTORY_SEPARATOR
- "%s' exists, but store file '%s/%s' "
- "does not exist.\n",
- localName.c_str(), (*i).c_str(),
- storeName.c_str(), (*i).c_str());
+ BOX_WARNING("Local file '" <<
+ localPathDisplay <<
+ "' exists, but store file '" <<
+ storePathDisplay <<
+ "' does not.");
rParams.mDifferences ++;
// Check the file modification time
{
struct stat st;
- if(::stat(localFileName.c_str(), &st) == 0)
+ if(::stat(localPath.c_str(), &st) == 0)
{
if(FileModificationTime(st) > rParams.mLatestFileUploadTime)
{
rParams.mDifferencesExplainedByModTime ++;
- printf("(the file above was modified after the last sync time -- might be reason for difference)\n");
+ BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
}
}
}
@@ -1612,26 +1878,58 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
localFiles.clear();
storeFiles.clear();
- // Now do the directories, recusively to check subdirectories
+ // Now do the directories, recursively to check subdirectories
for(std::set<std::pair<std::string, BackupStoreDirectory::Entry *> >::const_iterator i = storeDirs.begin(); i != storeDirs.end(); ++i)
{
+#ifdef WIN32
+ // Directory name is also in UTF-8 encoding,
+ // need to convert to console
+ std::string subdirNameDisplay;
+ if(!ConvertUtf8ToConsole(i->first.c_str(),
+ subdirNameDisplay))
+ return;
+#else
+ const std::string& subdirNameDisplay(i->first);
+#endif
+
+ std::string localPath(MakeFullPath
+ (rLocalDir, i->first));
+ std::string localPathDisplay(MakeFullPath
+ (localDirDisplay, subdirNameDisplay));
+ std::string storePathDisplay
+ (storeDirDisplay + "/" + subdirNameDisplay);
+
// Does the directory exist locally?
string_set_iter_t local(localDirs.find(i->first));
- if(local == localDirs.end())
+ if(local == localDirs.end() &&
+ rParams.mpExcludeDirs != NULL &&
+ rParams.mpExcludeDirs->IsExcluded(localPath))
+ {
+ // Not found -- report
+ BOX_WARNING("Local directory '" <<
+ localPathDisplay << "' is excluded, "
+ "but store directory '" <<
+ storePathDisplay << "' still exists.");
+ rParams.mDifferences ++;
+ }
+ else if(local == localDirs.end())
{
// Not found -- report
- printf("Local directory '%s"
- DIRECTORY_SEPARATOR "%s' "
- "does not exist, but store directory "
- "'%s/%s' does.\n",
- localName.c_str(), i->first.c_str(),
- storeName.c_str(), i->first.c_str());
+ BOX_WARNING("Local directory '" <<
+ localPathDisplay << "' does not exist, "
+ "but store directory '" <<
+ storePathDisplay << "' does.");
rParams.mDifferences ++;
}
+ else if(rParams.mpExcludeDirs != NULL &&
+ rParams.mpExcludeDirs->IsExcluded(localPath))
+ {
+ // don't recurse into excluded directories
+ }
else
{
// Compare directory
- Compare(i->second->GetObjectID(), rStoreDir + "/" + i->first, rLocalDir + DIRECTORY_SEPARATOR + i->first, rParams);
+ Compare(i->second->GetObjectID(), rStoreDir + "/" + i->first, localPath, rParams);
// Remove from set so that we know it's been compared
localDirs.erase(local);
@@ -1641,14 +1939,33 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Report any files which exist on the locally, but not on the store
for(std::set<std::string>::const_iterator i = localDirs.begin(); i != localDirs.end(); ++i)
{
- std::string localName(rLocalDir + DIRECTORY_SEPARATOR + *i);
+#ifdef WIN32
+ // File name is also in UTF-8 encoding,
+ // need to convert to console
+ std::string fileNameDisplay;
+ if(!ConvertUtf8ToConsole(i->c_str(), fileNameDisplay))
+ return;
+#else
+ const std::string& fileNameDisplay(*i);
+#endif
+
+ std::string localPath(MakeFullPath
+ (rLocalDir, *i));
+ std::string localPathDisplay(MakeFullPath
+ (localDirDisplay, fileNameDisplay));
+
+ std::string storePath
+ (rStoreDir + "/" + *i);
+ std::string storePathDisplay
+ (storeDirDisplay + "/" + fileNameDisplay);
+
// Should this be ignored (ie is excluded)?
- if(rParams.mpExcludeDirs == 0 || !(rParams.mpExcludeDirs->IsExcluded(localName)))
+ if(rParams.mpExcludeDirs == 0 || !(rParams.mpExcludeDirs->IsExcluded(localPath)))
{
- printf("Local directory '%s/%s' exists, but "
- "store directory '%s/%s' does not exist.\n",
- localName.c_str(), (*i).c_str(),
- storeName.c_str(), (*i).c_str());
+ BOX_WARNING("Local directory '" <<
+ localPathDisplay << "' exists, but "
+ "store directory '" <<
+ storePathDisplay << "' does not.");
rParams.mDifferences ++;
}
else
@@ -1681,7 +1998,7 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
// Check arguments
if(args.size() != 2)
{
- printf("Incorrect usage.\nrestore [-d] [-r] [-i] <directory-name> <local-directory-name>\n");
+ BOX_ERROR("Incorrect usage. restore [-d] [-r] [-i] <remote-name> <local-name>");
return;
}
@@ -1694,9 +2011,9 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
{
// Specified as ID.
dirID = ::strtoll(args[0].c_str(), 0, 16);
- if(dirID == LLONG_MIN || dirID == LLONG_MAX || dirID == 0)
+ if(dirID == std::numeric_limits<long long>::min() || dirID == std::numeric_limits<long long>::max() || dirID == 0)
{
- printf("Not a valid object ID (specified in hex)\n");
+ BOX_ERROR("Not a valid object ID (specified in hex)");
return;
}
}
@@ -1719,12 +2036,12 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
// Allowable?
if(dirID == 0)
{
- printf("Directory '%s' not found on server\n", args[0].c_str());
+ BOX_ERROR("Directory '" << args[0] << "' not found on server");
return;
}
if(dirID == BackupProtocolClientListDirectory::RootDirectory)
{
- printf("Cannot restore the root directory -- restore locations individually.\n");
+ BOX_ERROR("Cannot restore the root directory -- restore locations individually.");
return;
}
@@ -1736,25 +2053,62 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
#endif
// Go and restore...
- switch(BackupClientRestore(mrConnection, dirID, localName.c_str(),
- true /* print progress dots */, restoreDeleted,
- false /* don't undelete after restore! */,
- opts['r'] /* resume? */))
+ int result;
+
+ try
+ {
+ result = BackupClientRestore(mrConnection, dirID,
+ localName.c_str(),
+ true /* print progress dots */, restoreDeleted,
+ false /* don't undelete after restore! */,
+ opts['r'] /* resume? */);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to restore: " << e.what());
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ return;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to restore: unknown exception");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ return;
+ }
+
+ switch(result)
{
case Restore_Complete:
- printf("Restore complete\n");
+ BOX_INFO("Restore complete.");
break;
case Restore_ResumePossible:
- printf("Resume possible -- repeat command with -r flag to resume\n");
+ BOX_ERROR("Resume possible -- repeat command with -r flag to resume");
+ SetReturnCode(COMMAND_RETURN_ERROR);
break;
case Restore_TargetExists:
- printf("The target directory exists. You cannot restore over an existing directory.\n");
+ BOX_ERROR("The target directory exists. You cannot restore over an existing directory.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
break;
+ #ifdef WIN32
+ case Restore_TargetPathNotFound:
+ BOX_ERROR("The target directory path does not exist.\n"
+ "To restore to a directory whose parent "
+ "does not exist, create the parent first.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ break;
+ #endif
+
+ case Restore_UnknownError:
+ BOX_ERROR("Unknown error during restore.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ break;
+
default:
- printf("ERROR: Unknown restore result.\n");
+ BOX_ERROR("Unknown restore result " << result << ".");
+ SetReturnCode(COMMAND_RETURN_ERROR);
break;
}
}
@@ -1874,7 +2228,7 @@ void BackupQueries::CommandUndelete(const std::vector<std::string> &args, const
// Check arguments
if(args.size() != 1)
{
- printf("Incorrect usage.\nundelete <directory-name>\n");
+ BOX_ERROR("Incorrect usage. undelete <directory-name>");
return;
}
@@ -1892,12 +2246,12 @@ void BackupQueries::CommandUndelete(const std::vector<std::string> &args, const
// Allowable?
if(dirID == 0)
{
- printf("Directory '%s' not found on server\n", args[0].c_str());
+ BOX_ERROR("Directory '" << args[0] << "' not found on server.");
return;
}
if(dirID == BackupProtocolClientListDirectory::RootDirectory)
{
- printf("Cannot undelete the root directory.\n");
+ BOX_ERROR("Cannot undelete the root directory.");
return;
}
diff --git a/bin/bbackupquery/BackupQueries.h b/bin/bbackupquery/BackupQueries.h
index 3b4eec0d..a60c791e 100644
--- a/bin/bbackupquery/BackupQueries.h
+++ b/bin/bbackupquery/BackupQueries.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -74,7 +74,7 @@ private:
BackupQueries(const BackupQueries &);
public:
- void DoCommand(const char *Command);
+ void DoCommand(const char *Command, bool isFromCommandLine);
// Ready to stop?
bool Stop() {return mQuitNow;}
@@ -88,7 +88,7 @@ private:
void CommandChangeDir(const std::vector<std::string> &args, const bool *opts);
void CommandChangeLocalDir(const std::vector<std::string> &args);
void CommandGetObject(const std::vector<std::string> &args, const bool *opts);
- void CommandGet(const std::vector<std::string> &args, const bool *opts);
+ void CommandGet(std::vector<std::string> args, const bool *opts);
void CommandCompare(const std::vector<std::string> &args, const bool *opts);
void CommandRestore(const std::vector<std::string> &args, const bool *opts);
void CommandUndelete(const std::vector<std::string> &args, const bool *opts);
@@ -105,9 +105,12 @@ private:
~CompareParams();
void DeleteExcludeLists();
bool mQuickCompare;
+ bool mQuietCompare;
bool mIgnoreExcludes;
+ bool mIgnoreAttributes;
int mDifferences;
int mDifferencesExplainedByModTime;
+ int mUncheckedFiles;
int mExcludedDirs;
int mExcludedFiles;
const ExcludeList *mpExcludeFiles;
diff --git a/bin/bbackupquery/Makefile.extra b/bin/bbackupquery/Makefile.extra
index 633ec0fc..f347c451 100644
--- a/bin/bbackupquery/Makefile.extra
+++ b/bin/bbackupquery/Makefile.extra
@@ -1,6 +1,6 @@
# AUTOGEN SEEDING
autogen_Documentation.cpp: makedocumentation.pl documentation.txt
- perl makedocumentation.pl
+ $(PERL) makedocumentation.pl
diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp
index 1bd15f3c..2006f3d3 100644
--- a/bin/bbackupquery/bbackupquery.cpp
+++ b/bin/bbackupquery/bbackupquery.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -50,8 +50,14 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+
+#include <errno.h>
#include <stdio.h>
-#include <sys/types.h>
+
+#ifdef HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+#endif
+
#ifdef HAVE_LIBREADLINE
#ifdef HAVE_READLINE_READLINE_H
#include <readline/readline.h>
@@ -83,6 +89,7 @@
#include "FdGetLine.h"
#include "BackupClientCryptoKeys.h"
#include "BannerText.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -101,7 +108,11 @@ void PrintUsageAndExit()
int main(int argc, const char *argv[])
{
- MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupquery.memleaks", "bbackupquery")
+ int returnCode = 0;
+
+ MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupquery.memleaks",
+ "bbackupquery")
+ MAINHELPER_START
#ifdef WIN32
WSADATA info;
@@ -111,7 +122,7 @@ int main(int argc, const char *argv[])
if (WSAStartup(0x0101, &info) == SOCKET_ERROR)
{
- // throw error? perhaps give it its own id in the furture
+ // throw error? perhaps give it its own id in the future
THROW_EXCEPTION(BackupStoreException, Internal)
}
#endif
@@ -121,24 +132,34 @@ int main(int argc, const char *argv[])
BoxDebugTraceOn = false;
#endif
- int returnCode = 0;
-
- MAINHELPER_START
-
FILE *logFile = 0;
- // Filename for configuraiton file?
- const char *configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG;
+ // Filename for configuration file?
+ std::string configFilename;
+
+ #ifdef WIN32
+ configFilename = BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE;
+ #else
+ configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG;
+ #endif
// Flags
bool quiet = false;
bool readWrite = false;
+ Logging::SetProgramName("Box Backup (bbackupquery)");
+
+ #ifdef NDEBUG
+ int masterLevel = Log::NOTICE; // need an int to do math with
+ #else
+ int masterLevel = Log::INFO; // need an int to do math with
+ #endif
+
#ifdef WIN32
- const char* validOpts = "qwuc:l:";
+ const char* validOpts = "qvwuc:l:";
bool unicodeConsole = false;
#else
- const char* validOpts = "qwc:l:";
+ const char* validOpts = "qvwc:l:";
#endif
// See if there's another entry on the command line
@@ -147,11 +168,35 @@ int main(int argc, const char *argv[])
{
switch(c)
{
- case 'q':
- // Quiet mode
- quiet = true;
+ case 'q':
+ {
+ // Quiet mode
+ quiet = true;
+
+ if(masterLevel == Log::NOTHING)
+ {
+ BOX_FATAL("Too many '-q': "
+ "Cannot reduce logging "
+ "level any more");
+ return 2;
+ }
+ masterLevel--;
+ }
break;
-
+
+ case 'v':
+ {
+ if(masterLevel == Log::EVERYTHING)
+ {
+ BOX_FATAL("Too many '-v': "
+ "Cannot increase logging "
+ "level any more");
+ return 2;
+ }
+ masterLevel++;
+ }
+ break;
+
case 'w':
// Read/write mode
readWrite = true;
@@ -167,7 +212,8 @@ int main(int argc, const char *argv[])
logFile = ::fopen(optarg, "w");
if(logFile == 0)
{
- printf("Can't open log file '%s'\n", optarg);
+ BOX_ERROR("Failed to open log file '" <<
+ optarg << "': " << strerror(errno));
}
break;
@@ -186,11 +232,13 @@ int main(int argc, const char *argv[])
argc -= optind;
argv += optind;
+ Logging::SetGlobalLevel((Log::Level)masterLevel);
+
// Print banner?
if(!quiet)
{
const char *banner = BANNER_TEXT("Backup Query Tool");
- printf(banner);
+ BOX_NOTICE(banner);
}
#ifdef WIN32
@@ -198,18 +246,19 @@ int main(int argc, const char *argv[])
{
if (!SetConsoleCP(CP_UTF8))
{
- fprintf(stderr, "Failed to set input codepage: "
- "error %d\n", GetLastError());
+ BOX_ERROR("Failed to set input codepage: " <<
+ GetErrorMessage(GetLastError()));
}
if (!SetConsoleOutputCP(CP_UTF8))
{
- fprintf(stderr, "Failed to set output codepage: "
- "error %d\n", GetLastError());
+ BOX_ERROR("Failed to set output codepage: " <<
+ GetErrorMessage(GetLastError()));
}
// enable input of Unicode characters
- if (_setmode(_fileno(stdin), _O_TEXT) == -1)
+ if (_fileno(stdin) != -1 &&
+ _setmode(_fileno(stdin), _O_TEXT) == -1)
{
perror("Failed to set the console input to "
"binary mode");
@@ -218,12 +267,16 @@ int main(int argc, const char *argv[])
#endif // WIN32
// Read in the configuration file
- if(!quiet) printf("Using configuration file %s\n", configFilename);
+ if(!quiet) BOX_INFO("Using configuration file " << configFilename);
+
std::string errs;
- std::auto_ptr<Configuration> config(Configuration::LoadAndVerify(configFilename, &BackupDaemonConfigVerify, errs));
+ std::auto_ptr<Configuration> config(
+ Configuration::LoadAndVerify
+ (configFilename, &BackupDaemonConfigVerify, errs));
+
if(config.get() == 0 || !errs.empty())
{
- printf("Invalid configuration file:\n%s", errs.c_str());
+ BOX_FATAL("Invalid configuration file: " << errs);
return 1;
}
// Easier coding
@@ -243,12 +296,12 @@ int main(int argc, const char *argv[])
BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile").c_str());
// 2. Connect to server
- if(!quiet) printf("Connecting to store...\n");
+ if(!quiet) BOX_INFO("Connecting to store...");
SocketStreamTLS socket;
socket.Open(tlsContext, Socket::TypeINET, conf.GetKeyValue("StoreHostname").c_str(), BOX_PORT_BBSTORED);
// 3. Make a protocol, and handshake
- if(!quiet) printf("Handshake with store...\n");
+ if(!quiet) BOX_INFO("Handshake with store...");
BackupProtocolClient connection(socket);
connection.Handshake();
@@ -259,7 +312,7 @@ int main(int argc, const char *argv[])
}
// 4. Log in to server
- if(!quiet) printf("Login to store...\n");
+ if(!quiet) BOX_INFO("Login to store...");
// Check the version of the server
{
std::auto_ptr<BackupProtocolClientVersion> serverVersion(connection.QueryVersion(BACKUP_STORE_SERVER_VERSION));
@@ -283,12 +336,21 @@ int main(int argc, const char *argv[])
int c = 0;
while(c < argc && !context.Stop())
{
- context.DoCommand(argv[c++]);
+ context.DoCommand(argv[c++], true);
}
}
// Get commands from input
+
#ifdef HAVE_LIBREADLINE
+ // Must initialise the locale before using editline's readline(),
+ // otherwise cannot enter international characters.
+ if (setlocale(LC_ALL, "") == NULL)
+ {
+ BOX_ERROR("Failed to initialise locale. International "
+ "character support may not work.");
+ }
+
#ifdef HAVE_READLINE_HISTORY
using_history();
#endif
@@ -301,7 +363,7 @@ int main(int argc, const char *argv[])
// Ctrl-D pressed -- terminate now
break;
}
- context.DoCommand(command);
+ context.DoCommand(command, false);
if(last_cmd != 0 && ::strcmp(last_cmd, command) == 0)
{
free(command);
@@ -322,20 +384,23 @@ int main(int argc, const char *argv[])
#endif
#else
// Version for platforms which don't have readline by default
- FdGetLine getLine(fileno(stdin));
- while(!context.Stop())
+ if(fileno(stdin) >= 0)
{
- printf("query > ");
- fflush(stdout);
- std::string command(getLine.GetLine());
- context.DoCommand(command.c_str());
+ FdGetLine getLine(fileno(stdin));
+ while(!context.Stop())
+ {
+ printf("query > ");
+ fflush(stdout);
+ std::string command(getLine.GetLine());
+ context.DoCommand(command.c_str(), false);
+ }
}
#endif
// Done... stop nicely
- if(!quiet) printf("Logging off...\n");
+ if(!quiet) BOX_INFO("Logging off...");
connection.QueryFinished();
- if(!quiet) printf("Session finished.\n");
+ if(!quiet) BOX_INFO("Session finished.");
// Return code
returnCode = context.GetReturnCode();
@@ -348,13 +413,13 @@ int main(int argc, const char *argv[])
// Let everything be cleaned up on exit.
- MAINHELPER_END
-
#ifdef WIN32
// Clean up our sockets
WSACleanup();
#endif
+ MAINHELPER_END
+
return returnCode;
}
diff --git a/bin/bbackupquery/documentation.txt b/bin/bbackupquery/documentation.txt
index 429caabe..42217edc 100644
--- a/bin/bbackupquery/documentation.txt
+++ b/bin/bbackupquery/documentation.txt
@@ -104,6 +104,7 @@ compare <store-dir-name> <local-dir-name>
-c -- set return code
-q -- quick compare. Only checks file contents against checksums,
doesn't do a full download
+ -A -- ignore attribute differences
-E -- ignore exclusion settings
Comparing with the root directory is an error, use -a option instead.
@@ -122,7 +123,7 @@ compare <store-dir-name> <local-dir-name>
The root cannot be restored -- restore locations individually.
- -d -- restore a deleted directory.
+ -d -- restore a deleted directory or deleted files inside
-r -- resume an interrupted restoration
-i -- directory name is actually an ID
diff --git a/bin/bbackupquery/makedocumentation.pl b/bin/bbackupquery/makedocumentation.pl
index b39ef1f7..77d488c0 100755
--- a/bin/bbackupquery/makedocumentation.pl
+++ b/bin/bbackupquery/makedocumentation.pl
@@ -1,5 +1,5 @@
#!/usr/bin/perl
-# distribution boxbackup-0.10 (svn version: 494)
+# distribution boxbackup-0.11rc1 (svn version: 2023_2024)
#
# Copyright (c) 2003 - 2006
# Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbackupquery/makedocumentation.pl.in b/bin/bbackupquery/makedocumentation.pl.in
new file mode 100755
index 00000000..72e45a67
--- /dev/null
+++ b/bin/bbackupquery/makedocumentation.pl.in
@@ -0,0 +1,75 @@
+#!@PERL@
+use strict;
+
+print "Creating built-in documentation for bbackupquery...\n";
+
+open DOC,"documentation.txt" or die "Can't open documentation.txt file";
+my $section;
+my %help;
+my @in_order;
+
+while(<DOC>)
+{
+ if(m/\A>\s+(\w+)/)
+ {
+ $section = $1;
+ m/\A>\s+(.+)\Z/;
+ $help{$section} = $1."\n";
+ push @in_order,$section;
+ }
+ elsif(m/\A</)
+ {
+ $section = '';
+ }
+ elsif($section ne '')
+ {
+ $help{$section} .= $_;
+ }
+}
+
+close DOC;
+
+open OUT,">autogen_Documentation.cpp" or die "Can't open output file for writing";
+
+print OUT <<__E;
+//
+// Automatically generated file, do not edit.
+//
+
+#include "Box.h"
+
+#include "MemLeakFindOn.h"
+
+char *help_commands[] =
+{
+__E
+
+for(@in_order)
+{
+ print OUT qq:\t"$_",\n:;
+}
+
+print OUT <<__E;
+ 0
+};
+
+char *help_text[] =
+{
+__E
+
+for(@in_order)
+{
+ my $t = $help{$_};
+ $t =~ s/\t/ /g;
+ $t =~ s/\n/\\n/g;
+ $t =~ s/"/\\"/g;
+ print OUT qq:\t"$t",\n:;
+}
+
+print OUT <<__E;
+ 0
+};
+
+__E
+
+close OUT;
diff --git a/bin/bbstoreaccounts/bbstoreaccounts.cpp b/bin/bbstoreaccounts/bbstoreaccounts.cpp
index 2ed7c479..1c14cedb 100644
--- a/bin/bbstoreaccounts/bbstoreaccounts.cpp
+++ b/bin/bbstoreaccounts/bbstoreaccounts.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -75,12 +75,13 @@ void CheckSoftHardLimits(int64_t SoftLimit, int64_t HardLimit)
{
if(SoftLimit >= HardLimit)
{
- printf("ERROR: Soft limit must be less than the hard limit.\n");
+ BOX_FATAL("Soft limit must be less than the hard limit.");
exit(1);
}
if(SoftLimit > ((HardLimit * MAX_SOFT_LIMIT_SIZE) / 100))
{
- printf("ERROR: Soft limit must be no more than %d%% of the hard limit.\n", MAX_SOFT_LIMIT_SIZE);
+ BOX_FATAL("Soft limit must be no more than " <<
+ MAX_SOFT_LIMIT_SIZE << "% of the hard limit.");
exit(1);
}
}
@@ -91,7 +92,7 @@ int BlockSizeOfDiscSet(int DiscSet)
RaidFileController &controller(RaidFileController::GetController());
if(DiscSet < 0 || DiscSet >= controller.GetNumDiscSets())
{
- printf("Disc set %d does not exist\n", DiscSet);
+ BOX_FATAL("Disc set " << DiscSet << " does not exist.");
exit(1);
}
@@ -127,7 +128,7 @@ int64_t SizeStringToBlocks(const char *string, int DiscSet)
int64_t number = strtol(string, &endptr, 0);
if(endptr == string || number == LONG_MIN || number == LONG_MAX)
{
- printf("%s is an invalid number\n", string);
+ BOX_FATAL("'" << string << "' is not a valid number.");
exit(1);
}
@@ -154,7 +155,8 @@ int64_t SizeStringToBlocks(const char *string, int DiscSet)
break;
default:
- printf("%s has an invalid units specifier\nUse B for blocks, M for Mb, G for Gb, eg 2Gb\n", string);
+ BOX_FATAL(string << " has an invalid units specifier "
+ "(use B for blocks, M for Mb, G for Gb, eg 2Gb)");
exit(1);
break;
}
@@ -181,8 +183,8 @@ bool GetWriteLockOnAccount(NamedLock &rLock, const std::string rRootDir, int Dis
if(!gotLock)
{
// Couldn't lock the account -- just stop now
- printf("Couldn't lock the account -- did not change the limits\nTry again later.\n");
- return 1;
+ BOX_ERROR("Failed to lock the account, did not change limits. "
+ "Try again later.");
}
return gotLock;
@@ -206,7 +208,8 @@ int SetLimit(Configuration &rConfig, const std::string &rUsername, int32_t ID, c
// Already exists?
if(!db->EntryExists(ID))
{
- printf("Account %x does not exist\n", ID);
+ BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) <<
+ " does not exist.");
return 1;
}
@@ -236,7 +239,9 @@ int SetLimit(Configuration &rConfig, const std::string &rUsername, int32_t ID, c
// Save
info->Save();
- printf("Limits on account 0x%08x changed to %lld soft, %lld hard\n", ID, softlimit, hardlimit);
+ BOX_NOTICE("Limits on account " << BOX_FORMAT_ACCOUNT(ID) <<
+ " changed to " << softlimit << " soft, " <<
+ hardlimit << " hard.");
return 0;
}
@@ -249,7 +254,8 @@ int AccountInfo(Configuration &rConfig, int32_t ID)
// Exists?
if(!db->EntryExists(ID))
{
- printf("Account %x does not exist\n", ID);
+ BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) <<
+ " does not exist.");
return 1;
}
@@ -279,11 +285,12 @@ int DeleteAccount(Configuration &rConfig, const std::string &rUsername, int32_t
// Check user really wants to do this
if(AskForConfirmation)
{
- ::printf("Really delete account %08x?\n(type 'yes' to confirm)\n", ID);
+ BOX_WARNING("Really delete account " <<
+ BOX_FORMAT_ACCOUNT(ID) << "? (type 'yes' to confirm)");
char response[256];
if(::fgets(response, sizeof(response), stdin) == 0 || ::strcmp(response, "yes\n") != 0)
{
- printf("Deletion cancelled\n");
+ BOX_NOTICE("Deletion cancelled.");
return 0;
}
}
@@ -294,7 +301,8 @@ int DeleteAccount(Configuration &rConfig, const std::string &rUsername, int32_t
// Exists?
if(!db->EntryExists(ID))
{
- printf("Account %x does not exist\n", ID);
+ BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) <<
+ " does not exist.");
return 1;
}
@@ -356,24 +364,27 @@ int DeleteAccount(Configuration &rConfig, const std::string &rUsername, int32_t
toDelete.push_back((*i) + DIRECTORY_SEPARATOR + rootDir);
}
}
-
+
+ int retcode = 0;
+
// Thirdly, delete the directories...
for(std::vector<std::string>::const_iterator d(toDelete.begin()); d != toDelete.end(); ++d)
{
- ::printf("Deleting store directory %s...\n", (*d).c_str());
+ BOX_NOTICE("Deleting store directory " << (*d) << "...");
// Just use the rm command to delete the files
std::string cmd("rm -rf ");
cmd += *d;
// Run command
if(::system(cmd.c_str()) != 0)
{
- ::printf("ERROR: Deletion of %s failed.\n(when cleaning up, remember to delete all raid directories)\n", (*d).c_str());
- return 1;
+ BOX_ERROR("Failed to delete files in " << (*d) <<
+ ", delete them manually.");
+ retcode = 1;
}
}
// Success!
- return 0;
+ return retcode;
}
int CheckAccount(Configuration &rConfig, const std::string &rUsername, int32_t ID, bool FixErrors, bool Quiet)
@@ -384,7 +395,8 @@ int CheckAccount(Configuration &rConfig, const std::string &rUsername, int32_t I
// Exists?
if(!db->EntryExists(ID))
{
- printf("Account %x does not exist\n", ID);
+ BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) <<
+ " does not exist.");
return 1;
}
@@ -419,7 +431,8 @@ int CreateAccount(Configuration &rConfig, const std::string &rUsername, int32_t
// Already exists?
if(db->EntryExists(ID))
{
- printf("Account %x already exists\n", ID);
+ BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) <<
+ " already exists.");
return 1;
}
@@ -427,7 +440,7 @@ int CreateAccount(Configuration &rConfig, const std::string &rUsername, int32_t
BackupStoreAccounts acc(*db);
acc.Create(ID, DiscNumber, SoftLimit, HardLimit, rUsername);
- printf("Account %x created\n", ID);
+ BOX_NOTICE("Account " << BOX_FORMAT_ACCOUNT(ID) << " created.");
return 0;
}
@@ -440,12 +453,19 @@ void PrintUsageAndExit()
int main(int argc, const char *argv[])
{
- MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbstoreaccounts.memleaks", "bbstoreaccounts")
+ MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbstoreaccounts.memleaks",
+ "bbstoreaccounts")
MAINHELPER_START
- // Filename for configuraiton file?
- const char *configFilename = BOX_FILE_BBSTORED_DEFAULT_CONFIG;
+ // Filename for configuration file?
+ std::string configFilename;
+
+ #ifdef WIN32
+ configFilename = BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE;
+ #else
+ configFilename = BOX_FILE_BBSTORED_DEFAULT_CONFIG;
+ #endif
// See if there's another entry on the command line
int c;
@@ -469,10 +489,14 @@ int main(int argc, const char *argv[])
// Read in the configuration file
std::string errs;
- std::auto_ptr<Configuration> config(Configuration::LoadAndVerify(configFilename, &BackupConfigFileVerify, errs));
+ std::auto_ptr<Configuration> config(
+ Configuration::LoadAndVerify
+ (configFilename, &BackupConfigFileVerify, errs));
+
if(config.get() == 0 || !errs.empty())
{
- printf("Invalid configuration file:\n%s", errs.c_str());
+ BOX_ERROR("Invalid configuration file " << configFilename <<
+ ":" << errs);
}
// Get the user under which the daemon runs
@@ -512,7 +536,8 @@ int main(int argc, const char *argv[])
if(argc < 5
|| ::sscanf(argv[2], "%d", &discnum) != 1)
{
- printf("create requires raid file disc number, soft and hard limits\n");
+ BOX_ERROR("create requires raid file disc number, "
+ "soft and hard limits.");
return 1;
}
@@ -534,7 +559,7 @@ int main(int argc, const char *argv[])
// Change the limits on this account
if(argc < 4)
{
- printf("setlimit requires soft and hard limits\n");
+ BOX_ERROR("setlimit requires soft and hard limits.");
return 1;
}
@@ -568,7 +593,7 @@ int main(int argc, const char *argv[])
}
else
{
- ::printf("Unknown option %s.\n", argv[o]);
+ BOX_ERROR("Unknown option " << argv[o] << ".");
return 2;
}
}
@@ -578,7 +603,7 @@ int main(int argc, const char *argv[])
}
else
{
- printf("Unknown command '%s'\n", argv[0]);
+ BOX_ERROR("Unknown command '" << argv[0] << "'.");
return 1;
}
diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp
index dd2afcba..5d6855ee 100644
--- a/bin/bbstored/BBStoreDHousekeeping.cpp
+++ b/bin/bbstored/BBStoreDHousekeeping.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -48,7 +48,6 @@
#include "Box.h"
#include <stdio.h>
-#include <syslog.h>
#include "BackupStoreDaemon.h"
#include "BackupStoreAccountDatabase.h"
@@ -67,95 +66,143 @@
// Created: 11/12/03
//
// --------------------------------------------------------------------------
+void BackupStoreDaemon::HousekeepingInit()
+{
+
+ mLastHousekeepingRun = 0;
+}
+
void BackupStoreDaemon::HousekeepingProcess()
{
+ HousekeepingInit();
+
// Get the time between housekeeping runs
const Configuration &rconfig(GetConfiguration());
int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping"));
-
- int64_t lastHousekeepingRun = 0;
while(!StopRun())
{
- // Time now
+ RunHousekeepingIfNeeded();
+
+ // Calculate how long should wait before doing the next
+ // housekeeping run
int64_t timeNow = GetCurrentBoxTime();
- // Do housekeeping if the time interval has elapsed since the last check
- if((timeNow - lastHousekeepingRun) >= housekeepingInterval)
- {
- // Store the time
- lastHousekeepingRun = timeNow;
- ::syslog(LOG_INFO, "Starting housekeeping");
+ time_t secondsToGo = BoxTimeToSeconds(
+ (mLastHousekeepingRun + housekeepingInterval) -
+ timeNow);
+ if(secondsToGo < 1) secondsToGo = 1;
+ if(secondsToGo > 60) secondsToGo = 60;
+ int32_t millisecondsToGo = ((int)secondsToGo) * 1000;
+
+ // Check to see if there's any message pending
+ CheckForInterProcessMsg(0 /* no account */, millisecondsToGo);
+ }
+}
- // Get the list of accounts
- std::vector<int32_t> accounts;
- if(mpAccountDatabase)
- {
- mpAccountDatabase->GetAllAccountIDs(accounts);
- }
+void BackupStoreDaemon::RunHousekeepingIfNeeded()
+{
+ // Get the time between housekeeping runs
+ const Configuration &rconfig(GetConfiguration());
+ int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping"));
+
+ // Time now
+ int64_t timeNow = GetCurrentBoxTime();
+
+ // Do housekeeping if the time interval has elapsed since the last check
+ if((timeNow - mLastHousekeepingRun) < housekeepingInterval)
+ {
+ return;
+ }
+
+ // Store the time
+ mLastHousekeepingRun = timeNow;
+ BOX_INFO("Starting housekeeping");
+
+ // Get the list of accounts
+ std::vector<int32_t> accounts;
+ if(mpAccountDatabase)
+ {
+ mpAccountDatabase->GetAllAccountIDs(accounts);
+ }
- SetProcessTitle("housekeeping, active");
+ SetProcessTitle("housekeeping, active");
- // Check them all
- for(std::vector<int32_t>::const_iterator i = accounts.begin(); i != accounts.end(); ++i)
+ // Check them all
+ for(std::vector<int32_t>::const_iterator i = accounts.begin(); i != accounts.end(); ++i)
+ {
+ try
+ {
+ if(mpAccounts)
{
- try
- {
- if(mpAccounts)
- {
- // Get the account root
- std::string rootDir;
- int discSet = 0;
- mpAccounts->GetAccountRoot(*i, rootDir, discSet);
-
- // Do housekeeping on this account
- HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this);
- housekeeping.DoHousekeeping();
- }
- }
- catch(BoxException &e)
- {
- ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account",
- *i, e.what(), e.GetType(), e.GetSubType());
- }
- catch(std::exception &e)
- {
- ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account",
- *i, e.what());
- }
- catch(...)
- {
- ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account",
- *i);
- }
+ // Get the account root
+ std::string rootDir;
+ int discSet = 0;
+ mpAccounts->GetAccountRoot(*i, rootDir, discSet);
- // Check to see if there's any message pending
- CheckForInterProcessMsg(0 /* no account */);
-
- // Stop early?
- if(StopRun())
- {
- break;
- }
+ // Do housekeeping on this account
+ HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this);
+ housekeeping.DoHousekeeping();
}
-
- ::syslog(LOG_INFO, "Finished housekeeping");
}
-
- // Placed here for accuracy, if StopRun() is true, for example.
- SetProcessTitle("housekeeping, idle");
-
- // Calculate how long should wait before doing the next housekeeping run
- timeNow = GetCurrentBoxTime();
- time_t secondsToGo = BoxTimeToSeconds((lastHousekeepingRun + housekeepingInterval) - timeNow);
+ catch(BoxException &e)
+ {
+ BOX_ERROR("Housekeeping on account " <<
+ BOX_FORMAT_ACCOUNT(*i) << " threw exception, "
+ "aborting run for this account: " <<
+ e.what() << " (" <<
+ e.GetType() << "/" << e.GetSubType() << ")");
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Housekeeping on account " <<
+ BOX_FORMAT_ACCOUNT(*i) << " threw exception, "
+ "aborting run for this account: " <<
+ e.what());
+ }
+ catch(...)
+ {
+ BOX_ERROR("Housekeeping on account " <<
+ BOX_FORMAT_ACCOUNT(*i) << " threw exception, "
+ "aborting run for this account: "
+ "unknown exception");
+ }
+
+ int64_t timeNow = GetCurrentBoxTime();
+ time_t secondsToGo = BoxTimeToSeconds(
+ (mLastHousekeepingRun + housekeepingInterval) -
+ timeNow);
if(secondsToGo < 1) secondsToGo = 1;
if(secondsToGo > 60) secondsToGo = 60;
int32_t millisecondsToGo = ((int)secondsToGo) * 1000;
-
+
// Check to see if there's any message pending
CheckForInterProcessMsg(0 /* no account */, millisecondsToGo);
+
+ // Stop early?
+ if(StopRun())
+ {
+ break;
+ }
}
+
+ BOX_INFO("Finished housekeeping");
+
+ // Placed here for accuracy, if StopRun() is true, for example.
+ SetProcessTitle("housekeeping, idle");
}
+void BackupStoreDaemon::OnIdle()
+{
+ #ifdef WIN32
+ if (!mHousekeepingInited)
+ {
+ HousekeepingInit();
+ mHousekeepingInited = true;
+ }
+
+ RunHousekeepingIfNeeded();
+ #endif
+}
// --------------------------------------------------------------------------
//
@@ -168,6 +215,11 @@ void BackupStoreDaemon::HousekeepingProcess()
// --------------------------------------------------------------------------
bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitTime)
{
+ if(!mInterProcessCommsSocket.IsOpened())
+ {
+ return false;
+ }
+
// First, check to see if it's EOF -- this means something has gone wrong, and the housekeeping should terminate.
if(mInterProcessComms.IsEOF())
{
@@ -179,7 +231,7 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT
std::string line;
if(mInterProcessComms.GetLine(line, false /* no pre-processing */, MaximumWaitTime))
{
- TRACE1("housekeeping received command '%s' over interprocess comms\n", line.c_str());
+ TRACE1("Housekeeping received command '%s' over interprocess comms\n", line.c_str());
int account = 0;
@@ -201,7 +253,9 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT
if(account == AccountNum)
{
// Yes! -- need to stop now so when it retries to get the lock, it will succeed
- ::syslog(LOG_INFO, "Housekeeping giving way to connection for account 0x%08x", AccountNum);
+ BOX_INFO("Housekeeping on account " <<
+ BOX_FORMAT_ACCOUNT(AccountNum) <<
+ "giving way to client connection");
return true;
}
}
diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp
index d6ffe0a7..aa1a5f94 100644
--- a/bin/bbstored/BackupCommands.cpp
+++ b/bin/bbstored/BackupCommands.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -47,7 +47,8 @@
#include "Box.h"
-#include <syslog.h>
+#include <set>
+#include <sstream>
#include "autogen_BackupProtocolServer.h"
#include "BackupConstants.h"
@@ -62,6 +63,8 @@
#include "BackupStoreInfo.h"
#include "RaidFileController.h"
#include "FileStream.h"
+#include "InvisibleTempFileStream.h"
+#include "BufferedStream.h"
#include "MemLeakFindOn.h"
@@ -119,11 +122,26 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco
// 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() || !rContext.GetClientHasAccount())
+ if(mClientID != rContext.GetClientID())
{
- ::syslog(LOG_INFO, "Failed login: Client ID presented was %08X", mClientID);
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
- BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_BadLogin));
+ 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
@@ -132,9 +150,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco
// See if the context will get the lock
if(!rContext.AttemptToGetWriteLock())
{
- ::syslog(LOG_INFO, "Failed to get write lock (for Client ID %08X)", mClientID);
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
- BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_CannotLockStoreForWriting));
+ 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
@@ -151,7 +172,11 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco
rContext.SetPhase(BackupContext::Phase_Commands);
// Log login
- ::syslog(LOG_INFO, "Login: Client ID %08X, %s", mClientID, ((mFlags & Flags_ReadOnly) != Flags_ReadOnly)?"Read/Write":"Read-only");
+ 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;
@@ -171,7 +196,8 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco
// --------------------------------------------------------------------------
std::auto_ptr<ProtocolObject> BackupProtocolServerFinished::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext)
{
- ::syslog(LOG_INFO, "Session finished");
+ BOX_NOTICE("Session finished for Client ID " <<
+ BOX_FORMAT_ACCOUNT(rContext.GetClientID()));
// Let the context know about it
rContext.ReceivedFinishCommand();
@@ -342,13 +368,23 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto
en = rdir.FindEntryByID(id);
if(en == 0)
{
- ::syslog(LOG_ERR, "Object %llx in dir %llx for account %x references object %llx which does not exist in dir",
- mObjectID, mInDirectory, rContext.GetClientID(), id);
- return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
- BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_PatchConsistencyError));
+ 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);
+ }
+ 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
@@ -365,8 +401,11 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto
std::auto_ptr<IOStream> diff2(rContext.OpenObject(patchID));
// Choose a temporary filename for the result of the combination
- std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp",
- p + 16 /* rotate which disc it's on */));
+ std::ostringstream fs(rContext.GetStoreRoot());
+ fs << ".recombinetemp.";
+ fs << p;
+ std::string tempFn(fs.str());
+ tempFn = RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), tempFn, p + 16);
// Open the temporary file
std::auto_ptr<IOStream> combined;
@@ -374,14 +413,14 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto
{
{
// Write nastily to allow this to work with gcc 2.x
- std::auto_ptr<IOStream> t(new FileStream(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL));
+ std::auto_ptr<IOStream> t(
+ new InvisibleTempFileStream(
+ tempFn.c_str(),
+ O_RDWR | O_CREAT |
+ O_EXCL | O_BINARY |
+ O_TRUNC));
combined = t;
}
- // Unlink immediately as it's a temporary file
- if(::unlink(tempFn.c_str()) != 0)
- {
- THROW_EXCEPTION(CommonException, OSFileError);
- }
}
catch(...)
{
@@ -397,6 +436,7 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto
combined->Seek(0, IOStream::SeekType_Absolute);
// Then shuffle round for the next go
+ if (from.get()) from->Close();
from = combined;
}
@@ -416,9 +456,10 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto
// Open the object
std::auto_ptr<IOStream> object(rContext.OpenObject(mObjectID));
+ BufferedStream buf(*object);
// Verify it
- if(!BackupStoreFile::VerifyEncodedFileFormat(*object))
+ if(!BackupStoreFile::VerifyEncodedFileFormat(buf))
{
return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError(
BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_FileDoesNotVerify));
@@ -434,8 +475,9 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto
stream = t;
}
- // Object will be deleted when the stream is deleted, so can release the object auto_ptr here to
- // avoid premature deletiong
+ // Object will be deleted when the stream is deleted,
+ // so can release the object auto_ptr here to avoid
+ // premature deletion
object.release();
}
diff --git a/bin/bbstored/BackupConstants.h b/bin/bbstored/BackupConstants.h
index 2b44929c..664fea54 100644
--- a/bin/bbstored/BackupConstants.h
+++ b/bin/bbstored/BackupConstants.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp
index 2c741eeb..659cc5f8 100644
--- a/bin/bbstored/BackupContext.cpp
+++ b/bin/bbstored/BackupContext.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -62,6 +62,8 @@
#include "BackupStoreDaemon.h"
#include "RaidFileController.h"
#include "FileStream.h"
+#include "InvisibleTempFileStream.h"
+#include "BufferedStream.h"
#include "MemLeakFindOn.h"
@@ -343,7 +345,8 @@ BackupStoreDirectory &BackupContext::GetDirectoryInternal(int64_t ObjectID)
std::auto_ptr<BackupStoreDirectory> dir(new BackupStoreDirectory);
// Read it from the stream, then set it's revision ID
- dir->ReadFromStream(*objectFile, IOStream::TimeOutInfinite);
+ 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
@@ -491,13 +494,21 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod
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 definately goes away
+
+ // Unlink it immediately, so it definitely goes away
if(::unlink(tempFn.c_str()) != 0)
{
THROW_EXCEPTION(CommonException, OSFileError);
}
+#endif
// Stream the incoming diff to this temporary file
if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT))
diff --git a/bin/bbstored/BackupContext.h b/bin/bbstored/BackupContext.h
index b8aed74b..df4f2189 100644
--- a/bin/bbstored/BackupContext.h
+++ b/bin/bbstored/BackupContext.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp
index 06198ea4..5234d6e0 100644
--- a/bin/bbstored/BackupStoreDaemon.cpp
+++ b/bin/bbstored/BackupStoreDaemon.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -49,9 +49,12 @@
#include <stdlib.h>
#include <stdio.h>
-#include <syslog.h>
#include <signal.h>
+#ifdef HAVE_SYSLOG_H
+ #include <syslog.h>
+#endif
+
#include "BackupContext.h"
#include "BackupStoreDaemon.h"
#include "BackupStoreConfigVerify.h"
@@ -77,6 +80,7 @@ BackupStoreDaemon::BackupStoreDaemon()
mExtendedLogging(false),
mHaveForkedHousekeeping(false),
mIsHousekeepingProcess(false),
+ mHousekeepingInited(false),
mInterProcessComms(mInterProcessCommsSocket)
{
}
@@ -127,14 +131,9 @@ const char *BackupStoreDaemon::DaemonName() const
// Created: 1/1/04
//
// --------------------------------------------------------------------------
-const char *BackupStoreDaemon::DaemonBanner() const
+std::string BackupStoreDaemon::DaemonBanner() const
{
-#ifndef NDEBUG
- // Don't display banner in debug builds
- return 0;
-#else
return BANNER_TEXT("Backup Store Server");
-#endif
}
@@ -166,7 +165,23 @@ void BackupStoreDaemon::SetupInInitialProcess()
// Initialise the raid files controller
RaidFileController &rcontroller = RaidFileController::GetController();
- rcontroller.Initialise(config.GetKeyValue("RaidFileConf").c_str());
+
+ std::string raidFileConfig;
+
+ #ifdef WIN32
+ if (!config.KeyExists("RaidFileConf"))
+ {
+ raidFileConfig = BOX_GET_DEFAULT_RAIDFILE_CONFIG_FILE;
+ }
+ else
+ {
+ raidFileConfig = config.GetKeyValue("RaidFileConf");
+ }
+ #else
+ raidFileConfig = config.GetKeyValue("RaidFileConf");
+ #endif
+
+ rcontroller.Initialise(raidFileConfig);
// Load the account database
std::auto_ptr<BackupStoreAccountDatabase> pdb(BackupStoreAccountDatabase::Read(config.GetKeyValue("AccountDatabase").c_str()));
@@ -194,6 +209,9 @@ void BackupStoreDaemon::Run()
const Configuration &config(GetConfiguration());
mExtendedLogging = config.GetKeyValueBool("ExtendedLogging");
+#ifdef WIN32
+ // Housekeeping runs synchronously on Win32
+#else
// Fork off housekeeping daemon -- must only do this the first time Run() is called
if(!mHaveForkedHousekeeping)
{
@@ -223,7 +241,7 @@ void BackupStoreDaemon::Run()
// Change the log name
::openlog("bbstored/hk", LOG_PID, LOG_LOCAL6);
// Log that housekeeping started
- ::syslog(LOG_INFO, "Housekeeping process started");
+ BOX_INFO("Housekeeping process started");
// Ignore term and hup
// Parent will handle these and alert the child via the socket, don't want to randomly die
::signal(SIGHUP, SIG_IGN);
@@ -249,6 +267,7 @@ void BackupStoreDaemon::Run()
THROW_EXCEPTION(ServerException, SocketCloseError)
}
}
+#endif // WIN32
if(mIsHousekeepingProcess)
{
@@ -259,12 +278,18 @@ void BackupStoreDaemon::Run()
{
// In server process -- use the base class to do the magic
ServerTLS<BOX_PORT_BBSTORED>::Run();
-
+
+ if (!mInterProcessCommsSocket.IsOpened())
+ {
+ return;
+ }
+
// Why did it stop? Tell the housekeeping process to do the same
if(IsReloadConfigWanted())
{
mInterProcessCommsSocket.Write("h\n", 2);
}
+
if(IsTerminateWanted())
{
mInterProcessCommsSocket.Write("t\n", 2);
@@ -272,22 +297,54 @@ void BackupStoreDaemon::Run()
}
}
-
// --------------------------------------------------------------------------
//
// Function
// Name: BackupStoreDaemon::Connection(SocketStreamTLS &)
-// Purpose: Handles a connection
+// Purpose: Handles a connection, by catching exceptions and
+// delegating to Connection2
// Created: 2003/08/20
//
// --------------------------------------------------------------------------
void BackupStoreDaemon::Connection(SocketStreamTLS &rStream)
{
+ try
+ {
+ Connection2(rStream);
+ }
+ catch(BoxException &e)
+ {
+ BOX_ERROR("Error in child process, terminating connection: " <<
+ e.what() << " (" << e.GetType() << "/" <<
+ e.GetSubType() << ")");
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Error in child process, terminating connection: " <<
+ e.what());
+ }
+ catch(...)
+ {
+ BOX_ERROR("Error in child process, terminating connection: " <<
+ "unknown exception");
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupStoreDaemon::Connection2(SocketStreamTLS &)
+// Purpose: Handles a connection from bbackupd
+// Created: 2006/11/12
+//
+// --------------------------------------------------------------------------
+void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream)
+{
// Get the common name from the certificate
std::string clientCommonName(rStream.GetPeerCommonName());
// Log the name
- ::syslog(LOG_INFO, "Certificate CN: %s\n", clientCommonName.c_str());
+ BOX_INFO("Client certificate CN: " << clientCommonName);
// Check it
int32_t id;
@@ -333,8 +390,8 @@ void BackupStoreDaemon::LogConnectionStats(const char *commonName,
const SocketStreamTLS &s)
{
// Log the amount of data transferred
- ::syslog(LOG_INFO, "Connection statistics for %s: "
- "IN=%lld OUT=%lld TOTAL=%lld\n", commonName,
- s.GetBytesRead(), s.GetBytesWritten(),
- s.GetBytesRead() + s.GetBytesWritten());
+ BOX_INFO("Connection statistics for " << commonName << ":"
+ " IN=" << s.GetBytesRead() <<
+ " OUT=" << s.GetBytesWritten() <<
+ " TOTAL=" << (s.GetBytesRead() + s.GetBytesWritten()));
}
diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h
index c320003a..d636f451 100644
--- a/bin/bbstored/BackupStoreDaemon.h
+++ b/bin/bbstored/BackupStoreDaemon.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -76,10 +76,12 @@ private:
BackupStoreDaemon(const BackupStoreDaemon &rToCopy);
public:
- // For BackupContext to comminicate with housekeeping process
+ // For BackupContext to communicate with housekeeping process
void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen)
{
+#ifndef WIN32
mInterProcessCommsSocket.Write(Msg, MsgLen);
+#endif
}
protected:
@@ -88,10 +90,11 @@ protected:
virtual void Run();
- void Connection(SocketStreamTLS &rStream);
+ virtual void Connection(SocketStreamTLS &rStream);
+ void Connection2(SocketStreamTLS &rStream);
virtual const char *DaemonName() const;
- virtual const char *DaemonBanner() const;
+ virtual std::string DaemonBanner() const;
const ConfigurationVerify *GetConfigVerify() const;
@@ -107,9 +110,15 @@ private:
bool mExtendedLogging;
bool mHaveForkedHousekeeping;
bool mIsHousekeepingProcess;
+ bool mHousekeepingInited;
SocketStream mInterProcessCommsSocket;
IOStreamGetLine mInterProcessComms;
+
+ virtual void OnIdle();
+ void HousekeepingInit();
+ void RunHousekeepingIfNeeded();
+ int64_t mLastHousekeepingRun;
};
diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp
index dac69946..fc9e83f1 100644
--- a/bin/bbstored/HousekeepStoreAccount.cpp
+++ b/bin/bbstored/HousekeepStoreAccount.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -47,9 +47,10 @@
#include "Box.h"
-#include <map>
#include <stdio.h>
+#include <map>
+
#include "HousekeepStoreAccount.h"
#include "BackupStoreDaemon.h"
#include "StoreStructure.h"
@@ -61,6 +62,7 @@
#include "NamedLock.h"
#include "autogen_BackupStoreException.h"
#include "BackupStoreFile.h"
+#include "BufferedStream.h"
#include "MemLeakFindOn.h"
@@ -174,11 +176,18 @@ void HousekeepStoreAccount::DoHousekeeping()
|| (usedDeleted + mBlocksInDeletedFilesDelta) != mBlocksInDeletedFiles || usedDirectories != mBlocksInDirectories)
{
// Log this
- ::syslog(LOG_ERR, "On housekeeping, sizes in store do not match calculated sizes, correcting");
- ::syslog(LOG_ERR, "different (store,calc): acc 0x%08x, used (%lld,%lld), old (%lld,%lld), deleted (%lld,%lld), dirs (%lld,%lld)",
- mAccountID,
- (used + mBlocksUsedDelta), mBlocksUsed, (usedOld + mBlocksInOldFilesDelta), mBlocksInOldFiles,
- (usedDeleted + mBlocksInDeletedFilesDelta), mBlocksInDeletedFiles, usedDirectories, mBlocksInDirectories);
+ 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
@@ -210,17 +219,33 @@ void HousekeepStoreAccount::DoHousekeeping()
// Log deletion if anything was deleted
if(mFilesDeleted > 0 || mEmptyDirectoriesDeleted > 0)
{
- ::syslog(LOG_INFO, "Account 0x%08x, removed %lld blocks (%lld files, %lld dirs)%s", mAccountID, 0 - (mBlocksUsedDelta + removeASAPBlocksUsedDelta),
- mFilesDeleted, mEmptyDirectoriesDeleted,
- deleteInterrupted?" was interrupted":"");
+ BOX_INFO("Housekeeping on account " <<
+ BOX_FORMAT_ACCOUNT(mAccountID) << " "
+ "removed " <<
+ (0 - (mBlocksUsedDelta + removeASAPBlocksUsedDelta)) <<
+ " blocks (" << mFilesDeleted << " files, " <<
+ mEmptyDirectoriesDeleted << " dirs)" <<
+ (deleteInterrupted?" and was interrupted":""));
}
// 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());
+ 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);
@@ -263,6 +288,7 @@ void HousekeepStoreAccount::MakeObjectFilename(int64_t ObjectID, std::string &rF
// --------------------------------------------------------------------------
bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID)
{
+#ifndef WIN32
if((--mCountUntilNextInterprocessMsgCheck) <= 0)
{
mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY;
@@ -273,6 +299,7 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID)
return false;
}
}
+#endif
// Get the filename
std::string objectFilename;
@@ -288,7 +315,9 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID)
// Read the directory in
BackupStoreDirectory dir;
- dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite);
+ BufferedStream buf(*dirStream);
+ dir.ReadFromStream(buf, IOStream::TimeOutInfinite);
+ dirStream->Close();
// Is it empty?
if(dir.GetNumberOfEntries() == 0)
@@ -523,6 +552,7 @@ bool HousekeepStoreAccount::DeleteFiles()
// (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;
@@ -533,6 +563,7 @@ bool HousekeepStoreAccount::DeleteFiles()
return true;
}
}
+#endif
// Load up the directory it's in
// Get the filename
@@ -585,7 +616,14 @@ void HousekeepStoreAccount::DeleteFile(int64_t InDirectory, int64_t ObjectID, Ba
BackupStoreDirectory::Entry *pentry = rDirectory.FindEntryByID(ObjectID);
if(pentry == 0)
{
- ::syslog(LOG_ERR, "acc 0x%08x, object %lld not found in dir %lld, logic error/corruption? Run bbstoreaccounts check <accid> fix", mAccountID, ObjectID, InDirectory);
+ 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;
}
@@ -767,6 +805,7 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories()
// 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;
@@ -777,6 +816,7 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories()
return true;
}
}
+#endif
// Do not delete the root directory
if(*i == BACKUPSTORE_ROOT_DIRECTORY_ID)
diff --git a/bin/bbstored/HousekeepStoreAccount.h b/bin/bbstored/HousekeepStoreAccount.h
index 85180bf0..bdb012c6 100644
--- a/bin/bbstored/HousekeepStoreAccount.h
+++ b/bin/bbstored/HousekeepStoreAccount.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbstored/Makefile.extra b/bin/bbstored/Makefile.extra
index 187d53ef..94bc3fb9 100644
--- a/bin/bbstored/Makefile.extra
+++ b/bin/bbstored/Makefile.extra
@@ -5,5 +5,5 @@ GEN_CMD_SRV = $(MAKEPROTOCOL) Server backupprotocol.txt
# AUTOGEN SEEDING
autogen_BackupProtocolServer.cpp autogen_BackupProtocolServer.h: $(MAKEPROTOCOL) backupprotocol.txt
- perl $(GEN_CMD_SRV)
+ $(PERL) $(GEN_CMD_SRV)
diff --git a/bin/bbstored/bbstored-certs b/bin/bbstored/bbstored-certs
index bdaf50d5..22d6c5ad 100755
--- a/bin/bbstored/bbstored-certs
+++ b/bin/bbstored/bbstored-certs
@@ -1,5 +1,5 @@
#!/usr/bin/perl
-# distribution boxbackup-0.10 (svn version: 494)
+# distribution boxbackup-0.11rc1 (svn version: 2023_2024)
#
# Copyright (c) 2003 - 2006
# Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbstored/bbstored-certs.in b/bin/bbstored/bbstored-certs.in
new file mode 100755
index 00000000..e0554d94
--- /dev/null
+++ b/bin/bbstored/bbstored-certs.in
@@ -0,0 +1,319 @@
+#!@PERL@
+use strict;
+
+# validity period for root certificates -- default is a very long time
+my $root_sign_period = '10000';
+
+# but less so for client certificates
+my $sign_period = '5000';
+
+# check and get command line parameters
+if($#ARGV < 1)
+{
+ print <<__E;
+
+bbstored certificates utility.
+
+Bad command line parameters.
+Usage:
+ bbstored-certs certs-dir command [arguments]
+
+certs-dir is the directory holding the root keys and certificates for the backup system
+command is the action to perform, taking parameters.
+
+Commands are
+
+ init
+ -- generate initial root certificates (certs-dir must not already exist)
+ sign certificate-name
+ -- sign a client certificate
+ sign-server certificate-name
+ -- sign a server certificate
+
+Signing requires confirmation that the certificate is correct and should be signed.
+
+__E
+ exit(1);
+}
+
+# check for OPENSSL_CONF environment var being set
+if(exists $ENV{'OPENSSL_CONF'})
+{
+ print <<__E;
+
+---------------------------------------
+
+WARNING:
+ You have the OPENSSL_CONF environment variable set.
+ Use of non-standard openssl configs may cause problems.
+
+---------------------------------------
+
+__E
+}
+
+# directory structure:
+#
+# roots/
+# clientCA.pem -- root certificate for client (used on server)
+# serverCA.pem -- root certificate for servers (used on clients)
+# keys/
+# clientRootKey.pem -- root key for clients
+# serverRootKey.pem -- root key for servers
+# servers/
+# hostname.pem -- certificate for server 'hostname'
+# clients/
+# account.pem -- certficiate for account 'account' (ID in hex)
+#
+
+
+# check parameters
+my ($cert_dir,$command,@args) = @ARGV;
+
+# check directory exists
+if($command ne 'init')
+{
+ if(!-d $cert_dir)
+ {
+ die "$cert_dir does not exist";
+ }
+}
+
+# run command
+if($command eq 'init') {&cmd_init;}
+elsif($command eq 'sign') {&cmd_sign;}
+elsif($command eq 'sign-server') {&cmd_sign_server;}
+else
+{
+ die "Unknown command $command"
+}
+
+sub cmd_init
+{
+ # create directories
+ unless(mkdir($cert_dir,0700)
+ && mkdir($cert_dir.'/roots',0700)
+ && mkdir($cert_dir.'/keys',0700)
+ && mkdir($cert_dir.'/servers',0700)
+ && mkdir($cert_dir.'/clients',0700))
+ {
+ die "Failed to create directory structure"
+ }
+
+ # create root keys and certrs
+ cmd_init_create_root('client');
+ cmd_init_create_root('server');
+}
+
+sub cmd_init_create_root
+{
+ my $entity = $_[0];
+
+ my $cert = "$cert_dir/roots/".$entity.'CA.pem';
+ my $serial = "$cert_dir/roots/".$entity.'CA.srl';
+ my $key = "$cert_dir/keys/".$entity.'RootKey.pem';
+ my $csr = "$cert_dir/keys/".$entity.'RootCSR.pem';
+
+ # generate key
+ if(system("openssl genrsa -out $key 2048") != 0)
+ {
+ die "Couldn't generate private key."
+ }
+
+ # make CSR
+ die "Couldn't run openssl for CSR generation" unless
+ open(CSR,"|openssl req -new -key $key -sha1 -out $csr");
+ print CSR <<__E;
+.
+.
+.
+.
+.
+Backup system $entity root
+.
+.
+.
+
+__E
+ close CSR;
+ print "\n\n";
+ die "Certificate request wasn't created.\n" unless -f $csr;
+
+ # sign it to make a self-signed root CA key
+ if(system("openssl x509 -req -in $csr -sha1 -extensions v3_ca -signkey $key -out $cert -days $root_sign_period") != 0)
+ {
+ die "Couldn't generate root certificate."
+ }
+
+ # write the initial serial number
+ open SERIAL,">$serial" or die "Can't open $serial for writing";
+ print SERIAL "00\n";
+ close SERIAL;
+}
+
+sub cmd_sign
+{
+ my $csr = $args[0];
+
+ if(!-f $csr)
+ {
+ die "$csr does not exist";
+ }
+
+ # get the common name specified in this certificate
+ my $common_name = get_csr_common_name($csr);
+
+ # look OK?
+ unless($common_name =~ m/\ABACKUP-([A-Fa-f0-9]+)\Z/)
+ {
+ die "The certificate presented does not appear to be a backup client certificate"
+ }
+
+ my $acc = $1;
+
+ # check against filename
+ if(!($csr =~ m/(\A|\/)([A-Fa-f0-9]+)-/) || $2 ne $acc)
+ {
+ die "Certificate request filename does not match name in certificate ($common_name)"
+ }
+
+ print <<__E;
+
+This certificate is for backup account
+
+ $acc
+
+Ensure this matches the account number you are expecting. The filename is
+
+ $csr
+
+which should include this account number, and additionally, you should check
+that you received it from the right person.
+
+Signing the wrong certificate compromises the security of your backup system.
+
+Would you like to sign this certificate? (type 'yes' to confirm)
+__E
+
+ return unless get_confirmation();
+
+ # out certificate
+ my $out_cert = "$cert_dir/clients/$acc"."-cert.pem";
+
+ # sign it!
+ if(system("openssl x509 -req -in $csr -sha1 -extensions usr_crt -CA $cert_dir/roots/clientCA.pem -CAkey $cert_dir/keys/clientRootKey.pem -out $out_cert -days $sign_period") != 0)
+ {
+ die "Signing failed"
+ }
+
+ # tell user what to do next
+ print <<__E;
+
+
+Certificate signed.
+
+Send the files
+
+ $out_cert
+ $cert_dir/roots/serverCA.pem
+
+to the client.
+
+__E
+}
+
+sub cmd_sign_server
+{
+ my $csr = $args[0];
+
+ if(!-f $csr)
+ {
+ die "$csr does not exist";
+ }
+
+ # get the common name specified in this certificate
+ my $common_name = get_csr_common_name($csr);
+
+ # look OK?
+ if($common_name !~ m/\A[-a-zA-Z0-9.]+\Z/)
+ {
+ die "Invalid server name"
+ }
+
+ print <<__E;
+
+This certificate is for backup server
+
+ $common_name
+
+Signing the wrong certificate compromises the security of your backup system.
+
+Would you like to sign this certificate? (type 'yes' to confirm)
+__E
+
+ return unless get_confirmation();
+
+ # out certificate
+ my $out_cert = "$cert_dir/servers/$common_name"."-cert.pem";
+
+ # sign it!
+ if(system("openssl x509 -req -in $csr -sha1 -extensions usr_crt -CA $cert_dir/roots/serverCA.pem -CAkey $cert_dir/keys/serverRootKey.pem -out $out_cert -days $sign_period") != 0)
+ {
+ die "Signing failed"
+ }
+
+ # tell user what to do next
+ print <<__E;
+
+
+Certificate signed.
+
+Install the files
+
+ $out_cert
+ $cert_dir/roots/clientCA.pem
+
+on the server.
+
+__E
+}
+
+
+sub get_csr_common_name
+{
+ my $csr = $_[0];
+
+ open CSRTEXT,"openssl req -text -in $csr |" or die "Can't open openssl for reading";
+
+ my $subject;
+ while(<CSRTEXT>)
+ {
+ $subject = $1 if m/Subject:.+?CN=([-\.\w]+)/
+ }
+ close CSRTEXT;
+
+ if($subject eq '')
+ {
+ die "No subject found in CSR $csr"
+ }
+
+ return $subject
+}
+
+sub get_confirmation()
+{
+ my $line = <STDIN>;
+ chomp $line;
+ if(lc $line ne 'yes')
+ {
+ print "CANCELLED\n";
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+
+
diff --git a/bin/bbstored/bbstored-config b/bin/bbstored/bbstored-config
index 7325e383..76d8cad9 100755
--- a/bin/bbstored/bbstored-config
+++ b/bin/bbstored/bbstored-config
@@ -1,5 +1,5 @@
#!/usr/bin/perl
-# distribution boxbackup-0.10 (svn version: 494)
+# distribution boxbackup-0.11rc1 (svn version: 2023_2024)
#
# Copyright (c) 2003 - 2006
# Ben Summers and contributors. All rights reserved.
diff --git a/bin/bbstored/bbstored-config.in b/bin/bbstored/bbstored-config.in
new file mode 100755
index 00000000..7bd79716
--- /dev/null
+++ b/bin/bbstored/bbstored-config.in
@@ -0,0 +1,242 @@
+#!@PERL@
+use strict;
+
+# should be running as root
+if($> != 0)
+{
+ printf "\nWARNING: this should be run as root\n\n"
+}
+
+# check and get command line parameters
+if($#ARGV < 2)
+{
+ print <<__E;
+
+Setup bbstored config utility.
+
+Bad command line parameters.
+Usage:
+ bbstored-config config-dir server-hostname username [raidfile-config]
+
+config-dir usually /etc/box
+server-hostname is the hostname used by clients to connect to this server
+username is the user to run the server under
+raidfile-config is optional. Use if you have a non-standard raidfile.conf file.
+
+__E
+ exit(1);
+}
+
+# check for OPENSSL_CONF environment var being set
+if(exists $ENV{'OPENSSL_CONF'})
+{
+ print <<__E;
+
+---------------------------------------
+
+WARNING:
+ You have the OPENSSL_CONF environment variable set.
+ Use of non-standard openssl configs may cause problems.
+
+---------------------------------------
+
+__E
+}
+
+# default locations
+my $default_config_location = '/etc/box/bbstored.conf';
+
+# command line parameters
+my ($config_dir,$server,$username,$raidfile_config) = @ARGV;
+
+$raidfile_config = $config_dir . '/raidfile.conf' unless $raidfile_config ne '';
+
+# check server exists, but don't bother checking that it's actually this machine.
+{
+ my @r = gethostbyname($server);
+ if($#r < 0)
+ {
+ die "Server '$server' not found. (check server name, test DNS lookup failed.)"
+ }
+}
+
+# check this exists
+if(!-f $raidfile_config)
+{
+ print "The RaidFile configuration file $raidfile_config doesn't exist.\nYou may need to create it with raidfile-config.\nWon't configure bbstored without it.\n";
+ exit(1);
+}
+
+# check that the user exists
+die "You shouldn't run bbstored as root" if $username eq 'root';
+my $user_uid = 0;
+(undef,undef,$user_uid) = getpwnam($username);
+if($user_uid == 0)
+{
+ die "User $username doesn't exist\n";
+}
+
+# check that directories are writeable
+open RAIDCONF,$raidfile_config or die "Can't open $raidfile_config";
+{
+ my %done = ();
+ while(<RAIDCONF>)
+ {
+ next unless m/Dir\d\s*=\s*(.+)/;
+ my $d = $1;
+ $d = $d.'/backup' if -e $d.'/backup';
+ print "Checking permissions on $d\n";
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($d);
+ my $req_perms = ($uid == $user_uid)?0700:0007;
+ if(($mode & $req_perms) != $req_perms)
+ {
+ print "$username doesn't appear to have the necessary permissions on $d\n";
+ print "Either adjust permissions, or create a directory 'backup' inside the\n";
+ print "directory specified in raidfile.conf which is writable.\n";
+ exit(1);
+ }
+ }
+}
+close RAIDCONF;
+
+# ssl stuff
+my $private_key = "$config_dir/bbstored/$server-key.pem";
+my $certificate_request = "$config_dir/bbstored/$server-csr.pem";
+my $certificate = "$config_dir/bbstored/$server-cert.pem";
+my $ca_root_cert = "$config_dir/bbstored/clientCA.pem";
+
+# other files
+my $config_file = "$config_dir/bbstored.conf";
+my $accounts_file = "$config_dir/bbstored/accounts.txt";
+
+# summarise configuration
+
+print <<__E;
+
+Setup bbstored config utility.
+
+Configuration:
+ Writing configuration file: $config_file
+ Writing empty accounts file: $accounts_file
+ Server hostname: $server
+ RaidFile config: $raidfile_config
+
+__E
+
+# create directories
+if(!-d $config_dir)
+{
+ print "Creating $config_dir...\n";
+ mkdir $config_dir,0755 or die "Can't create $config_dir";
+}
+
+if(!-d "$config_dir/bbstored")
+{
+ print "Creating $config_dir/bbstored\n";
+ mkdir "$config_dir/bbstored",0755 or die "Can't create $config_dir/bbstored";
+}
+
+# create blank accounts file
+if(!-f $accounts_file)
+{
+ print "Creating blank accounts file\n";
+ open ACC,">$accounts_file";
+ close ACC;
+}
+
+# generate the private key for the server
+if(!-f $private_key)
+{
+ print "Generating private key...\n";
+ if(system("openssl genrsa -out $private_key 2048") != 0)
+ {
+ die "Couldn't generate private key."
+ }
+}
+
+# generate a certificate request
+if(!-f $certificate_request)
+{
+ die "Couldn't run openssl for CSR generation" unless
+ open(CSR,"|openssl req -new -key $private_key -sha1 -out $certificate_request");
+ print CSR <<__E;
+.
+.
+.
+.
+.
+$server
+.
+.
+.
+
+__E
+ close CSR;
+ print "\n\n";
+ die "Certificate request wasn't created.\n" unless -f $certificate_request
+}
+
+# write the configuration file
+print "Writing configuration file $config_file\n";
+open CONFIG,">$config_file" or die "Can't open config file for writing";
+print CONFIG <<__E;
+
+RaidFileConf = $raidfile_config
+AccountDatabase = $accounts_file
+
+# Uncomment this line to see exactly what commands are being received from clients.
+# ExtendedLogging = yes
+
+# scan all accounts for files which need deleting every 15 minutes.
+
+TimeBetweenHousekeeping = 900
+
+Server
+{
+ PidFile = /var/run/bbstored.pid
+ User = $username
+ ListenAddresses = inet:$server
+ CertificateFile = $certificate
+ PrivateKeyFile = $private_key
+ TrustedCAsFile = $ca_root_cert
+}
+
+
+__E
+
+close CONFIG;
+
+# explain to the user what they need to do next
+my $daemon_args = ($config_file eq $default_config_location)?'':" $config_file";
+
+print <<__E;
+
+===================================================================
+
+bbstored basic configuration complete.
+
+What you need to do now...
+
+1) Sign $certificate_request
+ using the bbstored-certs utility.
+
+2) Install the server certificate and root CA certificate as
+ $certificate
+ $ca_root_cert
+
+3) You may wish to read the configuration file
+ $config_file
+ and adjust as appropraite.
+
+4) Create accounts with bbstoreaccounts
+
+5) Start the backup store daemon with the command
+ /usr/local/bin/bbstored$daemon_args
+ in /etc/rc.local, or your local equivalent.
+
+===================================================================
+
+__E
+
+
+
diff --git a/bin/bbstored/bbstored.cpp b/bin/bbstored/bbstored.cpp
index ccf786cd..d3710b5f 100644
--- a/bin/bbstored/bbstored.cpp
+++ b/bin/bbstored/bbstored.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -48,6 +48,7 @@
#include "Box.h"
#include "BackupStoreDaemon.h"
#include "MainHelper.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -55,8 +56,19 @@ int main(int argc, const char *argv[])
{
MAINHELPER_START
+ Logging::SetProgramName("Box Backup (bbstored)");
+ Logging::ToConsole(true);
+ Logging::ToSyslog (true);
+
BackupStoreDaemon daemon;
- return daemon.Main(BOX_FILE_BBSTORED_DEFAULT_CONFIG, argc, argv);
+
+ #ifdef WIN32
+ return daemon.Main(BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE,
+ argc, argv);
+ #else
+ return daemon.Main(BOX_FILE_BBSTORED_DEFAULT_CONFIG,
+ argc, argv);
+ #endif
MAINHELPER_END
}
diff --git a/bootstrap b/bootstrap
index d7cd30e3..104b3933 100755
--- a/bootstrap
+++ b/bootstrap
@@ -1,5 +1,5 @@
#!/bin/sh
-# distribution boxbackup-0.10 (svn version: 494)
+# distribution boxbackup-0.11rc1 (svn version: 2023_2024)
#
# Copyright (c) 2003 - 2006
# Ben Summers and contributors. All rights reserved.
diff --git a/configure b/configure
index 304ff797..8e5d61c9 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# distribution boxbackup-0.10 (svn version: 494)
+# distribution boxbackup-0.11rc1 (svn version: 2023_2024)
#
# Copyright (c) 2003 - 2006
# Ben Summers and contributors. All rights reserved.
@@ -38,7 +38,7 @@
#
#
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for Box Backup 0.09.
+# Generated by GNU Autoconf 2.59 for Box Backup 0.10.
#
# Report bugs to <box@fluffy.co.uk>.
#
@@ -307,8 +307,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='Box Backup'
PACKAGE_TARNAME='box-backup'
-PACKAGE_VERSION='0.09'
-PACKAGE_STRING='Box Backup 0.09'
+PACKAGE_VERSION='0.10'
+PACKAGE_STRING='Box Backup 0.10'
PACKAGE_BUGREPORT='box@fluffy.co.uk'
ac_unique_file="lib/common/Box.h"
@@ -349,7 +349,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT CXXFLAGS_STRICT LDADD_RDYNAMIC CXXCPP EGREP RANDOM_DEVICE LIBOBJS bindir_expanded LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT CXXFLAGS_STRICT LDADD_RDYNAMIC PERL TARGET_PERL AR RANLIB CXXCPP EGREP RANDOM_DEVICE LIBOBJS bindir_expanded LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -818,7 +818,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures Box Backup 0.09 to adapt to many kinds of systems.
+\`configure' configures Box Backup 0.10 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -880,7 +880,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of Box Backup 0.09:";;
+ short | recursive ) echo "Configuration of Box Backup 0.10:";;
esac
cat <<\_ACEOF
@@ -898,7 +898,8 @@ Optional Features:
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --with-bdb-dir=DIR Berkeley DB installation directory
+ --with-bdb-headers=DIR Berkeley DB include files location
+ --with-bdb-lib=DIR Berkeley DB library location
--with-ssl-headers=DIR SSL include files location
--with-ssl-lib=DIR SSL library location
--with-random=FILE Use FILE as random number seed [auto-detected]
@@ -1012,7 +1013,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-Box Backup configure 0.09
+Box Backup configure 0.10
generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1026,7 +1027,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by Box Backup $as_me 0.09, which was
+It was created by Box Backup $as_me 0.10, which was
generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@
@@ -2208,10 +2209,158 @@ if test "x$GXX" = "xyes"; then
fi
+# Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PERL+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PERL in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="{ { echo "$as_me:$LINENO: error: perl executable was not found" >&5
+echo "$as_me: error: perl executable was not found" >&2;}
+ { (exit 1); exit 1; }; }"
+ ;;
+esac
+fi
+PERL=$ac_cv_path_PERL
+
+if test -n "$PERL"; then
+ echo "$as_me:$LINENO: result: $PERL" >&5
+echo "${ECHO_T}$PERL" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+
+case $target_os in
+mingw*)
+ TARGET_PERL=perl
+ ;;
+*)
+ TARGET_PERL=$PERL
+ ;;
+esac
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define PERL_EXECUTABLE "$TARGET_PERL"
+_ACEOF
+
+
+for ac_prog in ar
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$AR" && break
+done
+test -n "$AR" || AR="{ { echo "$as_me:$LINENO: error: cannot find ar executable" >&5
+echo "$as_me: error: cannot find ar executable" >&2;}
+ { (exit 1); exit 1; }; }"
+
+for ac_prog in ranlib
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$RANLIB" && break
+done
+test -n "$RANLIB" || RANLIB="{ { echo "$as_me:$LINENO: error: cannot find ranlib executable" >&5
+echo "$as_me: error: cannot find ranlib executable" >&2;}
+ { (exit 1); exit 1; }; }"
+
### Checks for libraries.
-if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then
+case $target_os in
+mingw32*) ;;
+winnt) ;;
+*)
echo "$as_me:$LINENO: checking for library containing nanosleep" >&5
echo $ECHO_N "checking for library containing nanosleep... $ECHO_C" >&6
if test "${ac_cv_search_nanosleep+set}" = set; then
@@ -2342,7 +2491,9 @@ echo "$as_me: error: cannot find a short sleep function (nanosleep)" >&2;}
{ (exit 1); exit 1; }; }
fi
-fi
+ ;;
+esac
+
echo "$as_me:$LINENO: checking for zlibVersion in -lz" >&5
echo $ECHO_N "checking for zlibVersion in -lz... $ECHO_C" >&6
@@ -3870,16 +4021,23 @@ done
ax_path_bdb_ok=no
- # Add --with-bdb-dir option to configure.
+ # Add --with-bdb-headers and --with-bdb-lib options
-# Check whether --with-bdb-dir or --without-bdb-dir was given.
-if test "${with_bdb_dir+set}" = set; then
- withval="$with_bdb_dir"
+# Check whether --with-bdb-headers or --without-bdb-headers was given.
+if test "${with_bdb_headers+set}" = set; then
+ withval="$with_bdb_headers"
+
+fi;
+
+
+# Check whether --with-bdb-lib or --without-bdb-lib was given.
+if test "${with_bdb_lib+set}" = set; then
+ withval="$with_bdb_lib"
fi;
# Check if --with-bdb-dir was specified.
- if test "x$with_bdb_dir" = "x" ; then
+ if test "x$with_bdb_headers" = "x" -a "x$with_bdb_lib" = "x"; then
# No option specified, so just search the system.
ax_path_bdb_no_options_ok=no
@@ -3972,7 +4130,7 @@ echo "${ECHO_T}$ax_path_bdb_no_options_HEADER_VERSION" >&6
-e 's/[^0-9]//g'`
- ax_compare_version_B=`echo "" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ ax_compare_version_B=`echo "1.x or 4.1" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
-e 's/Z\([0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
@@ -5186,7 +5344,7 @@ echo "${ECHO_T}no" >&6
-e 's/[^0-9]//g'`
- ax_compare_version_B=`echo "" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ ax_compare_version_B=`echo "1.x or 4.1" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
-e 's/Z\([0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
@@ -5445,7 +5603,7 @@ x$ax_compare_version_B" | sed 's/^ *//' | sort | sed "s/x${ax_compare_version_A}
-e 's/[^0-9]//g'`
- ax_compare_version_B=`echo "" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ ax_compare_version_B=`echo "1.x or 4.1" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
-e 's/Z\([0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
@@ -5491,14 +5649,13 @@ _ACEOF
ax_path_bdb_ok=yes
else
- { echo "$as_me:$LINENO: no Berkeley DB version or higher found" >&5
-echo "$as_me: no Berkeley DB version or higher found" >&6;}
+ { echo "$as_me:$LINENO: no Berkeley DB version 1.x or 4.1 or higher found" >&5
+echo "$as_me: no Berkeley DB version 1.x or 4.1 or higher found" >&6;}
fi
else
- # Set --with-bdb-dir option.
- ax_path_bdb_INC="$with_bdb_dir/include"
- ax_path_bdb_LIB="$with_bdb_dir/lib"
+ ax_path_bdb_INC="$with_bdb_headers"
+ ax_path_bdb_LIB="$with_bdb_lib"
ax_path_bdb_save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="-I$ax_path_bdb_INC $CPPFLAGS"
@@ -5604,7 +5761,7 @@ echo "${ECHO_T}$ax_path_bdb_no_options_HEADER_VERSION" >&6
-e 's/[^0-9]//g'`
- ax_compare_version_B=`echo "" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ ax_compare_version_B=`echo "1.x or 4.1" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
-e 's/Z\([0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
@@ -6818,7 +6975,7 @@ echo "${ECHO_T}no" >&6
-e 's/[^0-9]//g'`
- ax_compare_version_B=`echo "" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ ax_compare_version_B=`echo "1.x or 4.1" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
-e 's/Z\([0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
@@ -7077,7 +7234,7 @@ x$ax_compare_version_B" | sed 's/^ *//' | sort | sed "s/x${ax_compare_version_A}
-e 's/[^0-9]//g'`
- ax_compare_version_B=`echo "" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ ax_compare_version_B=`echo "1.x or 4.1" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
-e 's/Z\([0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
-e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
@@ -7125,8 +7282,8 @@ _ACEOF
BDB_LDFLAGS="-L$ax_path_bdb_LIB"
else
- { echo "$as_me:$LINENO: no Berkeley DB version or higher found" >&5
-echo "$as_me: no Berkeley DB version or higher found" >&6;}
+ { echo "$as_me:$LINENO: no Berkeley DB version 1.x or 4.1 or higher found" >&5
+echo "$as_me: no Berkeley DB version 1.x or 4.1 or higher found" >&6;}
fi
else
@@ -7852,7 +8009,10 @@ fi
### Checks for header files.
-if test "$target_os" != "mingw32"; then
+case $target_os in
+mingw32*) ;;
+winnt*) ;;
+*)
@@ -8183,7 +8343,8 @@ fi
fi
-fi
+ ;;
+esac
echo "$as_me:$LINENO: checking for ANSI C header files" >&5
echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
@@ -8427,7 +8588,8 @@ fi
-for ac_header in execinfo.h process.h pwd.h regex.h signal.h
+
+for ac_header in dlfcn.h execinfo.h getopt.h process.h pwd.h signal.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -9032,7 +9194,8 @@ fi
done
-for ac_header in sys/xattr.h
+
+for ac_header in sys/uio.h sys/xattr.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -9182,7 +9345,301 @@ fi
done
-if test "$ac_cv_header_regex_h" = "yes"; then
+if test "${ac_cv_header_regex_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for regex.h" >&5
+echo $ECHO_N "checking for regex.h... $ECHO_C" >&6
+if test "${ac_cv_header_regex_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_regex_h" >&5
+echo "${ECHO_T}$ac_cv_header_regex_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking regex.h usability" >&5
+echo $ECHO_N "checking regex.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <regex.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking regex.h presence" >&5
+echo $ECHO_N "checking regex.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <regex.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: regex.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: regex.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: regex.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: regex.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: regex.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: regex.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: regex.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: regex.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: regex.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: regex.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: regex.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: regex.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: regex.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: regex.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: regex.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: regex.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------- ##
+## Report this to box@fluffy.co.uk ##
+## ------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for regex.h" >&5
+echo $ECHO_N "checking for regex.h... $ECHO_C" >&6
+if test "${ac_cv_header_regex_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_regex_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_regex_h" >&5
+echo "${ECHO_T}$ac_cv_header_regex_h" >&6
+
+fi
+if test $ac_cv_header_regex_h = yes; then
+ have_regex_h=yes
+fi
+
+
+
+if test "$have_regex_h" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_REGEX_H 1
+_ACEOF
+
+else
+ if test "${ac_cv_header_pcreposix_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for pcreposix.h" >&5
+echo $ECHO_N "checking for pcreposix.h... $ECHO_C" >&6
+if test "${ac_cv_header_pcreposix_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_pcreposix_h" >&5
+echo "${ECHO_T}$ac_cv_header_pcreposix_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking pcreposix.h usability" >&5
+echo $ECHO_N "checking pcreposix.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <pcreposix.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking pcreposix.h presence" >&5
+echo $ECHO_N "checking pcreposix.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <pcreposix.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_cxx_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: pcreposix.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: pcreposix.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pcreposix.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: pcreposix.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: pcreposix.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: pcreposix.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pcreposix.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: pcreposix.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pcreposix.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: pcreposix.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pcreposix.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: pcreposix.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pcreposix.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: pcreposix.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: pcreposix.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: pcreposix.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------- ##
+## Report this to box@fluffy.co.uk ##
+## ------------------------------- ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for pcreposix.h" >&5
+echo $ECHO_N "checking for pcreposix.h... $ECHO_C" >&6
+if test "${ac_cv_header_pcreposix_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_pcreposix_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_pcreposix_h" >&5
+echo "${ECHO_T}$ac_cv_header_pcreposix_h" >&6
+
+fi
+if test $ac_cv_header_pcreposix_h = yes; then
+ have_pcreposix_h=yes
+fi
+
+
+fi
+
+if test "$have_pcreposix_h" = "yes"; then
echo "$as_me:$LINENO: checking for library containing regcomp" >&5
echo $ECHO_N "checking for library containing regcomp... $ECHO_C" >&6
if test "${ac_cv_search_regcomp+set}" = set; then
@@ -9243,7 +9700,7 @@ fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test "$ac_cv_search_regcomp" = no; then
- for ac_lib in pcreposix; do
+ for ac_lib in "pcreposix -lpcre"; do
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
@@ -9307,9 +9764,157 @@ echo "${ECHO_T}$ac_cv_search_regcomp" >&6
if test "$ac_cv_search_regcomp" != no; then
test "$ac_cv_search_regcomp" = "none required" || LIBS="$ac_cv_search_regcomp $LIBS"
+else
+ have_pcreposix_h=no_regcomp
+fi
+
fi
+if test "$have_pcreposix_h" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PCREPOSIX_H 1
+_ACEOF
+
+fi
+
+if test "$have_regex_h" = "yes" -o "$have_pcreposix_h" = "yes"; then
+ have_regex_support=yes
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_REGEX_SUPPORT 1
+_ACEOF
+
+else
+ have_regex_support=no
+fi
+
+echo "$as_me:$LINENO: checking for library containing dlsym" >&5
+echo $ECHO_N "checking for library containing dlsym... $ECHO_C" >&6
+if test "${ac_cv_search_dlsym+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+ac_cv_search_dlsym=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlsym ();
+int
+main ()
+{
+dlsym ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_dlsym="none required"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_dlsym" = no; then
+ for ac_lib in "dl"; do
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlsym ();
+int
+main ()
+{
+dlsym ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_search_dlsym="-l$ac_lib"
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_dlsym" >&5
+echo "${ECHO_T}$ac_cv_search_dlsym" >&6
+if test "$ac_cv_search_dlsym" != no; then
+ test "$ac_cv_search_dlsym" = "none required" || LIBS="$ac_cv_search_dlsym $LIBS"
+
+fi
+
### Checks for typedefs, structures, and compiler characteristics.
@@ -9827,6 +10432,7 @@ _ACEOF
fi
+
echo "$as_me:$LINENO: checking for stdbool.h that conforms to C99" >&5
echo $ECHO_N "checking for stdbool.h that conforms to C99... $ECHO_C" >&6
if test "${ac_cv_header_stdbool_h+set}" = set; then
@@ -10827,6 +11433,7 @@ _ACEOF
fi
+
echo "$as_me:$LINENO: checking for struct stat.st_flags" >&5
echo $ECHO_N "checking for struct stat.st_flags... $ECHO_C" >&6
if test "${ac_cv_member_struct_stat_st_flags+set}" = set; then
@@ -11165,6 +11772,7 @@ _ACEOF
fi
+
echo "$as_me:$LINENO: checking whether INFTIM is declared" >&5
echo $ECHO_N "checking whether INFTIM is declared... $ECHO_C" >&6
if test "${ac_cv_have_decl_INFTIM+set}" = set; then
@@ -11311,6 +11919,229 @@ _ACEOF
fi
+echo "$as_me:$LINENO: checking whether O_BINARY is declared" >&5
+echo $ECHO_N "checking whether O_BINARY is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_O_BINARY+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+#ifndef O_BINARY
+ char *p = (char *) O_BINARY;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_O_BINARY=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_O_BINARY=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_O_BINARY" >&5
+echo "${ECHO_T}$ac_cv_have_decl_O_BINARY" >&6
+if test $ac_cv_have_decl_O_BINARY = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_O_BINARY 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_O_BINARY 0
+_ACEOF
+
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking whether optreset is declared" >&5
+echo $ECHO_N "checking whether optreset is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_optreset+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <getopt.h>
+
+int
+main ()
+{
+#ifndef optreset
+ char *p = (char *) optreset;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_optreset=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_optreset=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_optreset" >&5
+echo "${ECHO_T}$ac_cv_have_decl_optreset" >&6
+if test $ac_cv_have_decl_optreset = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_OPTRESET 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_OPTRESET 0
+_ACEOF
+
+
+fi
+
+
+echo "$as_me:$LINENO: checking whether dirfd is declared" >&5
+echo $ECHO_N "checking whether dirfd is declared... $ECHO_C" >&6
+if test "${ac_cv_have_decl_dirfd+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+ #include <getopt.h>
+ #include <dirent.h>
+
+
+int
+main ()
+{
+#ifndef dirfd
+ char *p = (char *) dirfd;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_have_decl_dirfd=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_have_decl_dirfd=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_have_decl_dirfd" >&5
+echo "${ECHO_T}$ac_cv_have_decl_dirfd" >&6
+if test $ac_cv_have_decl_dirfd = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_DIRFD 1
+_ACEOF
+
+
+else
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_DIRFD 0
+_ACEOF
+
+
+fi
+
+
+
echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
if test "${ac_cv_header_time+set}" = set; then
@@ -11582,7 +12413,7 @@ main ()
DIR* dir = opendir(".");
struct dirent* res = NULL;
if(dir) res = readdir(dir);
- return res ? (res->d_type==DT_UNKNOWN) : 1;
+ return res ? (res->d_type != DT_FILE && res->d_type != DT_DIR) : 1;
;
return 0;
@@ -11993,165 +12824,6 @@ rm -f conftest*
fi
- echo "$as_me:$LINENO: checking whether LLONG_MAX is declared" >&5
-echo $ECHO_N "checking whether LLONG_MAX is declared... $ECHO_C" >&6
-if test "${ac_cv_have_decl_LLONG_MAX+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-#include <limits.h>
-
-int
-main ()
-{
-#ifndef LLONG_MAX
- char *p = (char *) LLONG_MAX;
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -z "$ac_cxx_werror_flag"
- || test ! -s conftest.err'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_have_decl_LLONG_MAX=yes
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_have_decl_LLONG_MAX=no
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_have_decl_LLONG_MAX" >&5
-echo "${ECHO_T}$ac_cv_have_decl_LLONG_MAX" >&6
-if test $ac_cv_have_decl_LLONG_MAX = yes; then
- have_llong_max=1
-fi
-
- if test -z "$have_llong_max"; then
- echo "$as_me:$LINENO: checking for max value of long long" >&5
-echo $ECHO_N "checking for max value of long long... $ECHO_C" >&6
- if test "$cross_compiling" = yes; then
- { echo "$as_me:$LINENO: WARNING: cross compiling: not checking" >&5
-echo "$as_me: WARNING: cross compiling: not checking" >&2;}
-
-else
- cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h. */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h. */
-
- #include <stdio.h>
- /* Why is this so damn hard? */
- #undef __GNUC__
- #undef __USE_ISOC99
- #define __USE_ISOC99
- #include <limits.h>
- #define DATA "conftest.llminmax"
- int main(void) {
- FILE *f;
- long long i, llmin, llmax = 0;
-
- if((f = fopen(DATA,"w")) == NULL)
- exit(1);
-
- #if defined(LLONG_MIN) && defined(LLONG_MAX)
- fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n");
- llmin = LLONG_MIN;
- llmax = LLONG_MAX;
- #else
- fprintf(stderr, "Calculating LLONG_MIN and LLONG_MAX\n");
- /* This will work on one's complement and two's complement */
- for (i = 1; i > llmax; i <<= 1, i++)
- llmax = i;
- llmin = llmax + 1LL; /* wrap */
- #endif
-
- /* Sanity check */
- if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax || llmax - 1 > llmax) {
- fprintf(f, "unknown unknown\n");
- exit(2);
- }
-
- if (fprintf(f ,"%lld %lld", llmin, llmax) < 0)
- exit(3);
-
- exit(0);
- }
-
-_ACEOF
-rm -f conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
-
- read llong_min llong_max < conftest.llminmax
- echo "$as_me:$LINENO: result: $llong_max" >&5
-echo "${ECHO_T}$llong_max" >&6
-
-cat >>confdefs.h <<_ACEOF
-#define LLONG_MAX ${llong_max}LL
-_ACEOF
-
- echo "$as_me:$LINENO: checking for min value of long long" >&5
-echo $ECHO_N "checking for min value of long long... $ECHO_C" >&6
- echo "$as_me:$LINENO: result: $llong_min" >&5
-echo "${ECHO_T}$llong_min" >&6
-
-cat >>confdefs.h <<_ACEOF
-#define LLONG_MIN ${llong_min}LL
-_ACEOF
-
-
-else
- echo "$as_me: program exited with status $ac_status" >&5
-echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-echo "$as_me:$LINENO: result: not found" >&5
-echo "${ECHO_T}not found" >&6
-fi
-rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
- fi
-
-
echo "$as_me:$LINENO: checking for pre-processor pragma defines" >&5
echo $ECHO_N "checking for pre-processor pragma defines... $ECHO_C" >&6
if test "${have_define_pragma+set}" = set; then
@@ -12511,7 +13183,11 @@ _ACEOF
fi
fi
-if test "$target_os" != "mingw32"; then
+
+case $target_os in
+mingw32*) ;;
+winnt*) ;;
+*)
# Check whether --with-random or --without-random was given.
@@ -12601,7 +13277,6 @@ _ACEOF
fi
-fi
@@ -13414,14 +14089,127 @@ _ACEOF
:
else
- if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then
{ { echo "$as_me:$LINENO: error: cannot work out how to discover mount points on your platform" >&5
echo "$as_me: error: cannot work out how to discover mount points on your platform" >&2;}
{ (exit 1); exit 1; }; }
- fi
fi
+ echo "$as_me:$LINENO: checking for struct dirent.d_ino" >&5
+echo $ECHO_N "checking for struct dirent.d_ino... $ECHO_C" >&6
+if test "${ac_cv_member_struct_dirent_d_ino+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <dirent.h>
+
+int
+main ()
+{
+static struct dirent ac_aggr;
+if (ac_aggr.d_ino)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_dirent_d_ino=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <dirent.h>
+
+int
+main ()
+{
+static struct dirent ac_aggr;
+if (sizeof ac_aggr.d_ino)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_cxx_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_member_struct_dirent_d_ino=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_dirent_d_ino=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_dirent_d_ino" >&5
+echo "${ECHO_T}$ac_cv_member_struct_dirent_d_ino" >&6
+if test $ac_cv_member_struct_dirent_d_ino = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_DIRENT_D_INO 1
+_ACEOF
+
+
+fi
+
+;;
+esac
+
if test "x$GXX" = "xyes"; then
echo "$as_me:$LINENO: checking for gcc version 3 or later" >&5
@@ -13895,7 +14683,8 @@ fi
-for ac_func in getpeereid lchown setproctitle getpid
+
+for ac_func in getpeereid lchown setproctitle getpid gettimeofday
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
echo "$as_me:$LINENO: checking for $ac_func" >&5
@@ -14762,6 +15551,14 @@ fi
echo "$as_me:$LINENO: result: $have_large_file_support" >&5
echo "${ECHO_T}$have_large_file_support" >&6
+if test "x$have_large_file_support" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LARGE_FILE_SUPPORT 1
+_ACEOF
+
+fi
+
## Find out how to do file locking
for ac_func in flock
@@ -15011,15 +15808,21 @@ _ACEOF
fi
+
+case $target_os in
+mingw32*) ;;
+winnt*) ;;
+*)
if test "x$ac_cv_func_flock" != "xyes" && \
test "x$ac_cv_have_decl_O_EXLOCK" != "xyes" && \
- test "x$ac_cv_have_decl_F_SETLK" != "xyes" && \
- test "$target_os" != "mingw32" -a "$target_os" != "winnt"
+ test "x$ac_cv_have_decl_F_SETLK" != "xyes"
then
{ { echo "$as_me:$LINENO: error: cannot work out how to do file locking on your platform" >&5
echo "$as_me: error: cannot work out how to do file locking on your platform" >&2;}
{ (exit 1); exit 1; }; }
fi
+;;
+esac
## Get tmpdir
temp_directory_name="/tmp"
@@ -15135,6 +15938,26 @@ exec_prefix=$saved_exec_prefix
### Output files
ac_config_files="$ac_config_files infrastructure/BoxPlatform.pm"
+
+ ac_config_files="$ac_config_files bin/bbackupd/bbackupd-config"
+ ac_config_files="$ac_config_files bin/bbackupquery/makedocumentation.pl"
+ ac_config_files="$ac_config_files bin/bbstored/bbstored-certs"
+ ac_config_files="$ac_config_files bin/bbstored/bbstored-config"
+ ac_config_files="$ac_config_files infrastructure/makebuildenv.pl"
+ ac_config_files="$ac_config_files infrastructure/makeparcels.pl"
+ ac_config_files="$ac_config_files infrastructure/makedistribution.pl"
+ ac_config_files="$ac_config_files lib/common/makeexception.pl"
+ ac_config_files="$ac_config_files lib/raidfile/raidfile-config"
+ ac_config_files="$ac_config_files lib/server/makeprotocol.pl"
+ ac_config_files="$ac_config_files runtest.pl"
+ ac_config_files="$ac_config_files test/backupstorefix/testfiles/testbackupstorefix.pl"
+ ac_config_files="$ac_config_files test/bbackupd/testfiles/bbackupd.conf"
+ ac_config_files="$ac_config_files test/bbackupd/testfiles/extcheck1.pl"
+ ac_config_files="$ac_config_files test/bbackupd/testfiles/extcheck2.pl"
+ ac_config_files="$ac_config_files test/bbackupd/testfiles/notifyscript.pl"
+ ac_config_files="$ac_config_files test/bbackupd/testfiles/syncallowscript.pl"
+
+# TODO: Need to do contrib/cygwin/install-cygwin-service.pl but location varies
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -15497,7 +16320,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
-This file was extended by Box Backup $as_me 0.09, which was
+This file was extended by Box Backup $as_me 0.10, which was
generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -15557,7 +16380,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-Box Backup config.status 0.09
+Box Backup config.status 0.10
configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
@@ -15660,6 +16483,23 @@ do
case "$ac_config_target" in
# Handling of arguments.
"infrastructure/BoxPlatform.pm" ) CONFIG_FILES="$CONFIG_FILES infrastructure/BoxPlatform.pm" ;;
+ "bin/bbackupd/bbackupd-config" ) CONFIG_FILES="$CONFIG_FILES bin/bbackupd/bbackupd-config" ;;
+ "bin/bbackupquery/makedocumentation.pl" ) CONFIG_FILES="$CONFIG_FILES bin/bbackupquery/makedocumentation.pl" ;;
+ "bin/bbstored/bbstored-certs" ) CONFIG_FILES="$CONFIG_FILES bin/bbstored/bbstored-certs" ;;
+ "bin/bbstored/bbstored-config" ) CONFIG_FILES="$CONFIG_FILES bin/bbstored/bbstored-config" ;;
+ "infrastructure/makebuildenv.pl" ) CONFIG_FILES="$CONFIG_FILES infrastructure/makebuildenv.pl" ;;
+ "infrastructure/makeparcels.pl" ) CONFIG_FILES="$CONFIG_FILES infrastructure/makeparcels.pl" ;;
+ "infrastructure/makedistribution.pl" ) CONFIG_FILES="$CONFIG_FILES infrastructure/makedistribution.pl" ;;
+ "lib/common/makeexception.pl" ) CONFIG_FILES="$CONFIG_FILES lib/common/makeexception.pl" ;;
+ "lib/raidfile/raidfile-config" ) CONFIG_FILES="$CONFIG_FILES lib/raidfile/raidfile-config" ;;
+ "lib/server/makeprotocol.pl" ) CONFIG_FILES="$CONFIG_FILES lib/server/makeprotocol.pl" ;;
+ "runtest.pl" ) CONFIG_FILES="$CONFIG_FILES runtest.pl" ;;
+ "test/backupstorefix/testfiles/testbackupstorefix.pl" ) CONFIG_FILES="$CONFIG_FILES test/backupstorefix/testfiles/testbackupstorefix.pl" ;;
+ "test/bbackupd/testfiles/bbackupd.conf" ) CONFIG_FILES="$CONFIG_FILES test/bbackupd/testfiles/bbackupd.conf" ;;
+ "test/bbackupd/testfiles/extcheck1.pl" ) CONFIG_FILES="$CONFIG_FILES test/bbackupd/testfiles/extcheck1.pl" ;;
+ "test/bbackupd/testfiles/extcheck2.pl" ) CONFIG_FILES="$CONFIG_FILES test/bbackupd/testfiles/extcheck2.pl" ;;
+ "test/bbackupd/testfiles/notifyscript.pl" ) CONFIG_FILES="$CONFIG_FILES test/bbackupd/testfiles/notifyscript.pl" ;;
+ "test/bbackupd/testfiles/syncallowscript.pl" ) CONFIG_FILES="$CONFIG_FILES test/bbackupd/testfiles/syncallowscript.pl" ;;
"lib/common/BoxConfig.h" ) CONFIG_HEADERS="$CONFIG_HEADERS lib/common/BoxConfig.h" ;;
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
@@ -15766,6 +16606,10 @@ s,@EXEEXT@,$EXEEXT,;t t
s,@OBJEXT@,$OBJEXT,;t t
s,@CXXFLAGS_STRICT@,$CXXFLAGS_STRICT,;t t
s,@LDADD_RDYNAMIC@,$LDADD_RDYNAMIC,;t t
+s,@PERL@,$PERL,;t t
+s,@TARGET_PERL@,$TARGET_PERL,;t t
+s,@AR@,$AR,;t t
+s,@RANLIB@,$RANLIB,;t t
s,@CXXCPP@,$CXXCPP,;t t
s,@EGREP@,$EGREP,;t t
s,@RANDOM_DEVICE@,$RANDOM_DEVICE,;t t
@@ -16003,6 +16847,26 @@ s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
rm -f $tmp/out
fi
+ # Run the commands associated with the file.
+ case $ac_file in
+ bin/bbackupd/bbackupd-config ) chmod +x bin/bbackupd/bbackupd-config ;;
+ bin/bbackupquery/makedocumentation.pl ) chmod +x bin/bbackupquery/makedocumentation.pl ;;
+ bin/bbstored/bbstored-certs ) chmod +x bin/bbstored/bbstored-certs ;;
+ bin/bbstored/bbstored-config ) chmod +x bin/bbstored/bbstored-config ;;
+ infrastructure/makebuildenv.pl ) chmod +x infrastructure/makebuildenv.pl ;;
+ infrastructure/makeparcels.pl ) chmod +x infrastructure/makeparcels.pl ;;
+ infrastructure/makedistribution.pl ) chmod +x infrastructure/makedistribution.pl ;;
+ lib/common/makeexception.pl ) chmod +x lib/common/makeexception.pl ;;
+ lib/raidfile/raidfile-config ) chmod +x lib/raidfile/raidfile-config ;;
+ lib/server/makeprotocol.pl ) chmod +x lib/server/makeprotocol.pl ;;
+ runtest.pl ) chmod +x runtest.pl ;;
+ test/backupstorefix/testfiles/testbackupstorefix.pl ) chmod +x test/backupstorefix/testfiles/testbackupstorefix.pl ;;
+ test/bbackupd/testfiles/bbackupd.conf ) chmod +x test/bbackupd/testfiles/bbackupd.conf ;;
+ test/bbackupd/testfiles/extcheck1.pl ) chmod +x test/bbackupd/testfiles/extcheck1.pl ;;
+ test/bbackupd/testfiles/extcheck2.pl ) chmod +x test/bbackupd/testfiles/extcheck2.pl ;;
+ test/bbackupd/testfiles/notifyscript.pl ) chmod +x test/bbackupd/testfiles/notifyscript.pl ;;
+ test/bbackupd/testfiles/syncallowscript.pl ) chmod +x test/bbackupd/testfiles/syncallowscript.pl ;;
+ esac
done
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF
@@ -16261,8 +17125,11 @@ fi
# Configure the Box build system
echo
-perl ./infrastructure/makebuildenv.pl &&
- perl ./infrastructure/makeparcels.pl
+if ! $PERL ./infrastructure/makebuildenv.pl \
+|| ! $PERL ./infrastructure/makeparcels.pl; then
+ echo "Making infrastructure failed!"
+ exit 1
+fi
# Write summary of important info
cat <<EOC
@@ -16270,6 +17137,7 @@ A summary of the build configuration is below. Box Backup will function
without these features, but will work better where they are present. Refer
to the documentation for more information on each feature.
+Regular expressions: $have_regex_support
Large files: $have_large_file_support
Berkeley DB: $ax_path_bdb_ok
Readline: $have_libreadline
diff --git a/configure.ac b/configure.ac
index 714603b2..3aa96832 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
-AC_INIT([Box Backup], 0.09, [box@fluffy.co.uk])
+AC_INIT([Box Backup], 0.10, [box@fluffy.co.uk])
AC_CONFIG_SRCDIR([lib/common/Box.h])
AC_CONFIG_HEADERS([lib/common/BoxConfig.h])
@@ -27,18 +27,42 @@ if test "x$GXX" = "xyes"; then
AC_SUBST([LDADD_RDYNAMIC], ['-rdynamic'])
fi
+AC_PATH_PROG([PERL], [perl], [AC_MSG_ERROR([[perl executable was not found]])])
+
+case $target_os in
+mingw*)
+ TARGET_PERL=perl
+ ;;
+*)
+ TARGET_PERL=$PERL
+ ;;
+esac
+
+AC_SUBST([TARGET_PERL])
+AC_DEFINE_UNQUOTED([PERL_EXECUTABLE], ["$TARGET_PERL"],
+ [Location of the perl executable])
+
+AC_CHECK_PROGS([AR], [ar],
+ [AC_MSG_ERROR([[cannot find ar executable]])])
+AC_CHECK_PROGS([RANLIB], [ranlib],
+ [AC_MSG_ERROR([[cannot find ranlib executable]])])
### Checks for libraries.
-if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then
+case $target_os in
+mingw32*) ;;
+winnt) ;;
+*)
AC_SEARCH_LIBS([nanosleep], [rt], [ac_have_nanosleep=yes],
[AC_MSG_ERROR([[cannot find a short sleep function (nanosleep)]])])
-fi
+ ;;
+esac
+
AC_CHECK_LIB([z], [zlibVersion],, [AC_MSG_ERROR([[cannot find zlib]])])
VL_LIB_READLINE([have_libreadline=yes], [have_libreadline=no])
## Check for Berkely DB. Restrict to certain versions
-AX_PATH_BDB(, [
+AX_PATH_BDB([1.x or 4.1], [
LIBS="$BDB_LIBS $LIBS"
LDFLAGS="$BDB_LDFLAGS $LDFLAGS"
CPPFLAGS="$CPPFLAGS $BDB_CPPFLAGS"
@@ -73,26 +97,52 @@ Upgrade or read the documentation for alternatives]])
### Checks for header files.
-if test "$target_os" != "mingw32"; then
+case $target_os in
+mingw32*) ;;
+winnt*) ;;
+*)
AC_HEADER_DIRENT
-fi
+ ;;
+esac
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS([execinfo.h process.h pwd.h regex.h signal.h])
+AC_CHECK_HEADERS([dlfcn.h execinfo.h getopt.h process.h pwd.h signal.h])
AC_CHECK_HEADERS([syslog.h time.h])
AC_CHECK_HEADERS([netinet/in.h])
AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h])
-AC_CHECK_HEADERS([sys/xattr.h])
+AC_CHECK_HEADERS([sys/uio.h sys/xattr.h])
+
+AC_CHECK_HEADER([regex.h], [have_regex_h=yes])
+
+if test "$have_regex_h" = "yes"; then
+ AC_DEFINE([HAVE_REGEX_H], [1], [Define to 1 if regex.h is available])
+else
+ AC_CHECK_HEADER([pcreposix.h], [have_pcreposix_h=yes])
+fi
+
+if test "$have_pcreposix_h" = "yes"; then
+ AC_SEARCH_LIBS([regcomp], ["pcreposix -lpcre"],,[have_pcreposix_h=no_regcomp])
+fi
+
+if test "$have_pcreposix_h" = "yes"; then
+ AC_DEFINE([HAVE_PCREPOSIX_H], [1], [Define to 1 if pcreposix.h is available])
+fi
-if test "$ac_cv_header_regex_h" = "yes"; then
- AC_SEARCH_LIBS([regcomp], [pcreposix])
+if test "$have_regex_h" = "yes" -o "$have_pcreposix_h" = "yes"; then
+ have_regex_support=yes
+ AC_DEFINE([HAVE_REGEX_SUPPORT], [1], [Define to 1 if regular expressions are supported])
+else
+ have_regex_support=no
fi
+AC_SEARCH_LIBS([dlsym], ["dl"])
+
### Checks for typedefs, structures, and compiler characteristics.
AC_CHECK_TYPES([u_int8_t, u_int16_t, u_int32_t, u_int64_t])
AC_CHECK_TYPES([uint8_t, uint16_t, uint32_t, uint64_t])
+
AC_HEADER_STDBOOL
AC_C_CONST
AC_C_BIGENDIAN
@@ -102,31 +152,46 @@ AC_TYPE_MODE_T
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
+
AC_CHECK_MEMBERS([struct stat.st_flags])
AC_CHECK_MEMBERS([struct stat.st_mtimespec])
AC_CHECK_MEMBERS([struct sockaddr_in.sin_len],,, [[
#include <sys/types.h>
#include <netinet/in.h>
]])
+
AC_CHECK_DECLS([INFTIM],,, [[#include <poll.h>]])
AC_CHECK_DECLS([SO_PEERCRED],,, [[#include <sys/socket.h>]])
+AC_CHECK_DECLS([O_BINARY],,,)
+
+AC_CHECK_DECLS([optreset],,, [[#include <getopt.h>]])
+AC_CHECK_DECLS([dirfd],,,
+ [[
+ #include <getopt.h>
+ #include <dirent.h>
+ ]])
+
AC_HEADER_TIME
AC_STRUCT_TM
AX_CHECK_DIRENT_D_TYPE
AC_SYS_LARGEFILE
-AX_CHECK_LLONG_MINMAX
AX_CHECK_DEFINE_PRAGMA
if test "x$ac_cv_c_bigendian" != "xyes"; then
AX_BSWAP64
fi
-if test "$target_os" != "mingw32"; then
+
+case $target_os in
+mingw32*) ;;
+winnt*) ;;
+*)
AX_RANDOM_DEVICE
-fi
-AX_CHECK_MOUNT_POINT(,[
- if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then
+ AX_CHECK_MOUNT_POINT(,[
AC_MSG_ERROR([[cannot work out how to discover mount points on your platform]])
- fi
])
+ AC_CHECK_MEMBERS([struct dirent.d_ino],,, [[#include <dirent.h>]])
+;;
+esac
+
AX_CHECK_MALLOC_WORKAROUND
@@ -136,7 +201,7 @@ AC_FUNC_CLOSEDIR_VOID
AC_FUNC_ERROR_AT_LINE
AC_TYPE_SIGNAL
AC_FUNC_STAT
-AC_CHECK_FUNCS([getpeereid lchown setproctitle getpid])
+AC_CHECK_FUNCS([getpeereid lchown setproctitle getpid gettimeofday])
# NetBSD implements kqueue too differently for us to get it fixed by 0.10
# TODO: Remove this when NetBSD kqueue implementation is working
netbsd_hack=`echo $target_os | sed 's/netbsd.*/netbsd/'`
@@ -160,17 +225,28 @@ AC_CACHE_CHECK([if we have large file support enabled], [have_large_file_support
[have_large_file_support=yes], [have_large_file_support=no]
)])
+if test "x$have_large_file_support" = "xyes"; then
+ AC_DEFINE([HAVE_LARGE_FILE_SUPPORT], [1],
+ [Define to 1 if large files are supported])
+fi
+
## Find out how to do file locking
AC_CHECK_FUNCS([flock])
AC_CHECK_DECLS([O_EXLOCK],,, [[#include <fcntl.h>]])
AC_CHECK_DECLS([F_SETLK],,, [[#include <fcntl.h>]])
+
+case $target_os in
+mingw32*) ;;
+winnt*) ;;
+*)
if test "x$ac_cv_func_flock" != "xyes" && \
test "x$ac_cv_have_decl_O_EXLOCK" != "xyes" && \
- test "x$ac_cv_have_decl_F_SETLK" != "xyes" && \
- test "$target_os" != "mingw32" -a "$target_os" != "winnt"
+ test "x$ac_cv_have_decl_F_SETLK" != "xyes"
then
AC_MSG_ERROR([[cannot work out how to do file locking on your platform]])
fi
+;;
+esac
## Get tmpdir
temp_directory_name="/tmp"
@@ -204,12 +280,33 @@ AC_SUBST([bindir_expanded])
### Output files
AC_CONFIG_FILES([infrastructure/BoxPlatform.pm])
+AX_CONFIG_SCRIPTS([bin/bbackupd/bbackupd-config
+ bin/bbackupquery/makedocumentation.pl
+ bin/bbstored/bbstored-certs
+ bin/bbstored/bbstored-config
+ infrastructure/makebuildenv.pl
+ infrastructure/makeparcels.pl
+ infrastructure/makedistribution.pl
+ lib/common/makeexception.pl
+ lib/raidfile/raidfile-config
+ lib/server/makeprotocol.pl
+ runtest.pl
+ test/backupstorefix/testfiles/testbackupstorefix.pl
+ test/bbackupd/testfiles/bbackupd.conf
+ test/bbackupd/testfiles/extcheck1.pl
+ test/bbackupd/testfiles/extcheck2.pl
+ test/bbackupd/testfiles/notifyscript.pl
+ test/bbackupd/testfiles/syncallowscript.pl])
+# TODO: Need to do contrib/cygwin/install-cygwin-service.pl but location varies
AC_OUTPUT
# Configure the Box build system
echo
-perl ./infrastructure/makebuildenv.pl &&
- perl ./infrastructure/makeparcels.pl
+if ! $PERL ./infrastructure/makebuildenv.pl \
+|| ! $PERL ./infrastructure/makeparcels.pl; then
+ echo "Making infrastructure failed!"
+ exit 1
+fi
# Write summary of important info
cat <<EOC
@@ -217,6 +314,7 @@ A summary of the build configuration is below. Box Backup will function
without these features, but will work better where they are present. Refer
to the documentation for more information on each feature.
+Regular expressions: $have_regex_support
Large files: $have_large_file_support
Berkeley DB: $ax_path_bdb_ok
Readline: $have_libreadline
diff --git a/contrib/cygwin/install-cygwin-service.pl b/contrib/cygwin/install-cygwin-service.pl.in
index 65758067..a580e99c 100755
--- a/contrib/cygwin/install-cygwin-service.pl
+++ b/contrib/cygwin/install-cygwin-service.pl.in
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!@PERL@ -w
# Contributed to the boxbackup project by Per Reedtz Thomsen. pthomsen@reedtz.com
diff --git a/contrib/rpm/boxbackup.spec b/contrib/rpm/boxbackup.spec
index 87d97da4..389bdfc9 100644
--- a/contrib/rpm/boxbackup.spec
+++ b/contrib/rpm/boxbackup.spec
@@ -1,6 +1,13 @@
%define bb_user_id 171
%define ident %{name}-%{version}
+# In official distribution tarballs, distribution files are copied to
+# the base directory (where configure is), so distribution_dir should be empty.
+# This is the default, overridden by the following block in non-distribution
+# builds.
+%define distribution_dir ''
+
+
# Detect distribution. So far we only special-case SUSE. If you need to make
# any distro specific changes to get the package building on your system
# please email them to boxbackup-dev@fluffy.co.uk
@@ -21,7 +28,7 @@
Summary: An automatic on-line backup system for UNIX.
Name: boxbackup
-Version: 0.10
+Version: 0.11rc1
Release: 1
License: BSD
Group: Applications/Archiving
@@ -72,6 +79,7 @@ This package contains the server.
%setup -q
%build
+echo -e '%{version}\n%{name}' > VERSION.txt
test -e configure || ./bootstrap
%configure
@@ -88,19 +96,28 @@ mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/box/bbackupd
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/box/bbstored
mkdir -p $RPM_BUILD_ROOT%{_var}/lib/box
-install -m 644 BUGS.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
-install -m 644 LINUX.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
-install -m 644 VERSION.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
-install -m 644 CONTACT.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
-install -m 644 DOCUMENTATION.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
-install -m 644 ExceptionCodes.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
-install -m 644 THANKS.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
-install -m 644 LICENSE.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
-install -m 644 TODO.txt $RPM_BUILD_ROOT%{_docdir}/%{ident}
+install -m 644 BUGS.txt \
+ $RPM_BUILD_ROOT%{_docdir}/%{ident}
+install -m 644 VERSION.txt \
+ $RPM_BUILD_ROOT%{_docdir}/%{ident}
+install -m 644 ExceptionCodes.txt \
+ $RPM_BUILD_ROOT%{_docdir}/%{ident}
+install -m 644 LICENSE.txt \
+ $RPM_BUILD_ROOT%{_docdir}/%{ident}
+
+install -m 644 %{distribution_dir}CONTACT.txt \
+ $RPM_BUILD_ROOT%{_docdir}/%{ident}
+install -m 644 %{distribution_dir}DOCUMENTATION.txt \
+ $RPM_BUILD_ROOT%{_docdir}/%{ident}
+install -m 644 %{distribution_dir}LINUX.txt \
+ $RPM_BUILD_ROOT%{_docdir}/%{ident}
+install -m 644 %{distribution_dir}THANKS.txt \
+ $RPM_BUILD_ROOT%{_docdir}/%{ident}
# Client
touch $RPM_BUILD_ROOT%{_sysconfdir}/box/bbackupd.conf
-install -m 755 contrib/%{dist}/bbackupd $RPM_BUILD_ROOT%{init_dir}
+install -m 755 %{distribution_dir}contrib/%{dist}/bbackupd \
+ $RPM_BUILD_ROOT%{init_dir}
%if %{is_suse}
ln -s ../../%{init_dir}/bbackupd $RPM_BUILD_ROOT%{_sbindir}/rcbbackupd
%endif
@@ -113,7 +130,8 @@ install %{client_dir}/bbackupd-config $RPM_BUILD_ROOT%{_sbindir}
# Server
touch $RPM_BUILD_ROOT%{_sysconfdir}/box/bbstored.conf
touch $RPM_BUILD_ROOT%{_sysconfdir}/box/raidfile.conf
-install -m 755 contrib/%{dist}/bbstored $RPM_BUILD_ROOT%{init_dir}
+install -m 755 %{distribution_dir}contrib/%{dist}/bbstored \
+ $RPM_BUILD_ROOT%{init_dir}
%if %{is_suse}
ln -s ../../%{init_dir}/bbstored $RPM_BUILD_ROOT%{_sbindir}/rcbbstored
%endif
@@ -195,6 +213,11 @@ rm -rf $RPM_BUILD_ROOT
%{_sbindir}/raidfile-config
%changelog
+* Sat Jan 13 2006 Chris Wilson <chris+box@qwirx.com>
+- Support building from an unofficial tarball (from svn) by changing
+ %{distribution_dir} at the top.
+- Write our RPM version number into VERSION.txt and hence compile it in
+
* Wed Dec 28 2005 Martin Ebourne <martin@zepler.org>
- Box now uses autoconf so use configure macro
diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in
index 9567d585..d2510627 100644
--- a/infrastructure/BoxPlatform.pm.in
+++ b/infrastructure/BoxPlatform.pm.in
@@ -1,39 +1,79 @@
package BoxPlatform;
use Exporter;
@ISA = qw/Exporter/;
-@EXPORT = qw/$build_os $build_cpu $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext/;
+@EXPORT = qw/$build_os $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows/;
BEGIN
{
# which OS are we building under?
- $build_os = `uname`;
- chomp $build_os;
- $build_cpu = `uname -p`;
- chomp $build_cpu;
+ $target_os = '@target_os@';
+ $target_windows = 0;
+ $target_windows = 1 if $target_os =~ m'^mingw32'
+ or $target_os eq "winnt";
+
+ if ($^O eq "MSWin32" and not -x "/usr/bin/uname")
+ {
+ $build_os = "winnt";
+ }
+ else
+ {
+ $build_os = `uname`;
+ chomp $build_os;
+ }
+
# 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/;
$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");
+
+ $bsd_make = ($build_os ne 'Linux' && $build_os ne 'CYGWIN' &&
+ $build_os ne "SunOS" && $build_os ne 'GNU/kFreeBSD');
# blank extra flags by default
$platform_compile_line_extra = '@CPPFLAGS@ @CXXFLAGS@ @CXXFLAGS_STRICT@';
$platform_compile_line_extra =~ s/ -O2//;
$platform_link_line_extra = '@LDFLAGS@';
$platform_lib_files = '@LIBS@';
- $target_os = '@target_os@';
$platform_exe_ext = '@EXEEXT@';
# get version
- open VERSION,"VERSION.txt" or die "VERSION.txt: $!";
+ if (! -r "VERSION.txt" and -r "../../VERSION.txt")
+ {
+ open VERSION,"../../VERSION.txt" or die "../../VERSION.txt: $!";
+ }
+ else
+ {
+ open VERSION,"VERSION.txt" or die "VERSION.txt: $!";
+ }
+
$product_version = <VERSION>;
chomp $product_version;
$product_name = <VERSION>;
chomp $product_name;
close VERSION;
+ if($product_version =~ /USE_SVN_VERSION/)
+ {
+ # for developers, use SVN version
+ my $svnversion = `svnversion .`;
+ chomp $svnversion;
+ $svnversion =~ tr/0-9A-Za-z/_/c;
+ open INFO,'svn info . |';
+ my $svnurl;
+ while(<INFO>)
+ {
+ if(m/^URL: (.+?)[\n\r]+/)
+ {
+ $svnurl = $1
+ }
+ }
+ close INFO;
+ $svnurl =~ m!box/(.+)$!;
+ my $svndir = $1;
+ $svndir =~ tr/0-9A-Za-z/_/c;
+ $product_version =~ s/USE_SVN_VERSION/$svndir.'_'.$svnversion/e;
+ }
# where to put the files
$install_into_dir = '@bindir_expanded@';
@@ -52,7 +92,7 @@ BEGIN
# test for fink installation
if(-d '/sw/include' && -d '/sw/lib')
{
- print "Fink installation detected, will use headers and libraries\n\n\n";
+ print "Fink installation detected, will use headers and libraries\n";
$platform_compile_line_extra = '-I/sw/include ';
$platform_link_line_extra = '-L/sw/lib ';
}
diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp
index 252a9f0f..9922a584 100644
--- a/infrastructure/buildenv-testmain-template.cpp
+++ b/infrastructure/buildenv-testmain-template.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -40,6 +40,9 @@
// AUTOMATICALLY GENERATED FILE
// do not edit
//
+// Note that infrastructure/buildenv-testmain-template.cpp is NOT
+// auto-generated, but test/*/_main.cpp are generated from it.
+//
// --------------------------------------------------------------------------
@@ -61,6 +64,11 @@
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
+#include <string>
+
+#ifdef HAVE_GETOPT_H
+ #include <getopt.h>
+#endif
#ifdef WIN32
#include "emu.h"
@@ -68,6 +76,12 @@
#include <syslog.h>
#endif
+#include <string>
+
+#include "Logging.h"
+#include "Test.h"
+#include "Timer.h"
+
#include "MemLeakFindOn.h"
int test(int argc, const char *argv[]);
@@ -79,77 +93,234 @@ int test(int argc, const char *argv[]);
#endif
int failures = 0;
+int first_fail_line;
+std::string first_fail_file;
+std::string bbackupd_args, bbstored_args, bbackupquery_args, test_args;
int filedes_open_at_beginning = -1;
#ifdef WIN32
// any way to check for open file descriptors on Win32?
-inline int count_filedes() { return 0; }
-inline bool checkfilesleftopen() { return false; }
+inline bool check_filedes(bool x) { return 0; }
+inline bool checkfilesleftopen() { return false; }
#else // !WIN32
-int count_filedes()
+#define FILEDES_MAX 256
+
+bool filedes_open[FILEDES_MAX];
+
+bool check_filedes(bool report)
{
- int c = 0;
+ bool allOk = true;
// See how many file descriptors there are with values < 256
- for(int d = 0; d < 256; ++d)
+ for(int d = 0; d < FILEDES_MAX; ++d)
{
if(::fcntl(d, F_GETFD) != -1)
{
// File descriptor obviously exists
- ++c;
+ if (report && !filedes_open[d])
+ {
+ struct stat st;
+ if (fstat(d, &st) == 0)
+ {
+ int m = st.st_mode;
+ #define flag(x) ((m & x) ? #x " " : "")
+ BOX_FATAL("File descriptor " << d <<
+ " left open (type == " <<
+ flag(S_IFIFO) <<
+ flag(S_IFCHR) <<
+ flag(S_IFDIR) <<
+ flag(S_IFBLK) <<
+ flag(S_IFREG) <<
+ flag(S_IFLNK) <<
+ flag(S_IFSOCK) <<
+ " or " << m << ")");
+ }
+ else
+ {
+ BOX_FATAL("File descriptor " << d <<
+ " left open (and stat failed)");
+ }
+
+ allOk = false;
+
+ }
+ else if (!report)
+ {
+ filedes_open[d] = true;
+ }
+ }
+ else
+ {
+ if (report && filedes_open[d])
+ {
+ BOX_FATAL("File descriptor " << d <<
+ " was open, now closed");
+ allOk = false;
+ }
+ else
+ {
+ filedes_open[d] = false;
+ }
}
}
+
+ if (!report && allOk)
+ {
+ filedes_open_at_beginning = 0;
+ }
- return c;
+ return !allOk;
}
bool checkfilesleftopen()
{
if(filedes_open_at_beginning == -1)
{
- // Not used correctly, pretend that there were things left open so this gets invesitgated
+ // Not used correctly, pretend that there were things
+ // left open so this gets investigated
+ BOX_FATAL("File descriptor test was not initialised");
return true;
}
- // make sure syslog log file is closed, if it was opened
- ::closelog();
-
// Count the file descriptors open
- return filedes_open_at_beginning != count_filedes();
+ return check_filedes(true);
}
#endif
-int main(int argc, const char *argv[])
+int main(int argc, char * const * argv)
{
// Start memory leak testing
MEMLEAKFINDER_START
+#ifdef HAVE_GETOPT_H
+ struct option longopts[] =
+ {
+ { "bbackupd-args", required_argument, NULL, 'c' },
+ { "bbstored-args", required_argument, NULL, 's' },
+ { "test-daemon-args", required_argument, NULL, 'd' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int ch;
+
+ while ((ch = getopt_long(argc, argv, "c:d:s:t:TUV", longopts, NULL))
+ != -1)
+ {
+ switch(ch)
+ {
+ case 'c':
+ {
+ if (bbackupd_args.length() > 0)
+ {
+ bbackupd_args += " ";
+ }
+ bbackupd_args += optarg;
+ }
+ break;
+
+ case 'd':
+ {
+ if (test_args.length() > 0)
+ {
+ test_args += " ";
+ }
+ test_args += optarg;
+ }
+ break;
+
+ case 's':
+ {
+ bbstored_args += " ";
+ bbstored_args += optarg;
+ }
+ break;
+
+ case 't':
+ {
+ Console::SetTag(optarg);
+ }
+ break;
+
+ case 'T':
+ {
+ Console::SetShowTime(true);
+ }
+ break;
+
+ case 'U':
+ {
+ Console::SetShowTime(true);
+ Console::SetShowTimeMicros(true);
+ }
+ break;
+
+ case 'V':
+ {
+ Logging::SetGlobalLevel(Log::EVERYTHING);
+ }
+ break;
+
+ case '?':
+ {
+ fprintf(stderr, "Unknown option: '%c'\n",
+ optopt);
+ exit(2);
+ }
+
+ default:
+ {
+ fprintf(stderr, "Unknown option code '%c'\n",
+ ch);
+ exit(2);
+ }
+ }
+ }
+
+ argc -= optind - 1;
+ argv += optind - 1;
+#endif // HAVE_GETOPT_H
+
// If there is more than one argument, then the test is doing something advanced, so leave it alone
bool fulltestmode = (argc == 1);
if(fulltestmode)
{
+ // banner
+ BOX_NOTICE("Running test TEST_NAME in " MODE_TEXT " mode...");
+
// Count open file descriptors for a very crude "files left open" test
- filedes_open_at_beginning = count_filedes();
+ check_filedes(false);
- // banner
- printf("Running test TEST_NAME in " MODE_TEXT " mode...\n");
+ #ifdef WIN32
+ // Under win32 we must initialise the Winsock library
+ // before using sockets
+
+ WSADATA info;
+ TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR)
+ #endif
}
+
try
{
- int returncode = test(argc, argv);
+ #ifdef BOX_MEMORY_LEAK_TESTING
+ memleakfinder_init();
+ #endif
+
+ Timers::Init();
+ int returncode = test(argc, (const char **)argv);
+ Timers::Cleanup();
// check for memory leaks, if enabled
#ifdef BOX_MEMORY_LEAK_TESTING
if(memleakfinder_numleaks() != 0)
{
failures++;
- printf("FAILURE: Memory leaks detected\n");
+ printf("FAILURE: Memory leaks detected in test code\n");
printf("==== MEMORY LEAKS =================================\n");
memleakfinder_reportleaks();
printf("===================================================\n");
@@ -166,7 +337,10 @@ int main(int argc, const char *argv[])
}
if(failures > 0)
{
- printf("FAILED: %d tests failed\n", failures);
+ printf("FAILED: %d tests failed (first at "
+ "%s:%d)\n", failures,
+ first_fail_file.c_str(),
+ first_fail_line);
}
else
{
diff --git a/infrastructure/m4/ax_check_dirent_d_type.m4 b/infrastructure/m4/ax_check_dirent_d_type.m4
index 87b93185..1c0e2ec2 100644
--- a/infrastructure/m4/ax_check_dirent_d_type.m4
+++ b/infrastructure/m4/ax_check_dirent_d_type.m4
@@ -24,7 +24,7 @@ AC_DEFUN([AX_CHECK_DIRENT_D_TYPE], [
DIR* dir = opendir(".");
struct dirent* res = NULL;
if(dir) res = readdir(dir);
- return res ? (res->d_type==DT_UNKNOWN) : 1;
+ return res ? (res->d_type != DT_FILE && res->d_type != DT_DIR) : 1;
]])],
[have_valid_dirent_d_type=yes], [have_valid_dirent_d_type=no]
)])
diff --git a/infrastructure/m4/ax_config_scripts.m4 b/infrastructure/m4/ax_config_scripts.m4
new file mode 100644
index 00000000..8f5436ae
--- /dev/null
+++ b/infrastructure/m4/ax_config_scripts.m4
@@ -0,0 +1,16 @@
+dnl @synopsis AX_CONFIG_SCRIPTS(SCRIPT_FILE, ...)
+dnl
+dnl Run AC_CONFIG_FILES on a list of scripts while preserving execute
+dnl permission.
+dnl
+dnl @category Automake
+dnl @author Martin Ebourne <martin@zepler.org>
+dnl @script
+dnl @license AllPermissive
+
+AC_DEFUN([AX_CONFIG_SCRIPTS],[
+ AC_REQUIRE([AC_CONFIG_FILES])dnl
+ m4_foreach([SCRIPT_FILE],
+ m4_quote(m4_split(m4_normalize([$1]))),
+ [AC_CONFIG_FILES(SCRIPT_FILE, m4_quote(chmod +x SCRIPT_FILE))])dnl
+])
diff --git a/infrastructure/m4/ax_path_bdb.m4 b/infrastructure/m4/ax_path_bdb.m4
index 08d71053..1a771048 100644
--- a/infrastructure/m4/ax_path_bdb.m4
+++ b/infrastructure/m4/ax_path_bdb.m4
@@ -12,10 +12,10 @@ dnl sets BDB_LIBS, BDB_CPPFLAGS, and BDB_LDFLAGS to the necessary
dnl values to add to LIBS, CPPFLAGS, and LDFLAGS, as well as setting
dnl BDB_VERSION to the version found. HAVE_DB_H is defined also.
dnl
-dnl The option --with-bdb-dir=DIR can be used to specify a specific
-dnl Berkeley DB installation to use.
+dnl The options --with-bdb-headers=DIR and --with-bdb-lib=DIR can be
+dnl used to specify a specific Berkeley DB installation to use.
dnl
-dnl An example of it's use is:
+dnl An example of its use is:
dnl
dnl AX_PATH_BDB([3],[
dnl LIBS="$BDB_LIBS $LIBS"
@@ -57,6 +57,8 @@ dnl Changes:
dnl
dnl 1/5/05 applied patch from Rafa Rzepecki to eliminate compiler
dnl warning about unused variable, argv
+dnl 1/7/07 Add --with-bdb-headers and --with-bdb-lib options
+dnl (James O'Gorman, james@netinertia.co.uk)
dnl
dnl @category InstalledPackages
dnl @author Tim Toolan <toolan@ele.uri.edu>
@@ -68,21 +70,24 @@ AC_DEFUN([AX_PATH_BDB], [
dnl # Used to indicate success or failure of this function.
ax_path_bdb_ok=no
- # Add --with-bdb-dir option to configure.
- AC_ARG_WITH([bdb-dir],
- [AC_HELP_STRING([--with-bdb-dir=DIR],
- [Berkeley DB installation directory])])
+ # Add --with-bdb-headers and --with-bdb-lib options
+ AC_ARG_WITH([bdb-headers],
+ [AC_HELP_STRING([--with-bdb-headers=DIR],
+ [Berkeley DB include files location])])
+ AC_ARG_WITH([bdb-lib],
+ [AC_HELP_STRING([--with-bdb-lib=DIR],
+ [Berkeley DB library location])])
+
# Check if --with-bdb-dir was specified.
- if test "x$with_bdb_dir" = "x" ; then
+ if test "x$with_bdb_headers" = "x" -a "x$with_bdb_lib" = "x"; then
# No option specified, so just search the system.
AX_PATH_BDB_NO_OPTIONS([$1], [HIGHEST], [
ax_path_bdb_ok=yes
])
else
- # Set --with-bdb-dir option.
- ax_path_bdb_INC="$with_bdb_dir/include"
- ax_path_bdb_LIB="$with_bdb_dir/lib"
+ ax_path_bdb_INC="$with_bdb_headers"
+ ax_path_bdb_LIB="$with_bdb_lib"
dnl # Save previous environment, and modify with new stuff.
ax_path_bdb_save_CPPFLAGS="$CPPFLAGS"
diff --git a/infrastructure/makebuildenv.pl b/infrastructure/makebuildenv.pl.in
index 94efa981..8664f3d7 100755
--- a/infrastructure/makebuildenv.pl
+++ b/infrastructure/makebuildenv.pl.in
@@ -1,42 +1,4 @@
-#!/usr/bin/perl
-# distribution boxbackup-0.10 (svn version: 494)
-#
-# Copyright (c) 2003 - 2006
-# 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 acknowledgment:
-# 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.
-#
-#
-#
+#!@PERL@
use strict;
use Symbol;
@@ -52,8 +14,7 @@ $|=1;
print "Box build environment setup.\n\n";
-
-my $implicit_dep = 'lib/common';
+my @implicit_deps = ('lib/common');
# work out platform variables
use lib 'infrastructure';
@@ -76,11 +37,15 @@ unless(-d 'local')
# flags about the environment
my %env_flags;
-my $windows_include_path = "-I../../lib/win32 ";
-if ($target_os ne "mingw32" && $target_os ne "winnt")
+my $windows_include_path = "";
+if ($target_windows)
+{
+ $module_dependency{"lib/common"} = ["lib/win32"];
+ push @implicit_deps, "lib/win32";
+}
+else
{
- $windows_include_path = "";
- $env_flags{'IGNORE_lib/win32'} = 1;
+ # $env_flags{'IGNORE_lib/win32'} = 1;
}
# print "Flag: $_\n" for(keys %env_flags);
@@ -96,6 +61,7 @@ while(<FINDAUTOGEN>)
my $dir = $1;
open FL,$file or die "Can't open $_ for reading";
my %vars;
+ $vars{PERL} = "@PERL@";
my $do_cmds = 0;
while(<FL>)
{
@@ -308,7 +274,7 @@ for(@modules_files)
push @md,$_ unless ignore_module($_)
}
}
- $module_dependency{$mod} = [$implicit_dep,@md];
+ $module_dependency{$mod} = [@implicit_deps,@md];
$module_library_link_opts{$mod} = [@lo];
# make directories, but not if we're using an external library and this a library module
@@ -323,8 +289,11 @@ for(@modules_files)
}
# make dirs for implicit dep
-mkdir "release/$implicit_dep",0755;
-mkdir "debug/$implicit_dep",0755;
+foreach my $dep (@implicit_deps)
+{
+ mkdir "release/$dep",0755;
+ mkdir "debug/$dep",0755;
+}
# write a list of all the modules we've configured to use
open CONFIGURED_MODS,'>local/modules.h' or die "Can't write configured modules list";
@@ -333,7 +302,7 @@ print CONFIGURED_MODS <<__E;
#ifndef _CONFIGURED_MODULES__H
#define _CONFIGURED_MODULES__H
__E
-for($implicit_dep,@modules)
+for(@implicit_deps,@modules)
{
my $m = $_;
$m =~ s~/~_~;
@@ -347,7 +316,7 @@ close CONFIGURED_MODS;
# now make a list of all the .h files we can find, recording which module they're in
my %hfiles;
-for my $mod (@modules, $implicit_dep)
+for my $mod (@modules, @implicit_deps)
{
opendir DIR,$mod;
my @items = readdir DIR;
@@ -384,7 +353,7 @@ for my $mod (@modules, $implicit_dep)
}
}
-for my $mod (@modules, $implicit_dep)
+for my $mod (@modules, @implicit_deps)
{
opendir DIR,$mod;
for my $h (grep /\.h\Z/i, readdir DIR)
@@ -410,9 +379,10 @@ for my $mod (@modules, $implicit_dep)
print "done\n\nGenerating Makefiles...\n";
+my %module_resources_win32;
# Then write a makefile for each module
-for my $mod (@modules, $implicit_dep)
+for my $mod (@implicit_deps, @modules)
{
print $mod,"\n";
@@ -431,31 +401,54 @@ for my $mod (@modules, $implicit_dep)
sub writetestfile
{
my ($filename,$runcmd,$module) = @_;
- open TESTFILE,">$filename" or die "Can't open test script file for $module for writing\n";
+
+ open TESTFILE,">$filename" or die "Can't open " .
+ "test script file for $module for writing\n";
print TESTFILE "#!/bin/sh\necho TEST: $module\n";
+
if(-d "$module/testfiles")
{
print TESTFILE <<__E;
+echo Killing any running daemons...
+test -r testfiles/bbackupd.pid && kill `cat testfiles/bbackupd.pid`
+test -r testfiles/bbstored.pid && kill `cat testfiles/bbstored.pid`
+
echo Removing old test files...
+chmod -R a+rwx testfiles
rm -rf testfiles
+
echo Copying new test files...
cp -p -R ../../../$module/testfiles .
+
__E
}
+
if(-e "$module/testextra")
{
- open FL,"$module/testextra" or die "Can't open $module/testextra";
+ open FL,"$module/testextra" or die
+ "Can't open $module/testextra";
while(<FL>) {print TESTFILE}
close FL;
}
+
print TESTFILE "$runcmd\n";
+
+ if(-d "$module/testfiles")
+ {
+ print TESTFILE <<__E;
+# echo Killing any running daemons...
+test -r testfiles/bbackupd.pid && kill `cat testfiles/bbackupd.pid`
+test -r testfiles/bbstored.pid && kill `cat testfiles/bbstored.pid`
+__E
+ }
+
close TESTFILE;
}
- writetestfile("$mod/_t",
- './test' . $platform_exe_ext . '$1 $2 $3 $4 $5', $mod);
- writetestfile("$mod/_t-gdb",
- 'gdb ./test ' . $platform_exe_ext, $mod);
+ writetestfile("$mod/_t", "GLIBCXX_FORCE_NEW=1 ".
+ './test' . $platform_exe_ext . ' "$@"', $mod);
+ writetestfile("$mod/_t-gdb", "GLIBCXX_FORCE_NEW=1 ".
+ 'gdb ./test' . $platform_exe_ext . ' "$@"', $mod);
}
@@ -478,14 +471,14 @@ __E
add_mod_deps(\@deps_raw, $mod);
# and then dedup and reorder them
my %d_done;
- for(my $a = $#deps_raw; $a >= 0; $a--)
+ foreach my $dep (reverse @deps_raw)
{
- if(!exists $d_done{$deps_raw[$a]})
+ if(!exists $d_done{$dep})
{
# insert
- push @all_deps_for_module, $deps_raw[$a];
+ push @all_deps_for_module, $dep;
# mark as done
- $d_done{$deps_raw[$a]} = 1;
+ $d_done{$dep} = 1;
}
}
}
@@ -521,7 +514,7 @@ __E
my $debug_link_extra = ($target_is_library)?'':'../../debug/lib/debug/debug.a';
my $release_flags = "-O2";
- if ($target_os eq "mingw32")
+ if ($target_windows)
{
$release_flags = "-O0 -g";
}
@@ -532,17 +525,19 @@ __E
# do not edit!
#
#
-CXX = g++
-AR = ar
-RANLIB = ranlib
+CXX = "@CXX@"
+AR = "@AR@"
+RANLIB = "@RANLIB@"
+PERL = "@PERL@"
+WINDRES = windres
.ifdef RELEASE
-CXXFLAGS = -DNDEBUG $release_flags -Wall $include_paths $extra_platform_defines -DBOX_VERSION="\\"$product_version\\""
+CXXFLAGS = -DNDEBUG $release_flags -Wall -Wundef $include_paths $extra_platform_defines -DBOX_VERSION="\\"$product_version\\""
OUTBASE = ../../release
OUTDIR = ../../release/$mod
DEPENDMAKEFLAGS = -D RELEASE
VARIENT = RELEASE
.else
-CXXFLAGS = -g -Wall $include_paths $extra_platform_defines -DBOX_VERSION="\\"$product_version\\""
+CXXFLAGS = -g -Wall -Wundef $include_paths $extra_platform_defines -DBOX_VERSION="\\"$product_version\\""
OUTBASE = ../../debug
OUTDIR = ../../debug/$mod
DEPENDMAKEFLAGS =
@@ -550,6 +545,40 @@ VARIENT = DEBUG
.endif
__E
+
+ if ($bsd_make)
+ {
+ print MAKE <<__E;
+.ifdef V
+HIDE =
+_CXX = \$(CXX)
+_LINK = \$(CXX)
+_WINDRES = \$(WINDRES)
+_AR = \$(AR)
+_RANLIB = \$(RANLIB)
+.else
+HIDE = @
+_CXX = @ echo "[CXX] " \$(*F) && \$(CXX)
+_LINK = @ echo "[LINK] " \$(*F) && \$(CXX)
+_WINDRES = @ echo "[WINDRES]" \$(*F) && \$(WINDRES)
+_AR = @ echo "[AR] " \$(*F) && \$(AR)
+_RANLIB = @ echo "[RANLIB] " \$(*F) && \$(RANLIB)
+.endif
+
+__E
+ }
+ else
+ {
+ print MAKE <<__E;
+HIDE = \$(if \$(V),,@)
+_CXX = \$(if \$(V),\$(CXX), @ echo "[CXX] \$<" && \$(CXX))
+_LINK = \$(if \$(V),\$(CXX), @ echo "[LINK] \$@" && \$(CXX))
+_WINDRES = \$(if \$(V),\$(WINDRES), @ echo "[WINDRES] \$<" && \$(WINDRES))
+_AR = \$(if \$(V),\$(AR), @ echo "[AR] \$@" && \$(AR))
+_RANLIB = \$(if \$(V),\$(RANLIB), @ echo "[RANLIB] \$@" && \$(RANLIB))
+
+__E
+ }
# read directory
opendir DIR,$mod;
@@ -582,7 +611,7 @@ __E
@items = (@items, @autogen_items);
}
- # first, obtain a list of depenencies within the .h files
+ # first, obtain a list of dependencies within the .h files
my %headers;
for my $h (grep /\.h\Z/i, @items)
{
@@ -602,19 +631,30 @@ __E
# then... do the cpp files...
my @obj_base;
- for my $cpp (@items)
+ for my $file (@items)
{
- next unless $cpp =~ m/\A(.+)\.cpp\Z/i;
- next if $cpp =~ /\A\._/; # Temp Mac OS Resource hack
+ my $is_cpp = $file =~ m/\A(.+)\.cpp\Z/i;
+ my $is_rc = $file =~ m/\A(.+)\.rc\Z/i;
+ my $base = $1;
+
+ if ($target_windows)
+ {
+ next if not $is_cpp and not $is_rc;
+ }
+ else
+ {
+ next if not $is_cpp;
+ }
+
+ next if $file =~ /\A\._/; # Temp Mac OS Resource hack
# store for later
- my $base = $1;
push @obj_base,$base;
# get the file...
- open FL,"$mod/$cpp";
+ open FL,"$mod/$file";
my $f;
- read FL,$f,-s "$mod/$cpp";
+ read FL,$f,-s "$mod/$file";
close FL;
my %dep;
@@ -628,10 +668,29 @@ __E
my $out_name = '$(OUTDIR)/'.$base.'.o';
# write the line for this cpp file
- $make .= $out_name.': '.join(' ',$cpp,map
- { ($hfiles{$_} eq $mod)?$_:'../../'.$hfiles{$_}."/$_" } keys %dep)."\n";
- $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra -c $cpp -o $out_name\n\n";
+ my @dep_paths = map
+ {
+ ($hfiles{$_} eq $mod)
+ ? $_
+ : '../../'.$hfiles{$_}."/$_"
+ }
+ keys %dep;
+
+ $make .= $out_name.': '.join(' ',$file,@dep_paths)."\n";
+ if ($is_cpp)
+ {
+ $make .= "\t\$(_CXX) \$(CXXFLAGS) $compile_line_extra ".
+ "-c $file -o $out_name\n\n";
+ }
+ elsif ($is_rc)
+ {
+ $make .= "\t\$(_WINDRES) $file $out_name\n\n";
+ my $res_list = $module_resources_win32{$mod};
+ $res_list ||= [];
+ push @$res_list, $base.'.o';
+ $module_resources_win32{$mod} = $res_list;
+ }
}
my $has_deps = ($#{$module_dependency{$mod}} >= 0);
@@ -665,7 +724,7 @@ __E
# run make for things we require
for my $dep (@all_deps_for_module)
{
- $deps_makeinfo .= "\t\t(cd ../../$dep; \$(MAKE)$sub_make_options \$(DEPENDMAKEFLAGS) -D NODEPS)\n";
+ $deps_makeinfo .= "\t\t\$(HIDE) (cd ../../$dep; \$(MAKE)$sub_make_options \$(DEPENDMAKEFLAGS) -D NODEPS)\n";
}
$deps_makeinfo .= ".\tendif\n.endif\n\n";
}
@@ -683,18 +742,35 @@ __E
additional_objects_from_make_fragment("$mod/Makefile.extra.$build_os", \@objs, \@makefile_includes);
my $o_file_list = join(' ',map {'$(OUTDIR)/'.$_.'.o'} @objs);
+
+ if ($has_deps and not $bsd_make)
+ {
+ print MAKE ".PHONY: all\n" .
+ "all: dep_modules $end_target\n\n";
+ }
+
print MAKE $end_target,': ',$o_file_list;
- print MAKE ' dep_modules' if $has_deps and not $bsd_make;
print MAKE " ",$lib_files unless $target_is_library;
print MAKE "\n";
+ if ($target_windows)
+ {
+ foreach my $dep (@all_deps_for_module)
+ {
+ my $res_list = $module_resources_win32{$dep};
+ next unless $res_list;
+ $o_file_list .= ' '.join(' ',
+ map {'$(OUTBASE)/'.$dep."/$_"} @$res_list);
+ }
+ }
+
# stuff to make the final target...
if($target_is_library)
{
# make a library archive...
- print MAKE "\t(echo -n > $end_target; rm $end_target)\n";
- print MAKE "\t\$(AR) -q $end_target $o_file_list\n";
- print MAKE "\t\$(RANLIB) $end_target\n";
+ print MAKE "\t\$(HIDE) (echo -n > $end_target; rm $end_target)\n";
+ print MAKE "\t\$(_AR) -q $end_target $o_file_list\n";
+ print MAKE "\t\$(_RANLIB) $end_target\n";
}
else
{
@@ -718,7 +794,7 @@ __E
}
# link line...
- print MAKE "\t\$(CXX) $link_line_extra -o $end_target $o_file_list $lib_files$lo $platform_lib_files\n";
+ print MAKE "\t\$(_LINK) $link_line_extra -o $end_target $o_file_list $lib_files$lo $platform_lib_files\n";
}
# tests need to copy the test file over
if($type eq 'test')
@@ -739,7 +815,7 @@ __E
print MAKE "clean:\n\t-rm -rf \$(OUTDIR)/*\n.\tifndef SUBCLEAN\n";
for my $dep (@all_deps_for_module)
{
- print MAKE "\t(cd ../../$dep; \$(MAKE) \$(DEPENDMAKEFLAGS) -D SUBCLEAN clean)\n";
+ print MAKE "\t\$(HIDE) (cd ../../$dep; \$(MAKE) \$(DEPENDMAKEFLAGS) -D SUBCLEAN clean)\n";
}
print MAKE ".\tendif\n";
diff --git a/infrastructure/makedistribution.pl.in b/infrastructure/makedistribution.pl.in
new file mode 100755
index 00000000..314259f6
--- /dev/null
+++ b/infrastructure/makedistribution.pl.in
@@ -0,0 +1,351 @@
+#!/usr/bin/perl
+#!@PERL@
+use strict;
+use Symbol;
+
+# comment string for various endings
+my %comment_chars = ('cpp' => '// ', 'h' => '// ', 'pl' => '# ', 'pm' => '# ', '' => '# ');
+
+# other extensions which need text copying, just to remove the private stuff
+my %text_files = ('txt' => 1, 'spec' => 1);
+
+# files which don't get the license added
+my %no_license = (); # 'filename' => 1
+
+# ----------------------------------------------
+
+# filled in from the manifest file
+my %no_license_dir = ();
+
+# distribution name
+my $distribution = $ARGV[0];
+die "No distribution name specified on the command line" if $distribution eq '';
+my $dist_root = "distribution/$distribution";
+
+# check distribution exists
+die "Distribution '$distribution' does not exist" unless -d $dist_root;
+
+# get version
+open VERSION,"$dist_root/VERSION.txt" or die "Can't open $dist_root/VERSION.txt";
+my $version = <VERSION>;
+chomp $version;
+my $archive_name = <VERSION>;
+chomp $archive_name;
+close VERSION;
+
+# consistency check
+die "Archive name '$archive_name' is not equal to the distribution name '$distribution'"
+ unless $archive_name eq $distribution;
+
+my $svnversion = `svnversion .`;
+chomp $svnversion;
+$svnversion =~ tr/0-9A-Za-z/_/c;
+
+if($version =~ /USE_SVN_VERSION/)
+{
+ # for developers, use SVN version
+ open INFO,'svn info . |';
+ my $svnurl;
+ while(<INFO>)
+ {
+ if(m/^URL: (.+?)[\n\r]+/)
+ {
+ $svnurl = $1;
+ }
+ }
+ close INFO;
+ $svnurl =~ m'box/(.+)$';
+ my $svndir = $1;
+ $svndir =~ tr/0-9A-Za-z/_/c;
+ $version =~ s/USE_SVN_VERSION/$svndir.'_'.$svnversion/e;
+}
+
+# make initial directory
+my $base_name = "$archive_name-$version";
+system "rm -rf $base_name";
+system "rm $base_name.tgz";
+mkdir $base_name,0755;
+
+# get license file
+open LICENSE,"$dist_root/LICENSE.txt" or die "Can't open $dist_root/LICENSE.txt";
+my $license_f;
+read LICENSE,$license_f,100000;
+close LICENSE;
+my @license = ('distribution '.$base_name.' (svn version: '.$svnversion.')',split(/\n/,$license_f));
+
+# copy files, make a note of all the modules included
+my %modules_included;
+my $private_sections_removed = 0;
+my $non_distribution_sections_removed = 0;
+sub copy_from_list
+{
+ my $list = $_[0];
+ open LIST,$list or die "Can't open $list";
+
+ while(<LIST>)
+ {
+ next unless m/\S/;
+ chomp;
+ my ($src,$dst) = split /\s+/;
+ $dst = $src if $dst eq '';
+ if($src eq 'MKDIR')
+ {
+ # actually we just need to make a directory here
+ mkdir "$base_name/$dst",0755;
+ }
+ elsif($src eq 'NO-LICENSE-IN-DIR')
+ {
+ # record that this directory shouldn't have the license added
+ $no_license_dir{$dst} = 1;
+ }
+ elsif($src eq 'REPLACE-VERSION-IN')
+ {
+ replace_version_in($dst);
+ }
+ elsif($src eq 'NO-LICENSE')
+ {
+ $no_license{$dst} = 1;
+ }
+ elsif($src eq 'RUN')
+ {
+ print "Running $dst...\n";
+ if(system($dst) != 0)
+ {
+ print "Error running $dst. Aborting.\n";
+ exit(1);
+ }
+ }
+ elsif(-d $src)
+ {
+ $modules_included{$_} = 1;
+ copy_dir($src,$dst);
+ }
+ else
+ {
+ copy_file($src,$dst);
+ }
+ }
+
+ close LIST;
+}
+copy_from_list("distribution/COMMON-MANIFEST.txt");
+copy_from_list("$dist_root/DISTRIBUTION-MANIFEST.txt");
+
+# Copy in the root directory and delete the DISTRIBUTION-MANIFEST file
+(system("cp $dist_root/*.* $base_name/") == 0)
+ or die "Copy of root extra files failed";
+unlink "$base_name/DISTRIBUTION-MANIFEST.txt"
+ or die "Delete of DISTRIBUTION-MANIFEST.txt file failed";
+replace_version_in("VERSION.txt");
+
+# produce a new modules file
+my $modules = gensym;
+open $modules,"modules.txt" or die "Can't open modules.txt for reading";
+open MODULES_OUT,">$base_name/modules.txt";
+
+while(<$modules>)
+{
+ # skip lines for modules which aren't included
+ next if m/\A(\w+\/\w+)\s/ && !exists $modules_included{$1};
+
+ # skip private sections
+ unless(skip_non_applicable_section($_, $modules, 'modules.txt'))
+ {
+ # copy line to out files
+ print MODULES_OUT
+ }
+}
+
+close MODULES_OUT;
+close $modules;
+
+# report on how many private sections were removed
+print "Private sections removed: $private_sections_removed\nNon-distribution sections removed: $non_distribution_sections_removed\n";
+
+# tar it up
+system "tar cf - $base_name | gzip -9 - > $base_name.tgz";
+
+sub copy_file
+{
+ my ($fn,$dst_fn) = @_;
+
+ my $ext;
+ $ext = $1 if $fn =~ m/\.(\w+)\Z/;
+
+ # licenses not used in this directory?
+ my $license_in_dir = 1;
+ $dst_fn =~ m~\A(.+)/[^/]+?\Z~;
+ $license_in_dir = 0 if exists $no_license_dir{$1};
+
+ # licensed or not?
+ if(exists $comment_chars{$ext} && !exists $no_license{$fn} && $license_in_dir)
+ {
+ my $b = $comment_chars{$ext};
+
+ # copy as text, inserting license
+ my $in = gensym;
+ open $in,$fn;
+ open OUT,">$base_name/$dst_fn";
+
+ my $first = <$in>;
+ if($first =~ m/\A#!/)
+ {
+ print OUT $first;
+ $first = '';
+ }
+
+ # write license
+ for(@license)
+ {
+ print OUT $b,$_,"\n"
+ }
+
+ if($first ne '')
+ {
+ print OUT $first;
+ }
+
+ while(<$in>)
+ {
+ unless(skip_non_applicable_section($_, $in, $fn))
+ {
+ print OUT
+ }
+ }
+
+ close OUT;
+ close $in;
+ }
+ else
+ {
+ if(exists $text_files{$ext})
+ {
+ # copy this as text, to remove private stuff
+ my $in = gensym;
+ open $in,$fn;
+ open OUT,">$base_name/$dst_fn";
+
+ while(<$in>)
+ {
+ unless(skip_non_applicable_section($_, $in, $fn))
+ {
+ print OUT
+ }
+ }
+
+ close OUT;
+ close $in;
+ }
+ else
+ {
+ # copy as binary
+ system 'cp',$fn,"$base_name/$dst_fn"
+ }
+ }
+
+ # copy executable bit from src
+ if(-x $fn)
+ {
+ system 'chmod','a+x',"$base_name/$dst_fn"
+ }
+ else
+ {
+ system 'chmod','a-x',"$base_name/$dst_fn"
+ }
+}
+
+sub skip_non_applicable_section
+{
+ my ($l, $filehandle, $filename) = @_;
+ if($l =~ m/BOX_PRIVATE_BEGIN/)
+ {
+ # skip private section
+ print "Removing private section from $filename\n";
+ $private_sections_removed++;
+ while(<$filehandle>) {last if m/BOX_PRIVATE_END/}
+
+ # skipped something
+ return 1;
+ }
+ elsif($l =~ m/IF_DISTRIBUTION\((.+?)\)/)
+ {
+ # which distributions does this apply to?
+ my $applies = 0;
+ for(split /,/,$1)
+ {
+ $applies = 1 if $_ eq $distribution
+ }
+ unless($applies)
+ {
+ # skip section?
+ print "Removing distribution specific section from $filename\n";
+ $non_distribution_sections_removed++;
+ while(<$filehandle>) {last if m/END_IF_DISTRIBUTION/}
+ }
+ # hide this line
+ return 1;
+ }
+ elsif($l =~ m/END_IF_DISTRIBUTION/)
+ {
+ # hide these lines
+ return 1;
+ }
+ else
+ {
+ # no skipping, return this line
+ return 0;
+ }
+}
+
+sub copy_dir
+{
+ my ($dir,$dst_dir) = @_;
+
+ # copy an entire directory... first make sure it exists
+ my @n = split /\//,$dst_dir;
+ my $d = $base_name;
+ for(@n)
+ {
+ $d .= '/';
+ $d .= $_;
+ mkdir $d,0755;
+ }
+
+ # then do each of the files within in
+ opendir DIR,$dir;
+ my @items = readdir DIR;
+ closedir DIR;
+
+ for(@items)
+ {
+ next if m/\A\./;
+ next if m/\A_/;
+ next if m/\AMakefile\Z/;
+ next if m/\Aautogen/;
+ next if !-f "$dir/$_";
+
+ copy_file("$dir/$_","$dst_dir/$_");
+ }
+}
+
+sub replace_version_in
+{
+ my ($file) = @_;
+
+ my $fn = $base_name . '/' . $file;
+ open IN,$fn or die "Can't open $fn";
+ open OUT,'>'.$fn.'.new' or die "Can't open $fn.new for writing";
+
+ while(<IN>)
+ {
+ s/###DISTRIBUTION-VERSION-NUMBER###/$version/g;
+ s/.*USE_SVN_VERSION.*/$version/g;
+ print OUT
+ }
+
+ close OUT;
+ close IN;
+
+ rename($fn.'.new', $fn) or die "Can't rename in place $fn";
+}
+
diff --git a/infrastructure/makeparcels.pl b/infrastructure/makeparcels.pl.in
index a4e9d771..0846ef46 100755
--- a/infrastructure/makeparcels.pl
+++ b/infrastructure/makeparcels.pl.in
@@ -1,42 +1,4 @@
-#!/usr/bin/perl
-# distribution boxbackup-0.10 (svn version: 494)
-#
-# Copyright (c) 2003 - 2006
-# 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 acknowledgment:
-# 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.
-#
-#
-#
+#!@PERL@
use strict;
use lib 'infrastructure';
@@ -116,7 +78,7 @@ MAKE = $make_command
__E
-print MAKE "all:\t",join(' ',map {parcel_target($_)} @parcels),"\n\n";
+print MAKE "all:\t",join(' ',map {"build-".$_} @parcels),"\n\n";
print MAKE "clean:\n";
for my $parcel (@parcels)
@@ -133,13 +95,18 @@ my $release_flag = BoxPlatform::make_flag('RELEASE');
for my $parcel (@parcels)
{
my $target = parcel_target($parcel);
+ print MAKE "build-$parcel:\t$target\n\n";
print MAKE $target,":\n";
my $dir = parcel_dir($parcel);
print MAKE "\ttest -d $dir || mkdir $dir\n";
- open SCRIPT,">parcels/scripts/install-$parcel" or die "Can't open installer script for $parcel for writing";
- print SCRIPT "#!/bin/sh\n\n";
+ unless ($target_windows)
+ {
+ open SCRIPT,">parcels/scripts/install-$parcel" or die
+ "Can't open installer script for $parcel for writing";
+ print SCRIPT "#!/bin/sh\n\n";
+ }
for(@{$parcel_contents{$parcel}})
{
@@ -161,7 +128,8 @@ for my $parcel (@parcels)
{
if ($optional)
{
- print MAKE "\ttest -r $name && cp $name $dir\n";
+ print MAKE "\ttest -r $name " .
+ "&& cp $name $dir || true\n";
}
else
{
@@ -172,21 +140,34 @@ for my $parcel (@parcels)
$name = $1;
}
- print SCRIPT "install $name $install_into_dir\n";
+ unless ($target_windows)
+ {
+ print SCRIPT "install $name $install_into_dir\n";
+ }
+ }
+
+ unless ($target_windows)
+ {
+ close SCRIPT;
+ chmod 0755,"parcels/scripts/install-$parcel";
}
- close SCRIPT;
-
- chmod 0755,"parcels/scripts/install-$parcel";
-
my $root = parcel_root($parcel);
- print MAKE "\tcp parcels/scripts/install-$parcel $dir\n";
+
+ unless ($target_windows)
+ {
+ print MAKE "\tcp parcels/scripts/install-$parcel $dir\n";
+ }
+
print MAKE "\t(cd parcels; tar cf - $root | gzip -9 - > $root.tgz )\n";
print MAKE "\n";
-
- print MAKE "install-$parcel:\n";
- print MAKE "\t(cd $dir; ./install-$parcel)\n\n";
+
+ unless ($target_windows)
+ {
+ print MAKE "install-$parcel:\n";
+ print MAKE "\t(cd $dir; ./install-$parcel)\n\n";
+ }
}
print MAKE <<__E;
diff --git a/infrastructure/mingw/configure.sh b/infrastructure/mingw/configure.sh
new file mode 100755
index 00000000..f1ad353f
--- /dev/null
+++ b/infrastructure/mingw/configure.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+if [ ! -r "/usr/i686-pc-mingw32/lib/libssl.a" ]; then
+ echo "Error: install OpenSSL as instructed by" \
+ "docs/backup/win32_build_on_cygwin_using_mingw.txt" >&2
+ exit 2
+fi
+
+if [ ! -r "/usr/lib/mingw/libpcreposix.a" \
+ -o ! -r "/usr/lib/mingw/libpcre.a" \
+ -o ! -r "/usr/include/mingw/pcreposix.h" ]; then
+ echo "Error: install PCRE as instructed by" \
+ "docs/backup/win32_build_on_cygwin_using_mingw.txt" >&2
+ exit 2
+fi
+
+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"
+
+if [ ! -x "configure" ]; then
+ if ! ./bootstrap; then
+ echo "Error: bootstrap failed, aborting." >&2
+ exit 1
+ fi
+fi
+
+if ! ./configure --target=i686-pc-mingw32; then
+ echo "Error: configure failed, aborting." >&2
+ exit 1
+fi
+
+exit 0
diff --git a/infrastructure/msvc/2003/bbackupctl.vcproj b/infrastructure/msvc/2003/bbackupctl.vcproj
index b46d99f7..b2249ff8 100644
--- a/infrastructure/msvc/2003/bbackupctl.vcproj
+++ b/infrastructure/msvc/2003/bbackupctl.vcproj
@@ -20,7 +20,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\..\db-4.2.52.NC\build_win32&quot;;&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;NDEBUG "
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -149,6 +149,9 @@
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+ <File
+ RelativePath="..\..\..\lib\win32\messages.rc">
+ </File>
</Filter>
</Files>
<Globals>
diff --git a/infrastructure/msvc/2003/bbackupd.vcproj b/infrastructure/msvc/2003/bbackupd.vcproj
index 4ca3470e..182c10a2 100644
--- a/infrastructure/msvc/2003/bbackupd.vcproj
+++ b/infrastructure/msvc/2003/bbackupd.vcproj
@@ -20,7 +20,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(SolutionDir)..\..\..\..\db-4.2.52.NC\build_win32&quot;;&quot;$(SolutionDir)..\..\..\..\boost_1_31_0&quot;;&quot;$(SolutionDir)..\..\..\..\openssl\include&quot;;&quot;$(SolutionDir)..\..\..\..\zlib\include&quot;;&quot;$(SolutionDir)..\..\..\lib\backupclient&quot;;&quot;$(SolutionDir)..\..\..\lib\server&quot;;&quot;$(SolutionDir)..\..\..\lib\crypto&quot;;&quot;$(SolutionDir)..\..\..\lib\compress&quot;;&quot;$(SolutionDir)..\..\..\lib\win32&quot;;&quot;$(SolutionDir)..\..\..\lib\common\&quot;"
- PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING"
+ PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;NDEBUG "
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -130,6 +130,9 @@
Name="bbackupd"
Filter="">
<File
+ RelativePath="..\..\..\bin\bbackupd\autogen_ClientException.cpp">
+ </File>
+ <File
RelativePath="..\..\..\bin\bbackupd\BackupClientContext.cpp">
</File>
<File
@@ -170,6 +173,9 @@
Name="bbackupd"
Filter="">
<File
+ RelativePath="..\..\..\bin\bbackupd\autogen_ClientException.h">
+ </File>
+ <File
RelativePath="..\..\..\bin\bbackupd\BackupClientContext.h">
</File>
<File
@@ -200,6 +206,9 @@
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+ <File
+ RelativePath="..\..\..\lib\win32\messages.rc">
+ </File>
</Filter>
<File
RelativePath="..\..\..\ReadMe.txt">
diff --git a/infrastructure/msvc/2003/boxbackup.ncb b/infrastructure/msvc/2003/boxbackup.ncb
deleted file mode 100644
index 8aacb715..00000000
--- a/infrastructure/msvc/2003/boxbackup.ncb
+++ /dev/null
Binary files differ
diff --git a/infrastructure/msvc/2003/boxbackup.sln b/infrastructure/msvc/2003/boxbackup.sln
index ede6faa1..d9a28041 100644
--- a/infrastructure/msvc/2003/boxbackup.sln
+++ b/infrastructure/msvc/2003/boxbackup.sln
@@ -1,7 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boxquery", "boxquery.vcproj", "{FE9EC666-4B3A-4370-B3D4-DEBD4A21F36E}"
ProjectSection(ProjectDependencies) = postProject
- {98598F62-FEA7-4134-AA29-0AD2315A214F} = {98598F62-FEA7-4134-AA29-0AD2315A214F}
{A089CEE6-EBF0-4232-A0C0-74850A8127A6} = {A089CEE6-EBF0-4232-A0C0-74850A8127A6}
EndProjectSection
EndProject
@@ -11,7 +10,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common.vcproj", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bbackupd", "bbackupd.vcproj", "{22D325FB-9131-4BD6-B390-968F0491D687}"
ProjectSection(ProjectDependencies) = postProject
- {98598F62-FEA7-4134-AA29-0AD2315A214F} = {98598F62-FEA7-4134-AA29-0AD2315A214F}
{A089CEE6-EBF0-4232-A0C0-74850A8127A6} = {A089CEE6-EBF0-4232-A0C0-74850A8127A6}
EndProjectSection
EndProject
@@ -25,10 +23,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bbackupctl", "bbackupctl.vc
{A089CEE6-EBF0-4232-A0C0-74850A8127A6} = {A089CEE6-EBF0-4232-A0C0-74850A8127A6}
EndProjectSection
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boost_regex", "lib\win32\boost_regex.vcproj", "{98598F62-FEA7-4134-AA29-0AD2315A214F}"
- ProjectSection(ProjectDependencies) = postProject
- EndProjectSection
-EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
@@ -55,10 +49,6 @@ Global
{9FD51412-E945-4457-A17A-CA3C505CF431}.Debug.Build.0 = Debug|Win32
{9FD51412-E945-4457-A17A-CA3C505CF431}.Release.ActiveCfg = Release|Win32
{9FD51412-E945-4457-A17A-CA3C505CF431}.Release.Build.0 = Release|Win32
- {98598F62-FEA7-4134-AA29-0AD2315A214F}.Debug.ActiveCfg = Debug|Win32
- {98598F62-FEA7-4134-AA29-0AD2315A214F}.Debug.Build.0 = Debug|Win32
- {98598F62-FEA7-4134-AA29-0AD2315A214F}.Release.ActiveCfg = Release|Win32
- {98598F62-FEA7-4134-AA29-0AD2315A214F}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
diff --git a/infrastructure/msvc/2003/boxbackup.suo b/infrastructure/msvc/2003/boxbackup.suo
deleted file mode 100644
index c461ff26..00000000
--- a/infrastructure/msvc/2003/boxbackup.suo
+++ /dev/null
Binary files differ
diff --git a/infrastructure/msvc/2003/boxquery.vcproj b/infrastructure/msvc/2003/boxquery.vcproj
index a2962c22..8d8cf20c 100644
--- a/infrastructure/msvc/2003/boxquery.vcproj
+++ b/infrastructure/msvc/2003/boxquery.vcproj
@@ -21,7 +21,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;;&quot;$(SolutionDir)..\..\..\..\boost_1_31_0&quot;"
- PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING"
+ PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;NDEBUG "
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -161,6 +161,9 @@
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+ <File
+ RelativePath="..\..\..\lib\win32\messages.rc">
+ </File>
</Filter>
<File
RelativePath="..\..\..\ReadMe.txt">
diff --git a/infrastructure/msvc/2003/common.vcproj b/infrastructure/msvc/2003/common.vcproj
index 553aaf1a..bdae0bb8 100644
--- a/infrastructure/msvc/2003/common.vcproj
+++ b/infrastructure/msvc/2003/common.vcproj
@@ -20,7 +20,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;;&quot;$(SolutionDir)..\..\..\..\boost_1_31_0\&quot;"
- PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_LIB;PLATFORM_DISABLE_MEM_LEAK_TESTING"
+ PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_LIB;PLATFORM_DISABLE_MEM_LEAK_TESTING;NDEBUG "
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -171,15 +171,24 @@
RelativePath="..\..\..\lib\common\IOStreamGetLine.cpp">
</File>
<File
+ RelativePath="..\..\..\lib\common\Logging.cpp">
+ </File>
+ <File
RelativePath="..\..\..\lib\common\MemBlockStream.cpp">
</File>
<File
RelativePath="..\..\..\lib\common\PartialReadStream.cpp">
</File>
<File
+ RelativePath="..\..\..\lib\common\PathUtils.cpp">
+ </File>
+ <File
RelativePath="..\..\..\lib\common\ReadGatherStream.cpp">
</File>
<File
+ RelativePath="..\..\..\lib\common\ReadLoggingStream.cpp">
+ </File>
+ <File
RelativePath="..\..\..\lib\common\StreamableMemBlock.cpp">
</File>
<File
@@ -287,6 +296,9 @@
<File
RelativePath="..\..\..\lib\win32\emu.cpp">
</File>
+ <File
+ RelativePath="..\..\..\lib\win32\getopt_long.cxx">
+ </File>
</Filter>
<Filter
Name="server"
@@ -327,6 +339,10 @@
<File
RelativePath="..\..\..\lib\server\TLSContext.cpp">
</File>
+ <File
+ RelativePath="..\..\..\lib\server\WinNamedPipeStream.cpp">
+ </File>
+
</Filter>
</Filter>
</Filter>
@@ -435,6 +451,9 @@
RelativePath="..\..\..\lib\server\LocalProcessStream.h">
</File>
<File
+ RelativePath="..\..\..\lib\common\Logging.h">
+ </File>
+ <File
RelativePath="..\..\..\lib\common\MainHelper.h">
</File>
<File
@@ -456,6 +475,9 @@
RelativePath="..\..\..\lib\common\PartialReadStream.h">
</File>
<File
+ RelativePath="..\..\..\lib\common\PathUtils.h">
+ </File>
+ <File
RelativePath="..\..\..\lib\common\ReadGatherStream.h">
</File>
<File
@@ -468,6 +490,9 @@
RelativePath="..\..\..\lib\common\Test.h">
</File>
<File
+ RelativePath="..\..\..\lib\common\Timer.h">
+ </File>
+ <File
RelativePath="..\..\..\lib\common\UnixUser.h">
</File>
<File
@@ -476,6 +501,9 @@
<File
RelativePath="..\..\..\lib\common\WaitForEvent.h">
</File>
+ <File
+ RelativePath="..\..\..\lib\common\BoxVersion.h">
+ </File>
</Filter>
<Filter
Name="backupclient"
@@ -569,6 +597,12 @@
<File
RelativePath="..\..\..\lib\win32\emu.h">
</File>
+ <File
+ RelativePath="..\..\..\lib\win32\getopt.h">
+ </File>
+ <File
+ RelativePath="..\..\..\lib\win32\WinNamedPipeStream.h">
+ </File>
</Filter>
<Filter
Name="server"
@@ -621,6 +655,9 @@
<File
RelativePath="..\..\..\lib\server\TLSContext.h">
</File>
+ <File
+ RelativePath="..\..\..\lib\server\WinNamedPipeStream.h">
+ </File>
</Filter>
</Filter>
</Filter>
diff --git a/infrastructure/msvc/2005/bbackupctl.vcproj b/infrastructure/msvc/2005/bbackupctl.vcproj
index 3da10702..ab75480c 100644
--- a/infrastructure/msvc/2005/bbackupctl.vcproj
+++ b/infrastructure/msvc/2005/bbackupctl.vcproj
@@ -4,6 +4,7 @@
Version="8.00"
Name="bbackupctl"
ProjectGUID="{9FD51412-E945-4457-A17A-CA3C505CF431}"
+ RootNamespace="bbackupctl"
Keyword="Win32Proj"
>
<Platforms>
@@ -41,7 +42,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\common&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;NDEBUG"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -61,7 +62,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Debug\common.lib"
+ AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Debug\common.lib $(ProjectDir)..\..\..\..\pcre\bin\debug\lib_pcreposix.lib $(ProjectDir)..\..\..\..\pcre\bin\debug\lib_pcre.lib"
OutputFile="$(OutDir)/bbackupctl.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
@@ -121,8 +122,8 @@
<Tool
Name="VCCLCompilerTool"
EnableFiberSafeOptimizations="true"
- AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
RuntimeLibrary="0"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
@@ -141,7 +142,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\lib\libeay32.lib $(ProjectDir)..\..\..\..\openssl\lib\ssleay32.lib $(ProjectDir)..\..\..\Release\common.lib"
+ AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Release\common.lib $(ProjectDir)..\..\..\..\pcre\bin\release\lib_pcreposix.lib $(ProjectDir)..\..\..\..\pcre\bin\release\lib_pcre.lib"
OutputFile="$(OutDir)/bbackupctl.exe"
LinkIncremental="1"
IgnoreDefaultLibraryNames=""
@@ -210,6 +211,10 @@
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
+ <File
+ RelativePath="..\..\..\lib\win32\messages.rc"
+ >
+ </File>
</Filter>
</Files>
<Globals>
diff --git a/infrastructure/msvc/2005/bbackupd.vcproj b/infrastructure/msvc/2005/bbackupd.vcproj
index dbcf89d3..abed0f4c 100644
--- a/infrastructure/msvc/2005/bbackupd.vcproj
+++ b/infrastructure/msvc/2005/bbackupd.vcproj
@@ -4,6 +4,7 @@
Version="8.00"
Name="bbackupd"
ProjectGUID="{22D325FB-9131-4BD6-B390-968F0491D687}"
+ RootNamespace="bbackupd"
Keyword="Win32Proj"
>
<Platforms>
@@ -41,7 +42,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(SolutionDir)..\..\..\lib\backupclient&quot;;&quot;$(SolutionDir)..\..\..\lib\common&quot;;&quot;$(SolutionDir)..\..\..\lib\compress&quot;;&quot;$(SolutionDir)..\..\..\lib\crypto&quot;;&quot;$(SolutionDir)..\..\..\lib\server&quot;;&quot;$(SolutionDir)..\..\..\lib\win32&quot;;&quot;$(SolutionDir)..\..\..\..\openssl\inc32&quot;;&quot;$(SolutionDir)..\..\..\..\zlib\include&quot;"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;NDEBUG"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -61,7 +62,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Debug\common.lib"
+ AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Debug\common.lib $(ProjectDir)..\..\..\..\pcre\bin\debug\lib_pcreposix.lib $(ProjectDir)..\..\..\..\pcre\bin\debug\lib_pcre.lib"
OutputFile="$(OutDir)/bbackupd.exe"
LinkIncremental="2"
IgnoreAllDefaultLibraries="false"
@@ -122,8 +123,8 @@
<Tool
Name="VCCLCompilerTool"
EnableFiberSafeOptimizations="true"
- AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;;&quot;$(SolutionDir)..\..\..\..\boost_1_31_0&quot;"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;BOOST_REGEX_NO_LIB"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(SolutionDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
RuntimeLibrary="0"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
@@ -142,7 +143,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\lib\libeay32.lib $(ProjectDir)..\..\..\..\openssl\lib\ssleay32.lib $(ProjectDir)..\..\..\Release\common.lib $(ProjectDir)..\..\..\lib\win32\Release\boost_regex.lib"
+ AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Release\common.lib $(ProjectDir)..\..\..\..\pcre\bin\release\lib_pcreposix.lib $(ProjectDir)..\..\..\..\pcre\bin\release\lib_pcre.lib"
OutputFile="$(OutDir)/bbackupd.exe"
LinkIncremental="1"
IgnoreDefaultLibraryNames=""
@@ -194,6 +195,10 @@
Name="bbackupd"
>
<File
+ RelativePath="..\..\..\bin\bbackupd\autogen_ClientException.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\bin\bbackupd\BackupClientContext.cpp"
>
</File>
@@ -240,6 +245,10 @@
Name="bbackupd"
>
<File
+ RelativePath="..\..\..\bin\bbackupd\autogen_ClientException.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\bin\bbackupd\BackupClientContext.h"
>
</File>
@@ -275,6 +284,10 @@
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
+ <File
+ RelativePath="..\..\..\lib\win32\messages.rc"
+ >
+ </File>
</Filter>
<File
RelativePath="..\..\..\ReadMe.txt"
diff --git a/infrastructure/msvc/2005/boxquery.vcproj b/infrastructure/msvc/2005/boxquery.vcproj
index 414399cd..1c6be061 100644
--- a/infrastructure/msvc/2005/boxquery.vcproj
+++ b/infrastructure/msvc/2005/boxquery.vcproj
@@ -42,7 +42,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\common&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;NDEBUG"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -62,7 +62,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Debug\common.lib"
+ AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Debug\common.lib $(ProjectDir)..\..\..\..\pcre\bin\debug\lib_pcreposix.lib $(ProjectDir)..\..\..\..\pcre\bin\debug\lib_pcre.lib"
OutputFile="$(OutDir)/bbackupquery.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
@@ -122,8 +122,8 @@
<Tool
Name="VCCLCompilerTool"
EnableFiberSafeOptimizations="true"
- AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;;&quot;$(SolutionDir)..\..\..\..\boost_1_31_0&quot;"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;BOOST_REGEX_NO_LIB"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;PCRE_STATIC"
RuntimeLibrary="0"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
@@ -142,7 +142,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\Release\common.lib $(ProjectDir)..\..\..\..\openssl\lib\libeay32.lib $(ProjectDir)..\..\..\..\openssl\lib\ssleay32.lib $(ProjectDir)..\..\..\lib\win32\Release\boost_regex.lib"
+ AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\Release\common.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\..\pcre\bin\release\lib_pcreposix.lib $(ProjectDir)..\..\..\..\pcre\bin\release\lib_pcre.lib"
OutputFile="$(OutDir)/bbackupquery.exe"
LinkIncremental="1"
IgnoreDefaultLibraryNames=""
@@ -231,6 +231,10 @@
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
+ <File
+ RelativePath="..\..\..\lib\win32\messages.rc"
+ >
+ </File>
</Filter>
<File
RelativePath="..\..\..\ReadMe.txt"
diff --git a/infrastructure/msvc/2005/common.vcproj b/infrastructure/msvc/2005/common.vcproj
index 127d2617..5a715be4 100644
--- a/infrastructure/msvc/2005/common.vcproj
+++ b/infrastructure/msvc/2005/common.vcproj
@@ -25,6 +25,8 @@
>
<Tool
Name="VCPreBuildEventTool"
+ Description="Determining Version Number"
+ CommandLine="perl $(InputDir)..\getversion.pl"
/>
<Tool
Name="VCCustomBuildTool"
@@ -41,8 +43,8 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\common&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;$(NOINHERIT)"
- PreprocessorDefinitions="WIN32;_DEBUG;_LIB;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;NDEBUG"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\common&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\..\pcre\pcre-6.7\&quot;;$(NOINHERIT)"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -108,8 +110,8 @@
<Tool
Name="VCCLCompilerTool"
EnableFiberSafeOptimizations="true"
- AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;;&quot;$(SolutionDir)..\..\..\..\boost_1_31_0\&quot;"
- PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;NDEBUG;_LIB;PLATFORM_DISABLE_MEM_LEAK_TESTING"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\..\pcre\pcre-6.7\&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
RuntimeLibrary="0"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
@@ -242,6 +244,10 @@
>
</File>
<File
+ RelativePath="..\..\..\lib\common\Logging.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\MemBlockStream.cpp"
>
</File>
@@ -250,14 +256,26 @@
>
</File>
<File
+ RelativePath="..\..\..\lib\common\PathUtils.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\ReadGatherStream.cpp"
>
</File>
<File
+ RelativePath="..\..\..\lib\common\ReadLoggingStream.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\StreamableMemBlock.cpp"
>
</File>
<File
+ RelativePath="..\..\..\lib\common\Timer.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\UnixUser.cpp"
>
</File>
@@ -394,7 +412,7 @@
>
</File>
<File
- RelativePath="..\..\..\lib\win32\WinNamedPipeStream.cpp"
+ RelativePath="..\..\..\lib\win32\getopt_long.cxx"
>
</File>
</Filter>
@@ -449,6 +467,10 @@
RelativePath="..\..\..\lib\server\TLSContext.cpp"
>
</File>
+ <File
+ RelativePath="..\..\..\lib\server\WinNamedPipeStream.cpp"
+ >
+ </File>
</Filter>
</Filter>
</Filter>
@@ -504,7 +526,7 @@
>
</File>
<File
- RelativePath="..\..\..\lib\common\BoxConfig.h"
+ RelativePath="..\..\..\lib\common\BoxConfig-MSVC.h"
>
</File>
<File
@@ -532,6 +554,10 @@
>
</File>
<File
+ RelativePath="..\..\..\lib\common\BoxVersion.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\CollectInBufferStream.h"
>
</File>
@@ -588,6 +614,10 @@
>
</File>
<File
+ RelativePath="..\..\..\lib\common\Logging.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\MainHelper.h"
>
</File>
@@ -616,10 +646,18 @@
>
</File>
<File
+ RelativePath="..\..\..\lib\common\PathUtils.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\ReadGatherStream.h"
>
</File>
<File
+ RelativePath="..\..\..\lib\common\ReadLoggingStream.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\StreamableMemBlock.h"
>
</File>
@@ -632,6 +670,10 @@
>
</File>
<File
+ RelativePath="..\..\..\lib\common\Timer.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\UnixUser.h"
>
</File>
@@ -764,7 +806,7 @@
>
</File>
<File
- RelativePath="..\..\..\lib\win32\WinNamedPipeStream.h"
+ RelativePath="..\..\..\lib\win32\getopt.h"
>
</File>
</Filter>
@@ -835,6 +877,10 @@
RelativePath="..\..\..\lib\server\TLSContext.h"
>
</File>
+ <File
+ RelativePath="..\..\..\lib\server\WinNamedPipeStream.h"
+ >
+ </File>
</Filter>
</Filter>
</Filter>
diff --git a/infrastructure/msvc/2005/win32test.vcproj b/infrastructure/msvc/2005/win32test.vcproj
index 91a7918e..460d7660 100644
--- a/infrastructure/msvc/2005/win32test.vcproj
+++ b/infrastructure/msvc/2005/win32test.vcproj
@@ -4,6 +4,7 @@
Version="8.00"
Name="win32test"
ProjectGUID="{28C29E72-76A2-4D0C-B35B-12D446733D2E}"
+ RootNamespace="win32test"
Keyword="Win32Proj"
>
<Platforms>
@@ -41,7 +42,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\bin\bbackupd&quot;;&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\common&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;NDEBUG"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -61,7 +62,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Debug\common.lib"
+ AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Debug\common.lib $(ProjectDir)..\..\..\..\pcre\bin\debug\lib_pcreposix.lib $(ProjectDir)..\..\..\..\pcre\bin\debug\lib_pcre.lib"
OutputFile="$(OutDir)/win32test.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
@@ -121,8 +122,8 @@
<Tool
Name="VCCLCompilerTool"
EnableFiberSafeOptimizations="true"
- AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\bin\bbackupd&quot;;&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\include&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\..\bin\bbackupd&quot;;&quot;$(ProjectDir)..\..\..\lib\backupclient&quot;;&quot;$(ProjectDir)..\..\..\lib\common\&quot;;&quot;$(ProjectDir)..\..\..\lib\compress&quot;;&quot;$(ProjectDir)..\..\..\lib\crypto&quot;;&quot;$(ProjectDir)..\..\..\lib\server&quot;;&quot;$(ProjectDir)..\..\..\lib\win32&quot;;&quot;$(ProjectDir)..\..\..\..\openssl\inc32&quot;;&quot;$(ProjectDir)..\..\..\..\zlib\include&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC"
RuntimeLibrary="0"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
@@ -141,7 +142,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\lib\libeay32.lib $(ProjectDir)..\..\..\..\openssl\lib\ssleay32.lib $(ProjectDir)..\..\..\Release\common.lib"
+ AdditionalDependencies="Ws2_32.lib $(ProjectDir)..\..\..\..\zlib\lib\zdll.lib $(ProjectDir)..\..\..\..\openssl\out32dll\libeay32.lib $(ProjectDir)..\..\..\..\openssl\out32dll\ssleay32.lib $(ProjectDir)..\..\..\Release\common.lib $(ProjectDir)..\..\..\..\pcre\bin\release\lib_pcreposix.lib $(ProjectDir)..\..\..\..\pcre\bin\release\lib_pcre.lib"
OutputFile="$(OutDir)/win32test.exe"
LinkIncremental="1"
IgnoreDefaultLibraryNames=""
diff --git a/infrastructure/msvc/getversion.pl b/infrastructure/msvc/getversion.pl
new file mode 100644
index 00000000..819ba1b2
--- /dev/null
+++ b/infrastructure/msvc/getversion.pl
@@ -0,0 +1,57 @@
+#!perl
+# distribution boxbackup-0.11rc1 (svn version: 2023_2024)
+#
+# Copyright (c) 2003 - 2006
+# 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 acknowledgment:
+# 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.
+#
+#
+#
+
+$basedir = $0;
+$basedir =~ s/\\[^\\]*$//;
+$basedir =~ s/\\[^\\]*$//;
+$basedir =~ s/\\[^\\]*$//;
+$basedir =~ s/\\[^\\]*$//;
+$basedir =~ s/\\[^\\]*$//;
+-d $basedir or die "$basedir: $!";
+chdir $basedir or die "$basedir: $!";
+
+require "$basedir\\infrastructure\\BoxPlatform.pm.in";
+
+open VERSIONFILE, "> $basedir/lib/common/BoxVersion.h"
+ or die "BoxVersion.h: $!";
+print VERSIONFILE "#define BOX_VERSION \"$BoxPlatform::product_version\"\n";
+close VERSIONFILE;
+
+exit 0;
diff --git a/lib/backupclient/BackupClientCryptoKeys.cpp b/lib/backupclient/BackupClientCryptoKeys.cpp
index f4ecfec4..8b061fab 100644
--- a/lib/backupclient/BackupClientCryptoKeys.cpp
+++ b/lib/backupclient/BackupClientCryptoKeys.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupClientCryptoKeys.h b/lib/backupclient/BackupClientCryptoKeys.h
index 87cb2dc9..19526bd6 100644
--- a/lib/backupclient/BackupClientCryptoKeys.h
+++ b/lib/backupclient/BackupClientCryptoKeys.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp
index 6e875cda..84639b0d 100644
--- a/lib/backupclient/BackupClientFileAttributes.cpp
+++ b/lib/backupclient/BackupClientFileAttributes.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -286,7 +286,9 @@ bool BackupClientFileAttributes::Compare(const BackupClientFileAttributes &rAttr
if(!IgnoreModTime)
{
- if(a1->ModificationTime != a2->ModificationTime)
+ int t1 = a1->ModificationTime / 1000000;
+ int t2 = a2->ModificationTime / 1000000;
+ if(t1 != t2)
{
return false;
}
@@ -294,7 +296,9 @@ bool BackupClientFileAttributes::Compare(const BackupClientFileAttributes &rAttr
if(!IgnoreAttrModTime)
{
- if(a1->AttrModificationTime != a2->AttrModificationTime)
+ int t1 = a1->AttrModificationTime / 1000000;
+ int t2 = a2->AttrModificationTime / 1000000;
+ if(t1 != t2)
{
return false;
}
@@ -382,8 +386,8 @@ void BackupClientFileAttributes::ReadAttributes(const char *Filename, bool ZeroM
// to be true (still aborts), but it can at least hold 2^32.
if (winTime >= 0x100000000LL || _gmtime64(&winTime) == 0)
{
- ::syslog(LOG_ERR, "Invalid Modification Time "
- "caught for file: %s", Filename);
+ BOX_ERROR("Invalid Modification Time caught for "
+ "file: '" << Filename << "'");
pattr->ModificationTime = 0;
}
@@ -393,8 +397,8 @@ void BackupClientFileAttributes::ReadAttributes(const char *Filename, bool ZeroM
if (winTime > 0x100000000LL || _gmtime64(&winTime) == 0)
{
- ::syslog(LOG_ERR, "Invalid Attribute Modification "
- "Time caught for file: %s", Filename);
+ BOX_ERROR("Invalid Attribute Modification Time "
+ "caught for file: '" << Filename << "'");
pattr->AttrModificationTime = 0;
}
#endif
@@ -616,7 +620,8 @@ void BackupClientFileAttributes::FillExtendedAttr(StreamableMemBlock &outputBloc
// Created: 2003/10/07
//
// --------------------------------------------------------------------------
-void BackupClientFileAttributes::WriteAttributes(const char *Filename) const
+void BackupClientFileAttributes::WriteAttributes(const char *Filename,
+ bool MakeUserWritable) const
{
// Got something loaded
if(GetSize() <= 0)
@@ -664,9 +669,8 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const
}
#ifdef WIN32
- ::syslog(LOG_WARNING,
- "Cannot create symbolic links on Windows: %s",
- Filename);
+ BOX_WARNING("Cannot create symbolic links on Windows: '" <<
+ Filename << "'");
#else
// Make a symlink, first deleting anything in the way
::unlink(Filename);
@@ -717,10 +721,24 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const
{
// 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
+ // Attr modification time will be changed anyway,
+ // nothing that can be done about it
+ #endif
// Try to apply
if(::utimes(Filename, times) != 0)
@@ -728,7 +746,12 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const
THROW_EXCEPTION(CommonException, OSFileError)
}
}
-
+
+ if (MakeUserWritable)
+ {
+ mode |= S_IRWXU;
+ }
+
// Apply everything else... (allowable mode flags only)
if(::chmod(Filename, mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX)) != 0) // mode must be done last (think setuid)
{
diff --git a/lib/backupclient/BackupClientFileAttributes.h b/lib/backupclient/BackupClientFileAttributes.h
index c11aaf83..0e5afe64 100644
--- a/lib/backupclient/BackupClientFileAttributes.h
+++ b/lib/backupclient/BackupClientFileAttributes.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -83,7 +83,8 @@ public:
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) const;
+ void WriteAttributes(const char *Filename,
+ bool MakeUserWritable = false) const;
bool IsSymLink() const;
diff --git a/lib/backupclient/BackupClientMakeExcludeList.cpp b/lib/backupclient/BackupClientMakeExcludeList.cpp
index 93bf074f..09226e0f 100644
--- a/lib/backupclient/BackupClientMakeExcludeList.cpp
+++ b/lib/backupclient/BackupClientMakeExcludeList.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupClientMakeExcludeList.h b/lib/backupclient/BackupClientMakeExcludeList.h
index b5a6c680..a2f85b6b 100644
--- a/lib/backupclient/BackupClientMakeExcludeList.h
+++ b/lib/backupclient/BackupClientMakeExcludeList.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp
index 4e657d5d..b49955f4 100644
--- a/lib/backupclient/BackupClientRestore.cpp
+++ b/lib/backupclient/BackupClientRestore.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -57,6 +57,7 @@
#include <set>
#include <limits.h>
#include <stdio.h>
+#include <errno.h>
#include "BackupClientRestore.h"
#include "autogen_BackupProtocolClient.h"
@@ -244,7 +245,7 @@ typedef struct
// Created: 23/11/03
//
// --------------------------------------------------------------------------
-static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t DirectoryID, std::string &rLocalDirectoryName,
+static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t DirectoryID, std::string &rLocalDirectoryName,
RestoreParams &Params, RestoreResumeInfo &rLevel)
{
// If we're resuming... check that we haven't got a next level to look at
@@ -261,11 +262,35 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
rLevel.RemoveLevel();
}
- // Save the resumption information
- Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
+ // Create the local directory, if not already done.
+ // Path and owner set later, just use restrictive owner mode.
- // Create the local directory (if not already done) -- path and owner set later, just use restrictive owner mode
- switch(ObjectExists(rLocalDirectoryName.c_str()))
+ int exists;
+
+ try
+ {
+ exists = ObjectExists(rLocalDirectoryName.c_str());
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to check existence for " <<
+ rLocalDirectoryName << ": " << e.what());
+ return Restore_UnknownError;
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to check existence for " <<
+ rLocalDirectoryName << ": " << e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to check existence for " <<
+ rLocalDirectoryName << ": unknown error");
+ return Restore_UnknownError;
+ }
+
+ switch(exists)
{
case ObjectExists_Dir:
// Do nothing
@@ -273,26 +298,152 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
case ObjectExists_File:
{
// File exists with this name, which is fun. Get rid of it.
- ::printf("WARNING: File present with name '%s', removing out of the way of restored directory. Use specific restore with ID to restore this object.", rLocalDirectoryName.c_str());
+ BOX_WARNING("File present with name '" <<
+ rLocalDirectoryName << "', removing " <<
+ "out of the way of restored directory. "
+ "Use specific restore with ID to "
+ "restore this object.");
if(::unlink(rLocalDirectoryName.c_str()) != 0)
{
- THROW_EXCEPTION(CommonException, OSFileError);
+ BOX_ERROR("Failed to delete file " <<
+ rLocalDirectoryName << ": " <<
+ strerror(errno));
+ return Restore_UnknownError;
}
- TRACE1("In restore, directory name collision with file %s", rLocalDirectoryName.c_str());
+ BOX_TRACE("In restore, directory name "
+ "collision with file " <<
+ rLocalDirectoryName);
}
- // follow through to... (no break)
+ break;
case ObjectExists_NoObject:
- if(::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0)
- {
- THROW_EXCEPTION(CommonException, OSFileError);
- }
+ // we'll create it in a second, after checking
+ // whether the parent directory exists
break;
default:
ASSERT(false);
break;
}
-
- // Fetch the directory listing from the server -- getting a list of files which is approparite to the restore type
+
+ std::string parentDirectoryName(rLocalDirectoryName);
+ if(parentDirectoryName[parentDirectoryName.size() - 1] ==
+ DIRECTORY_SEPARATOR_ASCHAR)
+ {
+ parentDirectoryName.resize(parentDirectoryName.size() - 1);
+ }
+
+ size_t lastSlash = parentDirectoryName.rfind(DIRECTORY_SEPARATOR_ASCHAR);
+
+ if(lastSlash == std::string::npos)
+ {
+ // might be a forward slash separator,
+ // especially in the unit tests!
+ lastSlash = parentDirectoryName.rfind('/');
+ }
+
+ if(lastSlash != std::string::npos)
+ {
+ // the target directory is a deep path, remove the last
+ // directory name and check that the resulting parent
+ // exists, otherwise the restore should fail.
+ parentDirectoryName.resize(lastSlash);
+
+ #ifdef WIN32
+ // if the path is a drive letter, then we need to
+ // add a a backslash to query the root directory.
+ if (lastSlash == 2 && parentDirectoryName[1] == ':')
+ {
+ parentDirectoryName += '\\';
+ }
+ else if (lastSlash == 0)
+ {
+ parentDirectoryName += '\\';
+ }
+ #endif
+
+ int parentExists;
+
+ try
+ {
+ parentExists = ObjectExists(parentDirectoryName.c_str());
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to check existence for " <<
+ parentDirectoryName << ": " << e.what());
+ return Restore_UnknownError;
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to check existence for " <<
+ parentDirectoryName << ": " << e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to check existence for " <<
+ parentDirectoryName << ": unknown error");
+ return Restore_UnknownError;
+ }
+
+ switch(parentExists)
+ {
+ case ObjectExists_Dir:
+ // this is fine, do nothing
+ break;
+
+ case ObjectExists_File:
+ BOX_ERROR("Failed to restore: '" <<
+ parentDirectoryName << "' "
+ "is a file, but should be a "
+ "directory.");
+ return Restore_TargetPathNotFound;
+
+ case ObjectExists_NoObject:
+ BOX_ERROR("Failed to restore: parent '" <<
+ parentDirectoryName << "' of target "
+ "directory does not exist.");
+ return Restore_TargetPathNotFound;
+
+ default:
+ BOX_ERROR("Failed to restore: unknown "
+ "result from ObjectExists('" <<
+ parentDirectoryName << "')");
+ return Restore_UnknownError;
+ }
+ }
+
+ if((exists == ObjectExists_NoObject ||
+ exists == ObjectExists_File) &&
+ ::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0)
+ {
+ BOX_ERROR("Failed to create directory '" <<
+ rLocalDirectoryName << "': " <<
+ strerror(errno));
+ return Restore_UnknownError;
+ }
+
+ // Save the restore info, in case it's needed later
+ try
+ {
+ Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to save resume info file '" <<
+ Params.mRestoreResumeInfoFilename << "': " <<
+ e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to save resume info file '" <<
+ Params.mRestoreResumeInfoFilename <<
+ "': unknown error");
+ return Restore_UnknownError;
+ }
+
+ // Fetch the directory listing from the server -- getting a
+ // list of files which is appropriate to the restore type
rConnection.QueryListDirectory(
DirectoryID,
Params.RestoreDeleted?(BackupProtocolClientListDirectory::Flags_Deleted):(BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING),
@@ -307,7 +458,23 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
// Apply attributes to the directory
const StreamableMemBlock &dirAttrBlock(dir.GetAttributes());
BackupClientFileAttributes dirAttr(dirAttrBlock);
- dirAttr.WriteAttributes(rLocalDirectoryName.c_str());
+
+ try
+ {
+ dirAttr.WriteAttributes(rLocalDirectoryName.c_str(), true);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to restore attributes for '" <<
+ rLocalDirectoryName << "': " << e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to restore attributes for '" <<
+ rLocalDirectoryName << "': unknown error");
+ return Restore_UnknownError;
+ }
int64_t bytesWrittenSinceLastRestoreInfoSave = 0;
@@ -324,8 +491,17 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
BackupStoreFilenameClear nm(en->GetName());
std::string localFilename(rLocalDirectoryName + DIRECTORY_SEPARATOR_ASCHAR + nm.GetClearFilename());
- // Unlink anything which already exists -- for resuming restores, we can't overwrite files already there.
- ::unlink(localFilename.c_str());
+ // Unlink anything which already exists:
+ // For resuming restores, we can't overwrite
+ // files already there.
+ if(ObjectExists(localFilename) != ObjectExists_NoObject &&
+ ::unlink(localFilename.c_str()) != 0)
+ {
+ BOX_ERROR("Failed to delete file '" <<
+ localFilename << "': " <<
+ strerror(errno));
+ return Restore_UnknownError;
+ }
// Request it from the store
rConnection.QueryGetFile(DirectoryID, en->GetObjectID());
@@ -335,17 +511,34 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
// Decode the file -- need to do different things depending on whether
// the directory entry has additional attributes
- if(en->HasAttributes())
+ try
{
- // Use these attributes
- const StreamableMemBlock &storeAttr(en->GetAttributes());
- BackupClientFileAttributes attr(storeAttr);
- BackupStoreFile::DecodeFile(*objectStream, localFilename.c_str(), rConnection.GetTimeout(), &attr);
+ if(en->HasAttributes())
+ {
+ // Use these attributes
+ const StreamableMemBlock &storeAttr(en->GetAttributes());
+ BackupClientFileAttributes attr(storeAttr);
+ BackupStoreFile::DecodeFile(*objectStream, localFilename.c_str(), rConnection.GetTimeout(), &attr);
+ }
+ else
+ {
+ // Use attributes stored in file
+ BackupStoreFile::DecodeFile(*objectStream, localFilename.c_str(), rConnection.GetTimeout());
+ }
}
- else
+ catch(std::exception &e)
{
- // Use attributes stored in file
- BackupStoreFile::DecodeFile(*objectStream, localFilename.c_str(), rConnection.GetTimeout());
+ BOX_ERROR("Failed to restore file '" <<
+ localFilename << "': " <<
+ e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to restore file '" <<
+ localFilename <<
+ "': unknown error");
+ return Restore_UnknownError;
}
// Progress display?
@@ -360,7 +553,34 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
// Save restore info?
int64_t fileSize;
- if(FileExists(localFilename.c_str(), &fileSize, true /* treat links as not existing */))
+ int exists;
+
+ try
+ {
+ exists = FileExists(
+ localFilename.c_str(),
+ &fileSize,
+ true /* treat links as not
+ existing */);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to determine "
+ "whether file exists: '" <<
+ localFilename << "': " <<
+ e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to determine "
+ "whether file exists: '" <<
+ localFilename << "': "
+ "unknown error");
+ return Restore_UnknownError;
+ }
+
+ if(exists)
{
// File exists...
bytesWrittenSinceLastRestoreInfoSave += fileSize;
@@ -368,7 +588,25 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
if(bytesWrittenSinceLastRestoreInfoSave > MAX_BYTES_WRITTEN_BETWEEN_RESTORE_INFO_SAVES)
{
// Save the restore info, in case it's needed later
- Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
+ try
+ {
+ Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to save resume info file '" <<
+ Params.mRestoreResumeInfoFilename <<
+ "': " << e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to save resume info file '" <<
+ Params.mRestoreResumeInfoFilename <<
+ "': unknown error");
+ return Restore_UnknownError;
+ }
+
bytesWrittenSinceLastRestoreInfoSave = 0;
}
}
@@ -380,12 +618,31 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
if(bytesWrittenSinceLastRestoreInfoSave != 0)
{
// Save the restore info, in case it's needed later
- Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename);
+ try
+ {
+ Params.mResumeInfo.Save(
+ Params.mRestoreResumeInfoFilename);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to save resume info file '" <<
+ Params.mRestoreResumeInfoFilename << "': " <<
+ e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to save resume info file '" <<
+ Params.mRestoreResumeInfoFilename <<
+ "': unknown error");
+ return Restore_UnknownError;
+ }
+
bytesWrittenSinceLastRestoreInfoSave = 0;
}
- // Recuse to directories
+ // Recurse to directories
{
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = 0;
@@ -402,7 +659,14 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
RestoreResumeInfo &rnextLevel(rLevel.AddLevel(en->GetObjectID(), nm.GetClearFilename()));
// Recurse
- BackupClientRestoreDir(rConnection, en->GetObjectID(), localDirname, Params, rnextLevel);
+ int result = BackupClientRestoreDir(
+ rConnection, en->GetObjectID(),
+ localDirname, Params, rnextLevel);
+
+ if (result != Restore_Complete)
+ {
+ return result;
+ }
// Remove the level for the above call
rLevel.RemoveLevel();
@@ -411,7 +675,27 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di
rLevel.mRestoredObjects.insert(en->GetObjectID());
}
}
- }
+ }
+
+ // now remove the user writable flag, if we added it earlier
+ try
+ {
+ dirAttr.WriteAttributes(rLocalDirectoryName.c_str(), false);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to restore attributes for '" <<
+ rLocalDirectoryName << "': " << e.what());
+ return Restore_UnknownError;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to restore attributes for '" <<
+ rLocalDirectoryName << "': unknown error");
+ return Restore_UnknownError;
+ }
+
+ return Restore_Complete;
}
@@ -482,7 +766,12 @@ int BackupClientRestore(BackupProtocolClient &rConnection, int64_t DirectoryID,
// Restore the directory
std::string localName(LocalDirectoryName);
- BackupClientRestoreDir(rConnection, DirectoryID, localName, params, params.mResumeInfo);
+ int result = BackupClientRestoreDir(rConnection, DirectoryID,
+ localName, params, params.mResumeInfo);
+ if (result != Restore_Complete)
+ {
+ return result;
+ }
// Undelete the directory on the server?
if(RestoreDeleted && UndeleteAfterRestoreDeleted)
diff --git a/lib/backupclient/BackupClientRestore.h b/lib/backupclient/BackupClientRestore.h
index 6421cc8a..120b6c9f 100644
--- a/lib/backupclient/BackupClientRestore.h
+++ b/lib/backupclient/BackupClientRestore.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -54,7 +54,9 @@ enum
{
Restore_Complete = 0,
Restore_ResumePossible = 1,
- Restore_TargetExists = 2
+ Restore_TargetExists = 2,
+ Restore_TargetPathNotFound = 3,
+ Restore_UnknownError = 4,
};
int BackupClientRestore(BackupProtocolClient &rConnection, int64_t DirectoryID, const char *LocalDirectoryName,
diff --git a/lib/backupclient/BackupDaemonConfigVerify.cpp b/lib/backupclient/BackupDaemonConfigVerify.cpp
index 02df95e8..214b0c48 100644
--- a/lib/backupclient/BackupDaemonConfigVerify.cpp
+++ b/lib/backupclient/BackupDaemonConfigVerify.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -115,11 +115,14 @@ static const ConfigurationVerifyKey verifyrootkeys[] =
// return "now" if it's allowed, or a number of seconds if it's not
{"MaximumDiffingTime", 0, ConfigTest_IsInt, 0},
+ {"DeleteRedundantLocationsAfter", "172800", ConfigTest_IsInt, 0},
{"FileTrackingSizeThreshold", 0, ConfigTest_Exists | ConfigTest_IsInt, 0},
{"DiffingUploadSizeThreshold", 0, ConfigTest_Exists | ConfigTest_IsInt, 0},
{"StoreHostname", 0, ConfigTest_Exists, 0},
- {"ExtendedLogging", "no", ConfigTest_IsBool, 0}, // make value "yes" to enable in config file
+ {"ExtendedLogging", "no", ConfigTest_IsBool, 0}, // extended log to syslog
+ {"ExtendedLogFile", NULL, 0, 0}, // extended log to a file
+ {"LogAllFileAccess", "no", ConfigTest_IsBool, 0},
{"CommandSocket", 0, 0, 0}, // not compulsory to have this
{"KeepAliveTime", 0, ConfigTest_IsInt, 0}, // optional
diff --git a/lib/backupclient/BackupDaemonConfigVerify.h b/lib/backupclient/BackupDaemonConfigVerify.h
index 92d9f6c4..b959e950 100644
--- a/lib/backupclient/BackupDaemonConfigVerify.h
+++ b/lib/backupclient/BackupDaemonConfigVerify.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreConstants.h b/lib/backupclient/BackupStoreConstants.h
index b7b1483d..f4c801db 100644
--- a/lib/backupclient/BackupStoreConstants.h
+++ b/lib/backupclient/BackupStoreConstants.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -78,14 +78,5 @@
// This is a multiple of the number of blocks in the diff from file.
#define BACKUP_FILE_DIFF_MAX_BLOCK_FIND_MULTIPLE 4096
-// How many seconds to wait before deleting unused root directory entries?
-#ifndef NDEBUG
- // Debug: 30 seconds (easier to test)
- #define BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER 30
-#else
- // Release: 2 days (plenty of time for sysadmins to notice, or change their mind)
- #define BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER 172800
-#endif
-
#endif // BACKUPSTORECONSTANTS__H
diff --git a/lib/backupclient/BackupStoreDirectory.cpp b/lib/backupclient/BackupStoreDirectory.cpp
index b7aa4511..d2e175e1 100644
--- a/lib/backupclient/BackupStoreDirectory.cpp
+++ b/lib/backupclient/BackupStoreDirectory.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -187,6 +187,11 @@ void BackupStoreDirectory::ReadFromStream(IOStream &rStream, int Timeout)
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!
diff --git a/lib/backupclient/BackupStoreDirectory.h b/lib/backupclient/BackupStoreDirectory.h
index cb11e028..cc0c4e93 100644
--- a/lib/backupclient/BackupStoreDirectory.h
+++ b/lib/backupclient/BackupStoreDirectory.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreException.h b/lib/backupclient/BackupStoreException.h
index 338bdfad..66dc7087 100644
--- a/lib/backupclient/BackupStoreException.h
+++ b/lib/backupclient/BackupStoreException.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp
index 4609dbc1..2bb70041 100644
--- a/lib/backupclient/BackupStoreFile.cpp
+++ b/lib/backupclient/BackupStoreFile.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -55,10 +55,8 @@
#include <string.h>
#include <new>
#include <string.h>
+
#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE
- #ifndef WIN32
- #include <syslog.h>
- #endif
#include <stdio.h>
#endif
@@ -84,6 +82,7 @@
#include "ReadGatherStream.h"
#include "Random.h"
#include "BackupStoreFileEncodeStream.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -327,6 +326,22 @@ void BackupStoreFile::DecodeFile(IOStream &rEncodedFile, const char *DecodedFile
// 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
stream->GetAttributes().WriteAttributes(DecodedFilename);
@@ -779,8 +794,7 @@ int BackupStoreFile::DecodedStream::Read(void *pBuffer, int NBytes, int Timeout)
// Warn and log this issue
if(!sWarnedAboutBackwardsCompatiblity)
{
- ::printf("WARNING: Decoded one or more files using backwards compatibility mode for block index.\n");
- ::syslog(LOG_ERR, "WARNING: Decoded one or more files using backwards compatibility mode for block index.\n");
+ BOX_WARNING("WARNING: Decoded one or more files using backwards compatibility mode for block index.");
sWarnedAboutBackwardsCompatiblity = true;
}
}
@@ -1521,9 +1535,8 @@ void BackupStoreFile::EncodingBuffer::Allocate(int Size)
// --------------------------------------------------------------------------
void BackupStoreFile::EncodingBuffer::Reallocate(int NewSize)
{
-#ifndef WIN32
- TRACE2("Reallocating EncodingBuffer from %d to %d\n", mBufferSize, NewSize);
-#endif
+ BOX_TRACE("Reallocating EncodingBuffer from " << mBufferSize <<
+ " to " << NewSize);
ASSERT(mpBuffer != 0);
uint8_t *buffer = (uint8_t*)BackupStoreFile::CodingChunkAlloc(NewSize);
if(buffer == 0)
diff --git a/lib/backupclient/BackupStoreFile.h b/lib/backupclient/BackupStoreFile.h
index 521db7f0..91e8b9aa 100644
--- a/lib/backupclient/BackupStoreFile.h
+++ b/lib/backupclient/BackupStoreFile.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -88,17 +88,16 @@ public:
DiffTimer();
virtual ~DiffTimer();
public:
- virtual void DoKeepAlive() = 0;
- virtual time_t GetTimeMgmtEpoch() = 0;
- virtual int GetMaximumDiffingTime() = 0;
- virtual int GetKeepaliveTime() = 0;
+ virtual void DoKeepAlive() = 0;
+ virtual int GetMaximumDiffingTime() = 0;
+ virtual bool IsManaged() = 0;
};
// --------------------------------------------------------------------------
//
// Class
// Name: BackupStoreFile
-// Purpose: Class to hold together utils for maniplating files.
+// Purpose: Class to hold together utils for manipulating files.
// Created: 2003/08/28
//
// --------------------------------------------------------------------------
diff --git a/lib/backupclient/BackupStoreFileCmbDiff.cpp b/lib/backupclient/BackupStoreFileCmbDiff.cpp
index 5b28fceb..903dbb81 100644
--- a/lib/backupclient/BackupStoreFileCmbDiff.cpp
+++ b/lib/backupclient/BackupStoreFileCmbDiff.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFileCmbIdx.cpp b/lib/backupclient/BackupStoreFileCmbIdx.cpp
index 8343f83f..61499334 100644
--- a/lib/backupclient/BackupStoreFileCmbIdx.cpp
+++ b/lib/backupclient/BackupStoreFileCmbIdx.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFileCombine.cpp b/lib/backupclient/BackupStoreFileCombine.cpp
index 0a1704eb..bb068b58 100644
--- a/lib/backupclient/BackupStoreFileCombine.cpp
+++ b/lib/backupclient/BackupStoreFileCombine.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFileCryptVar.cpp b/lib/backupclient/BackupStoreFileCryptVar.cpp
index 15c818e9..3442ba44 100644
--- a/lib/backupclient/BackupStoreFileCryptVar.cpp
+++ b/lib/backupclient/BackupStoreFileCryptVar.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFileCryptVar.h b/lib/backupclient/BackupStoreFileCryptVar.h
index 314499f2..4a78df72 100644
--- a/lib/backupclient/BackupStoreFileCryptVar.h
+++ b/lib/backupclient/BackupStoreFileCryptVar.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFileDiff.cpp b/lib/backupclient/BackupStoreFileDiff.cpp
index ecda26b2..b4612670 100644
--- a/lib/backupclient/BackupStoreFileDiff.cpp
+++ b/lib/backupclient/BackupStoreFileDiff.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -56,17 +56,18 @@
#include <sys/time.h>
#endif
+#include "BackupStoreConstants.h"
+#include "BackupStoreException.h"
#include "BackupStoreFile.h"
-#include "BackupStoreFileWire.h"
#include "BackupStoreFileCryptVar.h"
-#include "BackupStoreObjectMagic.h"
-#include "BackupStoreException.h"
#include "BackupStoreFileEncodeStream.h"
-#include "BackupStoreConstants.h"
+#include "BackupStoreFileWire.h"
+#include "BackupStoreObjectMagic.h"
+#include "CommonException.h"
#include "FileStream.h"
-#include "RollingChecksum.h"
#include "MD5Digest.h"
-#include "CommonException.h"
+#include "RollingChecksum.h"
+#include "Timer.h"
#include "MemLeakFindOn.h"
@@ -90,31 +91,6 @@ static bool SecondStageMatch(BlocksAvailableEntry *pFirstInHashList, RollingChec
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);
-// sDiffTimerExpired flags when the diff timer has expired. When true, the
-// diff routine should check the wall clock as soon as possible, to determine
-// whether it's time for a keepalive to be sent, or whether the diff has been
-// running for too long and should be terminated.
-static bool sDiffTimerExpired = false;
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupStoreFile::DiffTimerExpired()
-// Purpose: Notifies BackupStoreFile object that the diff operation
-// timer has expired, which may mean that a keepalive should
-// be sent, or the diff should be terminated. Called from an
-// external timer, so it should not do more than set a flag.
-//
-// Created: 19/1/06
-//
-// --------------------------------------------------------------------------
-void BackupStoreFile::DiffTimerExpired()
-{
- sDiffTimerExpired = true;
-}
-
-
// --------------------------------------------------------------------------
//
// Function
@@ -521,15 +497,11 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
BlocksAvailableEntry *pIndex, int64_t NumBlocks,
int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES], DiffTimer *pDiffTimer)
{
- time_t TimeMgmtEpoch = 0;
- int MaximumDiffingTime = 0;
- int KeepAliveTime = 0;
+ Timer maximumDiffingTime(0);
- if (pDiffTimer)
+ if(pDiffTimer && pDiffTimer->IsManaged())
{
- TimeMgmtEpoch = pDiffTimer->GetTimeMgmtEpoch();
- MaximumDiffingTime = pDiffTimer->GetMaximumDiffingTime();
- KeepAliveTime = pDiffTimer->GetKeepaliveTime();
+ maximumDiffingTime = Timer(pDiffTimer->GetMaximumDiffingTime());
}
std::map<int64_t, int32_t> goodnessOfFit;
@@ -551,10 +523,9 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
}
- // TODO: Use buffered file class
- // 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 use a buffering IOStream class which
- // reads data in at the size of the filesystem block size.
+ // 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);
@@ -579,7 +550,8 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
for(int s = BACKUP_FILE_DIFF_MAX_BLOCK_SIZES - 1; s >= 0; --s)
{
ASSERT(Sizes[s] <= bufSize);
- //TRACE2("Diff pass %d, for block size %d\n", s, Sizes[s]);
+ BOX_TRACE("Diff pass " << s << ", for block size " <<
+ Sizes[s]);
// Check we haven't finished
if(Sizes[s] == 0)
@@ -615,31 +587,20 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
int rollOverInitialBytes = 0;
while(true)
{
- if(sDiffTimerExpired)
+ if(maximumDiffingTime.HasExpired())
{
- ASSERT(TimeMgmtEpoch > 0);
ASSERT(pDiffTimer != NULL);
-
- time_t tTotalRunIntvl = time(NULL) - TimeMgmtEpoch;
-
- if(MaximumDiffingTime > 0 &&
- tTotalRunIntvl >= MaximumDiffingTime)
- {
- TRACE0("MaximumDiffingTime reached - "
- "suspending file diff\n");
- abortSearch = true;
- break;
- }
- else if(KeepAliveTime > 0)
- {
- TRACE0("KeepAliveTime reached - "
- "initiating keep-alive\n");
- pDiffTimer->DoKeepAlive();
- }
-
- sDiffTimerExpired = false;
+ 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;
@@ -698,6 +659,7 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
{
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
@@ -723,6 +685,10 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
// 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());
@@ -799,7 +765,9 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
if(BackupStoreFile::TraceDetailsOfDiffProcess)
{
// Trace out the found blocks in debug mode
- TRACE0("Diff: list of found blocks\n======== ======== ======== ========\n Offset BlkIdx Size Movement\n");
+ 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;
@@ -807,10 +775,13 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
{
orgLoc += pIndex[b].mSize;
}
- TRACE4("%8lld %8lld %8lld %8lld\n", i->first, i->second,
- (int64_t)(pIndex[i->second].mSize), i->first - orgLoc);
+ 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));
}
- TRACE0("======== ======== ======== ========\n");
+ BOX_TRACE("======== ======== ======== ========");
}
#endif
}
diff --git a/lib/backupclient/BackupStoreFileEncodeStream.cpp b/lib/backupclient/BackupStoreFileEncodeStream.cpp
index a9dc3b98..b75295bd 100644
--- a/lib/backupclient/BackupStoreFileEncodeStream.cpp
+++ b/lib/backupclient/BackupStoreFileEncodeStream.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -76,6 +76,7 @@ using namespace BackupStoreFileCryptVar;
BackupStoreFileEncodeStream::BackupStoreFileEncodeStream()
: mpRecipe(0),
mpFile(0),
+ mpLogging(0),
mStatus(Status_Header),
mSendData(true),
mTotalBlocks(0),
@@ -117,6 +118,13 @@ BackupStoreFileEncodeStream::~BackupStoreFileEncodeStream()
mpFile = 0;
}
+ // Clear up logging stream
+ if(mpLogging)
+ {
+ delete mpLogging;
+ mpLogging = 0;
+ }
+
// Free the recipe
if(mpRecipe != 0)
{
@@ -237,6 +245,9 @@ void BackupStoreFileEncodeStream::Setup(const char *Filename, BackupStoreFileEnc
{
// Open the file
mpFile = new FileStream(Filename);
+
+ // Create logging stream
+ mpLogging = new ReadLoggingStream(*mpFile);
// Work out the largest possible block required for the encoded data
mAllocatedBufferSize = BackupStoreFile::MaxBlockSizeForChunkSize(maxBlockClearSize);
@@ -305,7 +316,7 @@ void BackupStoreFileEncodeStream::CalculateBlockSizes(int64_t DataSize, int64_t
rNumBlocksOut = (DataSize + rBlockSizeOut - 1) / rBlockSizeOut;
- } while(rBlockSizeOut <= BACKUP_FILE_MAX_BLOCK_SIZE && rNumBlocksOut > BACKUP_FILE_INCREASE_BLOCK_SIZE_AFTER);
+ } while(rBlockSizeOut < BACKUP_FILE_MAX_BLOCK_SIZE && rNumBlocksOut > BACKUP_FILE_INCREASE_BLOCK_SIZE_AFTER);
// Last block size
rLastBlockSizeOut = DataSize - ((rNumBlocksOut - 1) * rBlockSizeOut);
@@ -512,7 +523,7 @@ void BackupStoreFileEncodeStream::SkipPreviousBlocksInInstruction()
}
// Move forward in the stream
- mpFile->Seek(sizeToSkip, IOStream::SeekType_Relative);
+ mpLogging->Seek(sizeToSkip, IOStream::SeekType_Relative);
}
@@ -556,14 +567,14 @@ void BackupStoreFileEncodeStream::EncodeCurrentBlock()
ASSERT(blockRawSize < mAllocatedBufferSize);
// Check file open
- if(mpFile == 0)
+ if(mpFile == 0 || mpLogging == 0)
{
// File should be open, but isn't. So logical error.
THROW_EXCEPTION(BackupStoreException, Internal)
}
// Read the data in
- if(!mpFile->ReadFullBuffer(mpRawBuffer, blockRawSize, 0 /* not interested in size if failure */))
+ 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
diff --git a/lib/backupclient/BackupStoreFileEncodeStream.h b/lib/backupclient/BackupStoreFileEncodeStream.h
index 34c0d6b1..0bc15b80 100644
--- a/lib/backupclient/BackupStoreFileEncodeStream.h
+++ b/lib/backupclient/BackupStoreFileEncodeStream.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -55,6 +55,7 @@
#include "CollectInBufferStream.h"
#include "MD5Digest.h"
#include "BackupStoreFile.h"
+#include "ReadLoggingStream.h"
namespace BackupStoreFileCreation
{
@@ -138,6 +139,7 @@ private:
Recipe *mpRecipe;
IOStream *mpFile; // source file
CollectInBufferStream mData; // buffer for header and index entries
+ ReadLoggingStream *mpLogging;
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
diff --git a/lib/backupclient/BackupStoreFileRevDiff.cpp b/lib/backupclient/BackupStoreFileRevDiff.cpp
index ac323532..276c6581 100644
--- a/lib/backupclient/BackupStoreFileRevDiff.cpp
+++ b/lib/backupclient/BackupStoreFileRevDiff.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFileWire.h b/lib/backupclient/BackupStoreFileWire.h
index 18625ee0..a77c96a3 100644
--- a/lib/backupclient/BackupStoreFileWire.h
+++ b/lib/backupclient/BackupStoreFileWire.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFilename.cpp b/lib/backupclient/BackupStoreFilename.cpp
index f17fa1b1..1d0725a3 100644
--- a/lib/backupclient/BackupStoreFilename.cpp
+++ b/lib/backupclient/BackupStoreFilename.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFilename.h b/lib/backupclient/BackupStoreFilename.h
index e2007d7e..fbb6d9f7 100644
--- a/lib/backupclient/BackupStoreFilename.h
+++ b/lib/backupclient/BackupStoreFilename.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreFilenameClear.cpp b/lib/backupclient/BackupStoreFilenameClear.cpp
index 768fc5fe..85658f62 100644
--- a/lib/backupclient/BackupStoreFilenameClear.cpp
+++ b/lib/backupclient/BackupStoreFilenameClear.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -51,6 +51,7 @@
#include "CipherContext.h"
#include "CipherBlowfish.h"
#include "Guards.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -241,9 +242,9 @@ static void EnsureEncDecBufferSize(int BufSize)
{
if(sEncDecBufferSize < BufSize)
{
-#ifndef WIN32
- TRACE2("Reallocating filename encoding/decoding buffer from %d to %d\n", sEncDecBufferSize, BufSize);
-#endif
+ BOX_TRACE("Reallocating filename encoding/decoding "
+ "buffer from " << sEncDecBufferSize <<
+ " to " << BufSize);
spEncDecBuffer->Resize(BufSize);
sEncDecBufferSize = BufSize;
MEMLEAKFINDER_NOT_A_LEAK(*spEncDecBuffer);
diff --git a/lib/backupclient/BackupStoreFilenameClear.h b/lib/backupclient/BackupStoreFilenameClear.h
index 39148f3d..49fe4456 100644
--- a/lib/backupclient/BackupStoreFilenameClear.h
+++ b/lib/backupclient/BackupStoreFilenameClear.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/BackupStoreObjectDump.cpp b/lib/backupclient/BackupStoreObjectDump.cpp
index 14f9da39..896ee95e 100644
--- a/lib/backupclient/BackupStoreObjectDump.cpp
+++ b/lib/backupclient/BackupStoreObjectDump.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -151,7 +151,13 @@ void BackupStoreDirectory::Dump(void *clibFileHandle, bool ToTrace)
// Output item
int16_t f = (*i)->GetFlags();
- OutputLine(file, ToTrace, "%06llx %4lld %016llx %4d %3d %4d%s%s%s%s%s%s\n",
+#ifdef WIN32
+ OutputLine(file, ToTrace,
+ "%06I64x %4I64d %016I64x %4d %3d %4d%s%s%s%s%s%s\n",
+#else
+ OutputLine(file, ToTrace,
+ "%06llx %4lld %016llx %4d %3d %4d%s%s%s%s%s%s\n",
+#endif
(*i)->GetObjectID(),
(*i)->GetSizeInBlocks(),
(*i)->GetAttributesHash(),
diff --git a/lib/backupclient/BackupStoreObjectMagic.h b/lib/backupclient/BackupStoreObjectMagic.h
index 58b5d7ef..063fac8b 100644
--- a/lib/backupclient/BackupStoreObjectMagic.h
+++ b/lib/backupclient/BackupStoreObjectMagic.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupclient/Makefile.extra b/lib/backupclient/Makefile.extra
index 66203e3c..925c880e 100644
--- a/lib/backupclient/Makefile.extra
+++ b/lib/backupclient/Makefile.extra
@@ -5,12 +5,12 @@ 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)
+ $(PERL) $(GEN_CMD_SRV)
MAKEEXCEPTION = ../../lib/common/makeexception.pl
# AUTOGEN SEEDING
autogen_BackupStoreException.h autogen_BackupStoreException.cpp: $(MAKEEXCEPTION) BackupStoreException.txt
- perl $(MAKEEXCEPTION) BackupStoreException.txt
+ $(PERL) $(MAKEEXCEPTION) BackupStoreException.txt
diff --git a/lib/backupstore/BackupStoreAccountDatabase.cpp b/lib/backupstore/BackupStoreAccountDatabase.cpp
index 8e276ba2..59067ad0 100644
--- a/lib/backupstore/BackupStoreAccountDatabase.cpp
+++ b/lib/backupstore/BackupStoreAccountDatabase.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupstore/BackupStoreAccountDatabase.h b/lib/backupstore/BackupStoreAccountDatabase.h
index 212a2838..2a9ab519 100644
--- a/lib/backupstore/BackupStoreAccountDatabase.h
+++ b/lib/backupstore/BackupStoreAccountDatabase.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp
index 1b82a580..135a2835 100644
--- a/lib/backupstore/BackupStoreAccounts.cpp
+++ b/lib/backupstore/BackupStoreAccounts.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -179,8 +179,9 @@ void BackupStoreAccounts::GetAccountRoot(int32_t ID, std::string &rRootDirOut, i
std::string BackupStoreAccounts::MakeAccountRootDir(int32_t ID, int DiscSet) const
{
char accid[64]; // big enough!
- ::sprintf(accid, "%08x/", ID);
- return std::string(std::string(BOX_RAIDFILE_ROOT_BBSTORED DIRECTORY_SEPARATOR) + accid);
+ ::sprintf(accid, "%08x" DIRECTORY_SEPARATOR, ID);
+ return std::string(std::string(BOX_RAIDFILE_ROOT_BBSTORED
+ DIRECTORY_SEPARATOR) + accid);
}
diff --git a/lib/backupstore/BackupStoreAccounts.h b/lib/backupstore/BackupStoreAccounts.h
index dee48148..2ee1198c 100644
--- a/lib/backupstore/BackupStoreAccounts.h
+++ b/lib/backupstore/BackupStoreAccounts.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupstore/BackupStoreCheck.cpp b/lib/backupstore/BackupStoreCheck.cpp
index af849c40..61895e2f 100644
--- a/lib/backupstore/BackupStoreCheck.cpp
+++ b/lib/backupstore/BackupStoreCheck.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -140,7 +140,7 @@ void BackupStoreCheck::Check()
// Couldn't lock the account -- just stop now
if(!mQuiet)
{
- ::printf("Couldn't lock the account -- did not check.\nTry again later after the client has disconnected.\nAlternatively, forcibly kill the server.\n");
+ 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)
}
@@ -148,41 +148,43 @@ void BackupStoreCheck::Check()
if(!mQuiet && mFixErrors)
{
- ::printf("NOTE: Will fix errors encountered during checking.\n");
+ BOX_NOTICE("Will fix errors encountered during checking.");
}
// Phase 1, check objects
if(!mQuiet)
{
- ::printf("Check store account ID %08x\nPhase 1, check objects...\n", mAccountID);
+ BOX_INFO("Checking store account ID " <<
+ BOX_FORMAT_ACCOUNT(mAccountID) << "...");
+ BOX_INFO("Phase 1, check objects...");
}
CheckObjects();
// Phase 2, check directories
if(!mQuiet)
{
- ::printf("Phase 2, check directories...\n");
+ BOX_INFO("Phase 2, check directories...");
}
CheckDirectories();
// Phase 3, check root
if(!mQuiet)
{
- ::printf("Phase 3, check root...\n");
+ BOX_INFO("Phase 3, check root...");
}
CheckRoot();
// Phase 4, check unattached objects
if(!mQuiet)
{
- ::printf("Phase 4, fix unattached objects...\n");
+ BOX_INFO("Phase 4, fix unattached objects...");
}
CheckUnattachedObjects();
// Phase 5, fix bad info
if(!mQuiet)
{
- ::printf("Phase 5, fix unrecovered inconsistencies...\n");
+ BOX_INFO("Phase 5, fix unrecovered inconsistencies...");
}
FixDirsWithWrongContainerID();
FixDirsWithLostDirs();
@@ -190,7 +192,7 @@ void BackupStoreCheck::Check()
// Phase 6, regenerate store info
if(!mQuiet)
{
- ::printf("Phase 6, regenerate store info...\n");
+ BOX_INFO("Phase 6, regenerate store info...");
}
WriteNewStoreInfo();
@@ -198,29 +200,40 @@ void BackupStoreCheck::Check()
if(mNumberErrorsFound > 0)
{
- ::printf("%lld errors found\n", mNumberErrorsFound);
+ BOX_WARNING("Finished checking store account ID " <<
+ BOX_FORMAT_ACCOUNT(mAccountID) << ": " <<
+ mNumberErrorsFound << " errors found");
if(!mFixErrors)
{
- ::printf("NOTE: No changes to the store account have been made.\n");
+ BOX_WARNING("No changes to the store account "
+ "have been made.");
}
if(!mFixErrors && mNumberErrorsFound > 0)
{
- ::printf("Run again with fix option to fix these errors\n");
+ BOX_WARNING("Run again with fix option to "
+ "fix these errors");
}
- if(mNumberErrorsFound > 0)
+ if(mFixErrors && mNumberErrorsFound > 0)
{
- ::printf("You should now use bbackupquery on the client machine to examine the store.\n");
+ BOX_WARNING("You should now use bbackupquery "
+ "on the client machine to examine the store.");
if(mLostAndFoundDirectoryID != 0)
{
- ::printf("A lost+found directory was created in the account root.\n"\
- "This contains files and directories which could not be matched to existing directories.\n"\
- "bbackupd will delete this directory in a few days time.\n");
+ BOX_WARNING("A lost+found directory was "
+ "created in the account root.\n"
+ "This contains files and directories "
+ "which could not be matched to "
+ "existing directories.\n"\
+ "bbackupd will delete this directory "
+ "in a few days time.");
}
}
}
else
{
- ::printf("Store account checked, no errors found.\n");
+ BOX_NOTICE("Finished checking store account ID " <<
+ BOX_FORMAT_ACCOUNT(mAccountID) << ": "
+ "no errors found");
}
}
@@ -342,7 +355,10 @@ int64_t BackupStoreCheck::CheckObjectsScanDir(int64_t StartID, int Level, const
}
else
{
- ::printf("Spurious or invalid directory %s/%s found%s -- delete manually\n", rDirName.c_str(), (*i).c_str(), mFixErrors?", deleting":"");
+ BOX_WARNING("Spurious or invalid directory " <<
+ rDirName << DIRECTORY_SEPARATOR <<
+ (*i) << " found, " <<
+ (mFixErrors?"deleting":"delete manually"));
++mNumberErrorsFound;
}
}
@@ -366,14 +382,15 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
std::string dirName;
StoreStructure::MakeObjectFilename(StartID, mStoreRoot, mDiscSetNumber, dirName, false /* don't make sure the dir exists */);
// Check expectations
- ASSERT(dirName.size() > 4 && dirName[dirName.size() - 4] == '/');
+ ASSERT(dirName.size() > 4 &&
+ dirName[dirName.size() - 4] == DIRECTORY_SEPARATOR_ASCHAR);
// Remove the filename from it
dirName.resize(dirName.size() - 4); // four chars for "/o00"
// Check directory exists
if(!RaidFileRead::DirectoryExists(mDiscSetNumber, dirName))
{
- TRACE1("RaidFile dir %s does not exist\n", dirName.c_str());
+ BOX_WARNING("RaidFile dir " << dirName << " does not exist");
return;
}
@@ -415,7 +432,9 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
if(!fileOK)
{
// Unexpected or bad file, delete it
- ::printf("Spurious file %s/%s found%s\n", dirName.c_str(), (*i).c_str(), mFixErrors?", deleting":"");
+ BOX_WARNING("Spurious file " << dirName <<
+ DIRECTORY_SEPARATOR << (*i) << " found" <<
+ (mFixErrors?", deleting":""));
++mNumberErrorsFound;
if(mFixErrors)
{
@@ -436,7 +455,9 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID)
if(!CheckAndAddObject(StartID | i, dirName + leaf))
{
// File was bad, delete it
- ::printf("Corrupted file %s%s found%s\n", dirName.c_str(), leaf, mFixErrors?", deleting":"");
+ BOX_WARNING("Corrupted file " << dirName <<
+ leaf << " found" <<
+ (mFixErrors?", deleting":""));
++mNumberErrorsFound;
if(mFixErrors)
{
@@ -504,11 +525,10 @@ bool BackupStoreCheck::CheckAndAddObject(int64_t ObjectID, const std::string &rF
}
// Add to usage counts
- int64_t s = file->GetDiscUsageInBlocks();
- mBlocksUsed += s;
+ mBlocksUsed += size;
if(!isFile)
{
- mBlocksInDirectories += s;
+ mBlocksInDirectories += size;
}
}
catch(...)
@@ -545,7 +565,7 @@ int64_t BackupStoreCheck::CheckFile(int64_t ObjectID, IOStream &rStream)
if(ObjectID == BACKUPSTORE_ROOT_DIRECTORY_ID)
{
// Get that dodgy thing deleted!
- ::printf("Have file as root directory. This is bad.\n");
+ BOX_ERROR("Have file as root directory. This is bad.");
return -1;
}
@@ -632,7 +652,9 @@ void BackupStoreCheck::CheckDirectories()
if(dir.CheckAndFix())
{
// Wasn't quite right, and has been modified
- ::printf("Directory ID %llx has bad structure\n", pblock->mID[e]);
+ BOX_WARNING("Directory ID " <<
+ BOX_FORMAT_OBJECTID(pblock->mID[e]) <<
+ " has bad structure");
++mNumberErrorsFound;
isModified = true;
}
@@ -658,7 +680,11 @@ void BackupStoreCheck::CheckDirectories()
!= ((en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) == BackupStoreDirectory::Entry::Flags_Dir))
{
// Entry is of wrong type
- ::printf("Directory ID %llx references object %llx which has a different type than expected.\n", pblock->mID[e], en->GetObjectID());
+ 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
@@ -666,8 +692,12 @@ void BackupStoreCheck::CheckDirectories()
// 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;
- ::printf("Directory ID %llx references object %llx which is already contained.\n", pblock->mID[e], en->GetObjectID());
}
else
{
@@ -681,13 +711,13 @@ void BackupStoreCheck::CheckDirectories()
if(iflags & Flags_IsDir)
{
// Add to will fix later list
- ::printf("Directory ID %llx has wrong container ID.\n", en->GetObjectID());
+ 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
- ::printf("File ID %llx has different container ID, probably moved\n", en->GetObjectID());
+ BOX_WARNING("File ID " << BOX_FORMAT_OBJECTID(en->GetObjectID()) << " has different container ID, probably moved");
}
// Fix entry for now
@@ -706,7 +736,7 @@ void BackupStoreCheck::CheckDirectories()
// Mark as changed
isModified = true;
// Tell user
- ::printf("Directory ID %llx has wrong size for object %llx\n", pblock->mID[e], en->GetObjectID());
+ BOX_WARNING("Directory ID " << BOX_FORMAT_OBJECTID(pblock->mID[e]) << " has wrong size for object " << BOX_FORMAT_OBJECTID(en->GetObjectID()));
}
}
}
@@ -722,7 +752,7 @@ void BackupStoreCheck::CheckDirectories()
{
// Just remove the entry
badEntry = true;
- ::printf("Directory ID %llx references object %llx which does not exist.\n", pblock->mID[e], en->GetObjectID());
+ BOX_WARNING("Directory ID " << BOX_FORMAT_OBJECTID(pblock->mID[e]) << " references object " << BOX_FORMAT_OBJECTID(en->GetObjectID()) << " which does not exist.");
}
}
@@ -765,7 +795,7 @@ void BackupStoreCheck::CheckDirectories()
if(isModified && mFixErrors)
{
- ::printf("Fixing directory ID %llx\n", pblock->mID[e]);
+ BOX_WARNING("Fixing directory ID " << BOX_FORMAT_OBJECTID(pblock->mID[e]));
// Save back to disc
RaidFileWrite fixed(mDiscSetNumber, filename);
diff --git a/lib/backupstore/BackupStoreCheck.h b/lib/backupstore/BackupStoreCheck.h
index f176ebad..d7e23c9b 100644
--- a/lib/backupstore/BackupStoreCheck.h
+++ b/lib/backupstore/BackupStoreCheck.h
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
diff --git a/lib/backupstore/BackupStoreCheck2.cpp b/lib/backupstore/BackupStoreCheck2.cpp
index 38e8bf92..e251799f 100644
--- a/lib/backupstore/BackupStoreCheck2.cpp
+++ b/lib/backupstore/BackupStoreCheck2.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -85,7 +85,7 @@ void BackupStoreCheck::CheckRoot()
}
else
{
- ::printf("Root directory doesn't exist\n");
+ BOX_WARNING("Root directory doesn't exist");
++mNumberErrorsFound;
@@ -156,7 +156,7 @@ void BackupStoreCheck::CheckUnattachedObjects()
if((flags & Flags_IsContained) == 0)
{
// Unattached object...
- ::printf("Object %llx is unattached.\n", pblock->mID[e]);
+ BOX_WARNING("Object " << BOX_FORMAT_OBJECTID(pblock->mID[e]) << " is unattached.");
++mNumberErrorsFound;
// What's to be done?
@@ -185,7 +185,7 @@ void BackupStoreCheck::CheckUnattachedObjects()
// Just delete it to be safe.
if(diffFromObjectID != 0)
{
- ::printf("Object %llx is unattached, and is a patch. Deleting, cannot reliably recover.\n", pblock->mID[e]);
+ BOX_WARNING("Object " << BOX_FORMAT_OBJECTID(pblock->mID[e]) << " is unattached, and is a patch. Deleting, cannot reliably recover.");
// Delete this object instead
if(mFixErrors)
@@ -267,11 +267,15 @@ bool BackupStoreCheck::TryToRecreateDirectory(int64_t MissingDirectoryID)
// Can recreate this! Wooo!
if(!mFixErrors)
{
- ::printf("Missing directory %llx could be recreated\n", MissingDirectoryID);
+ BOX_WARNING("Missing directory " <<
+ BOX_FORMAT_OBJECTID(MissingDirectoryID) <<
+ " could be recreated.");
mDirsAdded.insert(MissingDirectoryID);
return true;
}
- ::printf("Recreating missing directory %llx\n", MissingDirectoryID);
+
+ BOX_WARNING("Recreating missing directory " <<
+ BOX_FORMAT_OBJECTID(MissingDirectoryID));
// Create a blank directory
BackupStoreDirectory dir(MissingDirectoryID, missing->second /* containing dir ID */);
@@ -338,7 +342,7 @@ int64_t BackupStoreCheck::GetLostAndFoundDirID()
if(!dir.NameInUse(lostAndFound))
{
// Found a name which can be used
- ::printf("Lost and found dir has name %s\n", name);
+ BOX_WARNING("Lost and found dir has name " << name);
break;
}
}
@@ -562,7 +566,7 @@ void BackupStoreCheck::WriteNewStoreInfo()
}
catch(...)
{
- ::printf("Load of existing store info failed, regenerating.\n");
+ BOX_WARNING("Load of existing store info failed, regenerating.");
++mNumberErrorsFound;
}
@@ -589,7 +593,7 @@ void BackupStoreCheck::WriteNewStoreInfo()
}
else
{
- ::printf("NOTE: Soft limit for account changed to ensure housekeeping doesn't delete files on next run\n");
+ BOX_WARNING("Soft limit for account changed to ensure housekeeping doesn't delete files on next run.");
}
if(poldInfo.get() != 0 && poldInfo->GetBlocksHardLimit() > minHard)
{
@@ -597,7 +601,7 @@ void BackupStoreCheck::WriteNewStoreInfo()
}
else
{
- ::printf("NOTE: Hard limit for account changed to ensure housekeeping doesn't delete files on next run\n");
+ BOX_WARNING("Hard limit for account changed to ensure housekeeping doesn't delete files on next run.");
}
// Object ID
@@ -624,7 +628,7 @@ void BackupStoreCheck::WriteNewStoreInfo()
if(mFixErrors)
{
info->Save();
- ::printf("New store info file written successfully.\n");
+ BOX_NOTICE("New store info file written successfully.");
}
}
@@ -691,7 +695,7 @@ bool BackupStoreDirectory::CheckAndFix()
if(dependsOlder != 0 && FindEntryByID(dependsOlder) == 0)
{
// Has an older version marked, but this doesn't exist. Remove this mark
- TRACE2("Entry id %llx was marked that %llx depended on it, which doesn't exist, dependency info cleaered\n", (*i)->GetObjectID(), dependsOlder);
+ TRACE2("Entry id %llx was marked that %llx depended on it, which doesn't exist, dependency info cleared\n", (*i)->GetObjectID(), dependsOlder);
(*i)->SetDependsOlder(0);
diff --git a/lib/backupstore/BackupStoreCheckData.cpp b/lib/backupstore/BackupStoreCheckData.cpp
index 53a33d47..aaff18f6 100644
--- a/