summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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/lib/backupstore/BackupStoreCheckData.cpp
+++ b/lib/backupstore/BackupStoreCheckData.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/BackupStoreConfigVerify.cpp b/lib/backupstore/BackupStoreConfigVerify.cpp
index 5ecdcbb5..1e41fee4 100644
--- a/lib/backupstore/BackupStoreConfigVerify.cpp
+++ b/lib/backupstore/BackupStoreConfigVerify.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.
@@ -73,7 +73,13 @@ static const ConfigurationVerifyKey verifyrootkeys[] =
{"AccountDatabase", 0, ConfigTest_Exists, 0},
{"TimeBetweenHousekeeping", 0, ConfigTest_Exists | ConfigTest_IsInt, 0},
{"ExtendedLogging", "no", ConfigTest_IsBool, 0}, // make value "yes" to enable in config file
- {"RaidFileConf", BOX_FILE_RAIDFILE_DEFAULT_CONFIG, ConfigTest_LastEntry, 0}
+
+ #ifdef WIN32
+ {"RaidFileConf", "", ConfigTest_LastEntry, 0}
+ #else
+ {"RaidFileConf", BOX_FILE_RAIDFILE_DEFAULT_CONFIG, ConfigTest_LastEntry, 0}
+ #endif
+
};
const ConfigurationVerify BackupConfigFileVerify =
diff --git a/lib/backupstore/BackupStoreConfigVerify.h b/lib/backupstore/BackupStoreConfigVerify.h
index fee8ae42..7742cf8d 100644
--- a/lib/backupstore/BackupStoreConfigVerify.h
+++ b/lib/backupstore/BackupStoreConfigVerify.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/BackupStoreInfo.cpp b/lib/backupstore/BackupStoreInfo.cpp
index 28508b60..bf3d1c35 100644
--- a/lib/backupstore/BackupStoreInfo.cpp
+++ b/lib/backupstore/BackupStoreInfo.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.
@@ -162,7 +162,8 @@ void BackupStoreInfo::CreateNew(int32_t AccountID, const std::string &rRootDir,
};
// Generate the filename
- ASSERT(rRootDir[rRootDir.size() - 1] == DIRECTORY_SEPARATOR_ASCHAR);
+ ASSERT(rRootDir[rRootDir.size() - 1] == '/' ||
+ rRootDir[rRootDir.size() - 1] == DIRECTORY_SEPARATOR_ASCHAR);
std::string fn(rRootDir + INFO_FILENAME);
// Open the file for writing
diff --git a/lib/backupstore/BackupStoreInfo.h b/lib/backupstore/BackupStoreInfo.h
index 0c4241d7..fe34f62f 100644
--- a/lib/backupstore/BackupStoreInfo.h
+++ b/lib/backupstore/BackupStoreInfo.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.
@@ -56,7 +56,7 @@ class BackupStoreCheck;
// --------------------------------------------------------------------------
//
-// File
+// Class
// Name: BackupStoreInfo
// Purpose: Main backup store information storage
// Created: 2003/08/28
diff --git a/lib/backupstore/StoreStructure.cpp b/lib/backupstore/StoreStructure.cpp
index 68876fd6..8ec2d690 100644
--- a/lib/backupstore/StoreStructure.cpp
+++ b/lib/backupstore/StoreStructure.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/StoreStructure.h b/lib/backupstore/StoreStructure.h
index 8c1e871c..b961b598 100644
--- a/lib/backupstore/StoreStructure.h
+++ b/lib/backupstore/StoreStructure.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/common/Archive.h b/lib/common/Archive.h
index d8e93238..02d19a8c 100644
--- a/lib/common/Archive.h
+++ b/lib/common/Archive.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/common/BannerText.h b/lib/common/BannerText.h
index 61577e43..211edbb8 100644
--- a/lib/common/BannerText.h
+++ b/lib/common/BannerText.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.
@@ -49,7 +49,7 @@
#define BANNERTEXT__H
#define BANNER_TEXT(UtilityName) \
- "Box " UtilityName " v" BOX_VERSION ", (c) Ben Summers and contributors 2003-2006\n"
+ "Box " UtilityName " v" BOX_VERSION ", (c) Ben Summers and contributors 2003-2007"
#endif // BANNERTEXT__H
diff --git a/lib/common/BeginStructPackForWire.h b/lib/common/BeginStructPackForWire.h
index c7e3a069..716f715f 100644
--- a/lib/common/BeginStructPackForWire.h
+++ b/lib/common/BeginStructPackForWire.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/common/Box.h b/lib/common/Box.h
index 14a4a6ac..a262741d 100644
--- a/lib/common/Box.h
+++ b/lib/common/Box.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.
@@ -65,13 +65,14 @@
#endif
#ifdef SHOW_BACKTRACE_ON_EXCEPTION
- #include "Utils.h"
+ #include "Utils.h"
#define OPTIONAL_DO_BACKTRACE DumpStackBacktrace();
#else
#define OPTIONAL_DO_BACKTRACE
#endif
#include "CommonException.h"
+#include "Logging.h"
#ifndef NDEBUG
@@ -132,22 +133,27 @@
#ifdef BOX_MEMORY_LEAK_TESTING
// Memory leak testing
#include "MemLeakFinder.h"
+ #define DEBUG_NEW new(__FILE__,__LINE__)
#define MEMLEAKFINDER_NOT_A_LEAK(x) memleakfinder_notaleak(x);
+ #define MEMLEAKFINDER_NO_LEAKS MemLeakSuppressionGuard _guard;
+ #define MEMLEAKFINDER_INIT memleakfinder_init();
#define MEMLEAKFINDER_START {memleakfinder_global_enable = true;}
- #define MEMLEAKFINDER_STOP {memleakfinder_global_enable = false;}
+ #define MEMLEAKFINDER_STOP {memleakfinder_global_enable = false;}
#else
#define DEBUG_NEW new
#define MEMLEAKFINDER_NOT_A_LEAK(x)
+ #define MEMLEAKFINDER_NO_LEAKS
+ #define MEMLEAKFINDER_INIT
#define MEMLEAKFINDER_START
#define MEMLEAKFINDER_STOP
#endif
-
-#define THROW_EXCEPTION(type, subtype) \
- { \
- OPTIONAL_DO_BACKTRACE \
- TRACE1("Exception thrown: " #type "(" #subtype ") at " __FILE__ "(%d)\n", __LINE__) \
- throw type(type::subtype); \
+#define THROW_EXCEPTION(type, subtype) \
+ { \
+ OPTIONAL_DO_BACKTRACE \
+ BOX_WARNING("Exception thrown: " #type "(" #subtype ") at " \
+ __FILE__ "(" << __LINE__ << ")") \
+ throw type(type::subtype); \
}
// extra macros for converting to network byte order
diff --git a/lib/win32/config.h.win32 b/lib/common/BoxConfig-MSVC.h
index 42298545..29cff160 100644
--- a/lib/win32/config.h.win32
+++ b/lib/common/BoxConfig-MSVC.h
@@ -1,3 +1,41 @@
+// 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.
+//
+//
+//
/* lib/common/BoxConfig.h. Generated by configure. */
/* lib/common/BoxConfig.h.in. Generated from configure.ac by autoheader. */
/* Hacked by hand to work for MSVC by Chris Wilson */
@@ -56,6 +94,10 @@
you don't. */
#define HAVE_DECL_XATTR_NOFOLLOW 0
+/* Define to 1 if you have the declaration of `O_BINARY', and to 0 if you
+ don't. */
+#define HAVE_DECL_O_BINARY 1
+
/* Define to 1 if #define of pragmas works */
/* #undef HAVE_DEFINE_PRAGMA */
@@ -82,7 +124,7 @@
/* #undef HAVE_GETPEEREID */
/* Define to 1 if you have the `getpid' function. */
-#define HAVE_GETPID 1
+// #define HAVE_GETPID 1
/* Define to 1 if you have the `getxattr' function. */
/* #undef HAVE_GETXATTR */
@@ -172,7 +214,9 @@
/* #undef HAVE_READLINE_READLINE_H */
/* Define to 1 if you have the <regex.h> header file. */
-// #define HAVE_REGEX_H 1
+/* #undef HAVE_REGEX_H */
+#define HAVE_PCREPOSIX_H 1
+#define HAVE_REGEX_SUPPORT 1
/* Define to 1 if you have the `setproctitle' function. */
/* #undef HAVE_SETPROCTITLE */
@@ -268,7 +312,7 @@
// #define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
+// #define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/wait.h> header file. */
/* #undef HAVE_SYS_WAIT_H */
diff --git a/lib/common/BoxConfig.h b/lib/common/BoxConfig.h
new file mode 100644
index 00000000..0758963a
--- /dev/null
+++ b/lib/common/BoxConfig.h
@@ -0,0 +1,469 @@
+// 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.
+//
+//
+//
+/* lib/common/BoxConfig.h. Generated by configure. */
+/* lib/common/BoxConfig.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to major version for BDB_VERSION */
+#define BDB_VERSION_MAJOR 4
+
+/* Define to minor version for BDB_VERSION */
+#define BDB_VERSION_MINOR 3
+
+/* Define to point version for BDB_VERSION */
+#define BDB_VERSION_POINT 29
+
+/* Name of the 64 bit endian swapping function */
+#define BSWAP64 __cpu_to_be64
+
+/* Define to 1 if the `closedir' function returns void instead of `int'. */
+/* #undef CLOSEDIR_VOID */
+
+/* Define to 1 if non-aligned int16 access will fail */
+/* #undef HAVE_ALIGNED_ONLY_INT16 */
+
+/* Define to 1 if non-aligned int32 access will fail */
+/* #undef HAVE_ALIGNED_ONLY_INT32 */
+
+/* Define to 1 if non-aligned int64 access will fail */
+/* #undef HAVE_ALIGNED_ONLY_INT64 */
+
+/* Define to 1 if you have the <asm/byteorder.h> header file. */
+#define HAVE_ASM_BYTEORDER_H 1
+
+/* Define to 1 if BSWAP64 is defined to the name of a valid 64 bit endian
+ swapping function */
+#define HAVE_BSWAP64 1
+
+/* Define to 1 if you have the <db.h> header file. */
+#define HAVE_DB_H 1
+
+/* Define to 1 if you have the declaration of `dirfd', and to 0 if you don't.
+ */
+#define HAVE_DECL_DIRFD 1
+
+/* Define to 1 if you have the declaration of `F_SETLK', and to 0 if you
+ don't. */
+#define HAVE_DECL_F_SETLK 1
+
+/* Define to 1 if you have the declaration of `INFTIM', and to 0 if you don't.
+ */
+#define HAVE_DECL_INFTIM 0
+
+/* Define to 1 if you have the declaration of `optreset', and to 0 if you
+ don't. */
+#define HAVE_DECL_OPTRESET 0
+
+/* Define to 1 if you have the declaration of `O_BINARY', and to 0 if you
+ don't. */
+#define HAVE_DECL_O_BINARY 0
+
+/* Define to 1 if you have the declaration of `O_EXLOCK', and to 0 if you
+ don't. */
+#define HAVE_DECL_O_EXLOCK 0
+
+/* Define to 1 if you have the declaration of `SO_PEERCRED', and to 0 if you
+ don't. */
+#define HAVE_DECL_SO_PEERCRED 1
+
+/* Define to 1 if you have the declaration of `XATTR_NOFOLLOW', and to 0 if
+ you don't. */
+#define HAVE_DECL_XATTR_NOFOLLOW 0
+
+/* Define to 1 if #define of pragmas works */
+/* #undef HAVE_DEFINE_PRAGMA */
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <editline/readline.h> header file. */
+#define HAVE_EDITLINE_READLINE_H 1
+
+/* define if the compiler supports exceptions */
+#define HAVE_EXCEPTIONS
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#define HAVE_EXECINFO_H 1
+
+/* Define to 1 if you have the `flock' function. */
+#define HAVE_FLOCK 1
+
+/* Define to 1 if you have the `getmntent' function. */
+#define HAVE_GETMNTENT 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getpeereid' function. */
+/* #undef HAVE_GETPEEREID */
+
+/* Define to 1 if you have the `getpid' function. */
+#define HAVE_GETPID 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `getxattr' function. */
+#define HAVE_GETXATTR 1
+
+/* Define to 1 if you have the <history.h> header file. */
+/* #undef HAVE_HISTORY_H */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if large files are supported */
+#define HAVE_LARGE_FILE_SUPPORT 1
+
+/* Define to 1 if you have the `lchown' function. */
+#define HAVE_LCHOWN 1
+
+/* Define to 1 if you have the `lgetxattr' function. */
+#define HAVE_LGETXATTR 1
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#define HAVE_LIBCRYPTO 1
+
+/* Define if you have a readline compatible library */
+#define HAVE_LIBREADLINE 1
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#define HAVE_LIBSSL 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the `listxattr' function. */
+#define HAVE_LISTXATTR 1
+
+/* Define to 1 if you have the `llistxattr' function. */
+#define HAVE_LLISTXATTR 1
+
+/* Define to 1 if syscall lseek requires a dummy middle parameter */
+/* #undef HAVE_LSEEK_DUMMY_PARAM */
+
+/* Define to 1 if you have the `lsetxattr' function. */
+#define HAVE_LSETXATTR 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <mntent.h> header file. */
+#define HAVE_MNTENT_H 1
+
+/* Define to 1 if this platform supports mounts */
+#define HAVE_MOUNTS 1
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if SSL is pre-0.9.7 */
+/* #undef HAVE_OLD_SSL */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#define HAVE_OPENSSL_SSL_H 1
+
+/* Define to 1 if pcreposix.h is available */
+/* #undef HAVE_PCREPOSIX_H */
+
+/* Define to 1 if you have the <process.h> header file. */
+/* #undef HAVE_PROCESS_H */
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 (and set RANDOM_DEVICE) if a random device is available */
+#define HAVE_RANDOM_DEVICE 1
+
+/* Define to 1 if you have the <readline.h> header file. */
+/* #undef HAVE_READLINE_H */
+
+/* Define if your readline library has add_history */
+#define HAVE_READLINE_HISTORY 1
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+/* #undef HAVE_READLINE_HISTORY_H */
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+/* #undef HAVE_READLINE_READLINE_H */
+
+/* Define to 1 if regex.h is available */
+#define HAVE_REGEX_H 1
+
+/* Define to 1 if regular expressions are supported */
+#define HAVE_REGEX_SUPPORT 1
+
+/* Define to 1 if you have the `setproctitle' function. */
+/* #undef HAVE_SETPROCTITLE */
+
+/* Define to 1 if you have the `setxattr' function. */
+#define HAVE_SETXATTR 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if SSL is available */
+#define HAVE_SSL 1
+
+/* Define to 1 if you have the `statfs' function. */
+#define HAVE_STATFS 1
+
+/* Define to 1 if `stat' has the bug that it succeeds when given the
+ zero-length file name argument. */
+/* #undef HAVE_STAT_EMPTY_STRING_BUG */
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if `d_ino' is member of `struct dirent'. */
+#define HAVE_STRUCT_DIRENT_D_INO 1
+
+/* Define to 1 if `d_type' is member of `struct dirent'. */
+#define HAVE_STRUCT_DIRENT_D_TYPE 1
+
+/* Define to 1 if `mnt_dir' is member of `struct mntent'. */
+#define HAVE_STRUCT_MNTENT_MNT_DIR 1
+
+/* Define to 1 if `mnt_mountp' is member of `struct mnttab'. */
+/* #undef HAVE_STRUCT_MNTTAB_MNT_MOUNTP */
+
+/* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */
+/* #undef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+
+/* Define to 1 if `f_mntonname' is member of `struct statfs'. */
+/* #undef HAVE_STRUCT_STATFS_F_MNTONNAME */
+
+/* Define to 1 if `f_mntonname' is member of `struct statvfs'. */
+/* #undef HAVE_STRUCT_STATVFS_F_MNTONNAME */
+
+/* Define to 1 if `st_flags' is member of `struct stat'. */
+/* #undef HAVE_STRUCT_STAT_ST_FLAGS */
+
+/* Define to 1 if `st_mtimespec' is member of `struct stat'. */
+/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC */
+
+/* Define to 1 if you have the `syscall' function. */
+#define HAVE_SYSCALL 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define to 1 if you have the <sys/endian.h> header file. */
+/* #undef HAVE_SYS_ENDIAN_H */
+
+/* Define to 1 if you have the <sys/mnttab.h> header file. */
+/* #undef HAVE_SYS_MNTTAB_H */
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#define HAVE_SYS_MOUNT_H 1
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#define HAVE_SYS_SYSCALL_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <sys/xattr.h> header file. */
+#define HAVE_SYS_XATTR_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the system has the type `u_int16_t'. */
+#define HAVE_U_INT16_T 1
+
+/* Define to 1 if the system has the type `u_int32_t'. */
+#define HAVE_U_INT32_T 1
+
+/* Define to 1 if the system has the type `u_int64_t'. */
+#define HAVE_U_INT64_T 1
+
+/* Define to 1 if the system has the type `u_int8_t'. */
+#define HAVE_U_INT8_T 1
+
+/* Define to 1 if struct dirent.d_type is valid */
+/* #undef HAVE_VALID_DIRENT_D_TYPE */
+
+/* Define to 1 if the system has the type `_Bool'. */
+/* #undef HAVE__BOOL */
+
+/* Define to 1 if you have the `__syscall' function. */
+/* #undef HAVE___SYSCALL */
+
+/* Define to 1 if __syscall is available but needs a definition */
+/* #undef HAVE___SYSCALL_NEED_DEFN */
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "box@fluffy.co.uk"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "Box Backup"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "Box Backup 0.10"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "box-backup"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.10"
+
+/* Location of the perl executable */
+#define PERL_EXECUTABLE "/usr/bin/perl"
+
+/* Define to the filename of the random device (and set HAVE_RANDOM_DEVICE) */
+#define RANDOM_DEVICE "/dev/urandom"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* TMP directory name */
+#define TEMP_DIRECTORY_NAME "/tmp"
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#define _FILE_OFFSET_BITS 64
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if __USE_MALLOC is required work around STL memory leaks */
+/* #undef __USE_MALLOC */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef mode_t */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
diff --git a/lib/common/BoxConfig.h.in b/lib/common/BoxConfig.h.in
index 5e84c065..41568ea8 100644
--- a/lib/common/BoxConfig.h.in
+++ b/lib/common/BoxConfig.h.in
@@ -34,6 +34,10 @@
/* Define to 1 if you have the <db.h> header file. */
#undef HAVE_DB_H
+/* Define to 1 if you have the declaration of `dirfd', and to 0 if you don't.
+ */
+#undef HAVE_DECL_DIRFD
+
/* Define to 1 if you have the declaration of `F_SETLK', and to 0 if you
don't. */
#undef HAVE_DECL_F_SETLK
@@ -42,6 +46,14 @@
*/
#undef HAVE_DECL_INFTIM
+/* Define to 1 if you have the declaration of `optreset', and to 0 if you
+ don't. */
+#undef HAVE_DECL_OPTRESET
+
+/* Define to 1 if you have the declaration of `O_BINARY', and to 0 if you
+ don't. */
+#undef HAVE_DECL_O_BINARY
+
/* Define to 1 if you have the declaration of `O_EXLOCK', and to 0 if you
don't. */
#undef HAVE_DECL_O_EXLOCK
@@ -61,6 +73,9 @@
*/
#undef HAVE_DIRENT_H
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
/* Define to 1 if you have the <editline/readline.h> header file. */
#undef HAVE_EDITLINE_READLINE_H
@@ -76,12 +91,18 @@
/* Define to 1 if you have the `getmntent' function. */
#undef HAVE_GETMNTENT
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
/* Define to 1 if you have the `getpeereid' function. */
#undef HAVE_GETPEEREID
/* Define to 1 if you have the `getpid' function. */
#undef HAVE_GETPID
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
/* Define to 1 if you have the `getxattr' function. */
#undef HAVE_GETXATTR
@@ -94,6 +115,9 @@
/* Define to 1 if you have the `kqueue' function. */
#undef HAVE_KQUEUE
+/* Define to 1 if large files are supported */
+#undef HAVE_LARGE_FILE_SUPPORT
+
/* Define to 1 if you have the `lchown' function. */
#undef HAVE_LCHOWN
@@ -148,6 +172,9 @@
/* Define to 1 if you have the <openssl/ssl.h> header file. */
#undef HAVE_OPENSSL_SSL_H
+/* Define to 1 if pcreposix.h is available */
+#undef HAVE_PCREPOSIX_H
+
/* Define to 1 if you have the <process.h> header file. */
#undef HAVE_PROCESS_H
@@ -169,9 +196,12 @@
/* Define to 1 if you have the <readline/readline.h> header file. */
#undef HAVE_READLINE_READLINE_H
-/* Define to 1 if you have the <regex.h> header file. */
+/* Define to 1 if regex.h is available */
#undef HAVE_REGEX_H
+/* Define to 1 if regular expressions are supported */
+#undef HAVE_REGEX_SUPPORT
+
/* Define to 1 if you have the `setproctitle' function. */
#undef HAVE_SETPROCTITLE
@@ -206,6 +236,9 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
+/* Define to 1 if `d_ino' is member of `struct dirent'. */
+#undef HAVE_STRUCT_DIRENT_D_INO
+
/* Define to 1 if `d_type' is member of `struct dirent'. */
#undef HAVE_STRUCT_DIRENT_D_TYPE
@@ -271,6 +304,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
/* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H
@@ -319,12 +355,6 @@
/* Define to 1 if __syscall is available but needs a definition */
#undef HAVE___SYSCALL_NEED_DEFN
-/* max value of long long calculated by configure */
-#undef LLONG_MAX
-
-/* min value of long long calculated by configure */
-#undef LLONG_MIN
-
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
@@ -344,6 +374,9 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
+/* Location of the perl executable */
+#undef PERL_EXECUTABLE
+
/* Define to the filename of the random device (and set HAVE_RANDOM_DEVICE) */
#undef RANDOM_DEVICE
diff --git a/lib/common/BoxException.cpp b/lib/common/BoxException.cpp
index 3e897f1b..bf38fb1b 100644
--- a/lib/common/BoxException.cpp
+++ b/lib/common/BoxException.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/common/BoxException.h b/lib/common/BoxException.h
index 00ba77d4..4a5fbd24 100644
--- a/lib/common/BoxException.h
+++ b/lib/common/BoxException.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/common/BoxPlatform.h b/lib/common/BoxPlatform.h
index e3af29ff..1c94cf73 100644
--- a/lib/common/BoxPlatform.h
+++ b/lib/common/BoxPlatform.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.
@@ -59,7 +59,12 @@
#define PLATFORM_DEV_NULL "/dev/null"
+#ifdef _MSC_VER
+#include "BoxConfig-MSVC.h"
+#include "BoxVersion.h"
+#else
#include "BoxConfig.h"
+#endif
#ifdef WIN32
// need msvcrt version 6.1 or higher for _gmtime64()
@@ -78,8 +83,8 @@
#endif
#endif
-// Slight hack; disable interception on Darwin within raidfile test
-#ifdef __APPLE__
+// Slight hack; disable interception in raidfile test on Darwin and Windows
+#if defined __APPLE__ || defined WIN32
// TODO: Replace with autoconf test
#define PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
#endif
@@ -90,6 +95,14 @@
#define PLATFORM_DISABLE_MEM_LEAK_TESTING
#endif
+// Darwin also has a weird idea of permissions and dates on symlinks:
+// perms are fixed at creation time by your umask, and dates can't be
+// changed. This breaks unit tests if we try to compare these things.
+// See: http://lists.apple.com/archives/darwin-kernel/2006/Dec/msg00057.html
+#ifdef __APPLE__
+ #define PLATFORM_DISABLE_SYMLINK_ATTRIB_COMPARE
+#endif
+
// Find out if credentials on UNIX sockets can be obtained
#ifndef HAVE_GETPEEREID
#if !HAVE_DECL_SO_PEERCRED
@@ -135,8 +148,6 @@
#define HAVE_U_INT16_T
#define HAVE_U_INT32_T
#define HAVE_U_INT64_T
-
- typedef int pid_t;
#endif // WIN32 && !__MINGW32__
// Define missing types
@@ -176,6 +187,11 @@
#define INFTIM -1
#endif
+// for Unix compatibility with Windows :-)
+#if !HAVE_DECL_O_BINARY
+ #define O_BINARY 0
+#endif
+
#ifdef WIN32
typedef u_int64_t InodeRefType;
#else
@@ -187,4 +203,12 @@
#include "emu.h"
#endif
+// Solaris has no dirfd(x) macro or function, and we need one.
+// We cannot define macros with arguments directly using AC_DEFINE,
+// so do it here instead of in configure.ac.
+
+#ifndef HAVE_DECL_DIRFD
+ #define dirfd(x) (x)->d_fd
+#endif
+
#endif // BOXPLATFORM__H
diff --git a/lib/common/BoxPortsAndFiles.h b/lib/common/BoxPortsAndFiles.h
index 0f16fb77..6d734638 100644
--- a/lib/common/BoxPortsAndFiles.h
+++ b/lib/common/BoxPortsAndFiles.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,23 +52,27 @@
// Backup store daemon
-#define BOX_PORT_BBSTORED (BOX_PORT_BASE+1)
-#define BOX_FILE_BBSTORED_DEFAULT_CONFIG "/etc/box/bbstored.conf"
+#define BOX_PORT_BBSTORED (BOX_PORT_BASE+1)
+
// directory within the RAIDFILE root for the backup store daemon
-#define BOX_RAIDFILE_ROOT_BBSTORED "backup"
+#define BOX_RAIDFILE_ROOT_BBSTORED "backup"
-// Backup client daemon
+// configuration file paths
#ifdef WIN32
-#define BOX_FILE_BBACKUPD_DEFAULT_CONFIG "C:\\Program Files\\Box Backup\\bbackupd.conf"
+ // no default config file path, use these macros to call
+ // GetDefaultConfigFilePath() instead.
+
+ #define BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE \
+ GetDefaultConfigFilePath("bbackupd.conf").c_str()
+ #define BOX_GET_DEFAULT_RAIDFILE_CONFIG_FILE \
+ GetDefaultConfigFilePath("raidfile.conf").c_str()
+ #define BOX_GET_DEFAULT_BBSTORED_CONFIG_FILE \
+ GetDefaultConfigFilePath("bbstored.conf").c_str()
#else
#define BOX_FILE_BBACKUPD_DEFAULT_CONFIG "/etc/box/bbackupd.conf"
-#endif
-
-// RaidFile conf location default
#define BOX_FILE_RAIDFILE_DEFAULT_CONFIG "/etc/box/raidfile.conf"
-
-// Default name of the named pipe
-#define BOX_NAMED_PIPE_NAME L"\\\\.\\pipe\\boxbackup"
+#define BOX_FILE_BBSTORED_DEFAULT_CONFIG "/etc/box/bbstored.conf"
+#endif
#endif // BOXPORTSANDFILES__H
diff --git a/lib/common/BoxTime.cpp b/lib/common/BoxTime.cpp
index 7c858f0d..21f2f9b0 100644
--- a/lib/common/BoxTime.cpp
+++ b/lib/common/BoxTime.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,16 @@
#include "Box.h"
-#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+ #include <sys/time.h>
+#endif
+
+#ifdef HAVE_TIME_H
+ #include <time.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
#include "BoxTime.h"
@@ -57,13 +66,27 @@
//
// Function
// Name: GetCurrentBoxTime()
-// Purpose: Returns the current time as a box time. (1 sec precision)
+// Purpose: Returns the current time as a box time.
+// (1 sec precision, or better if supported by system)
// Created: 2003/10/08
//
// --------------------------------------------------------------------------
box_time_t GetCurrentBoxTime()
{
+ #ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) != 0)
+ {
+ BOX_ERROR("Failed to gettimeofday(), dropping "
+ "precision: " << strerror(errno));
+ }
+ else
+ {
+ box_time_t timeNow = (tv.tv_sec * MICRO_SEC_IN_SEC_LL)
+ + tv.tv_usec;
+ return timeNow;
+ }
+ #endif
+
return SecondsToBoxTime(time(0));
}
-
-
diff --git a/lib/common/BoxTime.h b/lib/common/BoxTime.h
index 880985ca..21896276 100644
--- a/lib/common/BoxTime.h
+++ b/lib/common/BoxTime.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.
@@ -73,6 +73,9 @@ inline uint64_t BoxTimeToMilliSeconds(box_time_t Time)
{
return Time / MILLI_SEC_IN_NANO_SEC_LL;
}
+inline uint64_t BoxTimeToMicroSeconds(box_time_t Time)
+{
+ return Time;
+}
#endif // BOXTIME__H
-
diff --git a/lib/common/BoxTimeToText.cpp b/lib/common/BoxTimeToText.cpp
index 7997376b..c212297c 100644
--- a/lib/common/BoxTimeToText.cpp
+++ b/lib/common/BoxTimeToText.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.
@@ -58,23 +58,31 @@
// --------------------------------------------------------------------------
//
// Function
-// Name: BoxTimeToISO8601String(box_time_t)
-// Purpose: Convert a 64 bit box time to a ISO 8601 complient string
+// Name: BoxTimeToISO8601String(box_time_t, bool)
+// Purpose: Convert a 64 bit box time to a ISO 8601 compliant
+// string, either in local or UTC time
// Created: 2003/10/10
//
// --------------------------------------------------------------------------
-std::string BoxTimeToISO8601String(box_time_t Time)
+std::string BoxTimeToISO8601String(box_time_t Time, bool localTime)
{
+ time_t timeInSecs = BoxTimeToSeconds(Time);
+ char str[128]; // more than enough space
+
#ifdef WIN32
struct tm *time;
- time_t bob = BoxTimeToSeconds(Time);
+ __time64_t winTime = timeInSecs;
- __time64_t winTime = bob;
+ if(localTime)
+ {
+ time = _localtime64(&winTime);
+ }
+ else
+ {
+ time = _gmtime64(&winTime);
+ }
- time = _gmtime64(&winTime);
- char str[128]; // more than enough space
-
- if ( time == NULL )
+ if(time == NULL)
{
// ::sprintf(str, "%016I64x ", bob);
return std::string("unable to convert time");
@@ -84,11 +92,17 @@ std::string BoxTimeToISO8601String(box_time_t Time)
time->tm_mon + 1, time->tm_mday, time->tm_hour,
time->tm_min, time->tm_sec);
#else // ! WIN32
- time_t timeInSecs = BoxTimeToSeconds(Time);
struct tm time;
- gmtime_r(&timeInSecs, &time);
+
+ if(localTime)
+ {
+ localtime_r(&timeInSecs, &time);
+ }
+ else
+ {
+ gmtime_r(&timeInSecs, &time);
+ }
- char str[128]; // more than enough space
sprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d", time.tm_year + 1900,
time.tm_mon + 1, time.tm_mday, time.tm_hour,
time.tm_min, time.tm_sec);
diff --git a/lib/common/BoxTimeToText.h b/lib/common/BoxTimeToText.h
index ce017c1d..9818ecb8 100644
--- a/lib/common/BoxTimeToText.h
+++ b/lib/common/BoxTimeToText.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.
@@ -51,7 +51,7 @@
#include <string>
#include "BoxTime.h"
-std::string BoxTimeToISO8601String(box_time_t Time);
+std::string BoxTimeToISO8601String(box_time_t Time, bool localTime);
#endif // BOXTIMETOTEXT__H
diff --git a/lib/common/BoxTimeToUnix.h b/lib/common/BoxTimeToUnix.h
index 0a4bdcad..4b644829 100644
--- a/lib/common/BoxTimeToUnix.h
+++ b/lib/common/BoxTimeToUnix.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/common/BufferedStream.cpp b/lib/common/BufferedStream.cpp
new file mode 100644
index 00000000..edf7122c
--- /dev/null
+++ b/lib/common/BufferedStream.cpp
@@ -0,0 +1,245 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BufferedStream.cpp
+// Purpose: Buffering wrapper around IOStreams
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "BufferedStream.h"
+#include "CommonException.h"
+
+#include <string.h>
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::BufferedStream(const char *, int, int)
+// Purpose: Constructor, set up buffer
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+BufferedStream::BufferedStream(IOStream& rSource)
+: mrSource(rSource), mBufferSize(0), mBufferPosition(0)
+{ }
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::Read(void *, int)
+// Purpose: Reads bytes from the file
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+int BufferedStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ if (mBufferSize == mBufferPosition)
+ {
+ // buffer is empty, fill it.
+
+ int numBytesRead = mrSource.Read(mBuffer, sizeof(mBuffer),
+ Timeout);
+
+ if (numBytesRead < 0)
+ {
+ return numBytesRead;
+ }
+
+ mBufferSize = numBytesRead;
+ }
+
+ int sizeToReturn = mBufferSize - mBufferPosition;
+
+ if (sizeToReturn > NBytes)
+ {
+ sizeToReturn = NBytes;
+ }
+
+ memcpy(pBuffer, mBuffer + mBufferPosition, sizeToReturn);
+ mBufferPosition += sizeToReturn;
+
+ if (mBufferPosition == mBufferSize)
+ {
+ // clear out the buffer
+ mBufferSize = 0;
+ mBufferPosition = 0;
+ }
+
+ return sizeToReturn;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::BytesLeftToRead()
+// Purpose: Returns number of bytes to read (may not be most efficient function ever)
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type BufferedStream::BytesLeftToRead()
+{
+ return mrSource.BytesLeftToRead() + mBufferSize - mBufferPosition;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::Write(void *, int)
+// Purpose: Writes bytes to the underlying stream (not supported)
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void BufferedStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(CommonException, NotSupported);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::GetPosition()
+// Purpose: Get position in stream
+// Created: 2003/08/21
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type BufferedStream::GetPosition() const
+{
+ return mrSource.GetPosition() - mBufferSize + mBufferPosition;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::Seek(pos_type, int)
+// Purpose: Seeks within file, as lseek, invalidate buffer
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void BufferedStream::Seek(IOStream::pos_type Offset, int SeekType)
+{
+ switch (SeekType)
+ {
+ case SeekType_Absolute:
+ {
+ // just go there
+ mrSource.Seek(Offset, SeekType);
+ }
+ break;
+
+ case SeekType_Relative:
+ {
+ // Actual underlying file position is
+ // (mBufferSize - mBufferPosition) ahead of us.
+ // Need to subtract that amount from the seek
+ // to seek forward that much less, putting the
+ // real pointer in the right place.
+ mrSource.Seek(Offset - mBufferSize + mBufferPosition,
+ SeekType);
+ }
+ break;
+
+ case SeekType_End:
+ {
+ // Actual underlying file position is
+ // (mBufferSize - mBufferPosition) ahead of us.
+ // Need to add that amount to the seek
+ // to seek backwards that much more, putting the
+ // real pointer in the right place.
+ mrSource.Seek(Offset + mBufferSize - mBufferPosition,
+ SeekType);
+ }
+ }
+
+ // always clear the buffer for now (may be slightly wasteful)
+ mBufferSize = 0;
+ mBufferPosition = 0;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::Close()
+// Purpose: Closes the underlying stream (not needed)
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void BufferedStream::Close()
+{
+ THROW_EXCEPTION(CommonException, NotSupported);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::StreamDataLeft()
+// Purpose: Any data left to write?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool BufferedStream::StreamDataLeft()
+{
+ return mrSource.StreamDataLeft();
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BufferedStream::StreamClosed()
+// Purpose: Is the stream closed?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool BufferedStream::StreamClosed()
+{
+ return mrSource.StreamClosed();
+}
+
diff --git a/lib/common/BufferedStream.h b/lib/common/BufferedStream.h
new file mode 100644
index 00000000..38df4316
--- /dev/null
+++ b/lib/common/BufferedStream.h
@@ -0,0 +1,81 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BufferedStream.h
+// Purpose: Buffering wrapper around IOStreams
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+
+#ifndef BUFFEREDSTREAM__H
+#define BUFFEREDSTREAM__H
+
+#include "IOStream.h"
+
+class BufferedStream : public IOStream
+{
+private:
+ IOStream& mrSource;
+ char mBuffer[4096];
+ int mBufferSize;
+ int mBufferPosition;
+
+public:
+ BufferedStream(IOStream& rSource);
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual pos_type GetPosition() const;
+ virtual void Seek(IOStream::pos_type Offset, int SeekType);
+ virtual void Close();
+
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+private:
+ BufferedStream(const BufferedStream &rToCopy)
+ : mrSource(rToCopy.mrSource) { /* do not call */ }
+};
+
+#endif // BUFFEREDSTREAM__H
+
+
diff --git a/lib/common/CollectInBufferStream.cpp b/lib/common/CollectInBufferStream.cpp
index 93cba893..fe3a77a6 100644
--- a/lib/common/CollectInBufferStream.cpp
+++ b/lib/common/CollectInBufferStream.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/common/CollectInBufferStream.h b/lib/common/CollectInBufferStream.h
index 90f6889b..5bebd12d 100644
--- a/lib/common/CollectInBufferStream.h
+++ b/lib/common/CollectInBufferStream.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/common/CommonException.h b/lib/common/CommonException.h
index 61bd654a..65f98962 100644
--- a/lib/common/CommonException.h
+++ b/lib/common/CommonException.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/common/CommonException.txt b/lib/common/CommonException.txt
index 5fa443d0..b2819886 100644
--- a/lib/common/CommonException.txt
+++ b/lib/common/CommonException.txt
@@ -44,3 +44,4 @@ KQueueNotSupportedOnThisPlatform 36
IOStreamGetLineNotEnoughDataToIgnore 37 Bad value passed to IOStreamGetLine::IgnoreBufferedData()
TempDirPathTooLong 38 Your temporary directory path is too long. Check the TMP and TEMP environment variables.
ArchiveBlockIncompleteRead 39 The Store Object Info File is too short or corrupted, and will be rewritten automatically when the next backup completes.
+AccessDenied 40 Access to the file or directory was denied. Please check the permissions.
diff --git a/lib/common/Configuration.cpp b/lib/common/Configuration.cpp
index a766434d..3ac0a354 100644
--- a/lib/common/Configuration.cpp
+++ b/lib/common/Configuration.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.
@@ -121,19 +121,16 @@ Configuration::~Configuration()
// Created: 2003/07/23
//
// --------------------------------------------------------------------------
-std::auto_ptr<Configuration> Configuration::LoadAndVerify(const char *Filename, const ConfigurationVerify *pVerify, std::string &rErrorMsg)
+std::auto_ptr<Configuration> Configuration::LoadAndVerify(
+ const std::string& rFilename,
+ const ConfigurationVerify *pVerify,
+ std::string &rErrorMsg)
{
- // Check arguments
- if(Filename == 0)
- {
- THROW_EXCEPTION(CommonException, BadArguments)
- }
-
// Just to make sure
rErrorMsg.erase();
// Open the file
- FileHandleGuard<O_RDONLY> file(Filename);
+ FileHandleGuard<O_RDONLY> file(rFilename);
// GetLine object
FdGetLine getline(file);
@@ -360,6 +357,7 @@ const std::string &Configuration::GetKeyValue(const char *pKeyName) const
if(i == mKeys.end())
{
+ BOX_ERROR("Missing configuration key: " << pKeyName);
THROW_EXCEPTION(CommonException, ConfigNoKey)
}
else
diff --git a/lib/common/Configuration.h b/lib/common/Configuration.h
index 46e1b25b..a64f00e9 100644
--- a/lib/common/Configuration.h
+++ b/lib/common/Configuration.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.
@@ -107,8 +107,15 @@ public:
MultiValueSeparator = '\x01'
};
- static std::auto_ptr<Configuration> LoadAndVerify(const char *Filename, const ConfigurationVerify *pVerify, std::string &rErrorMsg);
- static std::auto_ptr<Configuration> Load(const char *Filename, std::string &rErrorMsg) { return LoadAndVerify(Filename, 0, rErrorMsg); }
+ static std::auto_ptr<Configuration> LoadAndVerify(
+ const std::string& rFilename,
+ const ConfigurationVerify *pVerify,
+ std::string &rErrorMsg);
+
+ static std::auto_ptr<Configuration> Load(
+ const std::string& rFilename,
+ std::string &rErrorMsg)
+ { return LoadAndVerify(rFilename, 0, rErrorMsg); }
bool KeyExists(const char *pKeyName) const;
const std::string &GetKeyValue(const char *pKeyName) const;
diff --git a/lib/common/Conversion.h b/lib/common/Conversion.h
index a233e193..20298d87 100644
--- a/lib/common/Conversion.h
+++ b/lib/common/Conversion.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/common/ConversionString.cpp b/lib/common/ConversionString.cpp
index 6bd5741e..fbb1c9ff 100644
--- a/lib/common/ConversionString.cpp
+++ b/lib/common/ConversionString.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.
@@ -161,7 +161,7 @@ int32_t BoxConvert::_ConvertStringToInt(const char *pString, int Size)
void BoxConvert::_ConvertIntToString(std::string &rTo, int32_t From)
{
char text[64]; // size more than enough
- ::sprintf(text, "%d", From);
+ ::sprintf(text, "%d", (int)From);
rTo = text;
}
diff --git a/lib/common/DebugAssertFailed.cpp b/lib/common/DebugAssertFailed.cpp
index 581c6836..dc1942c5 100644
--- a/lib/common/DebugAssertFailed.cpp
+++ b/lib/common/DebugAssertFailed.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/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp
index 23132557..ff53985f 100644
--- a/lib/common/DebugMemLeakFinder.cpp
+++ b/lib/common/DebugMemLeakFinder.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.
@@ -63,6 +63,9 @@
#include <string.h>
#include <set>
+#include "MemLeakFinder.h"
+
+static bool memleakfinder_initialised = false;
bool memleakfinder_global_enable = false;
typedef struct
@@ -84,6 +87,17 @@ namespace
{
static std::map<void *, MallocBlockInfo> sMallocBlocks;
static std::map<void *, ObjectInfo> sObjectBlocks;
+ static bool sTrackingDataDestroyed = false;
+
+ static class DestructionWatchdog
+ {
+ public:
+ ~DestructionWatchdog()
+ {
+ sTrackingDataDestroyed = true;
+ }
+ }
+ sWatchdog;
static bool sTrackMallocInSection = false;
static std::set<void *> sSectionMallocBlocks;
@@ -93,11 +107,41 @@ namespace
static std::set<void *> sNotLeaks;
void *sNotLeaksPre[1024];
- int sNotLeaksPreNum = 0;
+ size_t sNotLeaksPreNum = 0;
+}
+
+void memleakfinder_init()
+{
+ ASSERT(!memleakfinder_initialised);
+ memleakfinder_initialised = true;
}
+MemLeakSuppressionGuard::MemLeakSuppressionGuard()
+{
+ ASSERT(memleakfinder_global_enable);
+ memleakfinder_global_enable = false;
+}
+
+MemLeakSuppressionGuard::~MemLeakSuppressionGuard()
+{
+ ASSERT(!memleakfinder_global_enable);
+ memleakfinder_global_enable = true;
+}
+
+// these functions may well allocate memory, which we don't want to track.
+static int sInternalAllocDepth = 0;
+
+class InternalAllocGuard
+{
+ public:
+ InternalAllocGuard () { sInternalAllocDepth++; }
+ ~InternalAllocGuard() { sInternalAllocDepth--; }
+};
+
void memleakfinder_malloc_add_block(void *b, size_t size, const char *file, int line)
{
+ InternalAllocGuard guard;
+
if(b != 0)
{
MallocBlockInfo i;
@@ -113,11 +157,13 @@ void memleakfinder_malloc_add_block(void *b, size_t size, const char *file, int
}
}
-
void *memleakfinder_malloc(size_t size, const char *file, int line)
{
+ InternalAllocGuard guard;
+
void *b = ::malloc(size);
if(!memleakfinder_global_enable) return b;
+ if(!memleakfinder_initialised) return b;
memleakfinder_malloc_add_block(b, size, file, line);
@@ -127,7 +173,9 @@ void *memleakfinder_malloc(size_t size, const char *file, int line)
void *memleakfinder_realloc(void *ptr, size_t size)
{
- if(!memleakfinder_global_enable)
+ InternalAllocGuard guard;
+
+ if(!memleakfinder_global_enable || !memleakfinder_initialised)
{
return ::realloc(ptr, size);
}
@@ -171,7 +219,9 @@ void *memleakfinder_realloc(void *ptr, size_t size)
void memleakfinder_free(void *ptr)
{
- if(memleakfinder_global_enable)
+ InternalAllocGuard guard;
+
+ if(memleakfinder_global_enable && memleakfinder_initialised)
{
// Check it's been allocated
std::map<void *, MallocBlockInfo>::iterator i(sMallocBlocks.find(ptr));
@@ -181,7 +231,7 @@ void memleakfinder_free(void *ptr)
}
else
{
- TRACE1("Block %x freed, but not known. Error? Or allocated in startup static allocation?\n", ptr);
+ TRACE1("Block %p freed, but not known. Error? Or allocated in startup static allocation?\n", ptr);
}
if(sTrackMallocInSection)
@@ -198,30 +248,44 @@ void memleakfinder_free(void *ptr)
void memleakfinder_notaleak_insert_pre()
{
+ InternalAllocGuard guard;
+
if(!memleakfinder_global_enable) return;
- for(int l = 0; l < sNotLeaksPreNum; l++)
+ if(!memleakfinder_initialised) return;
+
+ for(size_t l = 0; l < sNotLeaksPreNum; l++)
{
sNotLeaks.insert(sNotLeaksPre[l]);
}
+
sNotLeaksPreNum = 0;
}
bool is_leak(void *ptr)
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
memleakfinder_notaleak_insert_pre();
return sNotLeaks.find(ptr) == sNotLeaks.end();
}
void memleakfinder_notaleak(void *ptr)
{
+ InternalAllocGuard guard;
+
+ ASSERT(!sTrackingDataDestroyed);
+
memleakfinder_notaleak_insert_pre();
- if(memleakfinder_global_enable)
+ if(memleakfinder_global_enable && memleakfinder_initialised)
{
sNotLeaks.insert(ptr);
}
else
{
- sNotLeaksPre[sNotLeaksPreNum++] = ptr;
+ if ( sNotLeaksPreNum <
+ sizeof(sNotLeaksPre)/sizeof(*sNotLeaksPre) )
+ sNotLeaksPre[sNotLeaksPreNum++] = ptr;
}
/* {
std::map<void *, MallocBlockInfo>::iterator i(sMallocBlocks.find(ptr));
@@ -242,6 +306,11 @@ void memleakfinder_notaleak(void *ptr)
// start monitoring a section of code
void memleakfinder_startsectionmonitor()
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
+ ASSERT(!sTrackingDataDestroyed);
+
sTrackMallocInSection = true;
sSectionMallocBlocks.clear();
sTrackObjectsInSection = true;
@@ -251,6 +320,11 @@ void memleakfinder_startsectionmonitor()
// trace all blocks allocated and still allocated since memleakfinder_startsectionmonitor() called
void memleakfinder_traceblocksinsection()
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
+ ASSERT(!sTrackingDataDestroyed);
+
std::set<void *>::iterator s(sSectionMallocBlocks.begin());
for(; s != sSectionMallocBlocks.end(); ++s)
{
@@ -261,17 +335,22 @@ void memleakfinder_traceblocksinsection()
}
else
{
- TRACE4("Block 0x%08p size %d allocated at %s:%d\n", i->first, i->second.size, i->second.file, i->second.line);
+ TRACE4("Block %p size %d allocated at %s:%d\n", i->first, i->second.size, i->second.file, i->second.line);
}
}
for(std::map<void *, ObjectInfo>::const_iterator i(sSectionObjectBlocks.begin()); i != sSectionObjectBlocks.end(); ++i)
{
- TRACE5("Object%s 0x%08p size %d allocated at %s:%d\n", i->second.array?" []":"", i->first, i->second.size, i->second.file, i->second.line);
+ TRACE5("Object%s %p size %d allocated at %s:%d\n", i->second.array?" []":"", i->first, i->second.size, i->second.file, i->second.line);
}
}
int memleakfinder_numleaks()
{
+ InternalAllocGuard guard;
+
+ ASSERT(memleakfinder_initialised);
+ ASSERT(!sTrackingDataDestroyed);
+
int n = 0;
for(std::map<void *, MallocBlockInfo>::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i)
@@ -281,6 +360,7 @@ int memleakfinder_numleaks()
for(std::map<void *, ObjectInfo>::const_iterator i(sObjectBlocks.begin()); i != sObjectBlocks.end(); ++i)
{
+ const ObjectInfo& rInfo = i->second;
if(is_leak(i->first)) ++n;
}
@@ -289,24 +369,32 @@ int memleakfinder_numleaks()
void memleakfinder_reportleaks_file(FILE *file)
{
+ InternalAllocGuard guard;
+
+ ASSERT(!sTrackingDataDestroyed);
+
for(std::map<void *, MallocBlockInfo>::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i)
{
- if(is_leak(i->first)) ::fprintf(file, "Block 0x%08p size %d allocated at %s:%d\n", i->first, i->second.size, i->second.file, i->second.line);
+ if(is_leak(i->first)) ::fprintf(file, "Block 0x%p size %d allocated at %s:%d\n", i->first, i->second.size, i->second.file, i->second.line);
}
for(std::map<void *, ObjectInfo>::const_iterator i(sObjectBlocks.begin()); i != sObjectBlocks.end(); ++i)
{
- if(is_leak(i->first)) ::fprintf(file, "Object%s 0x%08p size %d allocated at %s:%d\n", i->second.array?" []":"", i->first, i->second.size, i->second.file, i->second.line);
+ if(is_leak(i->first)) ::fprintf(file, "Object%s 0x%p size %d allocated at %s:%d\n", i->second.array?" []":"", i->first, i->second.size, i->second.file, i->second.line);
}
}
void memleakfinder_reportleaks()
{
+ InternalAllocGuard guard;
+
// report to stdout
memleakfinder_reportleaks_file(stdout);
}
void memleakfinder_reportleaks_appendfile(const char *filename, const char *markertext)
{
+ InternalAllocGuard guard;
+
FILE *file = ::fopen(filename, "a");
if(file != 0)
{
@@ -324,7 +412,8 @@ void memleakfinder_reportleaks_appendfile(const char *filename, const char *mark
}
else
{
- printf("WARNING: Couldn't open memory leak results file %s for appending\n", filename);
+ BOX_WARNING("Couldn't open memory leak results file " <<
+ filename << " for appending");
}
}
@@ -353,7 +442,11 @@ void memleakfinder_setup_exit_report(const char *filename, const char *markertex
void add_object_block(void *block, size_t size, const char *file, int line, bool array)
{
+ InternalAllocGuard guard;
+
if(!memleakfinder_global_enable) return;
+ if(!memleakfinder_initialised) return;
+ ASSERT(!sTrackingDataDestroyed);
if(block != 0)
{
@@ -373,7 +466,11 @@ void add_object_block(void *block, size_t size, const char *file, int line, bool
void remove_object_block(void *block)
{
+ InternalAllocGuard guard;
+
if(!memleakfinder_global_enable) return;
+ if(!memleakfinder_initialised) return;
+ if(sTrackingDataDestroyed) return;
std::map<void *, ObjectInfo>::iterator i(sObjectBlocks.find(block));
if(i != sObjectBlocks.end())
@@ -393,34 +490,68 @@ void remove_object_block(void *block)
// If it's not in the list, just ignore it, as lots of stuff goes this way...
}
-void *operator new(size_t size, const char *file, int line)
+static void *internal_new(size_t size, const char *file, int line)
{
- void *r = ::malloc(size);
- add_object_block(r, size, file, line, false);
- //TRACE4("new(), %d, %s, %d, %08x\n", size, file, line, r);
+ void *r;
+
+ {
+ InternalAllocGuard guard;
+ r = ::malloc(size);
+ }
+
+ if (sInternalAllocDepth == 0)
+ {
+ InternalAllocGuard guard;
+ add_object_block(r, size, file, line, false);
+ //TRACE4("new(), %d, %s, %d, %08x\n", size, file, line, r);
+ }
+
return r;
}
+void *operator new(size_t size, const char *file, int line)
+{
+ return internal_new(size, file, line);
+}
+
void *operator new[](size_t size, const char *file, int line)
{
- void *r = ::malloc(size);
- add_object_block(r, size, file, line, true);
- //TRACE4("new[](), %d, %s, %d, %08x\n", size, file, line, r);
- return r;
+ return internal_new(size, file, line);
}
-void operator delete[](void *ptr) throw ()
+// where there is no doctor... need to override standard new() too
+// http://www.relisoft.com/book/tech/9new.html
+// disabled because it causes hangs on FC2 in futex() in test/common
+// while reading files. reason unknown.
+/*
+void *operator new(size_t size)
{
+ return internal_new(size, "standard libraries", 0);
+}
+*/
+
+void *operator new[](size_t size)
+{
+ return internal_new(size, "standard libraries", 0);
+}
+
+void internal_delete(void *ptr)
+{
+ InternalAllocGuard guard;
+
::free(ptr);
remove_object_block(ptr);
//TRACE1("delete[]() called, %08x\n", ptr);
}
+void operator delete[](void *ptr) throw ()
+{
+ internal_delete(ptr);
+}
+
void operator delete(void *ptr) throw ()
{
- ::free(ptr);
- remove_object_block(ptr);
- //TRACE1("delete() called, %08x\n", ptr);
+ internal_delete(ptr);
}
#endif // NDEBUG
diff --git a/lib/common/DebugPrintf.cpp b/lib/common/DebugPrintf.cpp
index 30defe98..749001ae 100644
--- a/lib/common/DebugPrintf.cpp
+++ b/lib/common/DebugPrintf.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/common/EndStructPackForWire.h b/lib/common/EndStructPackForWire.h
index 338743b5..67422858 100644
--- a/lib/common/EndStructPackForWire.h
+++ b/lib/common/EndStructPackForWire.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/common/EventWatchFilesystemObject.cpp b/lib/common/EventWatchFilesystemObject.cpp
index 7b7d5fc9..a5cc48e8 100644
--- a/lib/common/EventWatchFilesystemObject.cpp
+++ b/lib/common/EventWatchFilesystemObject.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,6 +47,7 @@
#include "Box.h"
+#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
@@ -55,6 +56,7 @@
#include "EventWatchFilesystemObject.h"
#include "autogen_CommonException.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -75,6 +77,9 @@ EventWatchFilesystemObject::EventWatchFilesystemObject(const char *Filename)
#ifdef HAVE_KQUEUE
if(mDescriptor == -1)
{
+ BOX_ERROR("EventWatchFilesystemObject: "
+ "Failed to open file '" << Filename << "': " <<
+ strerror(errno));
THROW_EXCEPTION(CommonException, OSFileOpenError)
}
#else
diff --git a/lib/common/EventWatchFilesystemObject.h b/lib/common/EventWatchFilesystemObject.h
index d6cb1d4c..38d4f772 100644
--- a/lib/common/EventWatchFilesystemObject.h
+++ b/lib/common/EventWatchFilesystemObject.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/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp
index 17026c6c..70a2243a 100644
--- a/lib/common/ExcludeList.cpp
+++ b/lib/common/ExcludeList.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,8 +47,12 @@
#include "Box.h"
-#ifdef HAVE_REGEX_H
- #include <regex.h>
+#ifdef HAVE_REGEX_SUPPORT
+ #ifdef HAVE_PCREPOSIX_H
+ #include <pcreposix.h>
+ #else
+ #include <regex.h>
+ #endif
#define EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED
#endif
@@ -56,6 +60,7 @@
#include "Utils.h"
#include "Configuration.h"
#include "Archive.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -83,7 +88,7 @@ ExcludeList::ExcludeList()
// --------------------------------------------------------------------------
ExcludeList::~ExcludeList()
{
-#ifdef HAVE_REGEX_H
+#ifdef HAVE_REGEX_SUPPORT
// free regex memory
while(mRegex.size() > 0)
{
@@ -103,6 +108,45 @@ ExcludeList::~ExcludeList()
}
}
+#ifdef WIN32
+std::string ExcludeList::ReplaceSlashesDefinite(const std::string& input) const
+{
+ std::string output = input;
+
+ for (std::string::size_type pos = output.find("/");
+ pos != std::string::npos;
+ pos = output.find("/"))
+ {
+ output.replace(pos, 1, DIRECTORY_SEPARATOR);
+ }
+
+ for (std::string::iterator i = output.begin(); i != output.end(); i++)
+ {
+ *i = tolower(*i);
+ }
+
+ return output;
+}
+
+std::string ExcludeList::ReplaceSlashesRegex(const std::string& input) const
+{
+ std::string output = input;
+
+ for (std::string::size_type pos = output.find("/");
+ pos != std::string::npos;
+ pos = output.find("/"))
+ {
+ output.replace(pos, 1, "\\" DIRECTORY_SEPARATOR);
+ }
+
+ for (std::string::iterator i = output.begin(); i != output.end(); i++)
+ {
+ *i = tolower(*i);
+ }
+
+ return output;
+}
+#endif
// --------------------------------------------------------------------------
//
@@ -126,7 +170,24 @@ void ExcludeList::AddDefiniteEntries(const std::string &rEntries)
{
if(i->size() > 0)
{
- mDefinite.insert(*i);
+ std::string entry = *i;
+
+ // Convert any forward slashes in the string
+ // to backslashes
+
+ #ifdef WIN32
+ entry = ReplaceSlashesDefinite(entry);
+ #endif
+
+ if (entry.size() > 0 && entry[entry.size() - 1] ==
+ DIRECTORY_SEPARATOR_ASCHAR)
+ {
+ BOX_WARNING("Exclude entry ends in path "
+ "separator, will never match: "
+ << entry);
+ }
+
+ mDefinite.insert(entry);
}
}
}
@@ -145,7 +206,7 @@ void ExcludeList::AddDefiniteEntries(const std::string &rEntries)
// --------------------------------------------------------------------------
void ExcludeList::AddRegexEntries(const std::string &rEntries)
{
-#ifdef HAVE_REGEX_H
+#ifdef HAVE_REGEX_SUPPORT
// Split strings up
std::vector<std::string> ens;
@@ -161,16 +222,32 @@ void ExcludeList::AddRegexEntries(const std::string &rEntries)
try
{
+ std::string entry = *i;
+
+ // Convert any forward slashes in the string
+ // to appropriately escaped backslashes
+
+ #ifdef WIN32
+ entry = ReplaceSlashesRegex(entry);
+ #endif
+
// Compile
- if(::regcomp(pregex, i->c_str(), REG_EXTENDED | REG_NOSUB) != 0)
+ int errcode = ::regcomp(pregex, entry.c_str(),
+ REG_EXTENDED | REG_NOSUB);
+
+ if (errcode != 0)
{
+ char buf[1024];
+ regerror(errcode, pregex, buf, sizeof(buf));
+ BOX_ERROR("Invalid regular expression: " <<
+ entry << ": " << buf);
THROW_EXCEPTION(CommonException, BadRegularExpression)
}
// Store in list of regular expressions
mRegex.push_back(pregex);
// Store in list of regular expression string for Serialize
- mRegexStr.push_back(i->c_str());
+ mRegexStr.push_back(entry.c_str());
}
catch(...)
{
@@ -196,10 +273,16 @@ void ExcludeList::AddRegexEntries(const std::string &rEntries)
// --------------------------------------------------------------------------
bool ExcludeList::IsExcluded(const std::string &rTest) const
{
+ std::string test = rTest;
+
+ #ifdef WIN32
+ test = ReplaceSlashesDefinite(test);
+ #endif
+
// Check against the always include list
if(mpAlwaysInclude != 0)
{
- if(mpAlwaysInclude->IsExcluded(rTest))
+ if(mpAlwaysInclude->IsExcluded(test))
{
// Because the "always include" list says it's 'excluded'
// this means it should actually be included.
@@ -208,17 +291,17 @@ bool ExcludeList::IsExcluded(const std::string &rTest) const
}
// Is it in the set of definite entries?
- if(mDefinite.find(rTest) != mDefinite.end())
+ if(mDefinite.find(test) != mDefinite.end())
{
return true;
}
// Check against regular expressions
-#ifdef HAVE_REGEX_H
+#ifdef HAVE_REGEX_SUPPORT
for(std::vector<regex_t *>::const_iterator i(mRegex.begin()); i != mRegex.end(); ++i)
{
// Test against this expression
- if(regexec(*i, rTest.c_str(), 0, 0 /* no match information required */, 0 /* no flags */) == 0)
+ if(regexec(*i, test.c_str(), 0, 0 /* no match information required */, 0 /* no flags */) == 0)
{
// match happened
return true;
@@ -270,7 +353,7 @@ void ExcludeList::Deserialize(Archive & rArchive)
//
mDefinite.clear();
-#ifdef HAVE_REGEX_H
+#ifdef HAVE_REGEX_SUPPORT
// free regex memory
while(mRegex.size() > 0)
{
@@ -311,7 +394,7 @@ void ExcludeList::Deserialize(Archive & rArchive)
//
//
//
-#ifdef HAVE_REGEX_H
+#ifdef HAVE_REGEX_SUPPORT
rArchive.Read(iCount);
if (iCount > 0)
@@ -348,7 +431,7 @@ void ExcludeList::Deserialize(Archive & rArchive)
}
}
}
-#endif // HAVE_REGEX_H
+#endif // HAVE_REGEX_SUPPORT
//
//
@@ -403,7 +486,7 @@ void ExcludeList::Serialize(Archive & rArchive) const
//
//
//
-#ifdef HAVE_REGEX_H
+#ifdef HAVE_REGEX_SUPPORT
// don't even try to save compiled regular expressions,
// use string copies instead.
ASSERT(mRegex.size() == mRegexStr.size());
@@ -416,7 +499,7 @@ void ExcludeList::Serialize(Archive & rArchive) const
{
rArchive.Write(*i);
}
-#endif // HAVE_REGEX_H
+#endif // HAVE_REGEX_SUPPORT
//
//
diff --git a/lib/common/ExcludeList.h b/lib/common/ExcludeList.h
index 1fde3b3f..2f52a212 100644
--- a/lib/common/ExcludeList.h
+++ b/lib/common/ExcludeList.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,7 +88,7 @@ public:
// Mainly for tests
unsigned int SizeOfDefiniteList() const {return mDefinite.size();}
unsigned int SizeOfRegexList() const
-#ifdef HAVE_REGEX_H
+#ifdef HAVE_REGEX_SUPPORT
{return mRegex.size();}
#else
{return 0;}
@@ -96,11 +96,16 @@ public:
private:
std::set<std::string> mDefinite;
-#ifdef HAVE_REGEX_H
+#ifdef HAVE_REGEX_SUPPORT
std::vector<regex_t *> mRegex;
std::vector<std::string> mRegexStr; // save original regular expression string-based source for Serialize
#endif
+#ifdef WIN32
+ std::string ReplaceSlashesDefinite(const std::string& input) const;
+ std::string ReplaceSlashesRegex (const std::string& input) const;
+#endif
+
// For exceptions to the excludes
ExcludeList *mpAlwaysInclude;
};
diff --git a/lib/common/FdGetLine.cpp b/lib/common/FdGetLine.cpp
index 26a4be1f..29016150 100644
--- a/lib/common/FdGetLine.cpp
+++ b/lib/common/FdGetLine.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/common/FdGetLine.h b/lib/common/FdGetLine.h
index efd42fd1..4b608904 100644
--- a/lib/common/FdGetLine.h
+++ b/lib/common/FdGetLine.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,10 @@
#ifdef NDEBUG
#define FDGETLINE_BUFFER_SIZE 1024
+#elif defined WIN32
+ // need enough space for at least one unicode character
+ // in UTF-8 when calling console_read() from bbackupquery
+ #define FDGETLINE_BUFFER_SIZE 5
#else
#define FDGETLINE_BUFFER_SIZE 4
#endif
diff --git a/lib/common/FileModificationTime.h b/lib/common/FileModificationTime.h
index 5d800e8e..174e1be6 100644
--- a/lib/common/FileModificationTime.h
+++ b/lib/common/FileModificationTime.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/common/FileStream.cpp b/lib/common/FileStream.cpp
index 57da9be8..9548ca72 100644
--- a/lib/common/FileStream.cpp
+++ b/lib/common/FileStream.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,9 @@
#include "Box.h"
#include "FileStream.h"
#include "CommonException.h"
+#include "Logging.h"
+
+#include <errno.h>
#include "MemLeakFindOn.h"
@@ -68,13 +71,21 @@ FileStream::FileStream(const char *Filename, int flags, int mode)
mIsEOF(false)
{
#ifdef WIN32
- if(mOSFileHandle == 0)
+ if(mOSFileHandle == INVALID_HANDLE_VALUE)
#else
if(mOSFileHandle < 0)
#endif
{
MEMLEAKFINDER_NOT_A_LEAK(this);
- THROW_EXCEPTION(CommonException, OSFileOpenError)
+
+ if(errno == EACCES)
+ {
+ THROW_EXCEPTION(CommonException, AccessDenied)
+ }
+ else
+ {
+ THROW_EXCEPTION(CommonException, OSFileOpenError)
+ }
}
#ifdef WIN32
this->fileName = Filename;
@@ -85,7 +96,7 @@ FileStream::FileStream(const char *Filename, int flags, int mode)
// --------------------------------------------------------------------------
//
// Function
-// Name: FileStream::FileStream(int)
+// Name: FileStream::FileStream(tOSFileHandle)
// Purpose: Constructor, using existing file descriptor
// Created: 2003/08/28
//
@@ -94,11 +105,19 @@ FileStream::FileStream(tOSFileHandle FileDescriptor)
: mOSFileHandle(FileDescriptor),
mIsEOF(false)
{
+#ifdef WIN32
+ if(mOSFileHandle == INVALID_HANDLE_VALUE)
+#else
if(mOSFileHandle < 0)
+#endif
{
MEMLEAKFINDER_NOT_A_LEAK(this);
+ BOX_ERROR("FileStream: called with invalid file handle");
THROW_EXCEPTION(CommonException, OSFileOpenError)
}
+#ifdef WIN32
+ this->fileName = "HANDLE";
+#endif
}
#if 0
@@ -114,9 +133,14 @@ FileStream::FileStream(const FileStream &rToCopy)
: mOSFileHandle(::dup(rToCopy.mOSFileHandle)),
mIsEOF(rToCopy.mIsEOF)
{
+#ifdef WIN32
+ if(mOSFileHandle == INVALID_HANDLE_VALUE)
+#else
if(mOSFileHandle < 0)
+#endif
{
MEMLEAKFINDER_NOT_A_LEAK(this);
+ BOX_ERROR("FileStream: copying unopened file");
THROW_EXCEPTION(CommonException, OSFileOpenError)
}
}
@@ -168,8 +192,14 @@ int FileStream::Read(void *pBuffer, int NBytes, int Timeout)
{
r = numBytesRead;
}
+ else if (GetLastError() == ERROR_BROKEN_PIPE)
+ {
+ r = 0;
+ }
else
{
+ BOX_ERROR("Failed to read from file: " <<
+ GetErrorMessage(GetLastError()));
r = -1;
}
#else
@@ -233,7 +263,7 @@ void FileStream::Write(const void *pBuffer, int NBytes)
NULL
);
- if ( (res == 0) || (numBytesWritten != NBytes))
+ if ((res == 0) || (numBytesWritten != (DWORD)NBytes))
{
// DWORD err = GetLastError();
THROW_EXCEPTION(CommonException, OSFileWriteError)
@@ -304,7 +334,7 @@ void FileStream::Seek(IOStream::pos_type Offset, int SeekType)
conv.QuadPart = Offset;
DWORD retVal = SetFilePointer(this->mOSFileHandle, conv.LowPart, &conv.HighPart, ConvertSeekTypeToOSWhence(SeekType));
- if ( retVal == INVALID_SET_FILE_POINTER && (GetLastError() != NO_ERROR) )
+ if(retVal == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
{
THROW_EXCEPTION(CommonException, OSFileError)
}
@@ -330,25 +360,22 @@ void FileStream::Seek(IOStream::pos_type Offset, int SeekType)
// --------------------------------------------------------------------------
void FileStream::Close()
{
- if(mOSFileHandle < 0)
+ if(mOSFileHandle == INVALID_FILE)
{
THROW_EXCEPTION(CommonException, FileAlreadyClosed)
}
+
#ifdef WIN32
if(::CloseHandle(mOSFileHandle) == 0)
- {
- THROW_EXCEPTION(CommonException, OSFileCloseError)
- }
- mOSFileHandle = NULL;
- mIsEOF = true;
#else
if(::close(mOSFileHandle) != 0)
+#endif
{
THROW_EXCEPTION(CommonException, OSFileCloseError)
}
- mOSFileHandle = -1;
+
+ mOSFileHandle = INVALID_FILE;
mIsEOF = true;
-#endif
}
diff --git a/lib/common/FileStream.h b/lib/common/FileStream.h
index 0335f691..d7d4f26f 100644
--- a/lib/common/FileStream.h
+++ b/lib/common/FileStream.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.
@@ -59,7 +59,7 @@
#endif
#ifdef WIN32
- #define INVALID_FILE NULL
+ #define INVALID_FILE INVALID_HANDLE_VALUE
typedef HANDLE tOSFileHandle;
#else
#define INVALID_FILE -1
diff --git a/lib/common/Guards.h b/lib/common/Guards.h
index e4c30c9a..a9467f08 100644
--- a/lib/common/Guards.h
+++ b/lib/common/Guards.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.
@@ -53,24 +53,30 @@
#include <unistd.h>
#endif
+#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
+
#include <new>
#include "CommonException.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
-template <int flags = O_RDONLY, int mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)>
+template <int flags = O_RDONLY | O_BINARY, int mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)>
class FileHandleGuard
{
public:
- FileHandleGuard(const char *filename)
- : mOSFileHandle(::open(filename, flags, mode))
+ FileHandleGuard(const std::string& rFilename)
+ : mOSFileHandle(::open(rFilename.c_str(), flags, mode))
{
if(mOSFileHandle < 0)
{
+ BOX_ERROR("FileHandleGuard: failed to open file '" <<
+ rFilename << "': " << strerror(errno));
THROW_EXCEPTION(CommonException, OSFileOpenError)
}
}
diff --git a/lib/common/IOStream.cpp b/lib/common/IOStream.cpp
index 9ad75f85..4a3b66fd 100644
--- a/lib/common/IOStream.cpp
+++ b/lib/common/IOStream.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/common/IOStream.h b/lib/common/IOStream.h
index 8d3c22e7..f05ba5a0 100644
--- a/lib/common/IOStream.h
+++ b/lib/common/IOStream.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/common/IOStreamGetLine.cpp b/lib/common/IOStreamGetLine.cpp
index dd0f66d9..31b3e112 100644
--- a/lib/common/IOStreamGetLine.cpp
+++ b/lib/common/IOStreamGetLine.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/common/IOStreamGetLine.h b/lib/common/IOStreamGetLine.h
index 525fea01..01451320 100644
--- a/lib/common/IOStreamGetLine.h
+++ b/lib/common/IOStreamGetLine.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/common/InvisibleTempFileStream.cpp b/lib/common/InvisibleTempFileStream.cpp
new file mode 100644
index 00000000..2ded2ce7
--- /dev/null
+++ b/lib/common/InvisibleTempFileStream.cpp
@@ -0,0 +1,77 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: InvisibleTempFileStream.cpp
+// Purpose: IOStream interface to temporary files that
+// delete themselves
+// Created: 2006/10/13
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "InvisibleTempFileStream.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: InvisibleTempFileStream::InvisibleTempFileStream
+// (const char *, int, int)
+// Purpose: Constructor, opens invisible file
+// Created: 2006/10/13
+//
+// --------------------------------------------------------------------------
+InvisibleTempFileStream::InvisibleTempFileStream(const char *Filename, int flags, int mode)
+#ifdef WIN32
+ : FileStream(::openfile(Filename, flags | O_TEMPORARY, mode))
+#else
+ : FileStream(::open(Filename, flags, mode))
+#endif
+{
+ #ifndef WIN32
+ if(unlink(Filename) != 0)
+ {
+ MEMLEAKFINDER_NOT_A_LEAK(this);
+ THROW_EXCEPTION(CommonException, OSFileOpenError)
+ }
+ #endif
+}
diff --git a/lib/common/InvisibleTempFileStream.h b/lib/common/InvisibleTempFileStream.h
new file mode 100644
index 00000000..48572755
--- /dev/null
+++ b/lib/common/InvisibleTempFileStream.h
@@ -0,0 +1,73 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: InvisibleTempFileStream.h
+// Purpose: FileStream interface to temporary files that
+// delete themselves
+// Created: 2006/10/13
+//
+// --------------------------------------------------------------------------
+
+#ifndef INVISIBLETEMPFILESTREAM__H
+#define INVISIBLETEMPFILESTREAM__H
+
+#include "FileStream.h"
+
+class InvisibleTempFileStream : public FileStream
+{
+public:
+ InvisibleTempFileStream(const char *Filename,
+#ifdef WIN32
+ int flags = (O_RDONLY | O_BINARY),
+#else
+ int flags = O_RDONLY,
+#endif
+ int mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
+
+private:
+ InvisibleTempFileStream(const InvisibleTempFileStream &rToCopy)
+ : FileStream(INVALID_FILE)
+ { /* do not call */ }
+};
+
+#endif // INVISIBLETEMPFILESTREAM__H
+
+
diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp
new file mode 100644
index 00000000..62c65e4c
--- /dev/null
+++ b/lib/common/Logging.cpp
@@ -0,0 +1,386 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Logging.cpp
+// Purpose: Generic logging core routines implementation
+// Created: 2006/12/16
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <errno.h>
+#include <time.h>
+
+#ifdef HAVE_SYSLOG_H
+ #include <syslog.h>
+#endif
+
+#include "Logging.h"
+
+#include <iomanip>
+
+#include "BoxTime.h"
+
+bool Logging::sLogToSyslog = false;
+bool Logging::sLogToConsole = false;
+bool Logging::sContextSet = false;
+
+std::vector<Logger*> Logging::sLoggers;
+std::string Logging::sContext;
+Console* Logging::spConsole = NULL;
+Syslog* Logging::spSyslog = NULL;
+Log::Level Logging::sGlobalLevel = Log::EVERYTHING;
+Logging Logging::sGlobalLogging; //automatic initialisation
+
+Logging::Logging()
+{
+ ASSERT(!spConsole);
+ ASSERT(!spSyslog);
+ spConsole = new Console();
+ spSyslog = new Syslog();
+ sLogToConsole = true;
+ sLogToSyslog = true;
+}
+
+Logging::~Logging()
+{
+ sLogToConsole = false;
+ sLogToSyslog = false;
+ delete spConsole;
+ delete spSyslog;
+ spConsole = NULL;
+ spSyslog = NULL;
+}
+
+void Logging::ToSyslog(bool enabled)
+{
+ if (!sLogToSyslog && enabled)
+ {
+ Add(spSyslog);
+ }
+
+ if (sLogToSyslog && !enabled)
+ {
+ Remove(spSyslog);
+ }
+
+ sLogToSyslog = enabled;
+}
+
+void Logging::ToConsole(bool enabled)
+{
+ if (!sLogToConsole && enabled)
+ {
+ Add(spConsole);
+ }
+
+ if (sLogToConsole && !enabled)
+ {
+ Remove(spConsole);
+ }
+
+ sLogToConsole = enabled;
+}
+
+void Logging::FilterConsole(Log::Level level)
+{
+ spConsole->Filter(level);
+}
+
+void Logging::FilterSyslog(Log::Level level)
+{
+ spSyslog->Filter(level);
+}
+
+void Logging::Add(Logger* pNewLogger)
+{
+ for (std::vector<Logger*>::iterator i = sLoggers.begin();
+ i != sLoggers.end(); i++)
+ {
+ if (*i == pNewLogger)
+ {
+ return;
+ }
+ }
+
+ sLoggers.insert(sLoggers.begin(), pNewLogger);
+}
+
+void Logging::Remove(Logger* pOldLogger)
+{
+ for (std::vector<Logger*>::iterator i = sLoggers.begin();
+ i != sLoggers.end(); i++)
+ {
+ if (*i == pOldLogger)
+ {
+ sLoggers.erase(i);
+ return;
+ }
+ }
+}
+
+void Logging::Log(Log::Level level, const std::string& rFile,
+ int line, const std::string& rMessage)
+{
+ if (level > sGlobalLevel)
+ {
+ return;
+ }
+
+ std::string newMessage;
+
+ if (sContextSet)
+ {
+ newMessage += "[" + sContext + "] ";
+ }
+
+ newMessage += rMessage;
+
+ for (std::vector<Logger*>::iterator i = sLoggers.begin();
+ i != sLoggers.end(); i++)
+ {
+ bool result = (*i)->Log(level, rFile, line, newMessage);
+ if (!result)
+ {
+ return;
+ }
+ }
+}
+
+void Logging::SetContext(std::string context)
+{
+ sContext = context;
+ sContextSet = true;
+}
+
+void Logging::ClearContext()
+{
+ sContextSet = false;
+}
+
+void Logging::SetProgramName(const std::string& rProgramName)
+{
+ for (std::vector<Logger*>::iterator i = sLoggers.begin();
+ i != sLoggers.end(); i++)
+ {
+ (*i)->SetProgramName(rProgramName);
+ }
+}
+
+Logger::Logger()
+: mCurrentLevel(Log::EVERYTHING)
+{
+ Logging::Add(this);
+}
+
+Logger::~Logger()
+{
+ Logging::Remove(this);
+}
+
+bool Console::sShowTime = false;
+bool Console::sShowTimeMicros = false;
+bool Console::sShowTag = false;
+std::string Console::sTag;
+
+void Console::SetTag(const std::string& rTag)
+{
+ sTag = rTag;
+ sShowTag = true;
+}
+
+void Console::SetShowTime(bool enabled)
+{
+ sShowTime = enabled;
+}
+
+void Console::SetShowTimeMicros(bool enabled)
+{
+ sShowTimeMicros = enabled;
+}
+
+bool Console::Log(Log::Level level, const std::string& rFile,
+ int line, std::string& rMessage)
+{
+ if (level > GetLevel())
+ {
+ return true;
+ }
+
+ FILE* target = stdout;
+
+ if (level <= Log::WARNING)
+ {
+ target = stderr;
+ }
+
+ std::string msg;
+
+ if (sShowTime)
+ {
+ box_time_t time_now = GetCurrentBoxTime();
+ time_t seconds = BoxTimeToSeconds(time_now);
+ int micros = BoxTimeToMicroSeconds(time_now) % MICRO_SEC_IN_SEC;
+
+ struct tm tm_now, *tm_ptr = &tm_now;
+
+ #ifdef WIN32
+ if ((tm_ptr = localtime(&seconds)) != NULL)
+ #else
+ if (localtime_r(&seconds, &tm_now) != NULL)
+ #endif
+ {
+ std::ostringstream buf;
+
+ buf << std::setfill('0') <<
+ std::setw(2) << tm_ptr->tm_hour << ":" <<
+ std::setw(2) << tm_ptr->tm_min << ":" <<
+ std::setw(2) << tm_ptr->tm_sec;
+
+ if (sShowTimeMicros)
+ {
+ buf << "." << std::setw(6) << micros;
+ }
+
+ buf << " ";
+ msg += buf.str();
+ }
+ else
+ {
+ msg += strerror(errno);
+ msg += " ";
+ }
+ }
+
+ if (sShowTag)
+ {
+ msg += "[" + sTag + "] ";
+ }
+
+ if (level <= Log::FATAL)
+ {
+ msg += "FATAL: ";
+ }
+ else if (level <= Log::ERROR)
+ {
+ msg += "ERROR: ";
+ }
+ else if (level <= Log::WARNING)
+ {
+ msg += "WARNING: ";
+ }
+ else if (level <= Log::NOTICE)
+ {
+ msg += "NOTICE: ";
+ }
+
+ msg += rMessage;
+
+ fprintf(target, "%s\n", msg.c_str());
+
+ return true;
+}
+
+bool Syslog::Log(Log::Level level, const std::string& rFile,
+ int line, std::string& rMessage)
+{
+ if (level > GetLevel())
+ {
+ return true;
+ }
+
+ int syslogLevel = LOG_ERR;
+
+ switch(level)
+ {
+ case Log::NOTHING: /* fall through */
+ case Log::FATAL: syslogLevel = LOG_CRIT; break;
+ case Log::ERROR: syslogLevel = LOG_ERR; break;
+ case Log::WARNING: syslogLevel = LOG_WARNING; break;
+ case Log::NOTICE: syslogLevel = LOG_NOTICE; break;
+ case Log::INFO: syslogLevel = LOG_INFO; break;
+ case Log::TRACE: /* fall through */
+ case Log::EVERYTHING: syslogLevel = LOG_DEBUG; break;
+ }
+
+ std::string msg;
+
+ if (level <= Log::FATAL)
+ {
+ msg = "FATAL: ";
+ }
+ else if (level <= Log::ERROR)
+ {
+ msg = "ERROR: ";
+ }
+ else if (level <= Log::WARNING)
+ {
+ msg = "WARNING: ";
+ }
+ else if (level <= Log::NOTICE)
+ {
+ msg = "NOTICE: ";
+ }
+
+ msg += rMessage;
+
+ syslog(syslogLevel, "%s", msg.c_str());
+
+ return true;
+}
+
+Syslog::Syslog()
+{
+ ::openlog("Box Backup", LOG_PID, LOG_LOCAL6);
+}
+
+Syslog::~Syslog()
+{
+ ::closelog();
+}
+
+void Syslog::SetProgramName(const std::string& rProgramName)
+{
+ mName = rProgramName;
+ ::closelog();
+ ::openlog(mName.c_str(), LOG_PID, LOG_LOCAL6);
+}
diff --git a/lib/common/Logging.h b/lib/common/Logging.h
new file mode 100644
index 00000000..3c011b8c
--- /dev/null
+++ b/lib/common/Logging.h
@@ -0,0 +1,241 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Logging.h
+// Purpose: Generic logging core routines declarations and macros
+// Created: 2006/12/16
+//
+// --------------------------------------------------------------------------
+
+#ifndef LOGGING__H
+#define LOGGING__H
+
+#include <iomanip>
+#include <sstream>
+#include <vector>
+
+/*
+#define BOX_LOG(level, stuff) \
+{ \
+ if(Log::sMaxLoggingLevelForAnyOutput >= level) \
+ std::ostringstream line; \
+ line << stuff; \
+ Log::Write(level, __FILE__, __LINE__, line.str()); \
+ } \
+}
+*/
+
+#define BOX_LOG(level, stuff) \
+{ \
+ std::ostringstream line; \
+ line << stuff; \
+ Logging::Log(level, __FILE__, __LINE__, line.str()); \
+}
+
+#define BOX_FATAL(stuff) BOX_LOG(Log::FATAL, stuff)
+#define BOX_ERROR(stuff) BOX_LOG(Log::ERROR, stuff)
+#define BOX_WARNING(stuff) BOX_LOG(Log::WARNING, stuff)
+#define BOX_NOTICE(stuff) BOX_LOG(Log::NOTICE, stuff)
+#define BOX_INFO(stuff) BOX_LOG(Log::INFO, stuff)
+#define BOX_TRACE(stuff) \
+ if (Logging::IsEnabled(Log::TRACE)) \
+ { BOX_LOG(Log::TRACE, stuff) }
+
+#define BOX_FORMAT_ACCOUNT(accno) \
+ std::hex << \
+ std::showbase << \
+ std::internal << \
+ std::setw(10) << \
+ std::setfill('0') << \
+ (accno) << \
+ std::dec
+
+#define BOX_FORMAT_OBJECTID(objectid) \
+ std::hex << \
+ std::showbase << \
+ (objectid) << \
+ std::dec
+
+#undef ERROR
+
+namespace Log
+{
+ enum Level
+ {
+ NOTHING = 1,
+ FATAL,
+ ERROR,
+ WARNING,
+ NOTICE,
+ INFO,
+ TRACE,
+ EVERYTHING
+ };
+}
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: Logger
+// Purpose: Abstract base class for log targets
+// Created: 2006/12/16
+//
+// --------------------------------------------------------------------------
+
+class Logger
+{
+ private:
+ Log::Level mCurrentLevel;
+
+ public:
+ Logger();
+ virtual ~Logger();
+
+ virtual bool Log(Log::Level level, const std::string& rFile,
+ int line, std::string& rMessage) = 0;
+
+ void Filter(Log::Level level)
+ {
+ mCurrentLevel = level;
+ }
+
+ virtual const char* GetType() = 0;
+ Log::Level GetLevel() { return mCurrentLevel; }
+
+ virtual void SetProgramName(const std::string& rProgramName) = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: Console
+// Purpose: Console logging target
+// Created: 2006/12/16
+//
+// --------------------------------------------------------------------------
+
+class Console : public Logger
+{
+ private:
+ static bool sShowTime;
+ static bool sShowTimeMicros;
+ static bool sShowTag;
+ static std::string sTag;
+
+ public:
+ virtual bool Log(Log::Level level, const std::string& rFile,
+ int line, std::string& rMessage);
+ virtual const char* GetType() { return "Console"; }
+ virtual void SetProgramName(const std::string& rProgramName) { }
+
+ static void SetTag(const std::string& rTag);
+ static void SetShowTime(bool enabled);
+ static void SetShowTimeMicros(bool enabled);
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: Syslog
+// Purpose: Syslog (or Windows Event Viewer) logging target
+// Created: 2006/12/16
+//
+// --------------------------------------------------------------------------
+
+class Syslog : public Logger
+{
+ private:
+ std::string mName;
+
+ public:
+ Syslog();
+ virtual ~Syslog();
+
+ virtual bool Log(Log::Level level, const std::string& rFile,
+ int line, std::string& rMessage);
+ virtual const char* GetType() { return "Syslog"; }
+ virtual void SetProgramName(const std::string& rProgramName);
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: Logging
+// Purpose: Static logging helper, keeps track of enabled loggers
+// and distributes log messages to them.
+// Created: 2006/12/16
+//
+// --------------------------------------------------------------------------
+
+class Logging
+{
+ private:
+ static std::vector<Logger*> sLoggers;
+ static bool sLogToSyslog, sLogToConsole;
+ static std::string sContext;
+ static bool sContextSet;
+ static Console* spConsole;
+ static Syslog* spSyslog;
+ static Log::Level sGlobalLevel;
+ static Logging sGlobalLogging;
+
+ public:
+ Logging ();
+ ~Logging();
+ static void ToSyslog (bool enabled);
+ static void ToConsole (bool enabled);
+ static void FilterSyslog (Log::Level level);
+ static void FilterConsole (Log::Level level);
+ static void Add (Logger* pNewLogger);
+ static void Remove (Logger* pOldLogger);
+ static void Log(Log::Level level, const std::string& rFile,
+ int line, const std::string& rMessage);
+ static void SetContext(std::string context);
+ static void ClearContext();
+ static void SetGlobalLevel(Log::Level level) { sGlobalLevel = level; }
+ static bool IsEnabled(Log::Level level)
+ {
+ return (int)sGlobalLevel >= (int)level;
+ }
+ static void SetProgramName(const std::string& rProgramName);
+};
+
+#endif // LOGGING__H
diff --git a/lib/common/MainHelper.h b/lib/common/MainHelper.h
index 72e13ed1..cca2fb82 100644
--- a/lib/common/MainHelper.h
+++ b/lib/common/MainHelper.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 @@
#define MAINHELPER_START \
if(argc == 2 && ::strcmp(argv[1], "--version") == 0) \
{ printf(BOX_VERSION "\n"); return 0; } \
+ MEMLEAKFINDER_INIT \
MEMLEAKFINDER_START \
try {
#define MAINHELPER_END \
diff --git a/lib/common/Makefile.extra b/lib/common/Makefile.extra
index 92e6fbb3..04dd8e71 100644
--- a/lib/common/Makefile.extra
+++ b/lib/common/Makefile.extra
@@ -3,9 +3,9 @@ MAKEEXCEPTION = ../../lib/common/makeexception.pl
# AUTOGEN SEEDING
autogen_CommonException.h autogen_CommonException.cpp: $(MAKEEXCEPTION) CommonException.txt
- perl $(MAKEEXCEPTION) CommonException.txt
+ $(PERL) $(MAKEEXCEPTION) CommonException.txt
# AUTOGEN SEEDING
autogen_ConversionException.h autogen_ConversionException.cpp: $(MAKEEXCEPTION) ConversionException.txt
- perl $(MAKEEXCEPTION) ConversionException.txt
+ $(PERL) $(MAKEEXCEPTION) ConversionException.txt
diff --git a/lib/common/MemBlockStream.cpp b/lib/common/MemBlockStream.cpp
index 99c73779..d4de0e8e 100644
--- a/lib/common/MemBlockStream.cpp
+++ b/lib/common/MemBlockStream.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/common/MemBlockStream.h b/lib/common/MemBlockStream.h
index 7fba6668..7cf60a3b 100644
--- a/lib/common/MemBlockStream.h
+++ b/lib/common/MemBlockStream.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/common/MemLeakFindOff.h b/lib/common/MemLeakFindOff.h
index 60619d45..264084f7 100644
--- a/lib/common/MemLeakFindOff.h
+++ b/lib/common/MemLeakFindOff.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/common/MemLeakFindOn.h b/lib/common/MemLeakFindOn.h
index a1aadaae..3e064752 100644
--- a/lib/common/MemLeakFindOn.h
+++ b/lib/common/MemLeakFindOn.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/common/MemLeakFinder.h b/lib/common/MemLeakFinder.h
index f653dde7..89c46cb9 100644
--- a/lib/common/MemLeakFinder.h
+++ b/lib/common/MemLeakFinder.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.
@@ -48,8 +48,6 @@
#ifndef MEMLEAKFINDER__H
#define MEMLEAKFINDER__H
-#define DEBUG_NEW new(__FILE__,__LINE__)
-
#ifdef MEMLEAKFINDER_FULL_MALLOC_MONITORING
// include stdlib now, to avoid problems with having the macros defined already
#include <stdlib.h>
@@ -58,6 +56,13 @@
// global enable flag
extern bool memleakfinder_global_enable;
+class MemLeakSuppressionGuard
+{
+ public:
+ MemLeakSuppressionGuard();
+ ~MemLeakSuppressionGuard();
+};
+
extern "C"
{
void *memleakfinder_malloc(size_t size, const char *file, int line);
@@ -65,6 +70,8 @@ extern "C"
void memleakfinder_free(void *ptr);
}
+void memleakfinder_init();
+
int memleakfinder_numleaks();
void memleakfinder_reportleaks();
@@ -79,12 +86,9 @@ void memleakfinder_traceblocksinsection();
void memleakfinder_notaleak(void *ptr);
-void *operator new(size_t size, const char *file, int line);
+void *operator new (size_t size, const char *file, int line);
void *operator new[](size_t size, const char *file, int line);
-void operator delete(void *ptr) throw ();
-void operator delete[](void *ptr) throw ();
-
// define the malloc functions now, if required
#ifdef MEMLEAKFINDER_FULL_MALLOC_MONITORING
#define malloc(X) memleakfinder_malloc(X, __FILE__, __LINE__)
@@ -93,6 +97,5 @@ void operator delete[](void *ptr) throw ();
#define MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
#endif
-
#endif // MEMLEAKFINDER__H
diff --git a/lib/common/NamedLock.cpp b/lib/common/NamedLock.cpp
index 632635b8..a844c810 100644
--- a/lib/common/NamedLock.cpp
+++ b/lib/common/NamedLock.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.
@@ -97,7 +97,7 @@ NamedLock::~NamedLock()
// Function
// Name: NamedLock::TryAndGetLock(const char *, int)
// Purpose: Trys to get a lock on the name in the file system.
-// IMPORTANT NOTE: If a file exists with this name, it will be deleted.
+// IMPORTANT NOTE: If a file exists with this name, it will be deleted.
// Created: 2003/08/28
//
// --------------------------------------------------------------------------
@@ -131,6 +131,7 @@ bool NamedLock::TryAndGetLock(const char *Filename, int mode)
int fd = ::open(Filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
if(fd == -1)
{
+ BOX_WARNING("Failed to open lockfile: " << Filename);
THROW_EXCEPTION(CommonException, OSFileError)
}
diff --git a/lib/common/NamedLock.h b/lib/common/NamedLock.h
index 61741499..ab05d4e0 100644
--- a/lib/common/NamedLock.h
+++ b/lib/common/NamedLock.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/common/PartialReadStream.cpp b/lib/common/PartialReadStream.cpp
index 03cd3e50..c0508fd4 100644
--- a/lib/common/PartialReadStream.cpp
+++ b/lib/common/PartialReadStream.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.
@@ -54,13 +54,15 @@
// --------------------------------------------------------------------------
//
// Function
-// Name: PartialReadStream::PartialReadStream(IOStream &, int)
-// Purpose: Constructor, taking another stream and the number of bytes
-// to be read from it.
+// Name: PartialReadStream::PartialReadStream(IOStream &,
+// pos_type)
+// Purpose: Constructor, taking another stream and the number of
+// bytes to be read from it.
// Created: 2003/08/26
//
// --------------------------------------------------------------------------
-PartialReadStream::PartialReadStream(IOStream &rSource, int BytesToRead)
+PartialReadStream::PartialReadStream(IOStream &rSource,
+ pos_type BytesToRead)
: mrSource(rSource),
mBytesLeft(BytesToRead)
{
diff --git a/lib/common/PartialReadStream.h b/lib/common/PartialReadStream.h
index b534d053..6f0e097b 100644
--- a/lib/common/PartialReadStream.h
+++ b/lib/common/PartialReadStream.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.
@@ -61,7 +61,7 @@
class PartialReadStream : public IOStream
{
public:
- PartialReadStream(IOStream &rSource, int BytesToRead);
+ PartialReadStream(IOStream &rSource, pos_type BytesToRead);
~PartialReadStream();
private:
// no copying allowed
@@ -77,7 +77,7 @@ public:
private:
IOStream &mrSource;
- int mBytesLeft;
+ pos_type mBytesLeft;
};
#endif // PARTIALREADSTREAM__H
diff --git a/lib/common/PathUtils.cpp b/lib/common/PathUtils.cpp
new file mode 100644
index 00000000..777be1ad
--- /dev/null
+++ b/lib/common/PathUtils.cpp
@@ -0,0 +1,72 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: PathUtils.cpp
+// Purpose: Platform-independent path manipulation
+// Created: 2007/01/17
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include <string>
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MakeFullPath(const std::string& rDir, const std::string& rFile)
+// Purpose: Combine directory and file name
+// Created: 2006/08/10
+//
+// --------------------------------------------------------------------------
+std::string MakeFullPath(const std::string& rDir, const std::string& rEntry)
+{
+ std::string result(rDir);
+
+ if (result.size() > 0 &&
+ result[result.size()-1] != DIRECTORY_SEPARATOR_ASCHAR)
+ {
+ result += DIRECTORY_SEPARATOR;
+ }
+
+ result += rEntry;
+
+ return result;
+}
diff --git a/lib/common/PathUtils.h b/lib/common/PathUtils.h
new file mode 100644
index 00000000..77e72bd5
--- /dev/null
+++ b/lib/common/PathUtils.h
@@ -0,0 +1,64 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: PathUtils.h
+// Purpose: Platform-independent path manipulation
+// Created: 2007/01/17
+//
+// --------------------------------------------------------------------------
+
+#ifndef PATHUTILS_H
+#define PATHUTILS_H
+
+#include <string>
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MakeFullPath(const std::string& rDir, const std::string& rFile)
+// Purpose: Combine directory and file name
+// Created: 2006/08/10
+//
+// --------------------------------------------------------------------------
+
+std::string MakeFullPath(const std::string& rDir, const std::string& rEntry);
+
+#endif // !PATHUTILS_H
diff --git a/lib/common/ReadGatherStream.cpp b/lib/common/ReadGatherStream.cpp
index 0cadb388..a9bfafc0 100644
--- a/lib/common/ReadGatherStream.cpp
+++ b/lib/common/ReadGatherStream.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.
@@ -97,8 +97,9 @@ ReadGatherStream::~ReadGatherStream()
//
// Function
// Name: ReadGatherStream::AddComponent(IOStream *)
-// Purpose: Add a component to this stream, returning the index of this component
-// in the internal list. Use this with AddBlock()
+// Purpose: Add a component to this stream, returning the index
+// of this component in the internal list. Use this
+// with AddBlock()
// Created: 10/12/03
//
// --------------------------------------------------------------------------
@@ -183,10 +184,10 @@ int ReadGatherStream::Read(void *pBuffer, int NBytes, int Timeout)
if(mPositionInCurrentBlock < mBlocks[mCurrentBlock].mLength)
{
// Read!
- int s = mBlocks[mCurrentBlock].mLength - mPositionInCurrentBlock;
+ pos_type s = mBlocks[mCurrentBlock].mLength - mPositionInCurrentBlock;
if(s > bytesToRead) s = bytesToRead;
- int r = mComponents[mBlocks[mCurrentBlock].mComponent]->Read(buffer, s, Timeout);
+ pos_type r = mComponents[mBlocks[mCurrentBlock].mComponent]->Read(buffer, s, Timeout);
// update variables
mPositionInCurrentBlock += r;
diff --git a/lib/common/ReadGatherStream.h b/lib/common/ReadGatherStream.h
index a3e4b34d..16103a98 100644
--- a/lib/common/ReadGatherStream.h
+++ b/lib/common/ReadGatherStream.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/common/ReadLoggingStream.cpp b/lib/common/ReadLoggingStream.cpp
new file mode 100644
index 00000000..7bf0cc9e
--- /dev/null
+++ b/lib/common/ReadLoggingStream.cpp
@@ -0,0 +1,245 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ReadLoggingStream.cpp
+// Purpose: Buffering wrapper around IOStreams
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <string.h>
+
+#include "ReadLoggingStream.h"
+#include "CommonException.h"
+#include "Logging.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::ReadLoggingStream(const char *, int, int)
+// Purpose: Constructor, set up buffer
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+ReadLoggingStream::ReadLoggingStream(IOStream& rSource)
+: mrSource(rSource),
+ mOffset(0),
+ mLength(mrSource.BytesLeftToRead()),
+ mTotalRead(0),
+ mStartTime(GetCurrentBoxTime())
+{ }
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::Read(void *, int)
+// Purpose: Reads bytes from the file
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+int ReadLoggingStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ int numBytesRead = mrSource.Read(pBuffer, NBytes, Timeout);
+
+ if (numBytesRead > 0)
+ {
+ mTotalRead += numBytesRead;
+ mOffset += numBytesRead;
+ }
+
+ if (mLength >= 0 && mTotalRead > 0)
+ {
+ box_time_t timeNow = GetCurrentBoxTime();
+ box_time_t elapsed = timeNow - mStartTime;
+ box_time_t finish = (elapsed * mLength) / mTotalRead;
+ box_time_t remain = finish - elapsed;
+
+ BOX_TRACE("Read " << numBytesRead << " bytes at " << mOffset <<
+ ", " << (mLength - mOffset) << " remain, eta " <<
+ BoxTimeToSeconds(remain) << "s");
+ }
+ else if (mLength >= 0 && mTotalRead == 0)
+ {
+ BOX_TRACE("Read " << numBytesRead << " bytes at " << mOffset <<
+ ", " << (mLength - mOffset) << " remain");
+ }
+ else
+ {
+ BOX_TRACE("Read " << numBytesRead << " bytes at " << mOffset <<
+ ", unknown bytes remaining");
+ }
+
+ return numBytesRead;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::BytesLeftToRead()
+// Purpose: Returns number of bytes to read (may not be most efficient function ever)
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type ReadLoggingStream::BytesLeftToRead()
+{
+ return mLength - mOffset;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::Write(void *, int)
+// Purpose: Writes bytes to the underlying stream (not supported)
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void ReadLoggingStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(CommonException, NotSupported);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::GetPosition()
+// Purpose: Get position in stream
+// Created: 2003/08/21
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type ReadLoggingStream::GetPosition() const
+{
+ return mOffset;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::Seek(pos_type, int)
+// Purpose: Seeks within file, as lseek, invalidate buffer
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void ReadLoggingStream::Seek(IOStream::pos_type Offset, int SeekType)
+{
+ mrSource.Seek(Offset, SeekType);
+
+ switch (SeekType)
+ {
+ case SeekType_Absolute:
+ {
+ // just go there
+ mOffset = Offset;
+ }
+ break;
+
+ case SeekType_Relative:
+ {
+ // Actual underlying file position is
+ // (mBufferSize - mBufferPosition) ahead of us.
+ // Need to subtract that amount from the seek
+ // to seek forward that much less, putting the
+ // real pointer in the right place.
+ mOffset += Offset;
+ }
+ break;
+
+ case SeekType_End:
+ {
+ // Actual underlying file position is
+ // (mBufferSize - mBufferPosition) ahead of us.
+ // Need to add that amount to the seek
+ // to seek backwards that much more, putting the
+ // real pointer in the right place.
+ mOffset = mLength - Offset;
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::Close()
+// Purpose: Closes the underlying stream (not needed)
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void ReadLoggingStream::Close()
+{
+ THROW_EXCEPTION(CommonException, NotSupported);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::StreamDataLeft()
+// Purpose: Any data left to write?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool ReadLoggingStream::StreamDataLeft()
+{
+ return mrSource.StreamDataLeft();
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadLoggingStream::StreamClosed()
+// Purpose: Is the stream closed?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool ReadLoggingStream::StreamClosed()
+{
+ return mrSource.StreamClosed();
+}
+
diff --git a/lib/common/ReadLoggingStream.h b/lib/common/ReadLoggingStream.h
new file mode 100644
index 00000000..a140de30
--- /dev/null
+++ b/lib/common/ReadLoggingStream.h
@@ -0,0 +1,81 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ReadLoggingStream.h
+// Purpose: Wrapper around IOStreams that logs read progress
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+
+#ifndef READLOGGINGSTREAM__H
+#define READLOGGINGSTREAM__H
+
+#include "IOStream.h"
+#include "BoxTime.h"
+
+class ReadLoggingStream : public IOStream
+{
+private:
+ IOStream& mrSource;
+ IOStream::pos_type mOffset, mLength, mTotalRead;
+ box_time_t mStartTime;
+
+public:
+ ReadLoggingStream(IOStream& rSource);
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual pos_type GetPosition() const;
+ virtual void Seek(IOStream::pos_type Offset, int SeekType);
+ virtual void Close();
+
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+private:
+ ReadLoggingStream(const ReadLoggingStream &rToCopy)
+ : mrSource(rToCopy.mrSource) { /* do not call */ }
+};
+
+#endif // READLOGGINGSTREAM__H
+
+
diff --git a/lib/common/StreamableMemBlock.cpp b/lib/common/StreamableMemBlock.cpp
index 4344eb26..ac7d131f 100644
--- a/lib/common/StreamableMemBlock.cpp
+++ b/lib/common/StreamableMemBlock.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/common/StreamableMemBlock.h b/lib/common/StreamableMemBlock.h
index 78d91f66..c50750cb 100644
--- a/lib/common/StreamableMemBlock.h
+++ b/lib/common/StreamableMemBlock.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/common/TemporaryDirectory.h b/lib/common/TemporaryDirectory.h
index a61982bf..fbc255e1 100644
--- a/lib/common/TemporaryDirectory.h
+++ b/lib/common/TemporaryDirectory.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/common/Test.h b/lib/common/Test.h
index 0cdcabb2..fcac260e 100644
--- a/lib/common/Test.h
+++ b/lib/common/Test.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.
@@ -48,26 +48,58 @@
#ifndef TEST__H
#define TEST__H
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
+#include <errno.h>
#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#include <stdio.h>
-
+#include <string>
+
+#ifdef WIN32
+#define BBACKUPCTL "..\\..\\bin\\bbackupctl\\bbackupctl.exe"
+#define BBACKUPD "..\\..\\bin\\bbackupd\\bbackupd.exe"
+#define BBSTORED "..\\..\\bin\\bbstored\\bbstored.exe"
+#define BBACKUPQUERY "..\\..\\bin\\bbackupquery\\bbackupquery.exe"
+#define BBSTOREACCOUNTS "..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts.exe"
+#define TEST_RETURN(actual, expected) TEST_THAT(actual == expected);
+#else
+#define BBACKUPCTL "../../bin/bbackupctl/bbackupctl"
+#define BBACKUPD "../../bin/bbackupd/bbackupd"
+#define BBSTORED "../../bin/bbstored/bbstored"
+#define BBACKUPQUERY "../../bin/bbackupquery/bbackupquery"
+#define BBSTOREACCOUNTS "../../bin/bbstoreaccounts/bbstoreaccounts"
+#define TEST_RETURN(actual, expected) TEST_THAT(actual == expected*256);
+#endif
+
extern int failures;
+extern int first_fail_line;
+extern std::string first_fail_file;
+extern std::string bbackupd_args, bbstored_args, bbackupquery_args, test_args;
+
+#define TEST_FAIL_WITH_MESSAGE(msg) \
+{ \
+ if (failures == 0) \
+ { \
+ first_fail_file = __FILE__; \
+ first_fail_line = __LINE__; \
+ } \
+ failures++; \
+ printf("FAILURE: " msg " at " __FILE__ "(%d)\n", __LINE__); \
+}
-#define TEST_FAIL_WITH_MESSAGE(msg) {failures++; printf("FAILURE: " msg " at " __FILE__ "(%d)\n", __LINE__);}
-#define TEST_ABORT_WITH_MESSAGE(msg) {failures++; printf("FAILURE: " msg " at " __FILE__ "(%d)\n", __LINE__); return 1;}
+#define TEST_ABORT_WITH_MESSAGE(msg) {TEST_FAIL_WITH_MESSAGE(msg); return 1;}
#define TEST_THAT(condition) {if(!(condition)) TEST_FAIL_WITH_MESSAGE("Condition [" #condition "] failed")}
#define TEST_THAT_ABORTONFAIL(condition) {if(!(condition)) TEST_ABORT_WITH_MESSAGE("Condition [" #condition "] failed")}
-// NOTE: The 0- bit it to allow this to work with stuff which has negative constants for flags (eg ConnectionException)
+// NOTE: The 0- bit is to allow this to work with stuff which has negative constants for flags (eg ConnectionException)
#define TEST_CHECK_THROWS(statement, excepttype, subtype) \
{ \
bool didthrow = false; \
@@ -117,30 +149,74 @@ inline int TestGetFileSize(const char *Filename)
return -1;
}
-inline int LaunchServer(const char *CommandLine, const char *pidFile)
+inline std::string ConvertPaths(const std::string& rOriginal)
{
- if(::system(CommandLine) != 0)
+#ifdef WIN32
+ // convert UNIX paths to native
+
+ std::string converted;
+ for (size_t i = 0; i < rOriginal.size(); i++)
{
- printf("Server: %s\n", CommandLine);
- TEST_FAIL_WITH_MESSAGE("Couldn't start server");
- return -1;
+ if (rOriginal[i] == '/')
+ {
+ converted += '\\';
+ }
+ else
+ {
+ converted += rOriginal[i];
+ }
}
- // time for it to start up
- ::sleep(1);
-
- // read pid file
+ return converted;
+
+#else // !WIN32
+ return rOriginal;
+#endif
+}
+
+inline int RunCommand(const std::string& rCommandLine)
+{
+ return ::system(ConvertPaths(rCommandLine).c_str());
+}
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+inline bool ServerIsAlive(int pid)
+{
+#ifdef WIN32
+ HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid);
+ if (hProcess == NULL)
+ {
+ if (GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ printf("Failed to open process %d: error %d\n",
+ pid, (int)GetLastError());
+ }
+ return false;
+ }
+ CloseHandle(hProcess);
+ return true;
+#else // !WIN32
+ if(pid == 0) return false;
+ return ::kill(pid, 0) != -1;
+#endif // WIN32
+}
+
+inline int ReadPidFile(const char *pidFile)
+{
if(!TestFileExists(pidFile))
{
- printf("Server: %s\n", CommandLine);
- TEST_FAIL_WITH_MESSAGE("Server didn't save PID file");
+ TEST_FAIL_WITH_MESSAGE("Server didn't save PID file "
+ "(perhaps one was already running?)");
return -1;
}
- FILE *f = fopen(pidFile, "r");
int pid = -1;
+
+ FILE *f = fopen(pidFile, "r");
if(f == NULL || fscanf(f, "%d", &pid) != 1)
{
- printf("Server: %s (pidfile %s)\n", CommandLine, pidFile);
TEST_FAIL_WITH_MESSAGE("Couldn't read PID file");
return -1;
}
@@ -149,160 +225,177 @@ inline int LaunchServer(const char *CommandLine, const char *pidFile)
return pid;
}
-#ifdef WIN32
-
-#include "WinNamedPipeStream.h"
-#include "IOStreamGetLine.h"
-#include "BoxPortsAndFiles.h"
-
-bool SendCommands(const std::string& rCmd)
+inline int LaunchServer(const std::string& rCommandLine, const char *pidFile)
{
- WinNamedPipeStream connection;
+#ifdef WIN32
- try
+ PROCESS_INFORMATION procInfo;
+
+ STARTUPINFO startInfo;
+ startInfo.cb = sizeof(startInfo);
+ startInfo.lpReserved = NULL;
+ startInfo.lpDesktop = NULL;
+ startInfo.lpTitle = NULL;
+ startInfo.dwFlags = 0;
+ startInfo.cbReserved2 = 0;
+ startInfo.lpReserved2 = NULL;
+
+ std::string cmd = ConvertPaths(rCommandLine);
+ CHAR* tempCmd = strdup(cmd.c_str());
+
+ DWORD result = CreateProcess
+ (
+ NULL, // lpApplicationName, naughty!
+ tempCmd, // lpCommandLine
+ NULL, // lpProcessAttributes
+ NULL, // lpThreadAttributes
+ false, // bInheritHandles
+ 0, // dwCreationFlags
+ NULL, // lpEnvironment
+ NULL, // lpCurrentDirectory
+ &startInfo, // lpStartupInfo
+ &procInfo // lpProcessInformation
+ );
+
+ free(tempCmd);
+
+ if (result == 0)
{
- connection.Connect(BOX_NAMED_PIPE_NAME);
- }
- catch(...)
- {
- printf("Failed to connect to daemon control socket.\n");
- return false;
+ DWORD err = GetLastError();
+ printf("Launch failed: %s: error %d\n", rCommandLine.c_str(),
+ (int)err);
+ return -1;
}
- // For receiving data
- IOStreamGetLine getLine(connection);
-
- // Wait for the configuration summary
- std::string configSummary;
- if(!getLine.GetLine(configSummary))
- {
- printf("Failed to receive configuration summary from daemon\n");
- return false;
- }
+ CloseHandle(procInfo.hProcess);
+ CloseHandle(procInfo.hThread);
- // Was the connection rejected by the server?
- if(getLine.IsEOF())
- {
- printf("Server rejected the connection.\n");
- return false;
- }
+#else // !WIN32
- // Decode it
- int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait;
- if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d",
- &autoBackup, &updateStoreInterval,
- &minimumFileAge, &maxUploadWait) != 4)
+ if(RunCommand(rCommandLine) != 0)
{
- printf("Config summary didn't decode\n");
- return false;
+ printf("Server: %s\n", rCommandLine.c_str());
+ TEST_FAIL_WITH_MESSAGE("Couldn't start server");
+ return -1;
}
- std::string cmds;
- bool expectResponse;
+#endif // WIN32
- if (rCmd != "")
- {
- cmds = rCmd;
- cmds += "\nquit\n";
- expectResponse = true;
- }
- else
+ #ifdef WIN32
+ // on other platforms there is no other way to get
+ // the PID, so a NULL pidFile doesn't make sense.
+
+ if (pidFile == NULL)
{
- cmds = "quit\n";
- expectResponse = false;
+ return (int)procInfo.dwProcessId;
}
-
- connection.Write(cmds.c_str(), cmds.size());
-
- // Read the response
- std::string line;
- bool statusOk = !expectResponse;
+ #endif
+
+ // time for it to start up
+ ::fprintf(stdout, "Starting server: %s\n", rCommandLine.c_str());
+ ::fprintf(stdout, "Waiting for server to start: ");
- while (expectResponse && !getLine.IsEOF() && getLine.GetLine(line))
+ for (int i = 0; i < 15; i++)
{
- // Is this an OK or error line?
- if (line == "ok")
- {
- statusOk = true;
- }
- else if (line == "error")
+ if (TestFileExists(pidFile))
{
- printf("ERROR (%s)\n", rCmd.c_str());
break;
}
- else
+
+ #ifdef WIN32
+ if (!ServerIsAlive((int)procInfo.dwProcessId))
{
- printf("WARNING: Unexpected response to command '%s': "
- "%s", rCmd.c_str(), line.c_str());
+ break;
}
+ #endif
+
+ ::fprintf(stdout, ".");
+ ::fflush(stdout);
+ ::sleep(1);
}
-
- return statusOk;
-}
-inline bool ServerIsAlive()
-{
- return SendCommands("");
-}
+ #ifdef WIN32
+ // on Win32 we can check whether the process is alive
+ // without even checking the PID file
-inline bool HUPServer(int pid)
-{
- return SendCommands("reload");
-}
+ if (!ServerIsAlive((int)procInfo.dwProcessId))
+ {
+ ::fprintf(stdout, "server died!\n");
+ TEST_FAIL_WITH_MESSAGE("Server died!");
+ return -1;
+ }
+ #endif
-inline bool KillServer(int pid)
-{
- TEST_THAT(SendCommands("terminate"));
+ if (!TestFileExists(pidFile))
+ {
+ ::fprintf(stdout, "timed out!\n");
+ TEST_FAIL_WITH_MESSAGE("Server didn't save PID file");
+ return -1;
+ }
+
+ ::fprintf(stdout, "done.\n");
+
+ // wait a second for the pid to be written to the file
::sleep(1);
- return !ServerIsAlive();
-}
-#else // !WIN32
+ // read pid file
+ int pid = ReadPidFile(pidFile);
-inline bool ServerIsAlive(int pid)
-{
- if(pid == 0) return false;
- return ::kill(pid, 0) != -1;
-}
+ #ifdef WIN32
+ // On Win32 we can check whether the PID in the pidFile matches
+ // the one returned by the system, which it always should.
-inline bool HUPServer(int pid)
-{
- if(pid == 0) return false;
- return ::kill(pid, SIGHUP) != -1;
-}
+ if (pid != (int)procInfo.dwProcessId)
+ {
+ printf("Server wrote wrong pid to file (%s): expected %d "
+ "but found %d\n", pidFile,
+ (int)procInfo.dwProcessId, pid);
+ TEST_FAIL_WITH_MESSAGE("Server wrote wrong pid to file");
+ return -1;
+ }
+ #endif
-inline bool KillServer(int pid)
-{
- if(pid == 0 || pid == -1) return false;
- bool KilledOK = ::kill(pid, SIGTERM) != -1;
- TEST_THAT(KilledOK);
- ::sleep(1);
- return !ServerIsAlive(pid);
+ return pid;
}
-#endif // WIN32
+#define TestRemoteProcessMemLeaks(filename) \
+ TestRemoteProcessMemLeaksFunc(filename, __FILE__, __LINE__)
-inline void TestRemoteProcessMemLeaks(const char *filename)
+inline void TestRemoteProcessMemLeaksFunc(const char *filename,
+ const char* file, int line)
{
#ifdef BOX_MEMORY_LEAK_TESTING
// Does the file exist?
if(!TestFileExists(filename))
{
+ if (failures == 0)
+ {
+ first_fail_file = file;
+ first_fail_line = line;
+ }
++failures;
- printf("FAILURE: MemLeak report not available (file %s)\n", filename);
+ printf("FAILURE: MemLeak report not available (file %s) "
+ "at %s:%d\n", filename, file, line);
}
else
{
// Is it empty?
if(TestGetFileSize(filename) > 0)
{
+ if (failures == 0)
+ {
+ first_fail_file = file;
+ first_fail_line = line;
+ }
++failures;
- printf("FAILURE: Memory leaks found in other process (file %s)\n==========\n", filename);
+ printf("FAILURE: Memory leaks found in other process "
+ "(file %s) at %s:%d\n==========\n",
+ filename, file, line);
FILE *f = fopen(filename, "r");
- char line[512];
- while(::fgets(line, sizeof(line), f) != 0)
+ char linebuf[512];
+ while(::fgets(linebuf, sizeof(linebuf), f) != 0)
{
- printf("%s", line);
+ printf("%s", linebuf);
}
fclose(f);
printf("==========\n");
@@ -314,5 +407,86 @@ inline void TestRemoteProcessMemLeaks(const char *filename)
#endif
}
-#endif // TEST__H
+inline void force_sync()
+{
+ TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf "
+ "force-sync") == 0);
+ TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+}
+
+inline void wait_for_sync_start()
+{
+ TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf "
+ "wait-for-sync") == 0);
+ TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+}
+
+inline void wait_for_sync_end()
+{
+ TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf "
+ "wait-for-end") == 0);
+ TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+}
+
+inline void sync_and_wait()
+{
+ TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf "
+ "sync-and-wait") == 0);
+ TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+}
+
+inline void terminate_bbackupd(int pid)
+{
+ TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf "
+ "terminate") == 0);
+ TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+
+ for (int i = 0; i < 20; i++)
+ {
+ if (!ServerIsAlive(pid)) break;
+ fprintf(stdout, ".");
+ fflush(stdout);
+ sleep(1);
+ }
+
+ TEST_THAT(!ServerIsAlive(pid));
+ TestRemoteProcessMemLeaks("bbackupd.memleaks");
+}
+
+
+// Wait a given number of seconds for something to complete
+inline void wait_for_operation(int seconds)
+{
+ printf("Waiting: ");
+ fflush(stdout);
+ for(int l = 0; l < seconds; ++l)
+ {
+ sleep(1);
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+inline void safe_sleep(int seconds)
+{
+#ifdef WIN32
+ Sleep(seconds * 1000);
+#else
+ struct timespec ts;
+ memset(&ts, 0, sizeof(ts));
+ ts.tv_sec = seconds;
+ ts.tv_nsec = 0;
+ BOX_TRACE("sleeping for " << seconds << " seconds");
+ while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
+ {
+ BOX_TRACE("safe_sleep interrupted with " <<
+ ts.tv_sec << "." << ts.tv_nsec <<
+ " secs remaining, sleeping again");
+ /* sleep again */
+ }
+#endif
+}
+#endif // TEST__H
diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp
new file mode 100644
index 00000000..068ef97b
--- /dev/null
+++ b/lib/common/Timer.cpp
@@ -0,0 +1,432 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Timer.cpp
+// Purpose: Generic timers which execute arbitrary code when
+// they expire.
+// Created: 5/11/2006
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <signal.h>
+
+#include "Timer.h"
+#include "Logging.h"
+
+#include "MemLeakFindOn.h"
+
+std::vector<Timer*>* Timers::spTimers = NULL;
+bool Timers::sRescheduleNeeded = false;
+
+typedef void (*sighandler_t)(int);
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static void Timers::Init()
+// Purpose: Initialise timers, prepare signal handler
+// Created: 5/11/2006
+//
+// --------------------------------------------------------------------------
+void Timers::Init()
+{
+ ASSERT(!spTimers);
+
+ #if defined WIN32 && ! defined PLATFORM_CYGWIN
+ // no support for signals at all
+ InitTimer();
+ SetTimerHandler(Timers::SignalHandler);
+ #else
+ struct sigaction newact, oldact;
+ newact.sa_handler = Timers::SignalHandler;
+ newact.sa_flags = SA_RESTART;
+ sigemptyset(&newact.sa_mask);
+ if (::sigaction(SIGALRM, &newact, &oldact) != 0)
+ {
+ BOX_ERROR("Failed to install signal handler");
+ THROW_EXCEPTION(CommonException, Internal);
+ }
+ ASSERT(oldact.sa_handler == 0);
+ #endif // WIN32 && !PLATFORM_CYGWIN
+
+ spTimers = new std::vector<Timer*>;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static void Timers::Cleanup()
+// Purpose: Clean up timers, stop signal handler
+// Created: 6/11/2006
+//
+// --------------------------------------------------------------------------
+void Timers::Cleanup()
+{
+ ASSERT(spTimers);
+ if (!spTimers)
+ {
+ BOX_ERROR("Tried to clean up timers when not initialised!");
+ return;
+ }
+
+ #if defined WIN32 && ! defined PLATFORM_CYGWIN
+ // no support for signals at all
+ FiniTimer();
+ SetTimerHandler(NULL);
+ #else
+ struct itimerval timeout;
+ memset(&timeout, 0, sizeof(timeout));
+
+ int result = ::setitimer(ITIMER_REAL, &timeout, NULL);
+ ASSERT(result == 0);
+
+ struct sigaction newact, oldact;
+ newact.sa_handler = SIG_DFL;
+ newact.sa_flags = SA_RESTART;
+ sigemptyset(&(newact.sa_mask));
+ if (::sigaction(SIGALRM, &newact, &oldact) != 0)
+ {
+ BOX_ERROR("Failed to remove signal handler");
+ THROW_EXCEPTION(CommonException, Internal);
+ }
+ ASSERT(oldact.sa_handler == Timers::SignalHandler);
+ #endif // WIN32 && !PLATFORM_CYGWIN
+
+ spTimers->clear();
+ delete spTimers;
+ spTimers = NULL;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static void Timers::Add(Timer&)
+// Purpose: Add a new timer to the set, and reschedule next wakeup
+// Created: 5/11/2006
+//
+// --------------------------------------------------------------------------
+void Timers::Add(Timer& rTimer)
+{
+ ASSERT(spTimers);
+ ASSERT(&rTimer);
+ spTimers->push_back(&rTimer);
+ Reschedule();
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static void Timers::Remove(Timer&)
+// Purpose: Removes the timer from the set (preventing it from
+// being called) and reschedule next wakeup
+// Created: 5/11/2006
+//
+// --------------------------------------------------------------------------
+void Timers::Remove(Timer& rTimer)
+{
+ ASSERT(spTimers);
+ ASSERT(&rTimer);
+
+ bool restart = true;
+ while (restart)
+ {
+ restart = false;
+
+ for (std::vector<Timer*>::iterator i = spTimers->begin();
+ i != spTimers->end(); i++)
+ {
+ if (&rTimer == *i)
+ {
+ spTimers->erase(i);
+ restart = true;
+ break;
+ }
+ }
+ }
+
+ Reschedule();
+}
+
+#define FORMAT_MICROSECONDS(t) \
+ (int)(t / 1000000) << "." << \
+ (int)(t % 1000000)
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static void Timers::Reschedule()
+// Purpose: Recalculate when the next wakeup is due
+// Created: 5/11/2006
+//
+// --------------------------------------------------------------------------
+void Timers::Reschedule()
+{
+ ASSERT(spTimers);
+ if (spTimers == NULL)
+ {
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+
+ #ifndef WIN32
+ struct sigaction oldact;
+ if (::sigaction(SIGALRM, NULL, &oldact) != 0)
+ {
+ BOX_ERROR("Failed to check signal handler");
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+
+ ASSERT(oldact.sa_handler == Timers::SignalHandler);
+
+ if (oldact.sa_handler != Timers::SignalHandler)
+ {
+ BOX_ERROR("Signal handler was " <<
+ (void *)oldact.sa_handler <<
+ ", expected " <<
+ (void *)Timers::SignalHandler);
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+ #endif
+
+ // Clear the reschedule-needed flag to false before we start.
+ // If a timer event occurs while we are scheduling, then we
+ // may or may not need to reschedule again, but this way
+ // we will do it anyway.
+ sRescheduleNeeded = false;
+
+ box_time_t timeNow = GetCurrentBoxTime();
+
+ // scan for, trigger and remove expired timers. Removal requires
+ // us to restart the scan each time, due to std::vector semantics.
+ bool restart = true;
+ while (restart)
+ {
+ restart = false;
+
+ for (std::vector<Timer*>::iterator i = spTimers->begin();
+ i != spTimers->end(); i++)
+ {
+ Timer& rTimer = **i;
+ int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow;
+
+ if (timeToExpiry <= 0)
+ {
+ BOX_TRACE("timer " << *i << " has expired, "
+ "triggering it");
+ rTimer.OnExpire();
+ spTimers->erase(i);
+ restart = true;
+ break;
+ }
+ else
+ {
+ BOX_TRACE("timer " << *i << " has not "
+ "expired, triggering in " <<
+ FORMAT_MICROSECONDS(timeToExpiry) <<
+ " seconds");
+ }
+ }
+ }
+
+ // Now the only remaining timers should all be in the future.
+ // Scan to find the next one to fire (earliest deadline).
+
+ int64_t timeToNextEvent = 0;
+
+ for (std::vector<Timer*>::iterator i = spTimers->begin();
+ i != spTimers->end(); i++)
+ {
+ Timer& rTimer = **i;
+ int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow;
+
+ if (timeToExpiry <= 0)
+ {
+ timeToExpiry = 1;
+ }
+
+ if (timeToNextEvent == 0 || timeToNextEvent > timeToExpiry)
+ {
+ timeToNextEvent = timeToExpiry;
+ }
+ }
+
+ ASSERT(timeToNextEvent >= 0);
+
+ struct itimerval timeout;
+ memset(&timeout, 0, sizeof(timeout));
+
+ timeout.it_value.tv_sec = BoxTimeToSeconds(timeToNextEvent);
+ timeout.it_value.tv_usec = (int)
+ (BoxTimeToMicroSeconds(timeToNextEvent) % MICRO_SEC_IN_SEC);
+
+ if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0)
+ {
+ BOX_ERROR("Failed to initialise timer\n");
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static void Timers::SignalHandler(unused)
+// Purpose: Called as signal handler. Nothing is safe in a signal
+// handler, not even traversing the list of timers, so
+// just request a reschedule in future, which will do
+// that for us, and trigger any expired timers at that
+// time.
+// Created: 5/11/2006
+//
+// --------------------------------------------------------------------------
+void Timers::SignalHandler(int iUnused)
+{
+ // ASSERT(spTimers);
+ Timers::RequestReschedule();
+}
+
+Timer::Timer(size_t timeoutSecs)
+: mExpires(GetCurrentBoxTime() + SecondsToBoxTime(timeoutSecs)),
+ mExpired(false)
+{
+ #ifndef NDEBUG
+ if (timeoutSecs == 0)
+ {
+ BOX_TRACE("timer " << this << " initialised for " <<
+ timeoutSecs << " secs, will not fire");
+ }
+ else
+ {
+ BOX_TRACE("timer " << this << " initialised for " <<
+ timeoutSecs << " secs, to fire at " <<
+ FORMAT_MICROSECONDS(mExpires));
+ }
+ #endif
+
+ if (timeoutSecs == 0)
+ {
+ mExpires = 0;
+ }
+ else
+ {
+ Timers::Add(*this);
+ }
+}
+
+Timer::~Timer()
+{
+ #ifndef NDEBUG
+ BOX_TRACE("timer " << this << " destroyed");
+ #endif
+
+ Timers::Remove(*this);
+}
+
+Timer::Timer(const Timer& rToCopy)
+: mExpires(rToCopy.mExpires),
+ mExpired(rToCopy.mExpired)
+{
+ #ifndef NDEBUG
+ if (mExpired)
+ {
+ BOX_TRACE("timer " << this << " initialised from timer " <<
+ &rToCopy << ", already expired, will not fire");
+ }
+ else if (mExpires == 0)
+ {
+ BOX_TRACE("timer " << this << " initialised from timer " <<
+ &rToCopy << ", no expiry, will not fire");
+ }
+ else
+ {
+ BOX_TRACE("timer " << this << " initialised from timer " <<
+ &rToCopy << " to fire at " <<
+ (int)(mExpires / 1000000) << "." <<
+ (int)(mExpires % 1000000));
+ }
+ #endif
+
+ if (!mExpired && mExpires != 0)
+ {
+ Timers::Add(*this);
+ }
+}
+
+Timer& Timer::operator=(const Timer& rToCopy)
+{
+ #ifndef NDEBUG
+ if (rToCopy.mExpired)
+ {
+ BOX_TRACE("timer " << this << " initialised from timer " <<
+ &rToCopy << ", already expired, will not fire");
+ }
+ else if (rToCopy.mExpires == 0)
+ {
+ BOX_TRACE("timer " << this << " initialised from timer " <<
+ &rToCopy << ", no expiry, will not fire");
+ }
+ else
+ {
+ BOX_TRACE("timer " << this << " initialised from timer " <<
+ &rToCopy << " to fire at " <<
+ (int)(rToCopy.mExpires / 1000000) << "." <<
+ (int)(rToCopy.mExpires % 1000000));
+ }
+ #endif
+
+ Timers::Remove(*this);
+ mExpires = rToCopy.mExpires;
+ mExpired = rToCopy.mExpired;
+ if (!mExpired && mExpires != 0)
+ {
+ Timers::Add(*this);
+ }
+ return *this;
+}
+
+void Timer::OnExpire()
+{
+ #ifndef NDEBUG
+ BOX_TRACE("timer " << this << " fired");
+ #endif
+
+ mExpired = true;
+}
diff --git a/lib/common/Timer.h b/lib/common/Timer.h
new file mode 100644
index 00000000..fb424e0c
--- /dev/null
+++ b/lib/common/Timer.h
@@ -0,0 +1,125 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Timer.h
+// Purpose: Generic timers which execute arbitrary code when
+// they expire.
+// Created: 5/11/2006
+//
+// --------------------------------------------------------------------------
+
+#ifndef TIMER__H
+#define TIMER__H
+
+#ifdef HAVE_SYS_TIME_H
+ #include <sys/time.h>
+#endif
+
+#include <vector>
+
+#include "BoxTime.h"
+
+#include "MemLeakFindOn.h"
+
+class Timer;
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: Timers
+// Purpose: Static class to manage all timers and arrange
+// efficient delivery of wakeup signals
+// Created: 19/3/04
+//
+// --------------------------------------------------------------------------
+class Timers
+{
+ private:
+ static std::vector<Timer*>* spTimers;
+ static void Reschedule();
+
+ static bool sRescheduleNeeded;
+ static void SignalHandler(int iUnused);
+
+ public:
+ static void Init();
+ static void Cleanup();
+ static void Add (Timer& rTimer);
+ static void Remove(Timer& rTimer);
+ static void RequestReschedule()
+ {
+ sRescheduleNeeded = true;
+ }
+
+ static void RescheduleIfNeeded()
+ {
+ if (sRescheduleNeeded)
+ {
+ Reschedule();
+ }
+ }
+};
+
+class Timer
+{
+public:
+ Timer(size_t timeoutSecs);
+ virtual ~Timer();
+ Timer(const Timer &);
+ Timer &operator=(const Timer &);
+
+public:
+ box_time_t GetExpiryTime() { return mExpires; }
+ virtual void OnExpire();
+ bool HasExpired()
+ {
+ Timers::RescheduleIfNeeded();
+ return mExpired;
+ }
+
+private:
+ box_time_t mExpires;
+ bool mExpired;
+};
+
+#include "MemLeakFindOff.h"
+
+#endif // TIMER__H
diff --git a/lib/common/UnixUser.cpp b/lib/common/UnixUser.cpp
index cea384fd..025f8db4 100644
--- a/lib/common/UnixUser.cpp
+++ b/lib/common/UnixUser.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.
@@ -116,8 +116,7 @@ UnixUser::~UnixUser()
if(mRevertOnDestruction)
{
// Revert to "real" user and group id of the process
- if(::setegid(::getgid()) != 0
- || ::seteuid(::getuid()) != 0)
+ if(::setegid(::getgid()) != 0 || ::seteuid(::getuid()) != 0)
{
THROW_EXCEPTION(CommonException, CouldNotRestoreProcessUser)
}
@@ -139,8 +138,7 @@ void UnixUser::ChangeProcessUser(bool Temporary)
if(Temporary)
{
// Change temporarily (change effective only)
- if(::setegid(mGID) != 0
- || ::seteuid(mUID) != 0)
+ if(::setegid(mGID) != 0 || ::seteuid(mUID) != 0)
{
THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser)
}
@@ -150,9 +148,8 @@ void UnixUser::ChangeProcessUser(bool Temporary)
}
else
{
- // Change perminantely (change all UIDs and GIDs)
- if(::setgid(mGID) != 0
- || ::setuid(mUID) != 0)
+ // Change permanently (change all UIDs and GIDs)
+ if(::setgid(mGID) != 0 || ::setuid(mUID) != 0)
{
THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser)
}
diff --git a/lib/common/UnixUser.h b/lib/common/UnixUser.h
index 47bacb39..aa52169d 100644
--- a/lib/common/UnixUser.h
+++ b/lib/common/UnixUser.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/common/Utils.cpp b/lib/common/Utils.cpp
index 7a7e59d1..def6e9b7 100644
--- a/lib/common/Utils.cpp
+++ b/lib/common/Utils.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.
@@ -58,6 +58,7 @@
#include "Utils.h"
#include "CommonException.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -109,14 +110,16 @@ void DumpStackBacktrace()
size = backtrace (array, 10);
strings = backtrace_symbols (array, size);
- printf ("Obtained %zd stack frames.\n", size);
+ BOX_TRACE("Obtained " << size << " stack frames.");
for(i = 0; i < size; i++)
- printf("%s\n", strings[i]);
+ {
+ BOX_TRACE(strings[i]);
+ }
-#ifndef MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
+#include "MemLeakFindOff.h"
free (strings);
-#endif
+#include "MemLeakFindOn.h"
}
#endif
@@ -133,7 +136,7 @@ void DumpStackBacktrace()
bool FileExists(const char *Filename, int64_t *pFileSize, bool TreatLinksAsNotExisting)
{
struct stat st;
- if(::stat(Filename, &st) != 0)
+ if(::lstat(Filename, &st) != 0)
{
if(errno == ENOENT)
{
@@ -170,15 +173,15 @@ bool FileExists(const char *Filename, int64_t *pFileSize, bool TreatLinksAsNotEx
// --------------------------------------------------------------------------
//
// Function
-// Name: ObjectExists(const char *)
+// Name: ObjectExists(const std::string& rFilename)
// Purpose: Does a object exist, and if so, is it a file or a directory?
// Created: 23/11/03
//
// --------------------------------------------------------------------------
-int ObjectExists(const char *Filename)
+int ObjectExists(const std::string& rFilename)
{
struct stat st;
- if(::stat(Filename, &st) != 0)
+ if(::stat(rFilename.c_str(), &st) != 0)
{
if(errno == ENOENT)
{
diff --git a/lib/common/Utils.h b/lib/common/Utils.h
index 1e99f8fe..76598611 100644
--- a/lib/common/Utils.h
+++ b/lib/common/Utils.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.
@@ -67,7 +67,7 @@ enum
ObjectExists_File = 1,
ObjectExists_Dir = 2
};
-int ObjectExists(const char *Filename);
+int ObjectExists(const std::string& rFilename);
#include "MemLeakFindOff.h"
diff --git a/lib/common/WaitForEvent.cpp b/lib/common/WaitForEvent.cpp
index f7ea7439..a8b0349b 100644
--- a/lib/common/WaitForEvent.cpp
+++ b/lib/common/WaitForEvent.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/common/WaitForEvent.h b/lib/common/WaitForEvent.h
index 5b2a2fbf..8d2a048a 100644
--- a/lib/common/WaitForEvent.h
+++ b/lib/common/WaitForEvent.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/common/ZeroStream.cpp b/lib/common/ZeroStream.cpp
new file mode 100644
index 00000000..e9717a1d
--- /dev/null
+++ b/lib/common/ZeroStream.cpp
@@ -0,0 +1,208 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ZeroStream.cpp
+// Purpose: An IOStream which returns all zeroes up to a certain size
+// Created: 2007/04/28
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "ZeroStream.h"
+#include "CommonException.h"
+
+#include <string.h>
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::ZeroStream(IOStream::pos_type)
+// Purpose: Constructor
+// Created: 2007/04/28
+//
+// --------------------------------------------------------------------------
+ZeroStream::ZeroStream(IOStream::pos_type size)
+: mSize(size), mPosition(0)
+{ }
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::Read(void *, int)
+// Purpose: Reads bytes from the file
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+int ZeroStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ ASSERT(NBytes > 0);
+
+ int bytesToRead = NBytes;
+
+ if (bytesToRead > mSize - mPosition)
+ {
+ bytesToRead = mSize - mPosition;
+ }
+
+ memset(pBuffer, 0, bytesToRead);
+ mPosition += bytesToRead;
+
+ return bytesToRead;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::BytesLeftToRead()
+// Purpose: Returns number of bytes to read (may not be most efficient function ever)
+// Created: 2007/01/16
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type ZeroStream::BytesLeftToRead()
+{
+ return mSize - mPosition;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::Write(void *, int)
+// Purpose: Writes bytes to the underlying stream (not supported)
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void ZeroStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(CommonException, NotSupported);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::GetPosition()
+// Purpose: Get position in stream
+// Created: 2003/08/21
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type ZeroStream::GetPosition() const
+{
+ return mPosition;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::Seek(pos_type, int)
+// Purpose: Seeks within file, as lseek, invalidate buffer
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void ZeroStream::Seek(IOStream::pos_type Offset, int SeekType)
+{
+ switch (SeekType)
+ {
+ case SeekType_Absolute:
+ {
+ mPosition = Offset;
+ }
+ break;
+
+ case SeekType_Relative:
+ {
+ mPosition += Offset;
+ }
+ break;
+
+ case SeekType_End:
+ {
+ mPosition = mSize - Offset;
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::Close()
+// Purpose: Closes the underlying stream (not needed)
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void ZeroStream::Close()
+{
+ THROW_EXCEPTION(CommonException, NotSupported);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::StreamDataLeft()
+// Purpose: Any data left to write?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool ZeroStream::StreamDataLeft()
+{
+ return false;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ZeroStream::StreamClosed()
+// Purpose: Is the stream closed?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool ZeroStream::StreamClosed()
+{
+ return false;
+}
+
diff --git a/lib/common/ZeroStream.h b/lib/common/ZeroStream.h
new file mode 100644
index 00000000..0e3f6e54
--- /dev/null
+++ b/lib/common/ZeroStream.h
@@ -0,0 +1,77 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ZeroStream.h
+// Purpose: An IOStream which returns all zeroes up to a certain size
+// Created: 2007/04/28
+//
+// --------------------------------------------------------------------------
+
+#ifndef ZEROSTREAM__H
+#define ZEROSTREAM__H
+
+#include "IOStream.h"
+
+class ZeroStream : public IOStream
+{
+private:
+ IOStream::pos_type mSize, mPosition;
+
+public:
+ ZeroStream(IOStream::pos_type mSize);
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual pos_type GetPosition() const;
+ virtual void Seek(IOStream::pos_type Offset, int SeekType);
+ virtual void Close();
+
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+private:
+ ZeroStream(const ZeroStream &rToCopy);
+};
+
+#endif // ZEROSTREAM__H
+
+
diff --git a/lib/common/makeexception.pl b/lib/common/makeexception.pl
index e6f8ab06..6043de0e 100755
--- a/lib/common/makeexception.pl
+++ b/lib/common/makeexception.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/lib/common/makeexception.pl.in b/lib/common/makeexception.pl.in
new file mode 100755
index 00000000..1564b75b
--- /dev/null
+++ b/lib/common/makeexception.pl.in
@@ -0,0 +1,277 @@
+#!@PERL@
+
+# global exception list file
+my $global_list = '../../ExceptionCodes.txt';
+
+
+my @exception;
+my @exception_desc;
+my $class;
+my $class_number;
+
+# read the description!
+
+open EXCEPTION_DESC,$ARGV[0] or die "Can't open $ARGV[0]";
+
+while(<EXCEPTION_DESC>)
+{
+ chomp; s/\A\s+//; s/#.+\Z//; s/\s+\Z//; s/\s+/ /g;
+ next unless m/\S/;
+
+ if(m/\AEXCEPTION\s+(.+)\s+(\d+)\Z/)
+ {
+ $class = $1;
+ $class_number = $2;
+ }
+ else
+ {
+ my ($name,$number,$description) = split /\s+/,$_,3;
+ if($name eq '' || $number =~ m/\D/)
+ {
+ die "Bad line '$_'";
+ }
+ if($exception[$number] ne '')
+ {
+ die "Duplicate exception number $number";
+ }
+ $exception[$number] = $name;
+ $exception_desc[$number] = $description;
+ }
+}
+
+die "Exception class and number not specified" unless $class ne '' && $class_number ne '';
+
+close EXCEPTION_DESC;
+
+# write the code
+print "Generating $class exception...\n";
+
+open CPP,">autogen_${class}Exception.cpp" or die "Can't open cpp file for writing";
+open H,">autogen_${class}Exception.h" or die "Can't open h file for writing";
+
+# write header file
+my $guardname = uc 'AUTOGEN_'.$class.'EXCEPTION_H';
+print H <<__E;
+
+// Auto-generated file -- do not edit
+
+#ifndef $guardname
+#define $guardname
+
+#include "BoxException.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: ${class}Exception
+// Purpose: Exception
+// Created: autogen
+//
+// --------------------------------------------------------------------------
+class ${class}Exception : public BoxException
+{
+public:
+ ${class}Exception(unsigned int SubType)
+ : mSubType(SubType)
+ {
+ }
+
+ ${class}Exception(const ${class}Exception &rToCopy)
+ : mSubType(rToCopy.mSubType)
+ {
+ }
+
+ ~${class}Exception() throw ()
+ {
+ }
+
+ enum
+ {
+ ExceptionType = $class_number
+ };
+
+ enum
+ {
+__E
+
+for(my $e = 0; $e <= $#exception; $e++)
+{
+ if($exception[$e] ne '')
+ {
+ print H "\t\t".$exception[$e].' = '.$e.(($e==$#exception)?'':',')."\n"
+ }
+}
+
+print H <<__E;
+ };
+
+ virtual unsigned int GetType() const throw();
+ virtual unsigned int GetSubType() const throw();
+ virtual const char *what() const throw();
+
+private:
+ unsigned int mSubType;
+};
+
+#endif // $guardname
+__E
+
+# -----------------------------------------------------------------------------------------------------------
+
+print CPP <<__E;
+
+// Auto-generated file -- do not edit
+
+#include "Box.h"
+#include "autogen_${class}Exception.h"
+
+#include "MemLeakFindOn.h"
+
+#ifdef EXCEPTION_CODENAMES_EXTENDED
+ #ifdef EXCEPTION_CODENAMES_EXTENDED_WITH_DESCRIPTION
+static const char *whats[] = {
+__E
+
+my $last_seen = -1;
+for(my $e = 0; $e <= $#exception; $e++)
+{
+ if($exception[$e] ne '')
+ {
+ for(my $s = $last_seen + 1; $s < $e; $s++)
+ {
+ print CPP "\t\"UNUSED\",\n"
+ }
+ my $ext = ($exception_desc[$e] ne '')?" ($exception_desc[$e])":'';
+ print CPP "\t\"${class} ".$exception[$e].$ext.'"'.(($e==$#exception)?'':',')."\n";
+ $last_seen = $e;
+ }
+}
+
+print CPP <<__E;
+};
+ #else
+static const char *whats[] = {
+__E
+
+$last_seen = -1;
+for(my $e = 0; $e <= $#exception; $e++)
+{
+ if($exception[$e] ne '')
+ {
+ for(my $s = $last_seen + 1; $s < $e; $s++)
+ {
+ print CPP "\t\"UNUSED\",\n"
+ }
+ print CPP "\t\"${class} ".$exception[$e].'"'.(($e==$#exception)?'':',')."\n";
+ $last_seen = $e;
+ }
+}
+
+print CPP <<__E;
+};
+ #endif
+#endif
+
+unsigned int ${class}Exception::GetType() const throw()
+{
+ return ${class}Exception::ExceptionType;
+}
+
+unsigned int ${class}Exception::GetSubType() const throw()
+{
+ return mSubType;
+}
+
+const char *${class}Exception::what() const throw()
+{
+#ifdef EXCEPTION_CODENAMES_EXTENDED
+ if(mSubType < 0 || mSubType > (sizeof(whats) / sizeof(whats[0])))
+ {
+ return "${class}";
+ }
+ return whats[mSubType];
+#else
+ return "${class}";
+#endif
+}
+
+__E
+
+close H;
+close CPP;
+
+# update the global exception list
+my $list_before;
+my $list_after;
+my $is_after = 0;
+if(open CURRENT,$global_list)
+{
+ while(<CURRENT>)
+ {
+ next if m/\A#/;
+
+ if(m/\AEXCEPTION TYPE (\w+) (\d+)/)
+ {
+ # check that the number isn't being reused
+ if($2 == $class_number && $1 ne $class)
+ {
+ die "Class number $class_number is being used by $class and $1 -- correct this.\n";
+ }
+ if($2 > $class_number)
+ {
+ # This class comes after the current one (ensures numerical ordering)
+ $is_after = 1;
+ }
+ if($1 eq $class)
+ {
+ # skip this entry
+ while(<CURRENT>)
+ {
+ last if m/\AEND TYPE/;
+ }
+ $_ = '';
+ }
+ }
+
+ if($is_after)
+ {
+ $list_after .= $_;
+ }
+ else
+ {
+ $list_before .= $_;
+ }
+ }
+
+ close CURRENT;
+}
+
+open GLOBAL,">$global_list" or die "Can't open global exception code listing for writing";
+
+print GLOBAL <<__E;
+#
+# automatically generated file, do not edit.
+#
+# This file lists all the exception codes used by the system.
+# Use to look up more detailed descriptions of meanings of errors.
+#
+__E
+
+print GLOBAL $list_before;
+
+print GLOBAL "EXCEPTION TYPE $class $class_number\n";
+for(my $e = 0; $e <= $#exception; $e++)
+{
+ if($exception[$e] ne '')
+ {
+ my $ext = ($exception_desc[$e] ne '')?" - $exception_desc[$e]":'';
+ print GLOBAL "($class_number/$e) - ${class} ".$exception[$e].$ext."\n";
+ }
+}
+print GLOBAL "END TYPE\n";
+
+print GLOBAL $list_after;
+
+close GLOBAL;
+
+
diff --git a/lib/compress/Compress.h b/lib/compress/Compress.h
index 5ec60fae..87f8b2f4 100644
--- a/lib/compress/Compress.h
+++ b/lib/compress/Compress.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.
@@ -39,7 +39,7 @@
// --------------------------------------------------------------------------
//
// File
-// Name: CompressContext.h
+// Name: Compress.h
// Purpose: Interface to zlib compression
// Created: 5/12/03
//
@@ -55,7 +55,7 @@
// --------------------------------------------------------------------------
//
// Class
-// Name: CompressContext
+// Name: Compress
// Purpose: Interface to zlib compression, only very slight wrapper.
// (Use CompressStream for a more friendly interface.)
// Created: 5/12/03
diff --git a/lib/compress/CompressException.h b/lib/compress/CompressException.h
index 1984d844..4f7b823f 100644
--- a/lib/compress/CompressException.h
+++ b/lib/compress/CompressException.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/compress/CompressStream.cpp b/lib/compress/CompressStream.cpp
index 090d1a41..b059fd65 100644
--- a/lib/compress/CompressStream.cpp
+++ b/lib/compress/CompressStream.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/compress/CompressStream.h b/lib/compress/CompressStream.h
index 603645ea..5ab69fd8 100644
--- a/lib/compress/CompressStream.h
+++ b/lib/compress/CompressStream.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/compress/Makefile.extra b/lib/compress/Makefile.extra
index 7ef9930c..3598f1c9 100644
--- a/lib/compress/Makefile.extra
+++ b/lib/compress/Makefile.extra
@@ -3,5 +3,5 @@ MAKEEXCEPTION = ../../lib/common/makeexception.pl
# AUTOGEN SEEDING
autogen_CompressException.h autogen_CompressException.cpp: $(MAKEEXCEPTION) CompressException.txt
- perl $(MAKEEXCEPTION) CompressException.txt
+ $(PERL) $(MAKEEXCEPTION) CompressException.txt
diff --git a/lib/crypto/CipherAES.cpp b/lib/crypto/CipherAES.cpp
index a8eb63f5..9245b298 100644
--- a/lib/crypto/CipherAES.cpp
+++ b/lib/crypto/CipherAES.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/crypto/CipherAES.h b/lib/crypto/CipherAES.h
index 3574b86f..3a4b501c 100644
--- a/lib/crypto/CipherAES.h
+++ b/lib/crypto/CipherAES.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/crypto/CipherBlowfish.cpp b/lib/crypto/CipherBlowfish.cpp
index 6997560e..9a7854e0 100644
--- a/lib/crypto/CipherBlowfish.cpp
+++ b/lib/crypto/CipherBlowfish.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/crypto/CipherBlowfish.h b/lib/crypto/CipherBlowfish.h
index 6cb862b3..43c653b3 100644
--- a/lib/crypto/CipherBlowfish.h
+++ b/lib/crypto/CipherBlowfish.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/crypto/CipherContext.cpp b/lib/crypto/CipherContext.cpp
index c31e613f..188a6257 100644
--- a/lib/crypto/CipherContext.cpp
+++ b/lib/crypto/CipherContext.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/crypto/CipherContext.h b/lib/crypto/CipherContext.h
index 427c78d2..72699645 100644
--- a/lib/crypto/CipherContext.h
+++ b/lib/crypto/CipherContext.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/crypto/CipherDescription.cpp b/lib/crypto/CipherDescription.cpp
index 826cfb93..9c0f7260 100644
--- a/lib/crypto/CipherDescription.cpp
+++ b/lib/crypto/CipherDescription.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/crypto/CipherDescription.h b/lib/crypto/CipherDescription.h
index 3f90d080..0f6b8628 100644
--- a/lib/crypto/CipherDescription.h
+++ b/lib/crypto/CipherDescription.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/crypto/CipherException.h b/lib/crypto/CipherException.h
index 4a41bf97..5882f50e 100644
--- a/lib/crypto/CipherException.h
+++ b/lib/crypto/CipherException.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/crypto/MD5Digest.cpp b/lib/crypto/MD5Digest.cpp
index 6464182d..2a5c282b 100644
--- a/lib/crypto/MD5Digest.cpp
+++ b/lib/crypto/MD5Digest.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/crypto/MD5Digest.h b/lib/crypto/MD5Digest.h
index fc9ebbba..68465f27 100644
--- a/lib/crypto/MD5Digest.h
+++ b/lib/crypto/MD5Digest.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/crypto/Makefile.extra b/lib/crypto/Makefile.extra
index a7e42000..f9d63a42 100644
--- a/lib/crypto/Makefile.extra
+++ b/lib/crypto/Makefile.extra
@@ -3,5 +3,5 @@ MAKEEXCEPTION = ../../lib/common/makeexception.pl
# AUTOGEN SEEDING
autogen_CipherException.cpp autogen_CipherException.h: $(MAKEEXCEPTION) CipherException.txt
- perl $(MAKEEXCEPTION) CipherException.txt
+ $(PERL) $(MAKEEXCEPTION) CipherException.txt
diff --git a/lib/crypto/Random.cpp b/lib/crypto/Random.cpp
index 549a9a91..7a3b1d94 100644
--- a/lib/crypto/Random.cpp
+++ b/lib/crypto/Random.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.
@@ -72,7 +72,8 @@ void Random::Initialise()
THROW_EXCEPTION(CipherException, RandomInitFailed)
}
#else
- ::fprintf(stderr, "No random device -- additional seeding of random number generator not performed.\n");
+ BOX_ERROR("No random device -- additional seeding of random number "
+ "generator not performed.");
#endif
}
diff --git a/lib/crypto/Random.h b/lib/crypto/Random.h
index 8ecf8a6c..aa3b4620 100644
--- a/lib/crypto/Random.h
+++ b/lib/crypto/Random.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/crypto/RollingChecksum.cpp b/lib/crypto/RollingChecksum.cpp
index 73e85319..0036a79e 100644
--- a/lib/crypto/RollingChecksum.cpp
+++ b/lib/crypto/RollingChecksum.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/crypto/RollingChecksum.h b/lib/crypto/RollingChecksum.h
index befc011f..5c20d527 100644
--- a/lib/crypto/RollingChecksum.h
+++ b/lib/crypto/RollingChecksum.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/test/raidfile/intercept.cpp b/lib/intercept/intercept.cpp
index aa756b60..b608db0b 100644
--- a/test/raidfile/intercept.cpp
+++ b/lib/intercept/intercept.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,14 +47,24 @@
#include "Box.h"
+#include "intercept.h"
+
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
#include <sys/types.h>
#include <unistd.h>
-#include <sys/uio.h>
+
+#ifdef HAVE_SYS_UIO_H
+ #include <sys/uio.h>
+#endif
+
#include <errno.h>
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
#if !defined(HAVE_SYSCALL) && !defined(HAVE___SYSCALL) && !defined(HAVE___SYSCALL_NEED_DEFN)
@@ -93,101 +103,183 @@
#include "MemLeakFindOn.h"
-bool intercept_enabled = false;
+int intercept_count = 0;
const char *intercept_filename = 0;
int intercept_filedes = -1;
off_t intercept_errorafter = 0;
int intercept_errno = 0;
int intercept_syscall = 0;
off_t intercept_filepos = 0;
+int intercept_delay_ms = 0;
+
+static opendir_t* opendir_real = NULL;
+static readdir_t* readdir_real = NULL;
+static readdir_t* readdir_hook = NULL;
+static closedir_t* closedir_real = NULL;
+static lstat_t* lstat_real = NULL;
+static lstat_t* lstat_hook = NULL;
+static const char* lstat_file = NULL;
#define SIZE_ALWAYS_ERROR -773
void intercept_clear_setup()
{
- intercept_enabled = false;
+ intercept_count = 0;
intercept_filename = 0;
intercept_filedes = -1;
intercept_errorafter = 0;
intercept_syscall = 0;
intercept_filepos = 0;
+ intercept_delay_ms = 0;
+ readdir_hook = NULL;
+ lstat_hook = NULL;
}
bool intercept_triggered()
{
- return !intercept_enabled;
+ return intercept_count == 0;
}
void intercept_setup_error(const char *filename, unsigned int errorafter, int errortoreturn, int syscalltoerror)
{
- TRACE4("Setup for error: %s, after %d, err %d, syscall %d\n", filename, errorafter, errortoreturn, syscalltoerror);
- intercept_enabled = true;
+ BOX_TRACE("Setup for error: " << filename <<
+ ", after " << errorafter <<
+ ", err " << errortoreturn <<
+ ", syscall " << syscalltoerror);
+
+ intercept_count = 1;
intercept_filename = filename;
intercept_filedes = -1;
intercept_errorafter = errorafter;
intercept_syscall = syscalltoerror;
intercept_errno = errortoreturn;
intercept_filepos = 0;
+ intercept_delay_ms = 0;
+}
+
+void intercept_setup_delay(const char *filename, unsigned int delay_after,
+ int delay_ms, int syscall_to_delay, int num_delays)
+{
+ BOX_TRACE("Setup for delay: " << filename <<
+ ", after " << delay_after <<
+ ", wait " << delay_ms << " ms" <<
+ ", times " << num_delays <<
+ ", syscall " << syscall_to_delay);
+
+ intercept_count = num_delays;
+ intercept_filename = filename;
+ intercept_filedes = -1;
+ intercept_errorafter = delay_after;
+ intercept_syscall = syscall_to_delay;
+ intercept_errno = 0;
+ intercept_filepos = 0;
+ intercept_delay_ms = delay_ms;
}
bool intercept_errornow(int d, int size, int syscallnum)
{
- if(intercept_filedes != -1 && d == intercept_filedes && syscallnum == intercept_syscall)
+ ASSERT(intercept_count > 0)
+
+ if (intercept_filedes == -1)
{
- //printf("Checking for err, %d, %d, %d\n", d, size, syscallnum);
- if(size == SIZE_ALWAYS_ERROR)
- {
- // Looks good for an error!
- TRACE2("Returning error %d for syscall %d\n", intercept_errno, syscallnum);
- return true;
- }
- // where are we in the file?
- if(intercept_filepos >= intercept_errorafter || intercept_filepos >= ((off_t)intercept_errorafter - size))
- {
- TRACE3("Returning error %d for syscall %d, file pos %d\n", intercept_errno, syscallnum, (int)intercept_filepos);
- return true;
- }
+ return false; // no error please!
+ }
+
+ if (d != intercept_filedes)
+ {
+ return false; // no error please!
+ }
+
+ if (syscallnum != intercept_syscall)
+ {
+ return false; // no error please!
+ }
+
+ bool ret = false; // no error unless one of the conditions matches
+
+ //printf("Checking for err, %d, %d, %d\n", d, size, syscallnum);
+
+ if (intercept_delay_ms != 0)
+ {
+ BOX_TRACE("Delaying " << intercept_delay_ms << " ms " <<
+ " for syscall " << syscallnum <<
+ " at " << intercept_filepos);
+
+ struct timespec tm;
+ tm.tv_sec = intercept_delay_ms / 1000;
+ tm.tv_nsec = (intercept_delay_ms % 1000) * 1000000;
+ while (nanosleep(&tm, &tm) != 0 &&
+ errno == EINTR) { }
}
- return false; // no error please!
+
+ if (size == SIZE_ALWAYS_ERROR)
+ {
+ // Looks good for an error!
+ BOX_TRACE("Returning error " << intercept_errno <<
+ " for syscall " << syscallnum);
+ ret = true;
+ }
+ else if (intercept_filepos + size < intercept_errorafter)
+ {
+ return false; // no error please
+ }
+ else if (intercept_errno != 0)
+ {
+ BOX_TRACE("Returning error " << intercept_errno <<
+ " for syscall " << syscallnum <<
+ " at " << intercept_filepos);
+ ret = true;
+ }
+
+ intercept_count--;
+ if (intercept_count == 0)
+ {
+ intercept_clear_setup();
+ }
+
+ return ret;
}
int intercept_reterr()
{
- intercept_enabled = false;
- intercept_filename = 0;
- intercept_filedes = -1;
- intercept_errorafter = 0;
- intercept_syscall = 0;
- return intercept_errno;
+ int err = intercept_errno;
+ intercept_clear_setup();
+ return err;
}
-#define CHECK_FOR_FAKE_ERROR_COND(D, S, CALL, FAILRES) \
- if(intercept_enabled) \
- { \
- if(intercept_errornow(D, S, CALL)) \
- { \
- errno = intercept_reterr(); \
- return FAILRES; \
- } \
+#define CHECK_FOR_FAKE_ERROR_COND(D, S, CALL, FAILRES) \
+ if(intercept_count > 0) \
+ { \
+ if(intercept_errornow(D, S, CALL)) \
+ { \
+ errno = intercept_reterr(); \
+ return FAILRES; \
+ } \
}
extern "C" int
open(const char *path, int flags, mode_t mode)
{
- if(intercept_enabled)
+ if(intercept_count > 0)
{
- if(intercept_syscall == SYS_open && strcmp(path, intercept_filename) == 0)
+ if(intercept_filename != NULL &&
+ intercept_syscall == SYS_open &&
+ strcmp(path, intercept_filename) == 0)
{
errno = intercept_reterr();
return -1;
}
}
+
#ifdef PLATFORM_NO_SYSCALL
int r = TEST_open(path, flags, mode);
#else
int r = syscall(SYS_open, path, flags, mode);
#endif
- if(intercept_enabled && intercept_filedes == -1)
+
+ if(intercept_filename != NULL &&
+ intercept_count > 0 &&
+ intercept_filedes == -1)
{
// Right file?
if(strcmp(intercept_filename, path) == 0)
@@ -196,6 +288,7 @@ open(const char *path, int flags, mode_t mode)
//printf("Found file to intercept, h = %d\n", r);
}
}
+
return r;
}
@@ -307,4 +400,186 @@ lseek(int fildes, off_t offset, int whence)
return r;
}
+void intercept_setup_readdir_hook(const char *dirname, readdir_t hookfn)
+{
+ if (hookfn != NULL && dirname == NULL)
+ {
+ dirname = intercept_filename;
+ ASSERT(dirname != NULL);
+ }
+
+ if (hookfn != NULL)
+ {
+ TRACE2("readdir hooked to %p for %s\n", hookfn, dirname);
+ }
+ else if (intercept_filename != NULL)
+ {
+ TRACE2("readdir unhooked from %p for %s\n", readdir_hook,
+ intercept_filename);
+ }
+
+ intercept_filename = dirname;
+ readdir_hook = hookfn;
+}
+
+void intercept_setup_lstat_hook(const char *filename, lstat_t hookfn)
+{
+ /*
+ if (hookfn != NULL)
+ {
+ TRACE2("lstat hooked to %p for %s\n", hookfn, filename);
+ }
+ else
+ {
+ TRACE2("lstat unhooked from %p for %s\n", lstat_hook,
+ lstat_file);
+ }
+ */
+
+ lstat_file = filename;
+ lstat_hook = hookfn;
+}
+
+static void * find_function(const char *pName)
+{
+ dlerror();
+ void *result = NULL;
+
+ #ifdef HAVE_LARGE_FILE_SUPPORT
+ {
+ // search for the 64-bit version first
+ std::string name64(pName);
+ name64 += "64";
+ result = dlsym(RTLD_NEXT, name64.c_str());
+ if (dlerror() == NULL && result != NULL)
+ {
+ return result;
+ }
+ }
+ #endif
+
+ result = dlsym(RTLD_NEXT, pName);
+ const char *errmsg = (const char *)dlerror();
+
+ if (errmsg == NULL)
+ {
+ return result;
+ }
+
+ BOX_ERROR("Failed to find real " << pName << " function: " << errmsg);
+ return NULL;
+}
+
+extern "C"
+DIR *opendir(const char *dirname)
+{
+ if (opendir_real == NULL)
+ {
+ opendir_real = (opendir_t*)find_function("opendir");
+ }
+
+ if (opendir_real == NULL)
+ {
+ perror("cannot find real opendir");
+ return NULL;
+ }
+
+ DIR* r = opendir_real(dirname);
+
+ if (readdir_hook != NULL &&
+ intercept_filename != NULL &&
+ intercept_filedes == -1 &&
+ strcmp(intercept_filename, dirname) == 0)
+ {
+ intercept_filedes = dirfd(r);
+ //printf("Found file to intercept, h = %d\n", r);
+ }
+
+ return r;
+}
+
+extern "C"
+struct dirent *readdir(DIR *dir)
+{
+ if (readdir_hook != NULL && dirfd(dir) == intercept_filedes)
+ {
+ return readdir_hook(dir);
+ }
+
+ if (readdir_real == NULL)
+ {
+ readdir_real = (readdir_t*)find_function("readdir");
+ }
+
+ if (readdir_real == NULL)
+ {
+ perror("cannot find real readdir");
+ return NULL;
+ }
+
+ return readdir_real(dir);
+}
+
+extern "C"
+int closedir(DIR *dir)
+{
+ if (dirfd(dir) == intercept_filedes)
+ {
+ intercept_filedes = -1;
+ }
+
+ if (closedir_real == NULL)
+ {
+ closedir_real = (closedir_t*)find_function("closedir");
+ }
+
+ if (closedir_real == NULL)
+ {
+ perror("cannot find real closedir");
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return closedir_real(dir);
+}
+
+extern "C" int
+#ifdef LINUX_WEIRD_LSTAT
+__lxstat(int ver, const char *file_name, STAT_STRUCT *buf)
+#else
+lstat(const char *file_name, STAT_STRUCT *buf)
+#endif
+{
+ if (lstat_real == NULL)
+ {
+ #ifdef LINUX_WEIRD_LSTAT
+ lstat_real = (lstat_t*)find_function("__lxstat");
+ #else
+ lstat_real = (lstat_t*)find_function("lstat");
+ #endif
+ }
+
+ if (lstat_real == NULL)
+ {
+ perror("cannot find real lstat");
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (lstat_hook == NULL || strcmp(file_name, lstat_file) != 0)
+ {
+ #ifdef LINUX_WEIRD_LSTAT
+ return lstat_real(ver, file_name, buf);
+ #else
+ return lstat_real(file_name, buf);
+ #endif
+ }
+
+ #ifdef LINUX_WEIRD_LSTAT
+ return lstat_hook(ver, file_name, buf);
+ #else
+ return lstat_hook(file_name, buf);
+ #endif
+}
+
#endif // n PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
diff --git a/lib/intercept/intercept.h b/lib/intercept/intercept.h
new file mode 100644
index 00000000..6748eeef
--- /dev/null
+++ b/lib/intercept/intercept.h
@@ -0,0 +1,85 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: intercept.h
+// Purpose: Syscall interception code for unit tests
+// Created: 2006/11/29
+//
+// --------------------------------------------------------------------------
+
+#ifndef INTERCEPT_H
+#define INTERCEPT_H
+#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+
+#include <dirent.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+extern "C"
+{
+ typedef DIR *(opendir_t) (const char *name);
+ typedef struct dirent *(readdir_t) (DIR *dir);
+ typedef struct dirent *(readdir_t) (DIR *dir);
+ typedef int (closedir_t)(DIR *dir);
+#if defined __GNUC__ && __GNUC__ >= 2
+#define LINUX_WEIRD_LSTAT
+#define STAT_STRUCT struct stat /* should be stat64 */
+ typedef int (lstat_t) (int ver, const char *file_name,
+ STAT_STRUCT *buf);
+#else
+#define STAT_STRUCT struct stat
+ typedef int (lstat_t) (const char *file_name,
+ STAT_STRUCT *buf);
+#endif
+}
+
+void intercept_setup_error(const char *filename, unsigned int errorafter,
+ int errortoreturn, int syscalltoerror);
+void intercept_setup_delay(const char *filename, unsigned int delay_after,
+ int delay_ms, int syscall_to_delay, int num_delays);
+bool intercept_triggered();
+
+void intercept_setup_readdir_hook(const char *dirname, readdir_t hookfn);
+void intercept_setup_lstat_hook (const char *filename, lstat_t hookfn);
+
+#endif // !PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+#endif // !INTERCEPT_H
diff --git a/lib/raidfile/Makefile.extra b/lib/raidfile/Makefile.extra
index 8d036633..4d904e8a 100644
--- a/lib/raidfile/Makefile.extra
+++ b/lib/raidfile/Makefile.extra
@@ -3,5 +3,5 @@ MAKEEXCEPTION = ../../lib/common/makeexception.pl
# AUTOGEN SEEDING
autogen_RaidFileException.h autogen_RaidFileException.cpp: $(MAKEEXCEPTION) RaidFileException.txt
- perl $(MAKEEXCEPTION) RaidFileException.txt
+ $(PERL) $(MAKEEXCEPTION) RaidFileException.txt
diff --git a/lib/raidfile/RaidFileController.cpp b/lib/raidfile/RaidFileController.cpp
index ad7ea1bb..4087d751 100644
--- a/lib/raidfile/RaidFileController.cpp
+++ b/lib/raidfile/RaidFileController.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.
@@ -97,13 +97,15 @@ RaidFileController::RaidFileController(const RaidFileController &rController)
// --------------------------------------------------------------------------
//
// Function
-// Name: RaidFileController::Initialise(const char *)
+// Name: RaidFileController::Initialise(const std::string&)
// Purpose: Initialises the system, loading the configuration file.
// Created: 2003/07/08
//
// --------------------------------------------------------------------------
-void RaidFileController::Initialise(const char *ConfigFilename)
+void RaidFileController::Initialise(const std::string& rConfigFilename)
{
+ MEMLEAKFINDER_NO_LEAKS;
+
static const ConfigurationVerifyKey verifykeys[] =
{
{"SetNumber", 0, ConfigTest_Exists | ConfigTest_IsInt, 0},
@@ -133,11 +135,12 @@ void RaidFileController::Initialise(const char *ConfigFilename)
// Load the configuration
std::string err;
- std::auto_ptr<Configuration> pconfig = Configuration::LoadAndVerify(ConfigFilename, &verify, err);
+ std::auto_ptr<Configuration> pconfig = Configuration::LoadAndVerify(
+ rConfigFilename, &verify, err);
if(pconfig.get() == 0 || !err.empty())
{
- fprintf(stderr, "RaidFile configuation file errors:\n%s", err.c_str());
+ BOX_ERROR("RaidFile configuration file errors: " << err);
THROW_EXCEPTION(RaidFileException, BadConfigFile)
}
diff --git a/lib/raidfile/RaidFileController.h b/lib/raidfile/RaidFileController.h
index 8fc3397a..e3e5352d 100644
--- a/lib/raidfile/RaidFileController.h
+++ b/lib/raidfile/RaidFileController.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.
@@ -119,7 +119,8 @@ public:
~RaidFileController();
public:
- void Initialise(const char *ConfigFilename = "/etc/box/raidfile.conf");
+ void Initialise(const std::string& rConfigFilename =
+ "/etc/box/raidfile.conf");
int GetNumDiscSets() {return mSetList.size();}
// --------------------------------------------------------------------------
diff --git a/lib/raidfile/RaidFileException.h b/lib/raidfile/RaidFileException.h
index 31378b9b..6ce00fd8 100644
--- a/lib/raidfile/RaidFileException.h
+++ b/lib/raidfile/RaidFileException.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/raidfile/RaidFileException.txt b/lib/raidfile/RaidFileException.txt
index 6ad74563..c69dc2a2 100644
--- a/lib/raidfile/RaidFileException.txt
+++ b/lib/raidfile/RaidFileException.txt
@@ -11,7 +11,7 @@ NotOpen 7
OSError 8 Error when accessing an underlying file. Check file permissions allow files to be read and written in the configured raid directories.
WriteFileOpenOnTransform 9
WrongNumberOfDiscsInSet 10 There should be three directories in each disc set.
-RaidFileDoesntExist 11
+RaidFileDoesntExist 11 Error when accessing a file on the store. Check the store with bbstoreaccounts check.
ErrorOpeningFileForRead 12
FileIsDamagedNotRecoverable 13
InvalidRaidFile 14
diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp
index f5ed2701..29adeab2 100644
--- a/lib/raidfile/RaidFileRead.cpp
+++ b/lib/raidfile/RaidFileRead.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,15 +47,21 @@
#include "Box.h"
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <syslog.h>
+#include <fcntl.h>
#include <stdarg.h>
-#include <dirent.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_UIO_H
+ #include <sys/uio.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+ #include <dirent.h>
+#endif
#include <stdio.h>
#include <string.h>
@@ -70,7 +76,10 @@
#include "MemLeakFindOn.h"
#define READ_NUMBER_DISCS_REQUIRED 3
-#define READV_MAX_BLOCKS 64
+#define READV_MAX_BLOCKS 64
+
+// We want to use POSIX fstat() for now, not the emulated one
+#undef fstat
// --------------------------------------------------------------------------
//
@@ -573,8 +582,8 @@ void RaidFileRead_Raid::MoveDamagedFileAlertDaemon(int SetNumber, const std::str
// --------------------------------------------------------------------------
void RaidFileRead_Raid::AttemptToRecoverFromIOError(bool Stripe1)
{
- TRACE3("Attempting to recover from I/O error: %d %s, on stripe %d\n", mSetNumber, mFilename.c_str(), Stripe1?1:2);
- ::syslog(LOG_ERR | LOG_LOCAL5, "Attempting to recover from I/O error: %d %s, on stripe %d\n", mSetNumber, mFilename.c_str(), Stripe1?1:2);
+ BOX_WARNING("Attempting to recover from I/O error: " << mSetNumber <<
+ " " << mFilename << ", on stripe " << (Stripe1?1:2));
// Close offending file
if(Stripe1)
@@ -621,7 +630,8 @@ void RaidFileRead_Raid::AttemptToRecoverFromIOError(bool Stripe1)
// Open the parity file
std::string parityFilename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, (2 + startDisc) % READ_NUMBER_DISCS_REQUIRED));
- mParityHandle = ::open(parityFilename.c_str(), O_RDONLY, 0555);
+ mParityHandle = ::open(parityFilename.c_str(),
+ O_RDONLY | O_BINARY, 0555);
if(mParityHandle == -1)
{
THROW_EXCEPTION(RaidFileException, OSError)
@@ -885,8 +895,10 @@ void RaidFileRead_Raid::SetPosition(pos_type FilePosition)
{
if(errno == EIO)
{
- TRACE3("I/O error when seeking in %d %s (to %d), stripe 1\n", mSetNumber, mFilename.c_str(), (int)FilePosition);
- ::syslog(LOG_ERR | LOG_LOCAL5, "I/O error when seeking in %d %s (to %d), stripe 1\n", mSetNumber, mFilename.c_str(), (int)FilePosition);
+ BOX_ERROR("I/O error when seeking in " <<
+ mSetNumber << " " << mFilename <<
+ " (to " << FilePosition << "), " <<
+ "stripe 1");
// Attempt to recover
AttemptToRecoverFromIOError(true /* is stripe 1 */);
ASSERT(mStripe1Handle == -1);
@@ -903,8 +915,10 @@ void RaidFileRead_Raid::SetPosition(pos_type FilePosition)
{
if(errno == EIO)
{
- TRACE3("I/O error when seeking in %d %s (to %d), stripe 2\n", mSetNumber, mFilename.c_str(), (int)FilePosition);
- ::syslog(LOG_ERR | LOG_LOCAL5, "I/O error when seeking in %d %s (to %d), stripe 2\n", mSetNumber, mFilename.c_str(), (int)FilePosition);
+ BOX_ERROR("I/O error when seeking in " <<
+ mSetNumber << " " << mFilename <<
+ " (to " << FilePosition << "), " <<
+ "stripe 2");
// Attempt to recover
AttemptToRecoverFromIOError(false /* is stripe 2 */);
ASSERT(mStripe2Handle == -1);
@@ -1055,7 +1069,8 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, Filename));
// Attempt to open
- int osFileHandle = ::open(writeFilename.c_str(), O_RDONLY, 0);
+ int osFileHandle = ::open(writeFilename.c_str(),
+ O_RDONLY | O_BINARY, 0);
if(osFileHandle == -1)
{
THROW_EXCEPTION(RaidFileException, ErrorOpeningFileForRead)
@@ -1077,8 +1092,9 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
{
if(existance != RaidFileUtil::AsRaid)
{
- TRACE2("Opening %d %s in normal mode, but parity file doesn't exist\n", SetNumber, Filename.c_str());
- ::syslog(LOG_ERR | LOG_LOCAL5, "Opening %d %s in normal mode, but parity file doesn't exist\n", SetNumber, Filename.c_str());
+ BOX_ERROR("Opening " << SetNumber << " " <<
+ Filename << " in normal mode, but "
+ "parity file doesn't exist");
// TODO: Alert recovery daemon
}
@@ -1093,13 +1109,15 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
try
{
// Open stripe1
- stripe1 = ::open(stripe1Filename.c_str(), O_RDONLY, 0555);
+ stripe1 = ::open(stripe1Filename.c_str(),
+ O_RDONLY | O_BINARY, 0555);
if(stripe1 == -1)
{
stripe1errno = errno;
}
// Open stripe2
- stripe2 = ::open(stripe2Filename.c_str(), O_RDONLY, 0555);
+ stripe2 = ::open(stripe2Filename.c_str(),
+ O_RDONLY | O_BINARY, 0555);
if(stripe2 == -1)
{
stripe2errno = errno;
@@ -1151,8 +1169,9 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
bool oktotryagain = true;
if(stripe1errno == EIO)
{
- TRACE2("I/O error on opening %d %s stripe 1, trying recovery mode\n", SetNumber, Filename.c_str());
- ::syslog(LOG_ERR | LOG_LOCAL5, "I/O error on opening %d %s stripe 1, trying recovery mode\n", SetNumber, Filename.c_str());
+ BOX_ERROR("I/O error on opening " <<
+ SetNumber << " " << Filename <<
+ " stripe 1, trying recovery mode");
RaidFileRead_Raid::MoveDamagedFileAlertDaemon(SetNumber, Filename, true /* is stripe 1 */);
existingFiles = existingFiles & ~RaidFileUtil::Stripe1Exists;
@@ -1167,8 +1186,9 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
if(stripe2errno == EIO)
{
- TRACE2("I/O error on opening %d %s stripe 2, trying recovery mode\n", SetNumber, Filename.c_str());
- ::syslog(LOG_ERR | LOG_LOCAL5, "I/O error on opening %d %s stripe 2, trying recovery mode\n", SetNumber, Filename.c_str());
+ BOX_ERROR("I/O error on opening " <<
+ SetNumber << " " << Filename <<
+ " stripe 2, trying recovery mode");
RaidFileRead_Raid::MoveDamagedFileAlertDaemon(SetNumber, Filename, false /* is stripe 2 */);
existingFiles = existingFiles & ~RaidFileUtil::Stripe2Exists;
@@ -1190,8 +1210,10 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
if(existance == RaidFileUtil::AsRaidWithMissingReadable)
{
- TRACE3("Attempting to open RAID file %d %s in recovery mode (stripe %d present)\n", SetNumber, Filename.c_str(), (existingFiles & RaidFileUtil::Stripe1Exists)?1:2);
- ::syslog(LOG_ERR | LOG_LOCAL5, "Attempting to open RAID file %d %s in recovery mode (stripe %d present)\n", SetNumber, Filename.c_str(), (existingFiles & RaidFileUtil::Stripe1Exists)?1:2);
+ BOX_ERROR("Attempting to open RAID file " << SetNumber <<
+ " " << Filename << " in recovery mode (stripe " <<
+ ((existingFiles & RaidFileUtil::Stripe1Exists)?1:2) <<
+ " present)");
// Generate the filenames of all the lovely files
std::string stripe1Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, Filename, (0 + startDisc) % READ_NUMBER_DISCS_REQUIRED));
@@ -1207,7 +1229,8 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
// Open stripe1?
if(existingFiles & RaidFileUtil::Stripe1Exists)
{
- stripe1 = ::open(stripe1Filename.c_str(), O_RDONLY, 0555);
+ stripe1 = ::open(stripe1Filename.c_str(),
+ O_RDONLY | O_BINARY, 0555);
if(stripe1 == -1)
{
THROW_EXCEPTION(RaidFileException, OSError)
@@ -1216,14 +1239,16 @@ std::auto_ptr<RaidFileRead> RaidFileRead::Open(int SetNumber, const std::string
// Open stripe2?
if(existingFiles & RaidFileUtil::Stripe2Exists)
{
- stripe2 = ::open(stripe2Filename.c_str(), O_RDONLY, 0555);
+ stripe2 = ::open(stripe2Filename.c_str(),
+ O_RDONLY | O_BINARY, 0555);
if(stripe2 == -1)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
}
// Open parity
- parity = ::open(parityFilename.c_str(), O_RDONLY, 0555);
+ parity = ::open(parityFilename.c_str(),
+ O_RDONLY | O_BINARY, 0555);
if(parity == -1)
{
THROW_EXCEPTION(RaidFileException, OSError)
diff --git a/lib/raidfile/RaidFileRead.h b/lib/raidfile/RaidFileRead.h
index 2648e1e1..09841d8b 100644
--- a/lib/raidfile/RaidFileRead.h
+++ b/lib/raidfile/RaidFileRead.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/raidfile/RaidFileUtil.cpp b/lib/raidfile/RaidFileUtil.cpp
index da5aa362..e36b3f21 100644
--- a/lib/raidfile/RaidFileUtil.cpp
+++ b/lib/raidfile/RaidFileUtil.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/raidfile/RaidFileUtil.h b/lib/raidfile/RaidFileUtil.h
index 738663a6..487fb51d 100644
--- a/lib/raidfile/RaidFileUtil.h
+++ b/lib/raidfile/RaidFileUtil.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/raidfile/RaidFileWrite.cpp b/lib/raidfile/RaidFileWrite.cpp
index 1e2440b9..04a7995c 100644
--- a/lib/raidfile/RaidFileWrite.cpp
+++ b/lib/raidfile/RaidFileWrite.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.
@@ -73,6 +73,9 @@
// Must have this number of discs in the set
#define TRANSFORM_NUMBER_DISCS_REQUIRED 3
+// we want to use POSIX fstat() for now, not the emulated one
+#undef fstat
+
// --------------------------------------------------------------------------
//
// Function
@@ -142,7 +145,8 @@ void RaidFileWrite::Open(bool AllowOverwrite)
writeFilename += 'X';
// Attempt to open
- mOSFileHandle = ::open(writeFilename.c_str(), O_WRONLY | O_CREAT,
+ mOSFileHandle = ::open(writeFilename.c_str(),
+ O_WRONLY | O_CREAT | O_BINARY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(mOSFileHandle == -1)
{
@@ -153,7 +157,7 @@ void RaidFileWrite::Open(bool AllowOverwrite)
#ifdef HAVE_FLOCK
int errnoBlock = EWOULDBLOCK;
if(::flock(mOSFileHandle, LOCK_EX | LOCK_NB) != 0)
-#else
+#elif HAVE_DECL_F_SETLK
int errnoBlock = EAGAIN;
struct flock desc;
desc.l_type = F_WRLCK;
@@ -161,6 +165,9 @@ void RaidFileWrite::Open(bool AllowOverwrite)
desc.l_start = 0;
desc.l_len = 0;
if(::fcntl(mOSFileHandle, F_SETLK, &desc) != 0)
+#else
+ int errnoBlock = ENOSYS;
+ if (0)
#endif
{
// Lock was not obtained.
@@ -280,23 +287,46 @@ void RaidFileWrite::Commit(bool ConvertToRaidNow)
}
// Rename it into place -- BEFORE it's closed so lock remains
+
+#ifdef WIN32
+ // Except on Win32 which doesn't allow renaming open files
+ // Close file...
+ if(::close(mOSFileHandle) != 0)
+ {
+ THROW_EXCEPTION(RaidFileException, OSError)
+ }
+ mOSFileHandle = -1;
+#endif // WIN32
+
RaidFileController &rcontroller(RaidFileController::GetController());
RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
// Get the filename for the write file
std::string renameTo(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
// And the current name
std::string renameFrom(renameTo + 'X');
+
+#ifdef WIN32
+ // need to delete the target first
+ if(::unlink(renameTo.c_str()) != 0 &&
+ GetLastError() != ERROR_FILE_NOT_FOUND)
+ {
+ THROW_EXCEPTION(RaidFileException, OSError)
+ }
+#endif
+
if(::rename(renameFrom.c_str(), renameTo.c_str()) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
+#ifndef WIN32
// Close file...
if(::close(mOSFileHandle) != 0)
{
THROW_EXCEPTION(RaidFileException, OSError)
}
mOSFileHandle = -1;
+#endif // !WIN32
// Raid it?
if(ConvertToRaidNow)
@@ -330,8 +360,15 @@ void RaidFileWrite::Discard()
writeFilename += 'X';
// Unlink and close it
- if((::unlink(writeFilename.c_str()) != 0)
- || (::close(mOSFileHandle) != 0))
+
+#ifdef WIN32
+ // On Win32 we must close it first
+ if (::close(mOSFileHandle) != 0 ||
+ ::unlink(writeFilename.c_str()) != 0)
+#else // !WIN32
+ if (::unlink(writeFilename.c_str()) != 0 ||
+ ::close(mOSFileHandle) != 0)
+#endif // !WIN32
{
THROW_EXCEPTION(RaidFileException, OSError)
}
@@ -426,13 +463,13 @@ void RaidFileWrite::TransformToRaidStorage()
try
{
#if HAVE_DECL_O_EXLOCK
- FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> stripe1(stripe1FilenameW.c_str());
- FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> stripe2(stripe2FilenameW.c_str());
- FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK)> parity(parityFilenameW.c_str());
+ FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> stripe1(stripe1FilenameW.c_str());
+ FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> stripe2(stripe2FilenameW.c_str());
+ FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> parity(parityFilenameW.c_str());
#else
- FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> stripe1(stripe1FilenameW.c_str());
- FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> stripe2(stripe2FilenameW.c_str());
- FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL)> parity(parityFilenameW.c_str());
+ FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> stripe1(stripe1FilenameW.c_str());
+ FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> stripe2(stripe2FilenameW.c_str());
+ FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> parity(parityFilenameW.c_str());
#endif
// Then... read in data...
@@ -568,6 +605,21 @@ void RaidFileWrite::TransformToRaidStorage()
parity.Close();
stripe2.Close();
stripe1.Close();
+
+#ifdef WIN32
+ // Must delete before renaming
+ #define CHECK_UNLINK(file) \
+ { \
+ if (::unlink(file) != 0 && errno != ENOENT) \
+ { \
+ THROW_EXCEPTION(RaidFileException, OSError); \
+ } \
+ }
+ CHECK_UNLINK(stripe1Filename.c_str());
+ CHECK_UNLINK(stripe2Filename.c_str());
+ CHECK_UNLINK(parityFilename.c_str());
+ #undef CHECK_UNLINK
+#endif
// Rename them into place
if(::rename(stripe1FilenameW.c_str(), stripe1Filename.c_str()) != 0
diff --git a/lib/raidfile/RaidFileWrite.h b/lib/raidfile/RaidFileWrite.h
index 89e31dc2..a3693f97 100644
--- a/lib/raidfile/RaidFileWrite.h
+++ b/lib/raidfile/RaidFileWrite.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/raidfile/raidfile-config b/lib/raidfile/raidfile-config
index d93bf519..41f38cd5 100755
--- a/lib/raidfile/raidfile-config
+++ b/lib/raidfile/raidfile-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/lib/raidfile/raidfile-config.in b/lib/raidfile/raidfile-config.in
new file mode 100755
index 00000000..f1098adc
--- /dev/null
+++ b/lib/raidfile/raidfile-config.in
@@ -0,0 +1,97 @@
+#!@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 != 4 && $#ARGV != 2)
+{
+ print <<__E;
+
+Setup raidfile config utility.
+
+Bad command line parameters.
+Usage:
+ raidfile-config config-dir block-size dir0 [dir1 dir2]
+
+config-dir usually /etc/box
+block-size must be a power of two, and usually the block or fragment size of your filing system
+dir0, dir1, dir2 are the directories used as the root of the raid file system
+
+If only one directory is specified, then userland RAID is disabled. Specifying three directories
+enables it.
+
+__E
+ exit(1);
+}
+
+my ($config_dir,$block_size,@dirs) = @ARGV;
+
+my $conf = $config_dir . '/raidfile.conf';
+
+# check dirs are unique, and exist
+my %d;
+for(@dirs)
+{
+ die "$_ is used twice" if exists $d{$_};
+ die "$_ is not a directory" unless -d $_;
+ die "$_ should be an absolute path" unless m/\A\//;
+ $d{$_} = 1;
+}
+
+# check block size is OK
+$block_size = int($block_size);
+die "Bad block size" if $block_size <= 0;
+my $c = 1;
+while(1)
+{
+ last if $c == $block_size;
+ die "Block size $block_size is not a power of two" if $c > $block_size;
+ $c = $c * 2;
+}
+
+# check that it doesn't already exist
+if(-f $conf)
+{
+ die "$conf already exists. Delete and try again"
+}
+
+# create directory
+if(!-d $config_dir)
+{
+ print "Creating $config_dir...\n";
+ mkdir $config_dir,0755 or die "Can't create $config_dir";
+}
+
+# adjust if userland RAID is disabled
+if($#dirs == 0)
+{
+ $dirs[1] = $dirs[0];
+ $dirs[2] = $dirs[0];
+ print "WARNING: userland RAID is disabled.\n"
+}
+
+# write the file
+open CONFIG,">$conf" or die "Can't open $conf for writing";
+
+print CONFIG <<__E;
+
+disc0
+{
+ SetNumber = 0
+ BlockSize = $block_size
+ Dir0 = $dirs[0]
+ Dir1 = $dirs[1]
+ Dir2 = $dirs[2]
+}
+
+__E
+
+close CONFIG;
+
+print "Config file written.\n";
+
diff --git a/lib/server/ConnectionException.txt b/lib/server/ConnectionException.txt
index 5056754f..c3429116 100644
--- a/lib/server/ConnectionException.txt
+++ b/lib/server/ConnectionException.txt
@@ -10,7 +10,7 @@ SocketConnectError 15 Probably a network issue between client and server, bad
TLSHandshakeFailed 30
TLSShutdownFailed 32
TLSWriteFailed 33 Probably a network issue between client and server.
-TLSReadFailed 34 Probably a network issue between client and server.
+TLSReadFailed 34 Probably a network issue between client and server, or a problem with the server.
TLSNoPeerCertificate 36
TLSPeerCertificateInvalid 37 Check certification process
TLSClosedWhenWriting 38
diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp
index 3366383a..facac900 100644
--- a/lib/server/Daemon.cpp
+++ b/lib/server/Daemon.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,16 +57,19 @@
#include <string.h>
#include <stdarg.h>
-#ifdef HAVE_SYSLOG_H
- #include <syslog.h>
+#ifdef WIN32
+ #include <ws2tcpip.h>
#endif
+#include <iostream>
+
#include "Daemon.h"
#include "Configuration.h"
#include "ServerException.h"
#include "Guards.h"
#include "UnixUser.h"
#include "FileModificationTime.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -82,11 +85,16 @@ Daemon *Daemon::spDaemon = 0;
//
// --------------------------------------------------------------------------
Daemon::Daemon()
- : mpConfiguration(0),
+ : mpConfiguration(NULL),
mReloadConfigWanted(false),
- mTerminateWanted(false)
+ mTerminateWanted(false),
+ mSingleProcess(false),
+ mRunInForeground(false),
+ mKeepConsoleOpenAfterFork(false),
+ mHaveConfigFile(false),
+ mAppName(DaemonName())
{
- if(spDaemon != 0)
+ if(spDaemon != NULL)
{
THROW_EXCEPTION(ServerException, AlreadyDaemonConstructed)
}
@@ -113,56 +121,267 @@ Daemon::~Daemon()
delete mpConfiguration;
mpConfiguration = 0;
}
+
+ ASSERT(spDaemon == this);
+ spDaemon = NULL;
}
// --------------------------------------------------------------------------
//
// Function
-// Name: Daemon::Main(const char *, int, const char *[])
-// Purpose: Starts the daemon off -- equivalent of C main() function
-// Created: 2003/07/29
+// Name: Daemon::GetOptionString()
+// Purpose: Returns the valid Getopt command-line options.
+// This should be overridden by subclasses to add
+// their own options, which should override
+// ProcessOption, handle their own, and delegate to
+// ProcessOption for the standard options.
+// Created: 2007/09/18
//
// --------------------------------------------------------------------------
-int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
+std::string Daemon::GetOptionString()
{
- // Banner (optional)
+ return "c:"
+ #ifndef WIN32
+ "DFk"
+ #endif
+ "hqvVt:T";
+}
+
+void Daemon::Usage()
+{
+ std::cout <<
+ DaemonBanner() << "\n"
+ "\n"
+ "Usage: " << mAppName << " [options] [config file]\n"
+ "\n"
+ "Options:\n"
+ " -c <file> Use the specified configuration file. If -c is omitted, the last\n"
+ " argument is the configuration file, or else the default \n"
+ " [" << GetConfigFileName() << "]\n"
+#ifndef WIN32
+ " -D Debugging mode, do not fork, one process only, one client only\n"
+ " -F Do not fork into background, but fork to serve multiple clients\n"
+ " -k Keep console open after fork, keep writing log messages to it\n"
+#endif
+ " -q Run more quietly, reduce verbosity level by one, can repeat\n"
+ " -v Run more verbosely, increase verbosity level by one, can repeat\n"
+ " -V Run at maximum verbosity\n"
+ " -t <tag> Tag console output with specified marker\n"
+ " -T Timestamp console output\n";
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Daemon::ProcessOption(int option)
+// Purpose: Processes the supplied option (equivalent to the
+// return code from getopt()). Return zero if the
+// option was handled successfully, or nonzero to
+// abort the program with that return value.
+// Created: 2007/09/18
+//
+// --------------------------------------------------------------------------
+int Daemon::ProcessOption(signed int option)
+{
+ switch(option)
{
- const char *banner = DaemonBanner();
- if(banner != 0)
+ case 'c':
{
- printf("%s", banner);
+ mConfigFileName = optarg;
+ mHaveConfigFile = true;
}
- }
+ break;
- std::string pidFileName;
+#ifndef WIN32
+ case 'D':
+ {
+ mSingleProcess = true;
+ }
+ break;
- try
- {
- // Find filename of config file
- mConfigFileName = DefaultConfigFile;
- if(argc >= 2)
+ case 'F':
{
- // First argument is config file, or it's -c and the next arg is the config file
- if(::strcmp(argv[1], "-c") == 0 && argc >= 3)
- {
- mConfigFileName = argv[2];
- }
- else
+ mRunInForeground = true;
+ }
+ break;
+
+ case 'k':
+ {
+ mKeepConsoleOpenAfterFork = true;
+ }
+ break;
+#endif
+
+ case 'h':
+ {
+ Usage();
+ return 2;
+ }
+ break;
+
+ case 'q':
+ {
+ if(mLogLevel == Log::NOTHING)
{
- mConfigFileName = argv[1];
+ BOX_FATAL("Too many '-q': "
+ "Cannot reduce logging "
+ "level any more");
+ return 2;
}
+ mLogLevel--;
}
-
- // Test mode with no daemonisation?
- bool asDaemon = true;
- if(argc >= 3)
+ break;
+
+ case 'v':
{
- if(::strcmp(argv[2], "SINGLEPROCESS") == 0)
+ if(mLogLevel == Log::EVERYTHING)
{
- asDaemon = false;
+ BOX_FATAL("Too many '-v': "
+ "Cannot increase logging "
+ "level any more");
+ return 2;
}
+ mLogLevel++;
+ }
+ break;
+
+ case 'V':
+ {
+ mLogLevel = Log::EVERYTHING;
+ }
+ break;
+
+ case 't':
+ {
+ Console::SetTag(optarg);
+ }
+ break;
+
+ case 'T':
+ {
+ Console::SetShowTime(true);
+ }
+ break;
+
+ case '?':
+ {
+ BOX_FATAL("Unknown option on command line: "
+ << "'" << (char)optopt << "'");
+ return 2;
+ }
+ break;
+
+ default:
+ {
+ BOX_FATAL("Unknown error in getopt: returned "
+ << "'" << option << "'");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Daemon::Main(const char *, int, const char *[])
+// Purpose: Parses command-line options, and then calls
+// Main(std::string& configFile, bool singleProcess)
+// to start the daemon.
+// Created: 2003/07/29
+//
+// --------------------------------------------------------------------------
+int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
+{
+ // Find filename of config file
+ mConfigFileName = DefaultConfigFile;
+ mAppName = argv[0];
+
+ #ifdef NDEBUG
+ mLogLevel = Log::NOTICE; // need an int to do math with
+ #else
+ mLogLevel = Log::INFO; // need an int to do math with
+ #endif
+
+ if (argc == 2 && strcmp(argv[1], "/?") == 0)
+ {
+ Usage();
+ return 2;
+ }
+
+ signed int c;
+
+ // reset getopt, just in case anybody used it before.
+ // unfortunately glibc and BSD differ on this point!
+ // http://www.ussg.iu.edu/hypermail/linux/kernel/0305.3/0262.html
+ #if HAVE_DECL_OPTRESET == 1
+ optind = 1;
+ optreset = 1;
+ #elif defined __GLIBC__
+ optind = 0;
+ #else // Solaris, any others?
+ optind = 1;
+ #endif
+
+ while((c = getopt(argc, (char * const *)argv,
+ GetOptionString().c_str())) != -1)
+ {
+ int returnCode = ProcessOption(c);
+
+ if (returnCode != 0)
+ {
+ return returnCode;
}
+ }
+ if (argc > optind && !mHaveConfigFile)
+ {
+ mConfigFileName = argv[optind]; optind++;
+ }
+
+ if (argc > optind && ::strcmp(argv[optind], "SINGLEPROCESS") == 0)
+ {
+ mSingleProcess = true; optind++;
+ }
+
+ if (argc > optind)
+ {
+ BOX_FATAL("Unknown parameter on command line: "
+ << "'" << std::string(argv[optind]) << "'");
+ return 2;
+ }
+
+ Logging::SetGlobalLevel((Log::Level)mLogLevel);
+
+ return Main(mConfigFileName);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Daemon::Main(const std::string& rConfigFileName)
+// Purpose: Starts the daemon off -- equivalent of C main() function
+// Created: 2003/07/29
+//
+// --------------------------------------------------------------------------
+int Daemon::Main(const std::string &rConfigFileName)
+{
+ // Banner (optional)
+ {
+ #ifndef NDEBUG
+ BOX_NOTICE(DaemonBanner());
+ #endif
+ }
+
+ std::string pidFileName;
+
+ mConfigFileName = rConfigFileName;
+
+ bool asDaemon = !mSingleProcess && !mRunInForeground;
+
+ try
+ {
// Load the configuration file.
std::string errors;
std::auto_ptr<Configuration> pconfig;
@@ -178,16 +397,9 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
if(e.GetType() == CommonException::ExceptionType &&
e.GetSubType() == CommonException::OSFileOpenError)
{
- fprintf(stderr, "%s: failed to start: "
- "failed to open configuration file: "
- "%s", DaemonName(),
- mConfigFileName.c_str());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: failed to start: "
- "failed to open configuration file: "
- "%s", DaemonName(),
- mConfigFileName.c_str());
-#endif
+ BOX_FATAL("Failed to start: failed to open "
+ "configuration file: "
+ << mConfigFileName);
return 1;
}
@@ -198,14 +410,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
if(pconfig.get() == 0 || !errors.empty())
{
// Tell user about errors
- fprintf(stderr, "%s: Errors in config file %s:\n%s",
- DaemonName(), mConfigFileName.c_str(),
- errors.c_str());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: Errors in config file %s:\n%s",
- DaemonName(), mConfigFileName.c_str(),
- errors.c_str());
-#endif
+ BOX_FATAL("Failed to start: errors in configuration "
+ "file: " << mConfigFileName << ": " << errors);
// And give up
return 1;
}
@@ -217,17 +423,6 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
// Let the derived class have a go at setting up stuff in the initial process
SetupInInitialProcess();
-#ifndef WIN32
- // Set signal handler
- struct sigaction sa;
- sa.sa_handler = SignalHandler;
- sa.sa_flags = 0;
- sigemptyset(&sa.sa_mask); // macro
- if(::sigaction(SIGHUP, &sa, NULL) != 0 || ::sigaction(SIGTERM, &sa, NULL) != 0)
- {
- THROW_EXCEPTION(ServerException, DaemoniseFailed)
- }
-
// Server configuration
const Configuration &serverConfig(
mpConfiguration->GetSubConfiguration("Server"));
@@ -235,7 +430,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
// Open PID file for writing
pidFileName = serverConfig.GetKeyValue("PidFile");
FileHandleGuard<(O_WRONLY | O_CREAT | O_TRUNC), (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)> pidFile(pidFileName.c_str());
-
+
+#ifndef WIN32
// Handle changing to a different user
if(serverConfig.KeyExists("User"))
{
@@ -264,7 +460,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
default:
// parent
- _exit(0);
+ // _exit(0);
return 0;
break;
@@ -278,7 +474,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
// Set new session
if(::setsid() == -1)
{
- ::syslog(LOG_ERR, "can't setsid");
+ BOX_ERROR("Failed to setsid(): " <<
+ strerror(errno));
THROW_EXCEPTION(ServerException, DaemoniseFailed)
}
@@ -301,24 +498,39 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
break;
}
}
-#endif // ! WIN32
- // open the log
- ::openlog(DaemonName(), LOG_PID, LOG_LOCAL6);
+ // Set signal handler
+ // Don't do this in the parent, since it might be anything
+ // (e.g. test/bbackupd)
+
+ struct sigaction sa;
+ sa.sa_handler = SignalHandler;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask); // macro
+ if(::sigaction(SIGHUP, &sa, NULL) != 0 || ::sigaction(SIGTERM, &sa, NULL) != 0)
+ {
+ THROW_EXCEPTION(ServerException, DaemoniseFailed)
+ }
+#endif // !WIN32
+
// Log the start message
- ::syslog(LOG_INFO, "Starting daemon (config: %s) (version "
- BOX_VERSION ")", mConfigFileName.c_str());
+ BOX_NOTICE("Starting daemon, version " << BOX_VERSION
+ << ", config: " << mConfigFileName);
-#ifndef WIN32
// Write PID to file
char pid[32];
+
+#ifdef WIN32
+ int pidsize = sprintf(pid, "%d", (int)GetCurrentProcessId());
+#else
int pidsize = sprintf(pid, "%d", (int)getpid());
+#endif
+
if(::write(pidFile, pid, pidsize) != pidsize)
{
- ::syslog(LOG_ERR, "can't write pid file");
+ BOX_FATAL("can't write pid file");
THROW_EXCEPTION(ServerException, DaemoniseFailed)
}
-#endif
// Set up memory leak reporting
#ifdef BOX_MEMORY_LEAK_TESTING
@@ -329,7 +541,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
}
#endif // BOX_MEMORY_LEAK_TESTING
- if(asDaemon)
+ if(asDaemon && !mKeepConsoleOpenAfterFork)
{
#ifndef WIN32
// Close standard streams
@@ -352,44 +564,47 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
{
::close(devnull);
}
-#endif // ! WIN32
// And definitely don't try and send anything to those file descriptors
// -- this has in the past sent text to something which isn't expecting it.
TRACE_TO_STDOUT(false);
+ Logging::ToConsole(false);
+#endif // ! WIN32
}
}
catch(BoxException &e)
{
- fprintf(stderr, "%s: failed to start: exception %s (%d/%d)\n",
- DaemonName(), e.what(), e.GetType(), e.GetSubType());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: failed to start: "
- "exception %s (%d/%d)\n", DaemonName(),
- e.what(), e.GetType(), e.GetSubType());
-#endif
+ BOX_FATAL("Failed to start: exception " << e.what()
+ << " (" << e.GetType()
+ << "/" << e.GetSubType() << ")");
return 1;
}
catch(std::exception &e)
{
- fprintf(stderr, "%s: failed to start: exception %s\n",
- DaemonName(), e.what());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: failed to start: exception %s\n",
- DaemonName(), e.what());
-#endif
+ BOX_FATAL("Failed to start: exception " << e.what());
return 1;
}
catch(...)
{
- fprintf(stderr, "%s: failed to start: unknown exception\n",
- DaemonName());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: failed to start: unknown exception\n",
- DaemonName());
-#endif
+ BOX_FATAL("Failed to start: unknown error");
return 1;
}
+
+#ifdef WIN32
+ // Under win32 we must initialise the Winsock library
+ // before using sockets
+
+ WSADATA info;
+
+ if (WSAStartup(0x0101, &info) == SOCKET_ERROR)
+ {
+ // will not run without sockets
+ BOX_FATAL("Failed to initialise Windows Sockets");
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+#endif
+
+ int retcode = 0;
// Main Daemon running
try
@@ -401,9 +616,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
if(mReloadConfigWanted && !mTerminateWanted)
{
// Need to reload that config file...
- ::syslog(LOG_INFO, "Reloading configuration "
- "(config: %s)",
- mConfigFileName.c_str());
+ BOX_NOTICE("Reloading configuration file: "
+ << mConfigFileName);
std::string errors;
std::auto_ptr<Configuration> pconfig =
Configuration::LoadAndVerify(
@@ -414,12 +628,12 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
if(pconfig.get() == 0 || !errors.empty())
{
// Tell user about errors
- ::syslog(LOG_ERR, "Errors in config "
- "file %s:\n%s",
- mConfigFileName.c_str(),
- errors.c_str());
+ BOX_FATAL("Error in configuration "
+ << "file: " << mConfigFileName
+ << ": " << errors);
// And give up
- return 1;
+ retcode = 1;
+ break;
}
// delete old configuration
@@ -440,29 +654,31 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
::unlink(pidFileName.c_str());
// Log
- ::syslog(LOG_INFO, "Terminating daemon");
+ BOX_NOTICE("Terminating daemon");
}
catch(BoxException &e)
{
- ::syslog(LOG_ERR, "%s: terminating due to exception %s "
- "(%d/%d)", DaemonName(), e.what(), e.GetType(),
- e.GetSubType());
- return 1;
+ BOX_FATAL("Terminating due to exception " << e.what()
+ << " (" << e.GetType()
+ << "/" << e.GetSubType() << ")");
+ retcode = 1;
}
catch(std::exception &e)
{
- ::syslog(LOG_ERR, "%s: terminating due to exception %s",
- DaemonName(), e.what());
- return 1;
+ BOX_FATAL("Terminating due to exception " << e.what());
+ retcode = 1;
}
catch(...)
{
- ::syslog(LOG_ERR, "%s: terminating due to unknown exception",
- DaemonName());
- return 1;
+ BOX_FATAL("Terminating due to unknown exception");
+ retcode = 1;
}
+
+#ifdef WIN32
+ WSACleanup();
+#endif
- return 0;
+ return retcode;
}
// --------------------------------------------------------------------------
@@ -539,9 +755,9 @@ const char *Daemon::DaemonName() const
// Created: 1/1/04
//
// --------------------------------------------------------------------------
-const char *Daemon::DaemonBanner() const
+std::string Daemon::DaemonBanner() const
{
- return 0;
+ return "Generic daemon using the Box Application Framework";
}
diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h
index ff36fba4..a500ec6a 100644
--- a/lib/server/Daemon.h
+++ b/lib/server/Daemon.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.
@@ -79,14 +79,18 @@ private:
public:
int Main(const char *DefaultConfigFile, int argc, const char *argv[]);
+
+ /* override this Main() if you want custom option processing: */
+ virtual int Main(const std::string &rConfigFile);
virtual void Run();
const Configuration &GetConfiguration() const;
const std::string &GetConfigFileName() const {return mConfigFileName;}
virtual const char *DaemonName() const;
- virtual const char *DaemonBanner() const;
+ virtual std::string DaemonBanner() const;
virtual const ConfigurationVerify *GetConfigVerify() const;
+ virtual void Usage();
bool StopRun() {return mReloadConfigWanted | mTerminateWanted;}
bool IsReloadConfigWanted() {return mReloadConfigWanted;}
@@ -103,18 +107,26 @@ public:
protected:
box_time_t GetLoadedConfigModifiedTime() const;
+ bool IsSingleProcess() { return mSingleProcess; }
+ virtual std::string GetOptionString();
+ virtual int ProcessOption(signed int option);
private:
static void SignalHandler(int sigraised);
box_time_t GetConfigFileModifiedTime() const;
-private:
std::string mConfigFileName;
Configuration *mpConfiguration;
box_time_t mLoadedConfigModifiedTime;
bool mReloadConfigWanted;
bool mTerminateWanted;
+ bool mSingleProcess;
+ bool mRunInForeground;
+ bool mKeepConsoleOpenAfterFork;
+ bool mHaveConfigFile;
+ int mLogLevel; // need an int to do math with
static Daemon *spDaemon;
+ std::string mAppName;
};
#define DAEMON_VERIFY_SERVER_KEYS {"PidFile", 0, ConfigTest_Exists, 0}, \
diff --git a/lib/server/LocalProcessStream.cpp b/lib/server/LocalProcessStream.cpp
index 7b8e78c6..f694fa58 100644
--- a/lib/server/LocalProcessStream.cpp
+++ b/lib/server/LocalProcessStream.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,10 +56,15 @@
#endif
#include "LocalProcessStream.h"
-#include "SocketStream.h"
#include "autogen_ServerException.h"
#include "Utils.h"
+#ifdef WIN32
+ #include "FileStream.h"
+#else
+ #include "SocketStream.h"
+#endif
+
#include "MemLeakFindOn.h"
#define MAX_ARGUMENTS 64
@@ -68,19 +73,22 @@
//
// Function
// Name: LocalProcessStream(const char *, pid_t &)
-// Purpose: Run a new process, and return a stream giving access to it's
-// stdin and stdout. Returns the PID of the new process -- this
-// must be waited on at some point to avoid zombies.
+// Purpose: Run a new process, and return a stream giving access
+// to its stdin and stdout (stdout and stderr on
+// Win32). Returns the PID of the new process -- this
+// must be waited on at some point to avoid zombies
+// (except on Win32).
// Created: 12/3/04
//
// --------------------------------------------------------------------------
std::auto_ptr<IOStream> LocalProcessStream(const char *CommandLine, pid_t &rPidOut)
{
+#ifndef WIN32
+
// Split up command
std::vector<std::string> command;
SplitString(std::string(CommandLine), ' ', command);
-#ifndef WIN32
// Build arguments
char *args[MAX_ARGUMENTS + 4];
{
@@ -139,10 +147,68 @@ std::auto_ptr<IOStream> LocalProcessStream(const char *CommandLine, pid_t &rPidO
// Return the stream object and PID
rPidOut = pid;
return stream;
+
#else // WIN32
- ::syslog(LOG_ERR, "vfork not implemented - LocalProcessStream.cpp");
- std::auto_ptr<IOStream> stream;
+
+ SECURITY_ATTRIBUTES secAttr;
+ secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ secAttr.bInheritHandle = TRUE;
+ secAttr.lpSecurityDescriptor = NULL;
+
+ HANDLE writeInChild, readFromChild;
+ if(!CreatePipe(&readFromChild, &writeInChild, &secAttr, 0))
+ {
+ BOX_ERROR("Failed to CreatePipe for child process: " <<
+ GetErrorMessage(GetLastError()));
+ THROW_EXCEPTION(ServerException, SocketPairFailed)
+ }
+ SetHandleInformation(readFromChild, HANDLE_FLAG_INHERIT, 0);
+
+ PROCESS_INFORMATION procInfo;
+ STARTUPINFO startupInfo;
+
+ ZeroMemory(&procInfo, sizeof(procInfo));
+ ZeroMemory(&startupInfo, sizeof(startupInfo));
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.hStdError = writeInChild;
+ startupInfo.hStdOutput = writeInChild;
+ startupInfo.hStdInput = INVALID_HANDLE_VALUE;
+ startupInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+ CHAR* commandLineCopy = (CHAR*)malloc(strlen(CommandLine) + 1);
+ strcpy(commandLineCopy, CommandLine);
+
+ BOOL result = CreateProcess(NULL,
+ commandLineCopy, // command line
+ NULL, // process security attributes
+ NULL, // primary thread security attributes
+ TRUE, // handles are inherited
+ 0, // creation flags
+ NULL, // use parent's environment
+ NULL, // use parent's current directory
+ &startupInfo, // STARTUPINFO pointer
+ &procInfo); // receives PROCESS_INFORMATION
+
+ free(commandLineCopy);
+
+ if(!result)
+ {
+ BOX_ERROR("Failed to CreateProcess: '" << CommandLine <<
+ "': " << GetErrorMessage(GetLastError()));
+ CloseHandle(writeInChild);
+ CloseHandle(readFromChild);
+ THROW_EXCEPTION(ServerException, ServerForkError)
+ }
+
+ CloseHandle(procInfo.hProcess);
+ CloseHandle(procInfo.hThread);
+ CloseHandle(writeInChild);
+
+ rPidOut = (int)(procInfo.dwProcessId);
+
+ std::auto_ptr<IOStream> stream(new FileStream(readFromChild));
return stream;
+
#endif // ! WIN32
}
diff --git a/lib/server/LocalProcessStream.h b/lib/server/LocalProcessStream.h
index 386ae21f..5547c79c 100644
--- a/lib/server/LocalProcessStream.h
+++ b/lib/server/LocalProcessStream.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/server/Makefile.extra b/lib/server/Makefile.extra
index 6cc0de2e..33fac0a1 100644
--- a/lib/server/Makefile.extra
+++ b/lib/server/Makefile.extra
@@ -3,9 +3,9 @@ MAKEEXCEPTION = ../../lib/common/makeexception.pl
# AUTOGEN SEEDING
autogen_ServerException.h autogen_ServerException.cpp: $(MAKEEXCEPTION) ServerException.txt
- perl $(MAKEEXCEPTION) ServerException.txt
+ $(PERL) $(MAKEEXCEPTION) ServerException.txt
# AUTOGEN SEEDING
autogen_ConnectionException.h autogen_ConnectionException.cpp: $(MAKEEXCEPTION) ConnectionException.txt
- perl $(MAKEEXCEPTION) ConnectionException.txt
+ $(PERL) $(MAKEEXCEPTION) ConnectionException.txt
diff --git a/lib/server/Protocol.cpp b/lib/server/Protocol.cpp
index d459bdcb..0f15beeb 100644
--- a/lib/server/Protocol.cpp
+++ b/lib/server/Protocol.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.
@@ -60,6 +60,7 @@
#include "ServerException.h"
#include "PartialReadStream.h"
#include "ProtocolUncertainStream.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -93,7 +94,8 @@ Protocol::Protocol(IOStream &rStream)
mLastErrorType(NoError),
mLastErrorSubType(NoError)
{
- TRACE1("Send block allocation size is %d\n", PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK);
+ BOX_TRACE("Send block allocation size is " <<
+ PROTOCOL_ALLOCATE_SEND_BLOCK_CHUNK);
}
// --------------------------------------------------------------------------
diff --git a/lib/server/Protocol.h b/lib/server/Protocol.h
index 7781ac7c..da665219 100644
--- a/lib/server/Protocol.h
+++ b/lib/server/Protocol.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/server/ProtocolObject.cpp b/lib/server/ProtocolObject.cpp
index 44466392..6b426141 100644
--- a/lib/server/ProtocolObject.cpp
+++ b/lib/server/ProtocolObject.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/server/ProtocolObject.h b/lib/server/ProtocolObject.h
index 0dbb2817..9b6736fa 100644
--- a/lib/server/ProtocolObject.h
+++ b/lib/server/ProtocolObject.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/server/ProtocolUncertainStream.cpp b/lib/server/ProtocolUncertainStream.cpp
index 5d22dc89..84ef6e38 100644
--- a/lib/server/ProtocolUncertainStream.cpp
+++ b/lib/server/ProtocolUncertainStream.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/server/ProtocolUncertainStream.h b/lib/server/ProtocolUncertainStream.h
index ea5346e7..6c4e88f4 100644
--- a/lib/server/ProtocolUncertainStream.h
+++ b/lib/server/ProtocolUncertainStream.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.
@@ -39,7 +39,7 @@
// --------------------------------------------------------------------------
//
// File
-// Name: PartialReadStream.h
+// Name: ProtocolUncertainStream.h
// Purpose: Read part of another stream
// Created: 2003/12/05
//
@@ -53,7 +53,7 @@
// --------------------------------------------------------------------------
//
// Class
-// Name: PartialReadStream
+// Name: ProtocolUncertainStream
// Purpose: Read part of another stream
// Created: 2003/12/05
//
diff --git a/lib/server/ProtocolWire.h b/lib/server/ProtocolWire.h
index 11add21e..64326f31 100644
--- a/lib/server/ProtocolWire.h
+++ b/lib/server/ProtocolWire.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/server/SSLLib.cpp b/lib/server/SSLLib.cpp
index b8316bc0..40b51da6 100644
--- a/lib/server/SSLLib.cpp
+++ b/lib/server/SSLLib.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.
@@ -52,10 +52,6 @@
#include <openssl/err.h>
#include <openssl/rand.h>
-#ifndef WIN32
-#include <syslog.h>
-#endif
-
#include "SSLLib.h"
#include "ServerException.h"
@@ -91,7 +87,8 @@ void SSLLib::Initialise()
THROW_EXCEPTION(ServerException, SSLRandomInitFailed)
}
#else
- ::fprintf(stderr, "No random device -- additional seeding of random number generator not performed.\n");
+ BOX_WARNING("No random device -- additional seeding of "
+ "random number generator not performed.");
#endif
}
@@ -111,13 +108,8 @@ void SSLLib::LogError(const char *ErrorDuringAction)
while((errcode = ERR_get_error()) != 0)
{
::ERR_error_string_n(errcode, errname, sizeof(errname));
- #ifndef NDEBUG
- if(SSLLib__TraceErrors)
- {
- TRACE2("SSL err during %s: %s\n", ErrorDuringAction, errname);
- }
- #endif
- ::syslog(LOG_ERR, "SSL err during %s: %s", ErrorDuringAction, errname);
+ BOX_ERROR("SSL error during " << ErrorDuringAction << ": " <<
+ errname);
}
}
diff --git a/lib/server/SSLLib.h b/lib/server/SSLLib.h
index b6fa9aad..7f0d5a2b 100644
--- a/lib/server/SSLLib.h
+++ b/lib/server/SSLLib.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/server/ServerControl.h b/lib/server/ServerControl.h
new file mode 100644
index 00000000..c8c746e4
--- /dev/null
+++ b/lib/server/ServerControl.h
@@ -0,0 +1,228 @@
+// 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.
+//
+//
+//
+#ifndef SERVER_CONTROL_H
+#define SERVER_CONTROL_H
+
+#include "Test.h"
+
+#ifdef WIN32
+
+#include "WinNamedPipeStream.h"
+#include "IOStreamGetLine.h"
+#include "BoxPortsAndFiles.h"
+
+static std::string sPipeName;
+
+static void SetNamedPipeName(const std::string& rPipeName)
+{
+ sPipeName = rPipeName;
+}
+
+static bool SendCommands(const std::string& rCmd)
+{
+ WinNamedPipeStream connection;
+
+ try
+ {
+ connection.Connect(sPipeName);
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to connect to daemon control socket");
+ return false;
+ }
+
+ // For receiving data
+ IOStreamGetLine getLine(connection);
+
+ // Wait for the configuration summary
+ std::string configSummary;
+ if(!getLine.GetLine(configSummary))
+ {
+ BOX_ERROR("Failed to receive configuration summary from daemon");
+ return false;
+ }
+
+ // Was the connection rejected by the server?
+ if(getLine.IsEOF())
+ {
+ BOX_ERROR("Server rejected the connection");
+ return false;
+ }
+
+ // Decode it
+ int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait;
+ if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d",
+ &autoBackup, &updateStoreInterval,
+ &minimumFileAge, &maxUploadWait) != 4)
+ {
+ BOX_ERROR("Config summary didn't decode");
+ return false;
+ }
+
+ std::string cmds;
+ bool expectResponse;
+
+ if (rCmd != "")
+ {
+ cmds = rCmd;
+ cmds += "\nquit\n";
+ expectResponse = true;
+ }
+ else
+ {
+ cmds = "quit\n";
+ expectResponse = false;
+ }
+
+ connection.Write(cmds.c_str(), cmds.size());
+
+ // Read the response
+ std::string line;
+ bool statusOk = !expectResponse;
+
+ while (expectResponse && !getLine.IsEOF() && getLine.GetLine(line))
+ {
+ // Is this an OK or error line?
+ if (line == "ok")
+ {
+ statusOk = true;
+ }
+ else if (line == "error")
+ {
+ BOX_ERROR(rCmd);
+ break;
+ }
+ else
+ {
+ BOX_WARNING("Unexpected response to command '" <<
+ rCmd << "': " << line)
+ }
+ }
+
+ return statusOk;
+}
+
+inline bool HUPServer(int pid)
+{
+ return SendCommands("reload");
+}
+
+inline bool KillServerInternal(int pid)
+{
+ HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, false, pid);
+ if (hProcess == NULL)
+ {
+ BOX_ERROR("Failed to open process " << pid << ": " <<
+ GetErrorMessage(GetLastError()));
+ return false;
+ }
+
+ if (!TerminateProcess(hProcess, 1))
+ {
+ BOX_ERROR("Failed to terminate process " << pid << ": " <<
+ GetErrorMessage(GetLastError()));
+ CloseHandle(hProcess);
+ return false;
+ }
+
+ CloseHandle(hProcess);
+ return true;
+}
+
+#else // !WIN32
+
+inline bool HUPServer(int pid)
+{
+ if(pid == 0) return false;
+ return ::kill(pid, SIGHUP) == 0;
+}
+
+inline bool KillServerInternal(int pid)
+{
+ if(pid == 0 || pid == -1) return false;
+ bool killed = (::kill(pid, SIGTERM) == 0);
+ if (!killed)
+ {
+ BOX_ERROR("Failed to kill process " << pid << ": " <<
+ strerror(errno));
+ }
+ TEST_THAT(killed);
+ return killed;
+}
+
+#endif // WIN32
+
+inline bool KillServer(int pid)
+{
+ if (!KillServerInternal(pid))
+ {
+ return false;
+ }
+
+ for (int i = 0; i < 30; i++)
+ {
+ if (i == 0)
+ {
+ printf("Waiting for server to die: ");
+ }
+
+ printf(".");
+ fflush(stdout);
+
+ if (!ServerIsAlive(pid)) break;
+ ::sleep(1);
+ if (!ServerIsAlive(pid)) break;
+ }
+
+ if (!ServerIsAlive(pid))
+ {
+ printf(" done.\n");
+ }
+ else
+ {
+ printf(" failed!\n");
+ }
+
+ fflush(stdout);
+
+ return !ServerIsAlive(pid);
+}
+
+#endif // SERVER_CONTROL_H
diff --git a/lib/server/ServerException.h b/lib/server/ServerException.h
index f6e59371..2d44271f 100644
--- a/lib/server/ServerException.h
+++ b/lib/server/ServerException.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/server/ServerStream.h b/lib/server/ServerStream.h
index e1136c72..0e81d05e 100644
--- a/lib/server/ServerStream.h
+++ b/lib/server/ServerStream.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,7 +52,6 @@
#include <errno.h>
#ifndef WIN32
- #include <syslog.h>
#include <sys/wait.h>
#endif
@@ -94,9 +93,11 @@ public:
return "generic-stream-server";
}
+ virtual void OnIdle() { }
+
virtual void Run()
{
- // Set process title as appropraite
+ // Set process title as appropriate
SetProcessTitle(ForkToHandleRequests?"server":"idle");
// Handle exceptions and child task quitting gracefully.
@@ -109,7 +110,10 @@ public:
{
if(childExit)
{
- ::syslog(LOG_ERR, "in server child, exception %s (%d/%d) -- terminating child", e.what(), e.GetType(), e.GetSubType());
+ BOX_ERROR("Error in child process, "
+ "terminating connection: exception " <<
+ e.what() << "(" << e.GetType() <<
+ "/" << e.GetSubType() << ")");
_exit(1);
}
else throw;
@@ -118,7 +122,9 @@ public:
{
if(childExit)
{
- ::syslog(LOG_ERR, "in server child, exception %s -- terminating child", e.what());
+ BOX_ERROR("Error in child process, "
+ "terminating connection: exception " <<
+ e.what());
_exit(1);
}
else throw;
@@ -127,7 +133,9 @@ public:
{
if(childExit)
{
- ::syslog(LOG_ERR, "in server child, unknown exception -- terminating child");
+ BOX_ERROR("Error in child process, "
+ "terminating connection: "
+ "unknown exception");
_exit(1);
}
else throw;
@@ -206,16 +214,22 @@ public:
}
else if(c[0] == "unix")
{
- // Check arguments size
- if(c.size() != 2)
- {
- THROW_EXCEPTION(ServerException, ServerStreamBadListenAddrs)
- }
+ #ifdef WIN32
+ BOX_WARNING("Ignoring request to listen on a Unix socket on Windows: " << addrlist[a]);
+ delete psocket;
+ psocket = NULL;
+ #else
+ // Check arguments size
+ if(c.size() != 2)
+ {
+ THROW_EXCEPTION(ServerException, ServerStreamBadListenAddrs)
+ }
- // unlink anything there
- ::unlink(c[1].c_str());
-
- psocket->Listen(Socket::TypeUNIX, c[1].c_str());
+ // unlink anything there
+ ::unlink(c[1].c_str());
+
+ psocket->Listen(Socket::TypeUNIX, c[1].c_str());
+ #endif // WIN32
}
else
{
@@ -223,8 +237,11 @@ public:
THROW_EXCEPTION(ServerException, ServerStreamBadListenAddrs)
}
- // Add to list of sockets
- mSockets.push_back(psocket);
+ if (psocket != NULL)
+ {
+ // Add to list of sockets
+ mSockets.push_back(psocket);
+ }
}
catch(...)
{
@@ -232,8 +249,11 @@ public:
throw;
}
- // Add to the list of things to wait on
- connectionWait.Add(psocket);
+ if (psocket != NULL)
+ {
+ // Add to the list of things to wait on
+ connectionWait.Add(psocket);
+ }
}
}
@@ -245,7 +265,8 @@ public:
if(psocket)
{
- // Get the incomming connection (with zero wait time)
+ // Get the incoming connection
+ // (with zero wait time)
std::string logMessage;
std::auto_ptr<StreamType> connection(psocket->Accept(0, &logMessage));
@@ -253,7 +274,8 @@ public:
if(connection.get())
{
// Since this is a template parameter, the if() will be optimised out by the compiler
- if(ForkToHandleRequests)
+ #ifndef WIN32 // no fork on Win32
+ if(ForkToHandleRequests && !IsSingleProcess())
{
pid_t pid = ::fork();
switch(pid)
@@ -289,20 +311,26 @@ public:
}
// Log it
- ::syslog(LOG_INFO, "%s (handling in child %d)", logMessage.c_str(), pid);
+ BOX_WARNING("Message from child process " << pid << ": " << logMessage);
}
else
{
- // Just handle in this connection
+ #endif // !WIN32
+ // Just handle in this process
SetProcessTitle("handling");
HandleConnection(*connection);
SetProcessTitle("idle");
+ #ifndef WIN32
}
+ #endif // !WIN32
}
}
-
+
+ OnIdle();
+
+ #ifndef WIN32
// Clean up child processes (if forking daemon)
- if(ForkToHandleRequests)
+ if(ForkToHandleRequests && !IsSingleProcess())
{
int status = 0;
int p = 0;
@@ -315,6 +343,7 @@ public:
}
} while(p > 0);
}
+ #endif // !WIN32
}
}
catch(...)
@@ -335,11 +364,15 @@ public:
virtual void Connection(StreamType &rStream) = 0;
protected:
- // For checking code in dervied classes -- use if you have an algorithm which
+ // For checking code in derived classes -- use if you have an algorithm which
// depends on the forking model in case someone changes it later.
bool WillForkToHandleRequests()
{
- return ForkToHandleRequests;
+ #ifdef WIN32
+ return false;
+ #else
+ return ForkToHandleRequests && !IsSingleProcess();
+ #endif // WIN32
}
private:
diff --git a/lib/server/ServerTLS.h b/lib/server/ServerTLS.h
index be53af4c..a74f0087 100644
--- a/lib/server/ServerTLS.h
+++ b/lib/server/ServerTLS.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/server/Socket.cpp b/lib/server/Socket.cpp
index 0939343d..95347af6 100644
--- a/lib/server/Socket.cpp
+++ b/lib/server/Socket.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,7 +55,6 @@
#ifndef WIN32
#include <sys/socket.h>
#include <netdb.h>
-#include <syslog.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
@@ -162,18 +161,20 @@ void Socket::LogIncomingConnection(const struct sockaddr *addr, socklen_t addrle
switch(addr->sa_family)
{
case AF_UNIX:
- ::syslog(LOG_INFO, "Incoming connection from local (UNIX socket)");
+ BOX_INFO("Incoming connection from local (UNIX socket)");
break;
case AF_INET:
{
sockaddr_in *a = (sockaddr_in*)addr;
- ::syslog(LOG_INFO, "Incoming connection from %s port %d", inet_ntoa(a->sin_addr), ntohs(a->sin_port));
+ BOX_INFO("Incoming connection from " <<
+ inet_ntoa(a->sin_addr) << " port " <<
+ ntohs(a->sin_port));
}
break;
default:
- ::syslog(LOG_INFO, "Incoming connection of unknown type");
+ BOX_WARNING("Incoming connection of unknown type");
break;
}
}
diff --git a/lib/server/Socket.h b/lib/server/Socket.h
index fc3a3a0c..f262bc3a 100644
--- a/lib/server/Socket.h
+++ b/lib/server/Socket.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/server/SocketListen.h b/lib/server/SocketListen.h
index 41a9fc3f..7b99631b 100644
--- a/lib/server/SocketListen.h
+++ b/lib/server/SocketListen.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/server/SocketStream.cpp b/lib/server/SocketStream.cpp
index 49bf18b2..38370598 100644
--- a/lib/server/SocketStream.cpp
+++ b/lib/server/SocketStream.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.
@@ -53,6 +53,7 @@
#include <sys/types.h>
#include <errno.h>
+#include <string.h>
#ifndef WIN32
#include <poll.h>
@@ -74,7 +75,7 @@
//
// --------------------------------------------------------------------------
SocketStream::SocketStream()
- : mSocketHandle(-1),
+ : mSocketHandle(INVALID_SOCKET_VALUE),
mReadClosed(false),
mWriteClosed(false),
mBytesRead(0),
@@ -123,7 +124,7 @@ SocketStream::SocketStream(const SocketStream &rToCopy)
{
THROW_EXCEPTION(ServerException, BadSocketHandle);
}
- if(mSocketHandle == -1)
+ if(mSocketHandle == INVALID_SOCKET_VALUE)
{
THROW_EXCEPTION(ServerException, DupError);
}
@@ -139,7 +140,7 @@ SocketStream::SocketStream(const SocketStream &rToCopy)
// --------------------------------------------------------------------------
SocketStream::~SocketStream()
{
- if(mSocketHandle != -1)
+ if(mSocketHandle != INVALID_SOCKET_VALUE)
{
Close();
}
@@ -155,7 +156,10 @@ SocketStream::~SocketStream()
// --------------------------------------------------------------------------
void SocketStream::Attach(int socket)
{
- if(mSocketHandle != -1) {THROW_EXCEPTION(ServerException, SocketAlreadyOpen)}
+ if(mSocketHandle != INVALID_SOCKET_VALUE)
+ {
+ THROW_EXCEPTION(ServerException, SocketAlreadyOpen)
+ }
mSocketHandle = socket;
ResetCounters();
@@ -172,7 +176,10 @@ void SocketStream::Attach(int socket)
// --------------------------------------------------------------------------
void SocketStream::Open(int Type, const char *Name, int Port)
{
- if(mSocketHandle != -1) {THROW_EXCEPTION(ServerException, SocketAlreadyOpen)}
+ if(mSocketHandle != INVALID_SOCKET_VALUE)
+ {
+ THROW_EXCEPTION(ServerException, SocketAlreadyOpen)
+ }
// Setup parameters based on type, looking up names if required
int sockDomain = 0;
@@ -182,7 +189,7 @@ void SocketStream::Open(int Type, const char *Name, int Port)
// Create the socket
mSocketHandle = ::socket(sockDomain, SOCK_STREAM, 0 /* let OS choose protocol */);
- if(mSocketHandle == -1)
+ if(mSocketHandle == INVALID_SOCKET_VALUE)
{
THROW_EXCEPTION(ServerException, SocketOpenError)
}
@@ -192,13 +199,29 @@ void SocketStream::Open(int Type, const char *Name, int Port)
{
// Dispose of the socket
#ifdef WIN32
+ DWORD err = WSAGetLastError();
::closesocket(mSocketHandle);
#else
+ int err = errno;
::close(mSocketHandle);
#endif
- mSocketHandle = -1;
+
+#ifdef WIN32
+ BOX_ERROR("Failed to connect to socket (type " << Type <<
+ ", name " << Name << ", port " << Port << "): " <<
+ GetErrorMessage(err)
+ );
+#else
+ BOX_ERROR("Failed to connect to socket (type " << Type <<
+ ", name " << Name << ", port " << Port << "): " <<
+ strerror(err) << " (" << err << ")"
+ );
+#endif
+
+ mSocketHandle = INVALID_SOCKET_VALUE;
THROW_EXCEPTION(ConnectionException, Conn_SocketConnectError)
}
+
ResetCounters();
}
@@ -212,7 +235,10 @@ void SocketStream::Open(int Type, const char *Name, int Port)
// --------------------------------------------------------------------------
int SocketStream::Read(void *pBuffer, int NBytes, int Timeout)
{
- if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+ if(mSocketHandle == INVALID_SOCKET_VALUE)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
if(Timeout != IOStream::TimeOutInfinite)
{
@@ -285,7 +311,10 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout)
// --------------------------------------------------------------------------
void SocketStream::Write(const void *pBuffer, int NBytes)
{
- if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+ if(mSocketHandle == INVALID_SOCKET_VALUE)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
// Buffer in byte sized type.
ASSERT(sizeof(char) == 1);
@@ -349,7 +378,10 @@ void SocketStream::Write(const void *pBuffer, int NBytes)
// --------------------------------------------------------------------------
void SocketStream::Close()
{
- if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+ if(mSocketHandle == INVALID_SOCKET_VALUE)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
#ifdef WIN32
if(::closesocket(mSocketHandle) == -1)
#else
@@ -358,7 +390,7 @@ void SocketStream::Close()
{
THROW_EXCEPTION(ServerException, SocketCloseError)
}
- mSocketHandle = -1;
+ mSocketHandle = INVALID_SOCKET_VALUE;
}
// --------------------------------------------------------------------------
@@ -371,7 +403,10 @@ void SocketStream::Close()
// --------------------------------------------------------------------------
void SocketStream::Shutdown(bool Read, bool Write)
{
- if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+ if(mSocketHandle == INVALID_SOCKET_VALUE)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
// Do anything?
if(!Read && !Write) return;
@@ -426,7 +461,10 @@ bool SocketStream::StreamClosed()
// --------------------------------------------------------------------------
tOSSocketHandle SocketStream::GetSocketHandle()
{
- if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)}
+ if(mSocketHandle == INVALID_SOCKET_VALUE)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
return mSocketHandle;
}
diff --git a/lib/server/SocketStream.h b/lib/server/SocketStream.h
index 17a2e4d7..efe3f9ce 100644
--- a/lib/server/SocketStream.h
+++ b/lib/server/SocketStream.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,8 +52,10 @@
#ifdef WIN32
typedef SOCKET tOSSocketHandle;
+ #define INVALID_SOCKET_VALUE (tOSSocketHandle)(-1)
#else
typedef int tOSSocketHandle;
+ #define INVALID_SOCKET_VALUE -1
#endif
// --------------------------------------------------------------------------
@@ -103,6 +105,7 @@ public:
off_t GetBytesRead() const {return mBytesRead;}
off_t GetBytesWritten() const {return mBytesWritten;}
void ResetCounters() {mBytesRead = mBytesWritten = 0;}
+ bool IsOpened() { return mSocketHandle != INVALID_SOCKET_VALUE; }
};
#endif // SOCKETSTREAM__H
diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp
index 0845f868..e7126120 100644
--- a/lib/server/SocketStreamTLS.cpp
+++ b/lib/server/SocketStreamTLS.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.
@@ -61,6 +61,7 @@
#include "SSLLib.h"
#include "ServerException.h"
#include "TLSContext.h"
+#include "BoxTime.h"
#include "MemLeakFindOn.h"
@@ -175,8 +176,12 @@ void SocketStreamTLS::Handshake(const TLSContext &rContext, bool IsServer)
THROW_EXCEPTION(ServerException, TLSAllocationFailed)
}
-#ifndef WIN32
// Make the socket non-blocking so timeouts on Read work
+
+#ifdef WIN32
+ u_long nonblocking = 1;
+ ioctlsocket(socket, FIONBIO, &nonblocking);
+#else // !WIN32
// This is more portable than using ioctl with FIONBIO
int statusFlags = 0;
if(::fcntl(socket, F_GETFL, &statusFlags) < 0
@@ -278,20 +283,30 @@ bool SocketStreamTLS::WaitWhenRetryRequired(int SSLErrorCode, int Timeout)
break;
}
p.revents = 0;
- switch(::poll(&p, 1, (Timeout == IOStream::TimeOutInfinite)?INFTIM:Timeout))
+
+ int64_t start, end;
+ start = BoxTimeToMilliSeconds(GetCurrentBoxTime());
+ end = start + Timeout;
+ int result;
+
+ do
{
- case -1:
- // error
- if(errno == EINTR)
+ int64_t now = BoxTimeToMilliSeconds(GetCurrentBoxTime());
+ int poll_timeout = (int)(end - now);
+ if (poll_timeout < 0) poll_timeout = 0;
+ if (Timeout == IOStream::TimeOutInfinite)
{
- // Signal. Do "time out"
- return false;
- }
- else
- {
- // Bad!
- THROW_EXCEPTION(ServerException, SocketPollError)
+ poll_timeout = INFTIM;
}
+ result = ::poll(&p, 1, poll_timeout);
+ }
+ while(result == -1 && errno == EINTR);
+
+ switch(result)
+ {
+ case -1:
+ // error - Bad!
+ THROW_EXCEPTION(ServerException, SocketPollError)
break;
case 0:
@@ -347,7 +362,7 @@ int SocketStreamTLS::Read(void *pBuffer, int NBytes, int Timeout)
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
- // wait for the requried data
+ // wait for the required data
// Will only get once around this loop, so don't need to calculate timeout values
if(WaitWhenRetryRequired(se, Timeout) == false)
{
diff --git a/lib/server/SocketStreamTLS.h b/lib/server/SocketStreamTLS.h
index dc1da5bc..41f78d76 100644
--- a/lib/server/SocketStreamTLS.h
+++ b/lib/server/SocketStreamTLS.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/server/TLSContext.cpp b/lib/server/TLSContext.cpp
index 87df562c..da0b320c 100644
--- a/lib/server/TLSContext.cpp
+++ b/lib/server/TLSContext.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.
@@ -99,6 +99,11 @@ TLSContext::~TLSContext()
// --------------------------------------------------------------------------
void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const char *PrivateKeyFile, const char *TrustedCAsFile)
{
+ if(mpContext != 0)
+ {
+ ::SSL_CTX_free(mpContext);
+ }
+
mpContext = ::SSL_CTX_new(AsServer?TLSv1_server_method():TLSv1_client_method());
if(mpContext == NULL)
{
diff --git a/lib/server/TLSContext.h b/lib/server/TLSContext.h
index 408b0039..88013396 100644
--- a/lib/server/TLSContext.h
+++ b/lib/server/TLSContext.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/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp
new file mode 100644
index 00000000..bb264da7
--- /dev/null
+++ b/lib/server/WinNamedPipeStream.cpp
@@ -0,0 +1,629 @@
+// 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.
+//
+//
+//
+// --------------------------------------------------------------------------
+//
+// File
+// Name: WinNamedPipeStream.cpp
+// Purpose: I/O stream interface for Win32 named pipes
+// Created: 2005/12/07
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#ifdef WIN32
+
+#ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <errno.h>
+#include <windows.h>
+
+#include "WinNamedPipeStream.h"
+#include "ServerException.h"
+#include "CommonException.h"
+#include "Socket.h"
+
+#include "MemLeakFindOn.h"
+
+std::string WinNamedPipeStream::sPipeNamePrefix = "\\\\.\\pipe\\";
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::WinNamedPipeStream()
+// Purpose: Constructor (create stream ready for Open() call)
+// Created: 2005/12/07
+//
+// --------------------------------------------------------------------------
+WinNamedPipeStream::WinNamedPipeStream()
+ : mSocketHandle(INVALID_HANDLE_VALUE),
+ mReadableEvent(INVALID_HANDLE_VALUE),
+ mBytesInBuffer(0),
+ mReadClosed(false),
+ mWriteClosed(false),
+ mIsServer(false),
+ mIsConnected(false)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::~WinNamedPipeStream()
+// Purpose: Destructor, closes stream if open
+// Created: 2005/12/07
+//
+// --------------------------------------------------------------------------
+WinNamedPipeStream::~WinNamedPipeStream()
+{
+ if (mSocketHandle != INVALID_HANDLE_VALUE)
+ {
+ try
+ {
+ Close();
+ }
+ catch (std::exception &e)
+ {
+ BOX_ERROR("Caught exception while destroying "
+ "named pipe, ignored: " << e.what());
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::Accept(const std::string& rName)
+// Purpose: Creates a new named pipe with the given name,
+// and wait for a connection on it
+// Created: 2005/12/07
+//
+// --------------------------------------------------------------------------
+void WinNamedPipeStream::Accept(const std::string& rName)
+{
+ if (mSocketHandle != INVALID_HANDLE_VALUE || mIsConnected)
+ {
+ THROW_EXCEPTION(ServerException, SocketAlreadyOpen)
+ }
+
+ std::string socket = sPipeNamePrefix + rName;
+
+ mSocketHandle = CreateNamedPipeA(
+ socket.c_str(), // pipe name
+ PIPE_ACCESS_DUPLEX | // read/write access
+ FILE_FLAG_OVERLAPPED, // enabled overlapped I/O
+ PIPE_TYPE_BYTE | // message type pipe
+ PIPE_READMODE_BYTE | // message-read mode
+ PIPE_WAIT, // blocking mode
+ 1, // max. instances
+ 4096, // output buffer size
+ 4096, // input buffer size
+ NMPWAIT_USE_DEFAULT_WAIT, // client time-out
+ NULL); // default security attribute
+
+ if (mSocketHandle == INVALID_HANDLE_VALUE)
+ {
+ BOX_ERROR("Failed to CreateNamedPipeA(" << socket << "): " <<
+ GetErrorMessage(GetLastError()));
+ THROW_EXCEPTION(ServerException, SocketOpenError)
+ }
+
+ bool connected = ConnectNamedPipe(mSocketHandle, (LPOVERLAPPED) NULL);
+
+ if (!connected)
+ {
+ BOX_ERROR("Failed to ConnectNamedPipe(" << socket << "): " <<
+ GetErrorMessage(GetLastError()));
+ Close();
+ THROW_EXCEPTION(ServerException, SocketOpenError)
+ }
+
+ mBytesInBuffer = 0;
+ mReadClosed = false;
+ mWriteClosed = false;
+ mIsServer = true; // must flush and disconnect before closing
+ mIsConnected = true;
+
+ // create the Readable event
+ mReadableEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (mReadableEvent == INVALID_HANDLE_VALUE)
+ {
+ BOX_ERROR("Failed to create the Readable event: " <<
+ GetErrorMessage(GetLastError()));
+ Close();
+ THROW_EXCEPTION(CommonException, Internal)
+ }
+
+ // initialise the OVERLAPPED structure
+ memset(&mReadOverlap, 0, sizeof(mReadOverlap));
+ mReadOverlap.hEvent = mReadableEvent;
+
+ // start the first overlapped read
+ if (!ReadFile(mSocketHandle, mReadBuffer, sizeof(mReadBuffer),
+ NULL, &mReadOverlap))
+ {
+ DWORD err = GetLastError();
+
+ if (err != ERROR_IO_PENDING)
+ {
+ BOX_ERROR("Failed to start overlapped read: " <<
+ GetErrorMessage(err));
+ Close();
+ THROW_EXCEPTION(ConnectionException,
+ Conn_SocketReadError)
+ }
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::Connect(const std::string& rName)
+// Purpose: Opens a connection to a listening named pipe
+// Created: 2005/12/07
+//
+// --------------------------------------------------------------------------
+void WinNamedPipeStream::Connect(const std::string& rName)
+{
+ if (mSocketHandle != INVALID_HANDLE_VALUE || mIsConnected)
+ {
+ THROW_EXCEPTION(ServerException, SocketAlreadyOpen)
+ }
+
+ std::string socket = sPipeNamePrefix + rName;
+
+ mSocketHandle = CreateFileA(
+ socket.c_str(), // pipe name
+ GENERIC_READ | // read and write access
+ GENERIC_WRITE,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING,
+ 0, // default attributes
+ NULL); // no template file
+
+ if (mSocketHandle == INVALID_HANDLE_VALUE)
+ {
+ DWORD err = GetLastError();
+ if (err == ERROR_PIPE_BUSY)
+ {
+ BOX_ERROR("Failed to connect to backup daemon: "
+ "it is busy with another connection");
+ }
+ else
+ {
+ BOX_ERROR("Failed to connect to backup daemon: " <<
+ GetErrorMessage(err));
+ }
+ THROW_EXCEPTION(ServerException, SocketOpenError)
+ }
+
+ mReadClosed = false;
+ mWriteClosed = false;
+ mIsServer = false; // just close the socket
+ mIsConnected = true;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::Read(void *pBuffer, int NBytes)
+// Purpose: Reads data from stream. Maybe returns less than asked for.
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ // TODO no support for timeouts yet
+ if (Timeout != IOStream::TimeOutInfinite)
+ {
+ THROW_EXCEPTION(CommonException, AssertFailed)
+ }
+
+ if (mSocketHandle == INVALID_HANDLE_VALUE || !mIsConnected)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
+
+ if (mReadClosed)
+ {
+ THROW_EXCEPTION(ConnectionException, SocketShutdownError)
+ }
+
+ // ensure safe to cast NBytes to unsigned
+ if (NBytes < 0)
+ {
+ THROW_EXCEPTION(CommonException, AssertFailed)
+ }
+
+ DWORD NumBytesRead;
+
+ if (mIsServer)
+ {
+ // satisfy from buffer if possible, to avoid
+ // blocking on read.
+ bool needAnotherRead = false;
+ if (mBytesInBuffer == 0)
+ {
+ // overlapped I/O completed successfully?
+ // (wait if needed)
+
+ if (GetOverlappedResult(mSocketHandle,
+ &mReadOverlap, &NumBytesRead, TRUE))
+ {
+ needAnotherRead = true;
+ }
+ else
+ {
+ DWORD err = GetLastError();
+
+ if (err == ERROR_HANDLE_EOF)
+ {
+ mReadClosed = true;
+ }
+ else
+ {
+ if (err == ERROR_BROKEN_PIPE)
+ {
+ BOX_ERROR("Control client "
+ "disconnected");
+ }
+ else
+ {
+ BOX_ERROR("Failed to wait for "
+ "ReadFile to complete: "
+ << GetErrorMessage(err));
+ }
+
+ Close();
+ THROW_EXCEPTION(ConnectionException,
+ Conn_SocketReadError)
+ }
+ }
+ }
+ else
+ {
+ NumBytesRead = 0;
+ }
+
+ size_t BytesToCopy = NumBytesRead + mBytesInBuffer;
+ size_t BytesRemaining = 0;
+
+ if (BytesToCopy > (size_t)NBytes)
+ {
+ BytesRemaining = BytesToCopy - NBytes;
+ BytesToCopy = NBytes;
+ }
+
+ memcpy(pBuffer, mReadBuffer, BytesToCopy);
+ memmove(mReadBuffer, mReadBuffer + BytesToCopy, BytesRemaining);
+
+ mBytesInBuffer = BytesRemaining;
+ NumBytesRead = BytesToCopy;
+
+ if (needAnotherRead)
+ {
+ // reinitialise the OVERLAPPED structure
+ memset(&mReadOverlap, 0, sizeof(mReadOverlap));
+ mReadOverlap.hEvent = mReadableEvent;
+ }
+
+ // start the next overlapped read
+ if (needAnotherRead && !ReadFile(mSocketHandle,
+ mReadBuffer + mBytesInBuffer,
+ sizeof(mReadBuffer) - mBytesInBuffer,
+ NULL, &mReadOverlap))
+ {
+ DWORD err = GetLastError();
+ if (err == ERROR_IO_PENDING)
+ {
+ // Don't reset yet, there might be data
+ // in the buffer waiting to be read,
+ // will check below.
+ // ResetEvent(mReadableEvent);
+ }
+ else if (err == ERROR_HANDLE_EOF)
+ {
+ mReadClosed = true;
+ }
+ else if (err == ERROR_BROKEN_PIPE)
+ {
+ BOX_ERROR("Control client disconnected");
+ mReadClosed = true;
+ }
+ else
+ {
+ BOX_ERROR("Failed to start overlapped read: "
+ << GetErrorMessage(err));
+ Close();
+ THROW_EXCEPTION(ConnectionException,
+ Conn_SocketReadError)
+ }
+ }
+
+ // If the read succeeded immediately, leave the event
+ // signaled, so that we will be called again to process
+ // the newly read data and start another overlapped read.
+ if (needAnotherRead && !mReadClosed)
+ {
+ // leave signalled
+ }
+ else if (!needAnotherRead && mBytesInBuffer > 0)
+ {
+ // leave signalled
+ }
+ else
+ {
+ // nothing left to read, reset the event
+ ResetEvent(mReadableEvent);
+ // FIXME: a pending read could have signalled
+ // the event (again) while we were busy reading.
+ // that signal would be lost, and the reading
+ // thread would block. Should be pretty obvious
+ // if this happens in practice: control client
+ // hangs.
+ }
+ }
+ else
+ {
+ if (!ReadFile(
+ mSocketHandle, // pipe handle
+ pBuffer, // buffer to receive reply
+ NBytes, // size of buffer
+ &NumBytesRead, // number of bytes read
+ NULL)) // not overlapped
+ {
+ DWORD err = GetLastError();
+
+ Close();
+
+ // ERROR_NO_DATA is a strange name for
+ // "The pipe is being closed". No exception wanted.
+
+ if (err == ERROR_NO_DATA ||
+ err == ERROR_PIPE_NOT_CONNECTED)
+ {
+ NumBytesRead = 0;
+ }
+ else
+ {
+ BOX_ERROR("Failed to read from control socket: "
+ << GetErrorMessage(err));
+ THROW_EXCEPTION(ConnectionException,
+ Conn_SocketReadError)
+ }
+ }
+
+ // Closed for reading at EOF?
+ if (NumBytesRead == 0)
+ {
+ mReadClosed = true;
+ }
+ }
+
+ return NumBytesRead;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::Write(void *pBuffer, int NBytes)
+// Purpose: Writes data, blocking until it's all done.
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void WinNamedPipeStream::Write(const void *pBuffer, int NBytes)
+{
+ if (mSocketHandle == INVALID_HANDLE_VALUE || !mIsConnected)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
+
+ // Buffer in byte sized type.
+ ASSERT(sizeof(char) == 1);
+ const char *pByteBuffer = (char *)pBuffer;
+
+ int NumBytesWrittenTotal = 0;
+
+ while (NumBytesWrittenTotal < NBytes)
+ {
+ DWORD NumBytesWrittenThisTime = 0;
+
+ bool Success = WriteFile(
+ mSocketHandle, // pipe handle
+ pByteBuffer + NumBytesWrittenTotal, // message
+ NBytes - NumBytesWrittenTotal, // message length
+ &NumBytesWrittenThisTime, // bytes written this time
+ NULL); // not overlapped
+
+ if (!Success)
+ {
+ DWORD err = GetLastError();
+ BOX_ERROR("Failed to write to control socket: " <<
+ GetErrorMessage(err));
+ Close();
+
+ // ERROR_NO_DATA is a strange name for
+ // "The pipe is being closed". No exception wanted.
+
+ if (err == ERROR_NO_DATA)
+ {
+ return;
+ }
+ else
+ {
+ THROW_EXCEPTION(ConnectionException,
+ Conn_SocketWriteError)
+ }
+ }
+
+ NumBytesWrittenTotal += NumBytesWrittenThisTime;
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::Close()
+// Purpose: Closes connection to remote socket
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void WinNamedPipeStream::Close()
+{
+ if (mSocketHandle == INVALID_HANDLE_VALUE && mIsConnected)
+ {
+ BOX_ERROR("Named pipe: inconsistent connected state");
+ mIsConnected = false;
+ }
+
+ if (mSocketHandle == INVALID_HANDLE_VALUE)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
+
+ if (mIsServer)
+ {
+ if (!CancelIo(mSocketHandle))
+ {
+ BOX_ERROR("Failed to cancel outstanding I/O: " <<
+ GetErrorMessage(GetLastError()));
+ }
+
+ if (mReadableEvent == INVALID_HANDLE_VALUE)
+ {
+ BOX_ERROR("Failed to destroy Readable event: "
+ "invalid handle");
+ }
+ else if (!CloseHandle(mReadableEvent))
+ {
+ BOX_ERROR("Failed to destroy Readable event: " <<
+ GetErrorMessage(GetLastError()));
+ }
+
+ mReadableEvent = INVALID_HANDLE_VALUE;
+
+ if (!FlushFileBuffers(mSocketHandle))
+ {
+ BOX_ERROR("Failed to FlushFileBuffers: " <<
+ GetErrorMessage(GetLastError()));
+ }
+
+ if (!DisconnectNamedPipe(mSocketHandle))
+ {
+ DWORD err = GetLastError();
+ if (err != ERROR_PIPE_NOT_CONNECTED)
+ {
+ BOX_ERROR("Failed to DisconnectNamedPipe: " <<
+ GetErrorMessage(err));
+ }
+ }
+
+ mIsServer = false;
+ }
+
+ bool result = CloseHandle(mSocketHandle);
+
+ mSocketHandle = INVALID_HANDLE_VALUE;
+ mIsConnected = false;
+ mReadClosed = true;
+ mWriteClosed = true;
+
+ if (!result)
+ {
+ BOX_ERROR("Failed to CloseHandle: " <<
+ GetErrorMessage(GetLastError()));
+ THROW_EXCEPTION(ServerException, SocketCloseError)
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::StreamDataLeft()
+// Purpose: Still capable of reading data?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool WinNamedPipeStream::StreamDataLeft()
+{
+ return !mReadClosed;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WinNamedPipeStream::StreamClosed()
+// Purpose: Connection been closed?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool WinNamedPipeStream::StreamClosed()
+{
+ return mWriteClosed;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::WriteAllBuffered()
+// Purpose: Ensures that any data which has been buffered is written to the stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void WinNamedPipeStream::WriteAllBuffered()
+{
+ if (mSocketHandle == INVALID_HANDLE_VALUE || !mIsConnected)
+ {
+ THROW_EXCEPTION(ServerException, BadSocketHandle)
+ }
+
+ if (!FlushFileBuffers(mSocketHandle))
+ {
+ BOX_ERROR("Failed to FlushFileBuffers: " <<
+ GetErrorMessage(GetLastError()));
+ }
+}
+
+
+#endif // WIN32
diff --git a/lib/win32/WinNamedPipeStream.h b/lib/server/WinNamedPipeStream.h
index 4779de08..c4ec1f3f 100644
--- a/lib/win32/WinNamedPipeStream.h
+++ b/lib/server/WinNamedPipeStream.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.
@@ -65,22 +65,24 @@ public:
~WinNamedPipeStream();
// server side - create the named pipe and listen for connections
- void Accept(const wchar_t* Name);
+ void Accept(const std::string& rName);
// client side - connect to a waiting server
- void Connect(const wchar_t* Name);
+ void Connect(const std::string& rName);
// both sides
virtual int Read(void *pBuffer, int NBytes,
int Timeout = IOStream::TimeOutInfinite);
virtual void Write(const void *pBuffer, int NBytes);
+ virtual void WriteAllBuffered();
virtual void Close();
virtual bool StreamDataLeft();
virtual bool StreamClosed();
bool IsConnected() { return mIsConnected; }
+ HANDLE GetSocketHandle() { return mSocketHandle; }
+ HANDLE GetReadableEvent() { return mReadableEvent; }
protected:
- HANDLE GetSocketHandle();
void MarkAsReadClosed() {mReadClosed = true;}
void MarkAsWriteClosed() {mWriteClosed = true;}
@@ -89,10 +91,16 @@ private:
{ /* do not call */ }
HANDLE mSocketHandle;
+ HANDLE mReadableEvent;
+ OVERLAPPED mReadOverlap;
+ uint8_t mReadBuffer[4096];
+ size_t mBytesInBuffer;
bool mReadClosed;
bool mWriteClosed;
bool mIsServer;
bool mIsConnected;
+
+ static std::string sPipeNamePrefix;
};
#endif // WINNAMEDPIPESTREAM__H
diff --git a/lib/server/makeprotocol.pl b/lib/server/makeprotocol.pl
index 71f2b46a..35fb3ad0 100755
--- a/lib/server/makeprotocol.pl
+++ b/lib/server/makeprotocol.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.
@@ -39,6 +39,9 @@
#
use strict;
+use lib "../../infrastructure";
+use BoxPlatform;
+
# Make protocol C++ classes from a protocol description file
# built in type info (values are is basic type, C++ typename)
@@ -538,11 +541,11 @@ __E
if($implement_syslog)
{
- my ($format,$args) = make_log_strings($cmd);
+ my ($log) = make_log_strings_framework($cmd);
print CPP <<__E;
void ${class}LogSysLog(const char *Action) const
{
- ::syslog(LOG_INFO,"%s $format",Action$args);
+ BOX_TRACE($log);
}
__E
}
@@ -864,8 +867,8 @@ if($implement_filelog || $implement_syslog)
}
if($implement_filelog)
{
- $fR .= qq~\tif(mLogToFile) { ::fprintf(mLogToFile, (Size==Protocol::ProtocolStream_SizeUncertain)?"Receiving stream, size uncertain":"Receiving stream, size %d\\n", Size); ::fflush(mLogToFile); }\n~;
- $fS .= qq~\tif(mLogToFile) { ::fprintf(mLogToFile, (Size==Protocol::ProtocolStream_SizeUncertain)?"Sending stream, size uncertain":"Sending stream, size %d\\n", Size); ::fflush(mLogToFile); }\n~;
+ $fR .= qq~\tif(mLogToFile) { ::fprintf(mLogToFile, (Size==Protocol::ProtocolStream_SizeUncertain)?"Receiving stream, size uncertain\\n":"Receiving stream, size %d\\n", Size); ::fflush(mLogToFile); }\n~;
+ $fS .= qq~\tif(mLogToFile) { ::fprintf(mLogToFile, (Size==Protocol::ProtocolStream_SizeUncertain)?"Sending stream, size uncertain\\n":"Sending stream, size %d\\n", Size); ::fflush(mLogToFile); }\n~;
}
print CPP <<__E;
@@ -1019,8 +1022,15 @@ sub make_log_strings
{
# need to translate it
my ($format,$arg) = @{$log_display_types{$ty}};
- push @str,$format;
$arg =~ s/VAR/m$nm/g;
+
+ if ($format eq "0x%llx" and $target_windows)
+ {
+ $format = "0x%I64x";
+ $arg = "(uint64_t)$arg";
+ }
+
+ push @str,$format;
push @arg,$arg;
}
else
@@ -1032,4 +1042,45 @@ sub make_log_strings
return ($cmd.'('.join(',',@str).')', join(',','',@arg));
}
+sub make_log_strings_framework
+{
+ my ($cmd) = @_;
+
+ my @args;
+
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ if(exists $log_display_types{$ty})
+ {
+ # need to translate it
+ my ($format,$arg) = @{$log_display_types{$ty}};
+ $arg =~ s/VAR/m$nm/g;
+
+ if ($format =~ m'x$')
+ {
+ $arg = "std::hex << std::showbase " .
+ "<< $arg << std::dec";
+ }
+
+ push @args, $arg;
+ }
+ else
+ {
+ # is opaque
+ push @args, '"OPAQUE"';
+ }
+ }
+
+ my $log_cmd = "Action << \" $cmd(\" ";
+ foreach my $arg (@args)
+ {
+ $arg = "<< $arg ";
+ }
+ $log_cmd .= join('<< "," ',@args);
+ $log_cmd .= '<< ")"';
+ return $log_cmd;
+}
+
diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in
new file mode 100755
index 00000000..269ff3f5
--- /dev/null
+++ b/lib/server/makeprotocol.pl.in
@@ -0,0 +1,1048 @@
+#!@PERL@
+use strict;
+
+use lib "../../infrastructure";
+use BoxPlatform;
+
+# Make protocol C++ classes from a protocol description file
+
+# built in type info (values are is basic type, C++ typename)
+# may get stuff added to it later if protocol uses extra types
+my %translate_type_info =
+(
+ 'int64' => [1, 'int64_t'],
+ 'int32' => [1, 'int32_t'],
+ 'int16' => [1, 'int16_t'],
+ 'int8' => [1, 'int8_t'],
+ 'bool' => [1, 'bool'],
+ 'string' => [0, 'std::string']
+);
+
+# built in instructions for logging various types
+# may be added to
+my %log_display_types =
+(
+ 'int64' => ['0x%llx', 'VAR'],
+ 'int32' => ['0x%x', 'VAR'],
+ 'int16' => ['0x%x', 'VAR'],
+ 'int8' => ['0x%x', 'VAR'],
+ 'bool' => ['%s', '((VAR)?"true":"false")'],
+ 'string' => ['%s', 'VAR.c_str()']
+);
+
+
+
+my ($type, $file) = @ARGV;
+
+if($type ne 'Server' && $type ne 'Client')
+{
+ die "Neither Server or Client is specified on command line\n";
+}
+
+open IN, $file or die "Can't open input file $file\n";
+
+print "Making $type protocol classes from $file...\n";
+
+my @extra_header_files;
+
+my $implement_syslog = 0;
+my $implement_filelog = 0;
+
+# read attributes
+my %attr;
+while(<IN>)
+{
+ # get and clean line
+ my $l = $_; $l =~ s/#.*\Z//; $l =~ s/\A\s+//; $l =~ s/\s+\Z//; next unless $l =~ m/\S/;
+
+ last if $l eq 'BEGIN_OBJECTS';
+
+ my ($k,$v) = split /\s+/,$l,2;
+
+ if($k eq 'ClientType')
+ {
+ add_type($v) if $type eq 'Client';
+ }
+ elsif($k eq 'ServerType')
+ {
+ add_type($v) if $type eq 'Server';
+ }
+ elsif($k eq 'ImplementLog')
+ {
+ my ($log_if_type,$log_type) = split /\s+/,$v;
+ if($type eq $log_if_type)
+ {
+ if($log_type eq 'syslog')
+ {
+ $implement_syslog = 1;
+ }
+ elsif($log_type eq 'file')
+ {
+ $implement_filelog = 1;
+ }
+ else
+ {
+ printf("ERROR: Unknown log type for implementation: $log_type\n");
+ exit(1);
+ }
+ }
+ }
+ elsif($k eq 'LogTypeToText')
+ {
+ my ($log_if_type,$type_name,$printf_format,$arg_template) = split /\s+/,$v;
+ if($type eq $log_if_type)
+ {
+ $log_display_types{$type_name} = [$printf_format,$arg_template]
+ }
+ }
+ else
+ {
+ $attr{$k} = $v;
+ }
+}
+
+sub add_type
+{
+ my ($protocol_name, $cpp_name, $header_file) = split /\s+/,$_[0];
+
+ $translate_type_info{$protocol_name} = [0, $cpp_name];
+ push @extra_header_files, $header_file;
+}
+
+# check attributes
+for(qw/Name ServerContextClass IdentString/)
+{
+ if(!exists $attr{$_})
+ {
+ die "Attribute $_ is required, but not specified\n";
+ }
+}
+
+my $protocol_name = $attr{'Name'};
+my ($context_class, $context_class_inc) = split /\s+/,$attr{'ServerContextClass'};
+my $ident_string = $attr{'IdentString'};
+
+my $current_cmd = '';
+my %cmd_contents;
+my %cmd_attributes;
+my %cmd_constants;
+my %cmd_id;
+my @cmd_list;
+
+# read in the command definitions
+while(<IN>)
+{
+ # get and clean line
+ my $l = $_; $l =~ s/#.*\Z//; $l =~ s/\s+\Z//; next unless $l =~ m/\S/;
+
+ # definitions or new command thing?
+ if($l =~ m/\A\s+/)
+ {
+ die "No command defined yet" if $current_cmd eq '';
+
+ # definition of component
+ $l =~ s/\A\s+//;
+
+ my ($type,$name,$value) = split /\s+/,$l;
+ if($type eq 'CONSTANT')
+ {
+ push @{$cmd_constants{$current_cmd}},"$name = $value"
+ }
+ else
+ {
+ push @{$cmd_contents{$current_cmd}},$type,$name;
+ }
+ }
+ else
+ {
+ # new command
+ my ($name,$id,@attributes) = split /\s+/,$l;
+ $cmd_attributes{$name} = [@attributes];
+ $cmd_id{$name} = int($id);
+ $current_cmd = $name;
+ push @cmd_list,$name;
+ }
+}
+
+close IN;
+
+
+
+# open files
+my $h_filename = 'autogen_'.$protocol_name.'Protocol'.$type.'.h';
+open CPP,'>autogen_'.$protocol_name.'Protocol'.$type.'.cpp';
+open H,">$h_filename";
+
+print CPP <<__E;
+
+// Auto-generated file -- do not edit
+
+#include "Box.h"
+#include "$h_filename"
+#include "IOStream.h"
+
+__E
+
+if($implement_syslog)
+{
+ print H <<EOF;
+#ifndef WIN32
+#include <syslog.h>
+#endif
+EOF
+}
+
+
+my $guardname = uc 'AUTOGEN_'.$protocol_name.'Protocol'.$type.'_H';
+print H <<__E;
+
+// Auto-generated file -- do not edit
+
+#ifndef $guardname
+#define $guardname
+
+#include "Protocol.h"
+#include "ProtocolObject.h"
+#include "ServerException.h"
+
+class IOStream;
+
+__E
+
+if($implement_filelog)
+{
+ print H qq~#include <stdio.h>\n~;
+}
+
+# extra headers
+for(@extra_header_files)
+{
+ print H qq~#include "$_"\n~
+}
+print H "\n";
+
+if($type eq 'Server')
+{
+ # need utils file for the server
+ print H '#include "Utils.h"',"\n\n"
+}
+
+
+my $derive_objects_from = 'ProtocolObject';
+my $objects_extra_h = '';
+my $objects_extra_cpp = '';
+if($type eq 'Server')
+{
+ # define the context
+ print H "class $context_class;\n\n";
+ print CPP "#include \"$context_class_inc\"\n\n";
+
+ # change class we derive the objects from
+ $derive_objects_from = $protocol_name.'ProtocolObject';
+
+ $objects_extra_h = <<__E;
+ virtual std::auto_ptr<ProtocolObject> DoCommand(${protocol_name}ProtocolServer &rProtocol, $context_class &rContext);
+__E
+ $objects_extra_cpp = <<__E;
+std::auto_ptr<ProtocolObject> ${derive_objects_from}::DoCommand(${protocol_name}ProtocolServer &rProtocol, $context_class &rContext)
+{
+ THROW_EXCEPTION(ConnectionException, Conn_Protocol_TriedToExecuteReplyCommand)
+}
+__E
+}
+
+print CPP qq~#include "MemLeakFindOn.h"\n~;
+
+if($type eq 'Client' && ($implement_syslog || $implement_filelog))
+{
+ # change class we derive the objects from
+ $derive_objects_from = $protocol_name.'ProtocolObjectCl';
+}
+if($implement_syslog)
+{
+ $objects_extra_h .= <<__E;
+ virtual void LogSysLog(const char *Action) const = 0;
+__E
+}
+if($implement_filelog)
+{
+ $objects_extra_h .= <<__E;
+ virtual void LogFile(const char *Action, FILE *file) const = 0;
+__E
+}
+
+if($derive_objects_from ne 'ProtocolObject')
+{
+ # output a definition for the protocol object derviced class
+ print H <<__E;
+class ${protocol_name}ProtocolServer;
+
+class $derive_objects_from : public ProtocolObject
+{
+public:
+ $derive_objects_from();
+ virtual ~$derive_objects_from();
+ $derive_objects_from(const $derive_objects_from &rToCopy);
+
+$objects_extra_h
+};
+__E
+
+ # and some cpp definitions
+ print CPP <<__E;
+${derive_objects_from}::${derive_objects_from}()
+{
+}
+${derive_objects_from}::~${derive_objects_from}()
+{
+}
+${derive_objects_from}::${derive_objects_from}(const $derive_objects_from &rToCopy)
+{
+}
+$objects_extra_cpp
+__E
+}
+
+
+
+my $classname_base = $protocol_name.'Protocol'.$type;
+
+# output the classes
+for my $cmd (@cmd_list)
+{
+ print H <<__E;
+class $classname_base$cmd : public $derive_objects_from
+{
+public:
+ $classname_base$cmd();
+ $classname_base$cmd(const $classname_base$cmd &rToCopy);
+ ~$classname_base$cmd();
+ int GetType() const;
+ enum
+ {
+ TypeID = $cmd_id{$cmd}
+ };
+__E
+ # constants
+ if(exists $cmd_constants{$cmd})
+ {
+ print H "\tenum\n\t{\n\t\t";
+ print H join(",\n\t\t",@{$cmd_constants{$cmd}});
+ print H "\n\t};\n";
+ }
+ # flags
+ if(obj_is_type($cmd,'EndsConversation'))
+ {
+ print H "\tbool IsConversationEnd() const;\n";
+ }
+ if(obj_is_type($cmd,'IsError'))
+ {
+ print H "\tbool IsError(int &rTypeOut, int &rSubTypeOut) const;\n";
+ }
+ if($type eq 'Server' && obj_is_type($cmd, 'Command'))
+ {
+ print H "\tstd::auto_ptr<ProtocolObject> DoCommand(${protocol_name}ProtocolServer &rProtocol, $context_class &rContext); // IMPLEMENT THIS\n"
+ }
+
+ # want to be able to read from streams?
+ my $read_from_streams = (obj_is_type($cmd,'Command') && $type eq 'Server') || (obj_is_type($cmd,'Reply') && $type eq 'Client');
+ my $write_to_streams = (obj_is_type($cmd,'Command') && $type eq 'Client') || (obj_is_type($cmd,'Reply') && $type eq 'Server');
+
+ if($read_from_streams)
+ {
+ print H "\tvoid SetPropertiesFromStreamData(Protocol &rProtocol);\n";
+
+ # write Get functions
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ print H "\t".translate_type_to_arg_type($ty)." Get$nm() {return m$nm;}\n";
+ }
+ }
+ my $param_con_args = '';
+ if($write_to_streams)
+ {
+ # extra constructor?
+ if($#{$cmd_contents{$cmd}} >= 0)
+ {
+ my @a;
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ push @a,translate_type_to_arg_type($ty)." $nm";
+ }
+ $param_con_args = join(', ',@a);
+ print H "\t$classname_base$cmd(".$param_con_args.");\n";
+ }
+ print H "\tvoid WritePropertiesToStreamData(Protocol &rProtocol) const;\n";
+ # set functions
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ print H "\tvoid Set$nm(".translate_type_to_arg_type($ty)." $nm) {m$nm = $nm;}\n";
+ }
+ }
+
+ if($implement_syslog)
+ {
+ print H "\tvirtual void LogSysLog(const char *Action) const;\n";
+ }
+ if($implement_filelog)
+ {
+ print H "\tvirtual void LogFile(const char *Action, FILE *file) const;\n";
+ }
+
+
+ # write member variables and setup for cpp file
+ my @def_constructor_list;
+ my @copy_constructor_list;
+ my @param_constructor_list;
+
+ print H "private:\n";
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ print H "\t".translate_type_to_member_type($ty)." m$nm;\n";
+
+ my ($basic,$typename) = translate_type($ty);
+ if($basic)
+ {
+ push @def_constructor_list, "m$nm(0)";
+ }
+ push @copy_constructor_list, "m$nm(rToCopy.m$nm)";
+ push @param_constructor_list, "m$nm($nm)";
+ }
+
+ # finish off
+ print H "};\n\n";
+
+ # now the cpp file...
+ my $def_con_vars = join(",\n\t ",@def_constructor_list);
+ $def_con_vars = "\n\t: ".$def_con_vars if $def_con_vars ne '';
+ my $copy_con_vars = join(",\n\t ",@copy_constructor_list);
+ $copy_con_vars = "\n\t: ".$copy_con_vars if $copy_con_vars ne '';
+ my $param_con_vars = join(",\n\t ",@param_constructor_list);
+ $param_con_vars = "\n\t: ".$param_con_vars if $param_con_vars ne '';
+
+ my $class = "$classname_base$cmd".'::';
+ print CPP <<__E;
+$class$classname_base$cmd()$def_con_vars
+{
+}
+$class$classname_base$cmd(const $classname_base$cmd &rToCopy)$copy_con_vars
+{
+}
+$class~$classname_base$cmd()
+{
+}
+int ${class}GetType() const
+{
+ return $cmd_id{$cmd};
+}
+__E
+ if($read_from_streams)
+ {
+ print CPP "void ${class}SetPropertiesFromStreamData(Protocol &rProtocol)\n{\n";
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ if($ty =~ m/\Avector/)
+ {
+ print CPP "\trProtocol.ReadVector(m$nm);\n";
+ }
+ else
+ {
+ print CPP "\trProtocol.Read(m$nm);\n";
+ }
+ }
+ print CPP "}\n";
+ }
+ if($write_to_streams)
+ {
+ # implement extra constructor?
+ if($param_con_vars ne '')
+ {
+ print CPP "$class$classname_base$cmd($param_con_args)$param_con_vars\n{\n}\n";
+ }
+ print CPP "void ${class}WritePropertiesToStreamData(Protocol &rProtocol) const\n{\n";
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ if($ty =~ m/\Avector/)
+ {
+ print CPP "\trProtocol.WriteVector(m$nm);\n";
+ }
+ else
+ {
+ print CPP "\trProtocol.Write(m$nm);\n";
+ }
+ }
+ print CPP "}\n";
+ }
+ if(obj_is_type($cmd,'EndsConversation'))
+ {
+ print CPP "bool ${class}IsConversationEnd() const\n{\n\treturn true;\n}\n";
+ }
+ if(obj_is_type($cmd,'IsError'))
+ {
+ # get parameters
+ my ($mem_type,$mem_subtype) = split /,/,obj_get_type_params($cmd,'IsError');
+ print CPP <<__E;
+bool ${class}IsError(int &rTypeOut, int &rSubTypeOut) const
+{
+ rTypeOut = m$mem_type;
+ rSubTypeOut = m$mem_subtype;
+ return true;
+}
+__E
+ }
+
+ if($implement_syslog)
+ {
+ my ($log) = make_log_strings_framework($cmd);
+ print CPP <<__E;
+void ${class}LogSysLog(const char *Action) const
+{
+ BOX_TRACE($log);
+}
+__E
+ }
+ if($implement_filelog)
+ {
+ my ($format,$args) = make_log_strings($cmd);
+ print CPP <<__E;
+void ${class}LogFile(const char *Action, FILE *File) const
+{
+ ::fprintf(File,"%s $format\\n",Action$args);
+ ::fflush(File);
+}
+__E
+ }
+}
+
+# finally, the protocol object itself
+print H <<__E;
+class $classname_base : public Protocol
+{
+public:
+ $classname_base(IOStream &rStream);
+ virtual ~$classname_base();
+
+ std::auto_ptr<$derive_objects_from> Receive();
+ void Send(const ${derive_objects_from} &rObject);
+__E
+if($implement_syslog)
+{
+ print H "\tvoid SetLogToSysLog(bool Log = false) {mLogToSysLog = Log;}\n";
+}
+if($implement_filelog)
+{
+ print H "\tvoid SetLogToFile(FILE *File = 0) {mLogToFile = File;}\n";
+}
+if($type eq 'Server')
+{
+ # need to put in the conversation function
+ print H "\tvoid DoServer($context_class &rContext);\n\n";
+ # and the send vector thing
+ print H "\tvoid SendStreamAfterCommand(IOStream *pStream);\n\n";
+}
+if($type eq 'Client')
+{
+ # add plain object taking query functions
+ my $with_params;
+ for my $cmd (@cmd_list)
+ {
+ if(obj_is_type($cmd,'Command'))
+ {
+ my $has_stream = obj_is_type($cmd,'StreamWithCommand');
+ my $argextra = $has_stream?', IOStream &rStream':'';
+ my $queryextra = $has_stream?', rStream':'';
+ my $reply = obj_get_type_params($cmd,'Command');
+ print H "\tstd::auto_ptr<$classname_base$reply> Query(const $classname_base$cmd &rQuery$argextra);\n";
+ my @a;
+ my @na;
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+ push @a,translate_type_to_arg_type($ty)." $nm";
+ push @na,"$nm";
+ }
+ my $ar = join(', ',@a);
+ my $nar = join(', ',@na);
+ $nar = "($nar)" if $nar ne '';
+
+ $with_params .= "\tinline std::auto_ptr<$classname_base$reply> Query$cmd($ar$argextra)\n\t{\n";
+ $with_params .= "\t\t$classname_base$cmd send$nar;\n";
+ $with_params .= "\t\treturn Query(send$queryextra);\n";
+ $with_params .= "\t}\n";
+ }
+ }
+ # quick hack to correct bad argument lists for commands with zero paramters but with streams
+ $with_params =~ s/\(, /(/g;
+ print H "\n",$with_params,"\n";
+}
+print H <<__E;
+private:
+ $classname_base(const $classname_base &rToCopy);
+__E
+if($type eq 'Server')
+{
+ # need to put the streams to send vector
+ print H "\tstd::vector<IOStream*> mStreamsToSend;\n\tvoid DeleteStreamsToSend();\n";
+}
+
+if($implement_filelog || $implement_syslog)
+{
+ print H <<__E;
+ virtual void InformStreamReceiving(u_int32_t Size);
+ virtual void InformStreamSending(u_int32_t Size);
+__E
+}
+
+if($implement_syslog)
+{
+ print H "private:\n\tbool mLogToSysLog;\n";
+}
+if($implement_filelog)
+{
+ print H "private:\n\tFILE *mLogToFile;\n";
+}
+print H <<__E;
+
+protected:
+ virtual std::auto_ptr<ProtocolObject> MakeProtocolObject(int ObjType);
+ virtual const char *GetIdentString();
+};
+
+__E
+
+my $construtor_extra = '';
+$construtor_extra .= ', mLogToSysLog(false)' if $implement_syslog;
+$construtor_extra .= ', mLogToFile(0)' if $implement_filelog;
+
+my $destructor_extra = ($type eq 'Server')?"\n\tDeleteStreamsToSend();":'';
+
+my $prefix = $classname_base.'::';
+print CPP <<__E;
+$prefix$classname_base(IOStream &rStream)
+ : Protocol(rStream)$construtor_extra
+{
+}
+$prefix~$classname_base()
+{$destructor_extra
+}
+const char *${prefix}GetIdentString()
+{
+ return "$ident_string";
+}
+std::auto_ptr<ProtocolObject> ${prefix}MakeProtocolObject(int ObjType)
+{
+ switch(ObjType)
+ {
+__E
+
+# do objects within this
+for my $cmd (@cmd_list)
+{
+ print CPP <<__E;
+ case $cmd_id{$cmd}:
+ return std::auto_ptr<ProtocolObject>(new $classname_base$cmd);
+ break;
+__E
+}
+
+print CPP <<__E;
+ default:
+ THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnknownCommandRecieved)
+ }
+}
+__E
+# write receieve and send functions
+print CPP <<__E;
+std::auto_ptr<$derive_objects_from> ${prefix}Receive()
+{
+ std::auto_ptr<${derive_objects_from}> preply((${derive_objects_from}*)(Protocol::Receive().release()));
+
+__E
+ if($implement_syslog)
+ {
+ print CPP <<__E;
+ if(mLogToSysLog)
+ {
+ preply->LogSysLog("Receive");
+ }
+__E
+ }
+ if($implement_filelog)
+ {
+ print CPP <<__E;
+ if(mLogToFile != 0)
+ {
+ preply->LogFile("Receive", mLogToFile);
+ }
+__E
+ }
+print CPP <<__E;
+
+ return preply;
+}
+
+void ${prefix}Send(const ${derive_objects_from} &rObject)
+{
+__E
+ if($implement_syslog)
+ {
+ print CPP <<__E;
+ if(mLogToSysLog)
+ {
+ rObject.LogSysLog("Send");
+ }
+__E
+ }
+ if($implement_filelog)
+ {
+ print CPP <<__E;
+ if(mLogToFile != 0)
+ {
+ rObject.LogFile("Send", mLogToFile);
+ }
+__E
+ }
+
+print CPP <<__E;
+ Protocol::Send(rObject);
+}
+
+__E
+# write server function?
+if($type eq 'Server')
+{
+ print CPP <<__E;
+void ${prefix}DoServer($context_class &rContext)
+{
+ // Handshake with client
+ Handshake();
+
+ // Command processing loop
+ bool inProgress = true;
+ while(inProgress)
+ {
+ // Get an object from the conversation
+ std::auto_ptr<${derive_objects_from}> pobj(Receive());
+
+__E
+ if($implement_syslog)
+ {
+ print CPP <<__E;
+ if(mLogToSysLog)
+ {
+ pobj->LogSysLog("Receive");
+ }
+__E
+ }
+ if($implement_filelog)
+ {
+ print CPP <<__E;
+ if(mLogToFile != 0)
+ {
+ pobj->LogFile("Receive", mLogToFile);
+ }
+__E
+ }
+ print CPP <<__E;
+
+ // Run the command
+ std::auto_ptr<${derive_objects_from}> preply((${derive_objects_from}*)(pobj->DoCommand(*this, rContext).release()));
+
+__E
+ if($implement_syslog)
+ {
+ print CPP <<__E;
+ if(mLogToSysLog)
+ {
+ preply->LogSysLog("Send");
+ }
+__E
+ }
+ if($implement_filelog)
+ {
+ print CPP <<__E;
+ if(mLogToFile != 0)
+ {
+ preply->LogFile("Send", mLogToFile);
+ }
+__E
+ }
+ print CPP <<__E;
+
+ // Send the reply
+ Send(*(preply.get()));
+
+ // Send any streams
+ for(unsigned int s = 0; s < mStreamsToSend.size(); s++)
+ {
+ // Send the streams
+ SendStream(*mStreamsToSend[s]);
+ }
+ // Delete these streams
+ DeleteStreamsToSend();
+
+ // Does this end the conversation?
+ if(pobj->IsConversationEnd())
+ {
+ inProgress = false;
+ }
+ }
+}
+
+void ${prefix}SendStreamAfterCommand(IOStream *pStream)
+{
+ ASSERT(pStream != NULL);
+ mStreamsToSend.push_back(pStream);
+}
+
+void ${prefix}DeleteStreamsToSend()
+{
+ for(std::vector<IOStream*>::iterator i(mStreamsToSend.begin()); i != mStreamsToSend.end(); ++i)
+ {
+ delete (*i);
+ }
+ mStreamsToSend.clear();
+}
+
+__E
+}
+
+# write logging functions?
+if($implement_filelog || $implement_syslog)
+{
+ my ($fR,$fS);
+
+ if($implement_syslog)
+ {
+ $fR .= qq~\tif(mLogToSysLog) { ::syslog(LOG_INFO, (Size==Protocol::ProtocolStream_SizeUncertain)?"Receiving stream, size uncertain":"Receiving stream, size %d", Size); }\n~;
+ $fS .= qq~\tif(mLogToSysLog) { ::syslog(LOG_INFO, (Size==Protocol::ProtocolStream_SizeUncertain)?"Sending stream, size uncertain":"Sending stream, size %d", Size); }\n~;
+ }
+ if($implement_filelog)
+ {
+ $fR .= qq~\tif(mLogToFile) { ::fprintf(mLogToFile, (Size==Protocol::ProtocolStream_SizeUncertain)?"Receiving stream, size uncertain\\n":"Receiving stream, size %d\\n", Size); ::fflush(mLogToFile); }\n~;
+ $fS .= qq~\tif(mLogToFile) { ::fprintf(mLogToFile, (Size==Protocol::ProtocolStream_SizeUncertain)?"Sending stream, size uncertain\\n":"Sending stream, size %d\\n", Size); ::fflush(mLogToFile); }\n~;
+ }
+
+ print CPP <<__E;
+
+void ${prefix}InformStreamReceiving(u_int32_t Size)
+{
+$fR}
+
+void ${prefix}InformStreamSending(u_int32_t Size)
+{
+$fS}
+
+__E
+}
+
+
+# write client Query functions?
+if($type eq 'Client')
+{
+ for my $cmd (@cmd_list)
+ {
+ if(obj_is_type($cmd,'Command'))
+ {
+ my $reply = obj_get_type_params($cmd,'Command');
+ my $reply_id = $cmd_id{$reply};
+ my $has_stream = obj_is_type($cmd,'StreamWithCommand');
+ my $argextra = $has_stream?', IOStream &rStream':'';
+ my $send_stream_extra = '';
+ if($has_stream)
+ {
+ $send_stream_extra = <<__E;
+
+ // Send stream after the command
+ SendStream(rStream);
+__E
+ }
+ print CPP <<__E;
+std::auto_ptr<$classname_base$reply> ${classname_base}::Query(const $classname_base$cmd &rQuery$argextra)
+{
+ // Send query
+ Send(rQuery);
+ $send_stream_extra
+ // Wait for the reply
+ std::auto_ptr<${derive_objects_from}> preply(Receive().release());
+
+ if(preply->GetType() == $reply_id)
+ {
+ // Correct response
+ return std::auto_ptr<$classname_base$reply>(($classname_base$reply*)preply.release());
+ }
+ else
+ {
+ // Set protocol error
+ int type, subType;
+ if(preply->IsError(type, subType))
+ {
+ SetError(type, subType);
+ TRACE2("Protocol: Error received %d/%d\\n", type, subType);
+ }
+ else
+ {
+ SetError(Protocol::UnknownError, Protocol::UnknownError);
+ }
+
+ // Throw an exception
+ THROW_EXCEPTION(ConnectionException, Conn_Protocol_UnexpectedReply)
+ }
+}
+__E
+ }
+ }
+}
+
+
+
+print H <<__E;
+#endif // $guardname
+
+__E
+
+# close files
+close H;
+close CPP;
+
+
+sub obj_is_type
+{
+ my ($c,$ty) = @_;
+ for(@{$cmd_attributes{$c}})
+ {
+ return 1 if $_ =~ m/\A$ty/;
+ }
+
+ return 0;
+}
+
+sub obj_get_type_params
+{
+ my ($c,$ty) = @_;
+ for(@{$cmd_attributes{$c}})
+ {
+ return $1 if $_ =~ m/\A$ty\((.+?)\)\Z/;
+ }
+ die "Can't find attribute $ty\n"
+}
+
+# returns (is basic type, typename)
+sub translate_type
+{
+ my $ty = $_[0];
+
+ if($ty =~ m/\Avector\<(.+?)\>\Z/)
+ {
+ my $v_type = $1;
+ my (undef,$v_ty) = translate_type($v_type);
+ return (0, 'std::vector<'.$v_ty.'>')
+ }
+ else
+ {
+ if(!exists $translate_type_info{$ty})
+ {
+ die "Don't know about type name $ty\n";
+ }
+ return @{$translate_type_info{$ty}}
+ }
+}
+
+sub translate_type_to_arg_type
+{
+ my ($basic,$typename) = translate_type(@_);
+ return $basic?$typename:'const '.$typename.'&'
+}
+
+sub translate_type_to_member_type
+{
+ my ($basic,$typename) = translate_type(@_);
+ return $typename
+}
+
+sub make_log_strings
+{
+ my ($cmd) = @_;
+
+ my @str;
+ my @arg;
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ if(exists $log_display_types{$ty})
+ {
+ # need to translate it
+ my ($format,$arg) = @{$log_display_types{$ty}};
+ $arg =~ s/VAR/m$nm/g;
+
+ if ($format eq "0x%llx" and $target_windows)
+ {
+ $format = "0x%I64x";
+ $arg = "(uint64_t)$arg";
+ }
+
+ push @str,$format;
+ push @arg,$arg;
+ }
+ else
+ {
+ # is opaque
+ push @str,'OPAQUE';
+ }
+ }
+ return ($cmd.'('.join(',',@str).')', join(',','',@arg));
+}
+
+sub make_log_strings_framework
+{
+ my ($cmd) = @_;
+
+ my @args;
+
+ for(my $x = 0; $x < $#{$cmd_contents{$cmd}}; $x+=2)
+ {
+ my ($ty,$nm) = (${$cmd_contents{$cmd}}[$x], ${$cmd_contents{$cmd}}[$x+1]);
+
+ if(exists $log_display_types{$ty})
+ {
+ # need to translate it
+ my ($format,$arg) = @{$log_display_types{$ty}};
+ $arg =~ s/VAR/m$nm/g;
+
+ if ($format =~ m'x$')
+ {
+ $arg = "std::hex << std::showbase " .
+ "<< $arg << std::dec";
+ }
+
+ push @args, $arg;
+ }
+ else
+ {
+ # is opaque
+ push @args, '"OPAQUE"';
+ }
+ }
+
+ my $log_cmd = "Action << \" $cmd(\" ";
+ foreach my $arg (@args)
+ {
+ $arg = "<< $arg ";
+ }
+ $log_cmd .= join('<< "," ',@args);
+ $log_cmd .= '<< ")"';
+ return $log_cmd;
+}
+
+
diff --git a/lib/win32/MSG00001.bin b/lib/win32/MSG00001.bin
new file mode 100755
index 00000000..b4377b85
--- /dev/null
+++ b/lib/win32/MSG00001.bin
Binary files differ
diff --git a/lib/win32/WinNamedPipeStream.cpp b/lib/win32/WinNamedPipeStream.cpp
deleted file mode 100644
index 2a27a206..00000000
--- a/lib/win32/WinNamedPipeStream.cpp
+++ /dev/null
@@ -1,350 +0,0 @@
-// 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.
-//
-//
-//
-// --------------------------------------------------------------------------
-//
-// File
-// Name: WinNamedPipeStream.cpp
-// Purpose: I/O stream interface for Win32 named pipes
-// Created: 2005/12/07
-//
-// --------------------------------------------------------------------------
-
-#include "Box.h"
-
-#ifdef WIN32
-
-#ifdef HAVE_UNISTD_H
- #include <unistd.h>
-#endif
-
-#include <sys/types.h>
-#include <errno.h>
-#include <windows.h>
-
-#include "WinNamedPipeStream.h"
-#include "ServerException.h"
-#include "CommonException.h"
-#include "Socket.h"
-
-#include "MemLeakFindOn.h"
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::WinNamedPipeStream()
-// Purpose: Constructor (create stream ready for Open() call)
-// Created: 2005/12/07
-//
-// --------------------------------------------------------------------------
-WinNamedPipeStream::WinNamedPipeStream()
- : mSocketHandle(NULL),
- mReadClosed(false),
- mWriteClosed(false),
- mIsServer(false),
- mIsConnected(false)
-{
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::~WinNamedPipeStream()
-// Purpose: Destructor, closes stream if open
-// Created: 2005/12/07
-//
-// --------------------------------------------------------------------------
-WinNamedPipeStream::~WinNamedPipeStream()
-{
- if (mSocketHandle != NULL)
- {
- Close();
- }
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::Accept(const char* Name)
-// Purpose: Creates a new named pipe with the given name,
-// and wait for a connection on it
-// Created: 2005/12/07
-//
-// --------------------------------------------------------------------------
-void WinNamedPipeStream::Accept(const wchar_t* pName)
-{
- if (mSocketHandle != NULL || mIsConnected)
- {
- THROW_EXCEPTION(ServerException, SocketAlreadyOpen)
- }
-
- mSocketHandle = CreateNamedPipeW(
- pName, // pipe name
- PIPE_ACCESS_DUPLEX, // read/write access
- PIPE_TYPE_MESSAGE | // message type pipe
- PIPE_READMODE_MESSAGE | // message-read mode
- PIPE_WAIT, // blocking mode
- 1, // max. instances
- 4096, // output buffer size
- 4096, // input buffer size
- NMPWAIT_USE_DEFAULT_WAIT, // client time-out
- NULL); // default security attribute
-
- if (mSocketHandle == NULL)
- {
- ::syslog(LOG_ERR, "CreateNamedPipeW failed: %d",
- GetLastError());
- THROW_EXCEPTION(ServerException, SocketOpenError)
- }
-
- bool connected = ConnectNamedPipe(mSocketHandle, (LPOVERLAPPED) NULL);
-
- if (!connected)
- {
- ::syslog(LOG_ERR, "ConnectNamedPipe failed: %d",
- GetLastError());
- Close();
- THROW_EXCEPTION(ServerException, SocketOpenError)
- }
-
- mReadClosed = false;
- mWriteClosed = false;
- mIsServer = true; // must flush and disconnect before closing
- mIsConnected = true;
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::Connect(const char* Name)
-// Purpose: Opens a connection to a listening named pipe
-// Created: 2005/12/07
-//
-// --------------------------------------------------------------------------
-void WinNamedPipeStream::Connect(const wchar_t* pName)
-{
- if (mSocketHandle != NULL || mIsConnected)
- {
- THROW_EXCEPTION(ServerException, SocketAlreadyOpen)
- }
-
- mSocketHandle = CreateFileW(
- pName, // pipe name
- GENERIC_READ | // read and write access
- GENERIC_WRITE,
- 0, // no sharing
- NULL, // default security attributes
- OPEN_EXISTING,
- 0, // default attributes
- NULL); // no template file
-
- if (mSocketHandle == INVALID_HANDLE_VALUE)
- {
- ::syslog(LOG_ERR, "Failed to connect to server's named pipe: "
- "error %d", GetLastError());
- THROW_EXCEPTION(ServerException, SocketOpenError)
- }
-
- mReadClosed = false;
- mWriteClosed = false;
- mIsServer = false; // just close the socket
- mIsConnected = true;
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::Read(void *pBuffer, int NBytes)
-// Purpose: Reads data from stream. Maybe returns less than asked for.
-// Created: 2003/07/31
-//
-// --------------------------------------------------------------------------
-int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout)
-{
- // TODO no support for timeouts yet
- ASSERT(Timeout == IOStream::TimeOutInfinite)
-
- if (mSocketHandle == NULL || !mIsConnected)
- {
- THROW_EXCEPTION(ServerException, BadSocketHandle)
- }
-
- DWORD NumBytesRead;
-
- bool Success = ReadFile(
- mSocketHandle, // pipe handle
- pBuffer, // buffer to receive reply
- NBytes, // size of buffer
- &NumBytesRead, // number of bytes read
- NULL); // not overlapped
-
- if (!Success)
- {
- THROW_EXCEPTION(ConnectionException, Conn_SocketReadError)
- }
-
- // Closed for reading at EOF?
- if (NumBytesRead == 0)
- {
- mReadClosed = true;
- }
-
- return NumBytesRead;
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::Write(void *pBuffer, int NBytes)
-// Purpose: Writes data, blocking until it's all done.
-// Created: 2003/07/31
-//
-// --------------------------------------------------------------------------
-void WinNamedPipeStream::Write(const void *pBuffer, int NBytes)
-{
- if (mSocketHandle == NULL || !mIsConnected)
- {
- THROW_EXCEPTION(ServerException, BadSocketHandle)
- }
-
- // Buffer in byte sized type.
- ASSERT(sizeof(char) == 1);
- const char *pByteBuffer = (char *)pBuffer;
-
- int NumBytesWrittenTotal = 0;
-
- while (NumBytesWrittenTotal < NBytes)
- {
- DWORD NumBytesWrittenThisTime = 0;
-
- bool Success = WriteFile(
- mSocketHandle, // pipe handle
- pByteBuffer + NumBytesWrittenTotal, // message
- NBytes - NumBytesWrittenTotal, // message length
- &NumBytesWrittenThisTime, // bytes written this time
- NULL); // not overlapped
-
- if (!Success)
- {
- mWriteClosed = true; // assume can't write again
- THROW_EXCEPTION(ConnectionException,
- Conn_SocketWriteError)
- }
-
- NumBytesWrittenTotal += NumBytesWrittenThisTime;
- }
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::Close()
-// Purpose: Closes connection to remote socket
-// Created: 2003/07/31
-//
-// --------------------------------------------------------------------------
-void WinNamedPipeStream::Close()
-{
- if (mSocketHandle == NULL && mIsConnected)
- {
- fprintf(stderr, "Inconsistent connected state\n");
- ::syslog(LOG_ERR, "Inconsistent connected state");
- mIsConnected = false;
- }
-
- if (mSocketHandle == NULL)
- {
- THROW_EXCEPTION(ServerException, BadSocketHandle)
- }
-
- if (mIsServer)
- {
- if (!FlushFileBuffers(mSocketHandle))
- {
- ::syslog(LOG_INFO, "FlushFileBuffers failed: %d",
- GetLastError());
- }
-
- if (!DisconnectNamedPipe(mSocketHandle))
- {
- ::syslog(LOG_ERR, "DisconnectNamedPipe failed: %d",
- GetLastError());
- }
-
- mIsServer = false;
- }
-
- bool result = CloseHandle(mSocketHandle);
-
- mSocketHandle = NULL;
- mIsConnected = false;
-
- if (!result)
- {
- ::syslog(LOG_ERR, "CloseHandle failed: %d", GetLastError());
- THROW_EXCEPTION(ServerException, SocketCloseError)
- }
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::StreamDataLeft()
-// Purpose: Still capable of reading data?
-// Created: 2003/08/02
-//
-// --------------------------------------------------------------------------
-bool WinNamedPipeStream::StreamDataLeft()
-{
- return !mReadClosed;
-}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: WinNamedPipeStream::StreamClosed()
-// Purpose: Connection been closed?
-// Created: 2003/08/02
-//
-// --------------------------------------------------------------------------
-bool WinNamedPipeStream::StreamClosed()
-{
- return mWriteClosed;
-}
-
-#endif // WIN32
diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp
index c3c0b6f2..e41430c6 100644
--- a/lib/win32/emu.cpp
+++ b/lib/win32/emu.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.
@@ -41,29 +41,31 @@
// Need at least 0x0500 to use GetFileSizeEx on Cygwin/MinGW
#define WINVER 0x0500
-#include "Box.h"
+#include "emu.h"
#ifdef WIN32
-// #include "emu.h"
-
-#include <windows.h>
+#include <assert.h>
#include <fcntl.h>
-// #include <atlenc.h>
+#include <process.h>
+#include <windows.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#ifdef HAVE_PROCESS_H
- #include <process.h>
-#endif
#include <string>
#include <list>
+#include <sstream>
+
+// message resource definitions for syslog()
+
+#include "messages.h"
// our implementation for a timer, based on a
// simple thread which sleeps for a period of time
+static bool gTimerInitialised = false;
static bool gFinishTimer;
static CRITICAL_SECTION gLock;
@@ -79,24 +81,31 @@ static void (__cdecl *gTimerFunc) (int) = NULL;
int setitimer(int type, struct itimerval *timeout, void *arg)
{
- if (ITIMER_VIRTUAL == type)
+ assert(gTimerInitialised);
+
+ if (ITIMER_REAL != type)
{
- EnterCriticalSection(&gLock);
- // we only need seconds for the mo!
- if (timeout->it_value.tv_sec == 0 &&
- timeout->it_value.tv_usec == 0)
- {
- gTimerList.clear();
- }
- else
- {
- Timer_t ourTimer;
- ourTimer.countDown = timeout->it_value.tv_sec;
- ourTimer.interval = timeout->it_interval.tv_sec;
- gTimerList.push_back(ourTimer);
- }
- LeaveCriticalSection(&gLock);
+ errno = ENOSYS;
+ return -1;
}
+
+ EnterCriticalSection(&gLock);
+
+ // we only need seconds for the mo!
+ if (timeout->it_value.tv_sec == 0 &&
+ timeout->it_value.tv_usec == 0)
+ {
+ gTimerList.clear();
+ }
+ else
+ {
+ Timer_t ourTimer;
+ ourTimer.countDown = timeout->it_value.tv_sec;
+ ourTimer.interval = timeout->it_interval.tv_sec;
+ gTimerList.push_back(ourTimer);
+ }
+
+ LeaveCriticalSection(&gLock);
// indicate success
return 0;
@@ -167,20 +176,26 @@ int SetTimerHandler(void (__cdecl *func ) (int))
void InitTimer(void)
{
- InitializeCriticalSection(&gLock);
+ assert(!gTimerInitialised);
+ InitializeCriticalSection(&gLock);
+
// create our thread
HANDLE ourThread = (HANDLE)_beginthreadex(NULL, 0, RunTimer, 0,
CREATE_SUSPENDED, NULL);
SetThreadPriority(ourThread, THREAD_PRIORITY_LOWEST);
ResumeThread(ourThread);
+
+ gTimerInitialised = true;
}
void FiniTimer(void)
{
+ assert(gTimerInitialised);
gFinishTimer = true;
EnterCriticalSection(&gLock);
DeleteCriticalSection(&gLock);
+ gTimerInitialised = false;
}
//Our constants we need to keep track of
@@ -241,6 +256,44 @@ bool EnableBackupRights( void )
}
}
+// forward declaration
+char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage);
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: GetDefaultConfigFilePath(std::string name)
+// Purpose: Calculates the default configuration file name,
+// by using the directory location of the currently
+// executing program, and appending the provided name.
+// In case of fire, returns an empty string.
+// Created: 26th May 2007
+//
+// --------------------------------------------------------------------------
+std::string GetDefaultConfigFilePath(const std::string& rName)
+{
+ WCHAR exePathWide[MAX_PATH];
+ GetModuleFileNameW(NULL, exePathWide, MAX_PATH-1);
+
+ char* exePathUtf8 = ConvertFromWideString(exePathWide, CP_UTF8);
+ if (exePathUtf8 == NULL)
+ {
+ return "";
+ }
+
+ std::string configfile = exePathUtf8;
+ delete [] exePathUtf8;
+
+ // make the default config file name,
+ // based on the program path
+ configfile = configfile.substr(0,
+ configfile.rfind('\\'));
+ configfile += "\\";
+ configfile += rName;
+
+ return configfile;
+}
+
// --------------------------------------------------------------------------
//
// Function
@@ -398,27 +451,34 @@ char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage)
// --------------------------------------------------------------------------
//
// Function
-// Name: ConvertUtf8ToConsole
-// Purpose: Converts a string from UTF-8 to the console
-// code page. On success, replaces contents of rDest
-// and returns true. In case of fire, logs the error
-// and returns false.
-// Created: 4th February 2006
+// Name: ConvertEncoding(const std::string&, int,
+// std::string&, int)
+// Purpose: Converts a string from one code page to another.
+// On success, replaces contents of rDest and returns
+// true. In case of fire, logs the error and returns
+// false.
+// Created: 15th October 2006
//
// --------------------------------------------------------------------------
-bool ConvertUtf8ToConsole(const char* pString, std::string& rDest)
+bool ConvertEncoding(const std::string& rSource, int sourceCodePage,
+ std::string& rDest, int destCodePage)
{
- WCHAR* pWide = ConvertToWideString(pString, CP_UTF8);
+ WCHAR* pWide = ConvertToWideString(rSource.c_str(), sourceCodePage);
if (pWide == NULL)
{
+ ::syslog(LOG_ERR, "Failed to convert string '%s' from "
+ "current code page %d to wide string: %s",
+ rSource.c_str(), sourceCodePage,
+ GetErrorMessage(GetLastError()).c_str());
return false;
}
- char* pConsole = ConvertFromWideString(pWide, GetConsoleOutputCP());
+ char* pConsole = ConvertFromWideString(pWide, destCodePage);
delete [] pWide;
if (!pConsole)
{
+ // Error should have been logged by ConvertFromWideString
return false;
}
@@ -428,39 +488,25 @@ bool ConvertUtf8ToConsole(const char* pString, std::string& rDest)
return true;
}
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: ConvertConsoleToUtf8
-// Purpose: Converts a string from the console code page
-// to UTF-8. On success, replaces contents of rDest
-// and returns true. In case of fire, logs the error
-// and returns false.
-// Created: 4th February 2006
-//
-// --------------------------------------------------------------------------
-bool ConvertConsoleToUtf8(const char* pString, std::string& rDest)
+bool ConvertToUtf8(const char* pString, std::string& rDest, int sourceCodePage)
{
- WCHAR* pWide = ConvertToWideString(pString, GetConsoleCP());
- if (pWide == NULL)
- {
- return false;
- }
-
- char* pConsole = ConvertFromWideString(pWide, CP_UTF8);
- delete [] pWide;
-
- if (!pConsole)
- {
- return false;
- }
+ return ConvertEncoding(pString, sourceCodePage, rDest, CP_UTF8);
+}
- rDest = pConsole;
- delete [] pConsole;
+bool ConvertFromUtf8(const char* pString, std::string& rDest, int destCodePage)
+{
+ return ConvertEncoding(pString, CP_UTF8, rDest, destCodePage);
+}
- return true;
+bool ConvertConsoleToUtf8(const char* pString, std::string& rDest)
+{
+ return ConvertEncoding(pString, GetConsoleCP(), rDest, CP_UTF8);
}
+bool ConvertUtf8ToConsole(const char* pString, std::string& rDest)
+{
+ return ConvertEncoding(pString, CP_UTF8, rDest, GetConsoleOutputCP());
+}
// --------------------------------------------------------------------------
//
@@ -472,28 +518,54 @@ bool ConvertConsoleToUtf8(const char* pString, std::string& rDest)
// --------------------------------------------------------------------------
std::string ConvertPathToAbsoluteUnicode(const char *pFileName)
{
+ std::string filename;
+ for (int i = 0; pFileName[i] != 0; i++)
+ {
+ if (pFileName[i] == '/')
+ {
+ filename += '\\';
+ }
+ else
+ {
+ filename += pFileName[i];
+ }
+ }
+
std::string tmpStr("\\\\?\\");
// Is the path relative or absolute?
// Absolute paths on Windows are always a drive letter
// followed by ':'
-
- if (pFileName[1] != ':')
+
+ char wd[PATH_MAX];
+ if (::getcwd(wd, PATH_MAX) == 0)
+ {
+ ::syslog(LOG_WARNING,
+ "Failed to open '%s': path too long",
+ pFileName);
+ errno = ENAMETOOLONG;
+ tmpStr = "";
+ return tmpStr;
+ }
+
+ if (filename.length() > 2 && filename[0] == '\\' &&
+ filename[1] == '\\')
+ {
+ tmpStr += "UNC\\";
+ filename.replace(0, 2, "");
+ // \\?\UNC\<server>\<share>
+ // see http://msdn2.microsoft.com/en-us/library/aa365247.aspx
+ }
+ else if (filename.length() >= 1 && filename[0] == '\\')
+ {
+ // root directory of current drive.
+ tmpStr = wd;
+ tmpStr.resize(2); // drive letter and colon
+ }
+ else if (filename.length() >= 2 && filename[1] != ':')
{
// Must be relative. We need to get the
// current directory to make it absolute.
-
- char wd[PATH_MAX];
- if (::getcwd(wd, PATH_MAX) == 0)
- {
- ::syslog(LOG_WARNING,
- "Failed to open '%s': path too long",
- pFileName);
- errno = ENAMETOOLONG;
- tmpStr = "";
- return tmpStr;
- }
-
tmpStr += wd;
if (tmpStr[tmpStr.length()] != '\\')
{
@@ -501,26 +573,59 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName)
}
}
- tmpStr += pFileName;
+ tmpStr += filename;
return tmpStr;
}
+std::string GetErrorMessage(DWORD errorCode)
+{
+ char* pMsgBuf = NULL;
+
+ DWORD chars = FormatMessage
+ (
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ errorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (char *)(&pMsgBuf),
+ 0, NULL
+ );
+
+ if (chars == 0 || pMsgBuf == NULL)
+ {
+ return std::string("failed to get error message");
+ }
+
+ // remove embedded newline
+ pMsgBuf[chars - 1] = 0;
+ pMsgBuf[chars - 2] = 0;
+
+ std::ostringstream line;
+ line << pMsgBuf << " (" << errorCode << ")";
+ LocalFree(pMsgBuf);
+
+ return line.str();
+}
+
// --------------------------------------------------------------------------
//
// Function
// Name: openfile
-// Purpose: replacement for any open calls - handles unicode filenames - supplied in utf8
+// Purpose: replacement for any open calls - handles unicode
+// filenames - supplied in utf8
// Created: 25th October 2004
//
// --------------------------------------------------------------------------
HANDLE openfile(const char *pFileName, int flags, int mode)
{
- std::string AbsPathWithUnicode = ConvertPathToAbsoluteUnicode(pFileName);
+ std::string AbsPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(pFileName);
if (AbsPathWithUnicode.size() == 0)
{
// error already logged by ConvertPathToAbsoluteUnicode()
- return NULL;
+ return INVALID_HANDLE_VALUE;
}
WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
@@ -529,68 +634,73 @@ HANDLE openfile(const char *pFileName, int flags, int mode)
if (pBuffer == NULL)
{
// error already logged by ConvertUtf8ToWideString()
- return NULL;
+ return INVALID_HANDLE_VALUE;
}
// flags could be O_WRONLY | O_CREAT | O_RDONLY
DWORD createDisposition = OPEN_EXISTING;
- DWORD shareMode = FILE_SHARE_READ;
- DWORD accessRights = FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_READ_EA;
+ DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE
+ | FILE_SHARE_DELETE;
+ DWORD accessRights = FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY
+ | FILE_READ_EA;
if (flags & O_WRONLY)
{
- shareMode = FILE_SHARE_WRITE;
+ accessRights = FILE_WRITE_DATA;
}
- if (flags & O_RDWR)
+ else if (flags & O_RDWR)
{
- shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ accessRights |= FILE_WRITE_ATTRIBUTES
+ | FILE_WRITE_DATA | FILE_WRITE_EA;
}
+
if (flags & O_CREAT)
{
createDisposition = OPEN_ALWAYS;
- shareMode |= FILE_SHARE_WRITE;
- accessRights |= FILE_WRITE_ATTRIBUTES
- | FILE_WRITE_DATA | FILE_WRITE_EA
- | FILE_ALL_ACCESS;
}
+
if (flags & O_TRUNC)
{
createDisposition = CREATE_ALWAYS;
}
- if (flags & O_EXCL)
+
+ if ((flags & O_CREAT) && (flags & O_EXCL))
+ {
+ createDisposition = CREATE_NEW;
+ }
+
+ if (flags & O_LOCK)
{
shareMode = 0;
}
+ DWORD winFlags = FILE_FLAG_BACKUP_SEMANTICS;
+ if (flags & O_TEMPORARY)
+ {
+ winFlags |= FILE_FLAG_DELETE_ON_CLOSE;
+ }
+
HANDLE hdir = CreateFileW(pBuffer,
accessRights,
shareMode,
NULL,
createDisposition,
- FILE_FLAG_BACKUP_SEMANTICS,
+ winFlags,
NULL);
delete [] pBuffer;
if (hdir == INVALID_HANDLE_VALUE)
{
- ::syslog(LOG_WARNING, "Failed to open file %s: "
- "error %i", pFileName, GetLastError());
- return NULL;
+ ::syslog(LOG_WARNING, "Failed to open file '%s': "
+ "%s", pFileName,
+ GetErrorMessage(GetLastError()).c_str());
+ return INVALID_HANDLE_VALUE;
}
return hdir;
}
-// MinGW provides a getopt implementation
-#ifndef __MINGW32__
-//works with getopt
-char *optarg;
-//optind looks like an index into the string - how far we have moved along
-int optind = 1;
-char nextchar = -1;
-#endif
-
// --------------------------------------------------------------------------
//
// Function
@@ -601,8 +711,6 @@ char nextchar = -1;
// --------------------------------------------------------------------------
int emu_fstat(HANDLE hdir, struct stat * st)
{
- ULARGE_INTEGER conv;
-
if (hdir == INVALID_HANDLE_VALUE)
{
::syslog(LOG_ERR, "Error: invalid file handle in emu_fstat()");
@@ -614,14 +722,23 @@ int emu_fstat(HANDLE hdir, struct stat * st)
if (!GetFileInformationByHandle(hdir, &fi))
{
::syslog(LOG_WARNING, "Failed to read file information: "
- "error %d", GetLastError());
+ "%s", GetErrorMessage(GetLastError()).c_str());
+ errno = EACCES;
+ return -1;
+ }
+
+ if (INVALID_FILE_ATTRIBUTES == fi.dwFileAttributes)
+ {
+ ::syslog(LOG_WARNING, "Failed to get file attributes: "
+ "%s", GetErrorMessage(GetLastError()).c_str());
errno = EACCES;
return -1;
}
memset(st, 0, sizeof(*st));
- // This next example is how we get our INODE (equivalent) information
+ // This is how we get our INODE (equivalent) information
+ ULARGE_INTEGER conv;
conv.HighPart = fi.nFileIndexHigh;
conv.LowPart = fi.nFileIndexLow;
st->st_ino = (_ino_t)conv.QuadPart;
@@ -631,41 +748,71 @@ int emu_fstat(HANDLE hdir, struct stat * st)
st->st_atime = ConvertFileTimeToTime_t(&fi.ftLastAccessTime);
st->st_mtime = ConvertFileTimeToTime_t(&fi.ftLastWriteTime);
- // size of the file
- LARGE_INTEGER st_size;
- if (!GetFileSizeEx(hdir, &st_size))
+ if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
- ::syslog(LOG_WARNING, "Failed to get file size: error %d",
- GetLastError());
- errno = EACCES;
- return -1;
+ st->st_size = 0;
+ }
+ else
+ {
+ // size of the file
+ LARGE_INTEGER st_size;
+ memset(&st_size, 0, sizeof(st_size));
+
+ if (!GetFileSizeEx(hdir, &st_size))
+ {
+ ::syslog(LOG_WARNING, "Failed to get file size: "
+ "%s", GetErrorMessage(GetLastError()).c_str());
+ errno = EACCES;
+ return -1;
+ }
+
+ conv.HighPart = st_size.HighPart;
+ conv.LowPart = st_size.LowPart;
+ st->st_size = (_off_t)conv.QuadPart;
}
- conv.HighPart = st_size.HighPart;
- conv.LowPart = st_size.LowPart;
- st->st_size = (_off_t)conv.QuadPart;
+ // at the mo
+ st->st_uid = 0;
+ st->st_gid = 0;
+ st->st_nlink = 1;
- //the mode of the file
- st->st_mode = 0;
- //DWORD res = GetFileAttributes((LPCSTR)tmpStr.c_str());
+ // the mode of the file
+ // mode zero will make it impossible to restore on Unix
+ // (no access to anybody, including the owner).
+ // we'll fake a sensible mode:
+ // all objects get user read (0400)
+ // if it's a directory it gets user execute (0100)
+ // if it's not read-only it gets user write (0200)
+ st->st_mode = S_IREAD;
- if (INVALID_FILE_ATTRIBUTES != fi.dwFileAttributes)
+ if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
- if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- st->st_mode |= S_IFDIR;
- }
- else
- {
- st->st_mode |= S_IFREG;
- }
+ st->st_mode |= S_IFDIR | S_IEXEC;
}
else
{
- ::syslog(LOG_WARNING, "Failed to get file attributes: "
- "error %d", GetLastError());
- errno = EACCES;
- return -1;
+ st->st_mode |= S_IFREG;
+ }
+
+ if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
+ {
+ st->st_mode |= S_IWRITE;
+ }
+
+ // st_dev is normally zero, regardless of the drive letter,
+ // since backup locations can't normally span drives. However,
+ // a reparse point does allow all kinds of weird stuff to happen.
+ // We set st_dev to 1 for a reparse point, so that Box will detect
+ // a change of device number (from 0) and refuse to recurse down
+ // the reparse point (which could lead to havoc).
+
+ if (fi.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ {
+ st->st_dev = 1;
+ }
+ else
+ {
+ st->st_dev = 0;
}
return 0;
@@ -681,9 +828,10 @@ int emu_fstat(HANDLE hdir, struct stat * st)
// Created: 10th December 2004
//
// --------------------------------------------------------------------------
-HANDLE OpenFileByNameUtf8(const char* pFileName)
+HANDLE OpenFileByNameUtf8(const char* pFileName, DWORD flags)
{
- std::string AbsPathWithUnicode = ConvertPathToAbsoluteUnicode(pFileName);
+ std::string AbsPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(pFileName);
if (AbsPathWithUnicode.size() == 0)
{
@@ -701,7 +849,7 @@ HANDLE OpenFileByNameUtf8(const char* pFileName)
}
HANDLE handle = CreateFileW(pBuffer,
- FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_READ_EA,
+ flags,
FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
@@ -715,7 +863,7 @@ HANDLE OpenFileByNameUtf8(const char* pFileName)
// at least one process must have the file open -
// in this case someone else does.
handle = CreateFileW(pBuffer,
- 0,
+ READ_CONTROL,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
@@ -729,14 +877,16 @@ HANDLE OpenFileByNameUtf8(const char* pFileName)
{
DWORD err = GetLastError();
- if (err == ERROR_FILE_NOT_FOUND)
+ if (err == ERROR_FILE_NOT_FOUND ||
+ err == ERROR_PATH_NOT_FOUND)
{
errno = ENOENT;
}
else
{
- ::syslog(LOG_WARNING,
- "Failed to open '%s': error %d", pFileName, err);
+ ::syslog(LOG_WARNING, "Failed to open '%s': "
+ "%s", pFileName,
+ GetErrorMessage(err).c_str());
errno = EACCES;
}
@@ -757,12 +907,8 @@ HANDLE OpenFileByNameUtf8(const char* pFileName)
// --------------------------------------------------------------------------
int emu_stat(const char * pName, struct stat * st)
{
- // at the mo
- st->st_uid = 0;
- st->st_gid = 0;
- st->st_nlink = 1;
-
- HANDLE handle = OpenFileByNameUtf8(pName);
+ HANDLE handle = OpenFileByNameUtf8(pName,
+ FILE_READ_ATTRIBUTES | FILE_READ_EA);
if (handle == NULL)
{
@@ -795,7 +941,8 @@ int emu_stat(const char * pName, struct stat * st)
// --------------------------------------------------------------------------
int statfs(const char * pName, struct statfs * s)
{
- HANDLE handle = OpenFileByNameUtf8(pName);
+ HANDLE handle = OpenFileByNameUtf8(pName,
+ FILE_READ_ATTRIBUTES | FILE_READ_EA);
if (handle == NULL)
{
@@ -807,7 +954,8 @@ int statfs(const char * pName, struct statfs * s)
if (!GetFileInformationByHandle(handle, &fi))
{
::syslog(LOG_WARNING, "Failed to get file information "
- "for '%s': error %d", pName, GetLastError());
+ "for '%s': %s", pName,
+ GetErrorMessage(GetLastError()).c_str());
CloseHandle(handle);
errno = EACCES;
return -1;
@@ -817,7 +965,7 @@ int statfs(const char * pName, struct statfs * s)
_ui64toa(fi.dwVolumeSerialNumber, s->f_mntonname + 1, 16);
// pseudo unix mount point
- s->f_mntonname[0] = DIRECTORY_SEPARATOR_ASCHAR;
+ s->f_mntonname[0] = '\\';
CloseHandle(handle); // close the handle
@@ -827,6 +975,115 @@ int statfs(const char * pName, struct statfs * s)
// --------------------------------------------------------------------------
//
// Function
+// Name: emu_utimes
+// Purpose: replacement for the POSIX utimes() function,
+// works with unicode filenames supplied in utf8 format,
+// sets creation time instead of last access time.
+// Created: 25th July 2006
+//
+// --------------------------------------------------------------------------
+int emu_utimes(const char * pName, const struct timeval times[])
+{
+ FILETIME creationTime;
+ if (!ConvertTime_tToFileTime(times[0].tv_sec, &creationTime))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ FILETIME modificationTime;
+ if (!ConvertTime_tToFileTime(times[1].tv_sec, &modificationTime))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ HANDLE handle = OpenFileByNameUtf8(pName, FILE_WRITE_ATTRIBUTES);
+
+ if (handle == NULL)
+ {
+ // errno already set and error logged by OpenFileByNameUtf8()
+ return -1;
+ }
+
+ if (!SetFileTime(handle, &creationTime, NULL, &modificationTime))
+ {
+ ::syslog(LOG_ERR, "Failed to set times on '%s': %s", pName,
+ GetErrorMessage(GetLastError()).c_str());
+ CloseHandle(handle);
+ return 1;
+ }
+
+ CloseHandle(handle);
+ return 0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: emu_chmod
+// Purpose: replacement for the POSIX chmod function,
+// works with unicode filenames supplied in utf8 format
+// Created: 26th July 2006
+//
+// --------------------------------------------------------------------------
+int emu_chmod(const char * pName, mode_t mode)
+{
+ std::string AbsPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(pName);
+
+ if (AbsPathWithUnicode.size() == 0)
+ {
+ // error already logged by ConvertPathToAbsoluteUnicode()
+ return -1;
+ }
+
+ WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
+ // We are responsible for freeing pBuffer
+
+ if (pBuffer == NULL)
+ {
+ // error already logged by ConvertUtf8ToWideString()
+ free(pBuffer);
+ return -1;
+ }
+
+ DWORD attribs = GetFileAttributesW(pBuffer);
+ if (attribs == INVALID_FILE_ATTRIBUTES)
+ {
+ ::syslog(LOG_ERR, "Failed to get file attributes of '%s': %s",
+ pName, GetErrorMessage(GetLastError()).c_str());
+ errno = EACCES;
+ free(pBuffer);
+ return -1;
+ }
+
+ if (mode & S_IWRITE)
+ {
+ attribs &= ~FILE_ATTRIBUTE_READONLY;
+ }
+ else
+ {
+ attribs |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ if (!SetFileAttributesW(pBuffer, attribs))
+ {
+ ::syslog(LOG_ERR, "Failed to set file attributes of '%s': %s",
+ pName, GetErrorMessage(GetLastError()).c_str());
+ errno = EACCES;
+ free(pBuffer);
+ return -1;
+ }
+
+ delete [] pBuffer;
+ return 0;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
// Name: opendir
// Purpose: replacement for unix function, uses win32 findfirst routines
// Created: 25th October 2004
@@ -903,7 +1160,7 @@ struct dirent *readdir(DIR *dp)
if (!dp->result.d_name ||
_wfindnext(dp->fd, &dp->info) != -1)
{
- den = &dp->result;
+ den = &dp->result;
std::wstring input(dp->info.name);
memset(tempbuff, 0, sizeof(tempbuff));
WideCharToMultiByte(CP_UTF8, 0, dp->info.name,
@@ -911,6 +1168,14 @@ struct dirent *readdir(DIR *dp)
NULL, NULL);
//den->d_name = (char *)dp->info.name;
den->d_name = &tempbuff[0];
+ if (dp->info.attrib & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ den->d_type = S_IFDIR;
+ }
+ else
+ {
+ den->d_type = S_IFREG;
+ }
}
}
else
@@ -980,10 +1245,10 @@ int poll (struct pollfd *ufds, unsigned long nfds, int timeout)
fd_set readfd;
fd_set writefd;
- readfd.fd_count = 0;
- writefd.fd_count = 0;
+ FD_ZERO(&readfd);
+ FD_ZERO(&writefd);
- struct pollfd *ufdsTmp = ufds;
+ // struct pollfd *ufdsTmp = ufds;
timeval timOut;
timeval *tmpptr;
@@ -996,41 +1261,61 @@ int poll (struct pollfd *ufds, unsigned long nfds, int timeout)
timOut.tv_sec = timeout / 1000;
timOut.tv_usec = timeout * 1000;
- if (ufds->events & POLLIN)
+ for (unsigned long i = 0; i < nfds; i++)
{
- for (unsigned long i = 0; i < nfds; i++)
+ struct pollfd* ufd = &(ufds[i]);
+
+ if (ufd->events & POLLIN)
{
- readfd.fd_array[i] = ufdsTmp->fd;
- readfd.fd_count++;
+ FD_SET(ufd->fd, &readfd);
}
- }
- if (ufds->events & POLLOUT)
- {
- for (unsigned long i = 0; i < nfds; i++)
+ if (ufd->events & POLLOUT)
{
+ FD_SET(ufd->fd, &writefd);
+ }
- writefd.fd_array[i]=ufdsTmp->fd;
- writefd.fd_count++;
+ if (ufd->events & ~(POLLIN | POLLOUT))
+ {
+ printf("Unsupported poll bits %d",
+ ufd->events);
+ return -1;
}
}
- int noffds = select(0, &readfd, &writefd, 0, tmpptr);
+ int nready = select(0, &readfd, &writefd, 0, tmpptr);
- if (noffds == SOCKET_ERROR)
+ if (nready == SOCKET_ERROR)
{
// int errval = WSAGetLastError();
- ufdsTmp = ufds;
+ struct pollfd* pufd = ufds;
for (unsigned long i = 0; i < nfds; i++)
{
- ufdsTmp->revents = POLLERR;
- ufdsTmp++;
+ pufd->revents = POLLERR;
+ pufd++;
}
return (-1);
}
+ else if (nready > 0)
+ {
+ for (unsigned long i = 0; i < nfds; i++)
+ {
+ struct pollfd *ufd = &(ufds[i]);
- return noffds;
+ if (FD_ISSET(ufd->fd, &readfd))
+ {
+ ufd->revents |= POLLIN;
+ }
+
+ if (FD_ISSET(ufd->fd, &writefd))
+ {
+ ufd->revents |= POLLOUT;
+ }
+ }
+ }
+
+ return nready;
}
catch (...)
{
@@ -1040,9 +1325,151 @@ int poll (struct pollfd *ufds, unsigned long nfds, int timeout)
return -1;
}
-HANDLE gSyslogH = 0;
+// copied from MSDN: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/eventlog/base/adding_a_source_to_the_registry.asp
+
+BOOL AddEventSource
+(
+ LPTSTR pszSrcName, // event source name
+ DWORD dwNum // number of categories
+)
+{
+ // Work out the executable file name, to register ourselves
+ // as the event source
+
+ WCHAR cmd[MAX_PATH];
+ DWORD len = GetModuleFileNameW(NULL, cmd, MAX_PATH);
+
+ if (len == 0)
+ {
+ ::syslog(LOG_ERR, "Failed to get the program file name: %s",
+ GetErrorMessage(GetLastError()).c_str());
+ return FALSE;
+ }
+
+ // Create the event source as a subkey of the log.
+
+ std::string regkey("SYSTEM\\CurrentControlSet\\Services\\EventLog\\"
+ "Application\\");
+ regkey += pszSrcName;
+
+ HKEY hk;
+ DWORD dwDisp;
+
+ if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, regkey.c_str(),
+ 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_WRITE, NULL, &hk, &dwDisp))
+ {
+ ::syslog(LOG_ERR, "Failed to create the registry key: %s",
+ GetErrorMessage(GetLastError()).c_str());
+ return FALSE;
+ }
+
+ // Set the name of the message file.
+
+ if (RegSetValueExW(hk, // subkey handle
+ L"EventMessageFile", // value name
+ 0, // must be zero
+ REG_EXPAND_SZ, // value type
+ (LPBYTE)cmd, // pointer to value data
+ len*sizeof(WCHAR))) // data size
+ {
+ ::syslog(LOG_ERR, "Failed to set the event message file: %s",
+ GetErrorMessage(GetLastError()).c_str());
+ RegCloseKey(hk);
+ return FALSE;
+ }
+
+ // Set the supported event types.
+
+ DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
+ EVENTLOG_INFORMATION_TYPE;
+
+ if (RegSetValueEx(hk, // subkey handle
+ "TypesSupported", // value name
+ 0, // must be zero
+ REG_DWORD, // value type
+ (LPBYTE) &dwData, // pointer to value data
+ sizeof(DWORD))) // length of value data
+ {
+ ::syslog(LOG_ERR, "Failed to set the supported types: %s",
+ GetErrorMessage(GetLastError()).c_str());
+ RegCloseKey(hk);
+ return FALSE;
+ }
+
+ // Set the category message file and number of categories.
+
+ if (RegSetValueExW(hk, // subkey handle
+ L"CategoryMessageFile", // value name
+ 0, // must be zero
+ REG_EXPAND_SZ, // value type
+ (LPBYTE)cmd, // pointer to value data
+ len*sizeof(WCHAR))) // data size
+ {
+ ::syslog(LOG_ERR, "Failed to set the category message file: "
+ "%s", GetErrorMessage(GetLastError()).c_str());
+ RegCloseKey(hk);
+ return FALSE;
+ }
+
+ if (RegSetValueEx(hk, // subkey handle
+ "CategoryCount", // value name
+ 0, // must be zero
+ REG_DWORD, // value type
+ (LPBYTE) &dwNum, // pointer to value data
+ sizeof(DWORD))) // length of value data
+ {
+ ::syslog(LOG_ERR, "Failed to set the category count: %s",
+ GetErrorMessage(GetLastError()).c_str());
+ RegCloseKey(hk);
+ return FALSE;
+ }
+
+ RegCloseKey(hk);
+ return TRUE;
+}
+
+static HANDLE gSyslogH = 0;
static bool sHaveWarnedEventLogFull = false;
+void openlog(const char * daemonName, int, int)
+{
+ // register a default event source, so that we can
+ // log errors with the process of adding or registering our own.
+ gSyslogH = RegisterEventSource(
+ NULL, // uses local computer
+ daemonName); // source name
+ if (gSyslogH == NULL)
+ {
+ }
+
+ char* name = strdup(daemonName);
+ BOOL success = AddEventSource(name, 0);
+ free(name);
+
+ if (!success)
+ {
+ ::syslog(LOG_ERR, "Failed to add our own event source");
+ return;
+ }
+
+ HANDLE newSyslogH = RegisterEventSource(NULL, daemonName);
+ if (newSyslogH == NULL)
+ {
+ ::syslog(LOG_ERR, "Failed to register our own event source: "
+ "%s", GetErrorMessage(GetLastError()).c_str());
+ return;
+ }
+
+ DeregisterEventSource(gSyslogH);
+ gSyslogH = newSyslogH;
+}
+
+void closelog(void)
+{
+ DeregisterEventSource(gSyslogH);
+}
+
void syslog(int loglevel, const char *frmt, ...)
{
WORD errinfo;
@@ -1082,17 +1509,32 @@ void syslog(int loglevel, const char *frmt, ...)
va_start(args, frmt);
int len = vsnprintf(buffer, sizeof(buffer)-1, sixfour.c_str(), args);
- ASSERT(len < sizeof(buffer))
+ assert(len >= 0);
+ if (len < 0)
+ {
+ printf("%s\r\n", buffer);
+ fflush(stdout);
+ return;
+ }
+
+ assert((size_t)len < sizeof(buffer));
buffer[sizeof(buffer)-1] = 0;
va_end(args);
LPCSTR strings[] = { buffer, NULL };
+ if (gSyslogH == 0)
+ {
+ printf("%s\r\n", buffer);
+ fflush(stdout);
+ return;
+ }
+
if (!ReportEvent(gSyslogH, // event log handle
errinfo, // event type
0, // category zero
- MSG_ERR_EXIST, // event identifier -
+ MSG_ERR, // event identifier -
// we will call them all the same
NULL, // no user security identifier
1, // one substitution string
@@ -1108,13 +1550,15 @@ void syslog(int loglevel, const char *frmt, ...)
{
printf("Unable to send message to Event Log "
"(Event Log is full):\r\n");
+ fflush(stdout);
sHaveWarnedEventLogFull = TRUE;
}
}
else
{
- printf("Unable to send message to Event Log: "
- "error %i:\r\n", (int)err);
+ printf("Unable to send message to Event Log: %s:\r\n",
+ GetErrorMessage(err).c_str());
+ fflush(stdout);
}
}
else
@@ -1122,17 +1566,36 @@ void syslog(int loglevel, const char *frmt, ...)
sHaveWarnedEventLogFull = false;
}
- printf("%s\r\n", buffer);
+ // printf("%s\r\n", buffer);
+ // fflush(stdout);
}
int emu_chdir(const char* pDirName)
{
+ /*
+ std::string AbsPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(pDirName);
+
+ if (AbsPathWithUnicode.size() == 0)
+ {
+ // error already logged by ConvertPathToAbsoluteUnicode()
+ return -1;
+ }
+
+ WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
+ */
+
WCHAR* pBuffer = ConvertUtf8ToWideString(pDirName);
if (!pBuffer) return -1;
+
int result = SetCurrentDirectoryW(pBuffer);
delete [] pBuffer;
+
if (result != 0) return 0;
+
errno = EACCES;
+ fprintf(stderr, "Failed to change directory to '%s': %s\n",
+ pDirName, GetErrorMessage(GetLastError()).c_str());
return -1;
}
@@ -1145,7 +1608,7 @@ char* emu_getcwd(char* pBuffer, int BufSize)
return NULL;
}
- if (len > BufSize)
+ if ((int)len > BufSize)
{
errno = ENAMETOOLONG;
return NULL;
@@ -1162,6 +1625,7 @@ char* emu_getcwd(char* pBuffer, int BufSize)
if (result <= 0 || result >= len)
{
errno = EACCES;
+ delete [] pWide;
return NULL;
}
@@ -1182,7 +1646,16 @@ char* emu_getcwd(char* pBuffer, int BufSize)
int emu_mkdir(const char* pPathName)
{
- WCHAR* pBuffer = ConvertToWideString(pPathName, CP_UTF8);
+ std::string AbsPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(pPathName);
+
+ if (AbsPathWithUnicode.size() == 0)
+ {
+ // error already logged by ConvertPathToAbsoluteUnicode()
+ return -1;
+ }
+
+ WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
if (!pBuffer)
{
return -1;
@@ -1202,18 +1675,112 @@ int emu_mkdir(const char* pPathName)
int emu_unlink(const char* pFileName)
{
- WCHAR* pBuffer = ConvertToWideString(pFileName, CP_UTF8);
+ std::string AbsPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(pFileName);
+
+ if (AbsPathWithUnicode.size() == 0)
+ {
+ // error already logged by ConvertPathToAbsoluteUnicode()
+ return -1;
+ }
+
+ WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
if (!pBuffer)
{
return -1;
}
BOOL result = DeleteFileW(pBuffer);
+ DWORD err = GetLastError();
delete [] pBuffer;
if (!result)
{
- errno = EACCES;
+ if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
+ {
+ errno = ENOENT;
+ }
+ else if (err == ERROR_SHARING_VIOLATION)
+ {
+ errno = EBUSY;
+ }
+ else if (err == ERROR_ACCESS_DENIED)
+ {
+ errno = EACCES;
+ }
+ else
+ {
+ ::syslog(LOG_WARNING, "Failed to delete file "
+ "'%s': %s", pFileName,
+ GetErrorMessage(err).c_str());
+ errno = ENOSYS;
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+int emu_rename(const char* pOldFileName, const char* pNewFileName)
+{
+ std::string OldPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(pOldFileName);
+
+ if (OldPathWithUnicode.size() == 0)
+ {
+ // error already logged by ConvertPathToAbsoluteUnicode()
+ return -1;
+ }
+
+ WCHAR* pOldBuffer = ConvertUtf8ToWideString(OldPathWithUnicode.c_str());
+ if (!pOldBuffer)
+ {
+ return -1;
+ }
+
+ std::string NewPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(pNewFileName);
+
+ if (NewPathWithUnicode.size() == 0)
+ {
+ // error already logged by ConvertPathToAbsoluteUnicode()
+ delete [] pOldBuffer;
+ return -1;
+ }
+
+ WCHAR* pNewBuffer = ConvertUtf8ToWideString(NewPathWithUnicode.c_str());
+ if (!pNewBuffer)
+ {
+ delete [] pOldBuffer;
+ return -1;
+ }
+
+ BOOL result = MoveFileW(pOldBuffer, pNewBuffer);
+ DWORD err = GetLastError();
+ delete [] pOldBuffer;
+ delete [] pNewBuffer;
+
+ if (!result)
+ {
+ if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
+ {
+ errno = ENOENT;
+ }
+ else if (err == ERROR_SHARING_VIOLATION)
+ {
+ errno = EBUSY;
+ }
+ else if (err == ERROR_ACCESS_DENIED)
+ {
+ errno = EACCES;
+ }
+ else
+ {
+ ::syslog(LOG_WARNING, "Failed to rename file "
+ "'%s' to '%s': %s", pOldFileName, pNewFileName,
+ GetErrorMessage(err).c_str());
+ errno = ENOSYS;
+ }
return -1;
}
@@ -1227,12 +1794,12 @@ int console_read(char* pBuffer, size_t BufferSize)
if (hConsole == INVALID_HANDLE_VALUE)
{
::fprintf(stderr, "Failed to get a handle on standard input: "
- "error %d\n", GetLastError());
+ "%s", GetErrorMessage(GetLastError()).c_str());
return -1;
}
- int WideSize = BufferSize / 5;
- WCHAR* pWideBuffer = new WCHAR [WideSize];
+ size_t WideSize = BufferSize / 5;
+ WCHAR* pWideBuffer = new WCHAR [WideSize + 1];
if (!pWideBuffer)
{
@@ -1245,23 +1812,117 @@ int console_read(char* pBuffer, size_t BufferSize)
if (!ReadConsoleW(
hConsole,
pWideBuffer,
- WideSize - 1,
+ WideSize, // will not be null terminated by ReadConsole
&numCharsRead,
NULL // reserved
))
{
- ::fprintf(stderr, "Failed to read from console: error %d\n",
- GetLastError());
+ ::fprintf(stderr, "Failed to read from console: %s\n",
+ GetErrorMessage(GetLastError()).c_str());
return -1;
}
pWideBuffer[numCharsRead] = 0;
char* pUtf8 = ConvertFromWideString(pWideBuffer, GetConsoleCP());
+ delete [] pWideBuffer;
+
strncpy(pBuffer, pUtf8, BufferSize);
delete [] pUtf8;
return strlen(pBuffer);
}
+int readv (int filedes, const struct iovec *vector, size_t count)
+{
+ int bytes = 0;
+
+ for (size_t i = 0; i < count; i++)
+ {
+ int result = read(filedes, vector[i].iov_base,
+ vector[i].iov_len);
+ if (result < 0)
+ {
+ return result;
+ }
+ bytes += result;
+ }
+
+ return bytes;
+}
+
+int writev(int filedes, const struct iovec *vector, size_t count)
+{
+ int bytes = 0;
+
+ for (size_t i = 0; i < count; i++)
+ {
+ int result = write(filedes, vector[i].iov_base,
+ vector[i].iov_len);
+ if (result < 0)
+ {
+ return result;
+ }
+ bytes += result;
+ }
+
+ return bytes;
+}
+
+// need this for conversions
+time_t ConvertFileTimeToTime_t(FILETIME *fileTime)
+{
+ SYSTEMTIME stUTC;
+ struct tm timeinfo;
+
+ // Convert the last-write time to local time.
+ FileTimeToSystemTime(fileTime, &stUTC);
+
+ memset(&timeinfo, 0, sizeof(timeinfo));
+ timeinfo.tm_sec = stUTC.wSecond;
+ timeinfo.tm_min = stUTC.wMinute;
+ timeinfo.tm_hour = stUTC.wHour;
+ timeinfo.tm_mday = stUTC.wDay;
+ timeinfo.tm_wday = stUTC.wDayOfWeek;
+ timeinfo.tm_mon = stUTC.wMonth - 1;
+ // timeinfo.tm_yday = ...;
+ timeinfo.tm_year = stUTC.wYear - 1900;
+
+ time_t retVal = mktime(&timeinfo) - _timezone;
+ return retVal;
+}
+
+bool ConvertTime_tToFileTime(const time_t from, FILETIME *pTo)
+{
+ time_t adjusted = from + _timezone;
+ struct tm *time_breakdown = gmtime(&adjusted);
+ if (time_breakdown == NULL)
+ {
+ ::syslog(LOG_ERR, "Error: failed to convert time format: "
+ "%d is not a valid time\n", from);
+ return false;
+ }
+
+ SYSTEMTIME stUTC;
+ stUTC.wSecond = time_breakdown->tm_sec;
+ stUTC.wMinute = time_breakdown->tm_min;
+ stUTC.wHour = time_breakdown->tm_hour;
+ stUTC.wDay = time_breakdown->tm_mday;
+ stUTC.wDayOfWeek = time_breakdown->tm_wday;
+ stUTC.wMonth = time_breakdown->tm_mon + 1;
+ stUTC.wYear = time_breakdown->tm_year + 1900;
+ stUTC.wMilliseconds = 0;
+
+ // Convert the last-write time to local time.
+ if (!SystemTimeToFileTime(&stUTC, pTo))
+ {
+ syslog(LOG_ERR, "Failed to convert between time formats: %s",
+ GetErrorMessage(GetLastError()).c_str());
+ return false;
+ }
+
+ return true;
+}
+
#endif // WIN32
+
diff --git a/lib/win32/emu.h b/lib/win32/emu.h
index 7e7700f4..e67eeae9 100644
--- a/lib/win32/emu.h
+++ b/lib/win32/emu.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.
@@ -41,7 +41,47 @@
#if ! defined EMU_INCLUDE && defined WIN32
#define EMU_INCLUDE
-#define _INO_T_DEFINED
+// basic types, may be required by other headers since we
+// don't include sys/types.h
+
+#ifdef __MINGW32__
+ #include <stdint.h>
+#else // MSVC
+ typedef unsigned __int64 u_int64_t;
+ typedef unsigned __int64 uint64_t;
+ typedef __int64 int64_t;
+ typedef unsigned __int32 uint32_t;
+ typedef unsigned __int32 u_int32_t;
+ typedef __int32 int32_t;
+ typedef unsigned __int16 uint16_t;
+ typedef __int16 int16_t;
+ typedef unsigned __int8 uint8_t;
+ typedef __int8 int8_t;
+#endif
+
+// emulated types, present on MinGW but not MSVC or vice versa
+
+#ifdef __MINGW32__
+ typedef uint32_t u_int32_t;
+#else
+ typedef unsigned int mode_t;
+ typedef unsigned int pid_t;
+
+ // must define _INO_T_DEFINED before including <sys/types.h>
+ // to replace it with our own.
+ typedef u_int64_t _ino_t;
+ #define _INO_T_DEFINED
+#endif
+
+// set up to include the necessary parts of Windows headers
+
+#define WIN32_LEAN_AND_MEAN
+
+#ifndef __MSVCRT_VERSION__
+#define __MSVCRT_VERSION__ 0x0601
+#endif
+
+// Windows headers
#include <winsock2.h>
#include <fcntl.h>
@@ -57,11 +97,13 @@
#include <string>
+// emulated functions
+
#define gmtime_r( _clock, _result ) \
( *(_result) = *gmtime( (_clock) ), \
(_result) )
-#define ITIMER_VIRTUAL 0
+#define ITIMER_REAL 0
#ifdef _MSC_VER
// Microsoft decided to deprecate the standard POSIX functions. Great!
@@ -79,17 +121,11 @@ int setitimer(int type, struct itimerval *timeout, void *arg);
void InitTimer(void);
void FiniTimer(void);
-inline int geteuid(void)
-{
- //lets pretend to be root!
- return 0;
-}
-
struct passwd {
char *pw_name;
char *pw_passwd;
- uid_t pw_uid;
- gid_t pw_gid;
+ int pw_uid;
+ int pw_gid;
time_t pw_change;
char *pw_class;
char *pw_gecos;
@@ -127,14 +163,6 @@ inline struct passwd * getpwnam(const char * name)
#define S_ISDIR(x) (S_IFDIR & x)
#endif
-inline int utimes(const char * Filename, timeval[])
-{
- //again I am guessing this is quite important to
- //be functioning, as large restores would be a problem
-
- //indicate success
- return 0;
-}
inline int chown(const char * Filename, u_int32_t uid, u_int32_t gid)
{
//important - this needs implementing
@@ -151,46 +179,9 @@ inline int chown(const char * Filename, u_int32_t uid, u_int32_t gid)
return 0;
}
-int emu_chdir (const char* pDirName);
-int emu_unlink(const char* pFileName);
-char* emu_getcwd(char* pBuffer, int BufSize);
-
-#ifdef _MSC_VER
- inline int emu_chmod(const char * Filename, int mode)
- {
- // indicate success
- return 0;
- }
-
- #define chmod(file, mode) emu_chmod(file, mode)
- #define chdir(directory) emu_chdir(directory)
- #define unlink(file) emu_unlink(file)
- #define getcwd(buffer, size) emu_getcwd(buffer, size)
-#else
- inline int chmod(const char * Filename, int mode)
- {
- // indicate success
- return 0;
- }
-
- inline int chdir(const char* pDirName)
- {
- return emu_chdir(pDirName);
- }
-
- inline char* getcwd(char* pBuffer, int BufSize)
- {
- return emu_getcwd(pBuffer, BufSize);
- }
-
- inline int unlink(const char* pFileName)
- {
- return emu_unlink(pFileName);
- }
-#endif
-
-//I do not perceive a need to change the user or group on a backup client
-//at any rate the owner of a service can be set in the service settings
+// Windows and Unix owners and groups are pretty fundamentally different.
+// Ben prefers that we kludge here rather than litter the code with #ifdefs.
+// Pretend to be root, and pretend that set...() operations succeed.
inline int setegid(int)
{
return true;
@@ -215,6 +206,10 @@ inline int getuid(void)
{
return 0;
}
+inline int geteuid(void)
+{
+ return 0;
+}
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
@@ -222,59 +217,7 @@ inline int getuid(void)
// MinGW provides a getopt implementation
#ifndef __MINGW32__
-
-// this will need to be implemented if we see fit that command line
-// options are going to be used! (probably then:)
-// where the calling function looks for the parsed parameter
-extern char *optarg;
-
-// optind looks like an index into the string - how far we have moved along
-extern int optind;
-extern char nextchar;
-
-inline int getopt(int count, char * const * args, const char * tolookfor)
-{
- if (optind >= count) return -1;
-
- std::string str((const char *)args[optind]);
- std::string interestin(tolookfor);
- int opttolookfor = 0;
- int index = -1;
- // just initialize the string - just in case it is used.
- // optarg[0] = 0;
- std::string opt;
-
- if (count == 0) return -1;
-
- do
- {
- if (index != -1)
- {
- str = str.substr(index+1, str.size());
- }
-
- index = (int)str.find('-');
-
- if (index == -1) return -1;
-
- opt = str[1];
-
- optind ++;
- str = args[optind];
- }
- while ((opttolookfor = (int)interestin.find(opt)) == -1);
-
- if (interestin[opttolookfor+1] == ':')
- {
-
- // strcpy(optarg, str.c_str());
- optarg = args[optind];
- optind ++;
- }
-
- // indicate we have finished
- return opt[0];
-}
+#include "getopt.h"
#endif // !__MINGW32__
#define timespec timeval
@@ -290,25 +233,9 @@ struct itimerval
#define tv_nsec tv_usec
#ifndef __MINGW32__
- typedef unsigned __int64 u_int64_t;
- typedef unsigned __int64 uint64_t;
- typedef __int64 int64_t;
- typedef unsigned __int32 uint32_t;
- typedef unsigned __int32 u_int32_t;
- typedef __int32 int32_t;
- typedef unsigned __int16 uint16_t;
- typedef __int16 int16_t;
- typedef unsigned __int8 uint8_t;
- typedef __int8 int8_t;
-
typedef int socklen_t;
#endif
-// I (re-)defined here for the moment; has to be removed later !!!
-#ifndef BOX_VERSION
-#define BOX_VERSION "0.09hWin32"
-#endif
-
#define S_IRGRP S_IWRITE
#define S_IWGRP S_IREAD
#define S_IROTH S_IWRITE | S_IREAD
@@ -322,26 +249,20 @@ struct itimerval
#define vsnprintf _vsnprintf
#ifndef __MINGW32__
-typedef unsigned int mode_t;
-#endif
-
-int emu_mkdir(const char* pPathName);
-
-inline int mkdir(const char *pPathName, mode_t mode)
-{
- return emu_mkdir(pPathName);
-}
-
-#ifndef __MINGW32__
inline int strcasecmp(const char *s1, const char *s2)
{
return _stricmp(s1,s2);
}
#endif
+#ifdef _DIRENT_H_
+#error You must not include the MinGW dirent.h!
+#endif
+
struct dirent
{
char *d_name;
+ unsigned long d_type;
};
struct DIR
@@ -358,32 +279,24 @@ DIR *opendir(const char *name);
struct dirent *readdir(DIR *dp);
int closedir(DIR *dp);
+// local constant to open file exclusively without shared access
+#define O_LOCK 0x10000
+
HANDLE openfile(const char *filename, int flags, int mode);
+#define LOG_DEBUG LOG_INFO
#define LOG_INFO 6
+#define LOG_NOTICE LOG_INFO
#define LOG_WARNING 4
#define LOG_ERR 3
+#define LOG_CRIT LOG_ERR
#define LOG_PID 0
+#define LOG_LOCAL5 0
#define LOG_LOCAL6 0
-extern HANDLE gSyslogH;
-void MyReportEvent(LPCTSTR *szMsg, DWORD errinfo);
-inline void openlog(const char * daemonName, int, int)
-{
- gSyslogH = RegisterEventSource(
- NULL, // uses local computer
- daemonName); // source name
- if (gSyslogH == NULL)
- {
- }
-}
-
-inline void closelog(void)
-{
- DeregisterEventSource(gSyslogH);
-}
-
-void syslog(int loglevel, const char *fmt, ...);
+void openlog (const char * daemonName, int, int);
+void closelog(void);
+void syslog (int loglevel, const char *fmt, ...);
#ifndef __MINGW32__
#define strtoll _strtoi64
@@ -448,73 +361,82 @@ struct stat {
time_t st_mtime;
time_t st_ctime;
};
+#endif // 0
+
+// need this for conversions
+time_t ConvertFileTimeToTime_t(FILETIME *fileTime);
+bool ConvertTime_tToFileTime(const time_t from, FILETIME *pTo);
+
+int emu_chdir (const char* pDirName);
+int emu_mkdir (const char* pPathName);
+int emu_unlink (const char* pFileName);
+int emu_fstat (HANDLE file, struct stat* st);
+int emu_stat (const char* pName, struct stat* st);
+int emu_utimes (const char* pName, const struct timeval[]);
+int emu_chmod (const char* pName, mode_t mode);
+char* emu_getcwd (char* pBuffer, int BufSize);
+int emu_rename (const char* pOldName, const char* pNewName);
+
+#define chdir(directory) emu_chdir (directory)
+#define mkdir(path, mode) emu_mkdir (path)
+#define unlink(file) emu_unlink (file)
+#define stat(filename, struct) emu_stat (filename, struct)
+#define lstat(filename, struct) emu_stat (filename, struct)
+#define fstat(handle, struct) emu_fstat (handle, struct)
+#define utimes(buffer, times) emu_utimes (buffer, times)
+#define chmod(file, mode) emu_chmod (file, mode)
+#define getcwd(buffer, size) emu_getcwd (buffer, size)
+#define rename(oldname, newname) emu_rename (oldname, newname)
-#ifndef __MINGW32__
-typedef u_int64_t _ino_t;
-#endif
-#endif
-
-int emu_stat(const char * name, struct stat * st);
-int emu_fstat(HANDLE file, struct stat * st);
int statfs(const char * name, struct statfs * s);
-//need this for converstions
-inline time_t ConvertFileTimeToTime_t(FILETIME *fileTime)
-{
- SYSTEMTIME stUTC;
- struct tm timeinfo;
-
- // Convert the last-write time to local time.
- FileTimeToSystemTime(fileTime, &stUTC);
- // SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
-
- memset(&timeinfo, 0, sizeof(timeinfo));
- timeinfo.tm_sec = stUTC.wSecond;
- timeinfo.tm_min = stUTC.wMinute;
- timeinfo.tm_hour = stUTC.wHour;
- timeinfo.tm_mday = stUTC.wDay;
- timeinfo.tm_wday = stUTC.wDayOfWeek;
- timeinfo.tm_mon = stUTC.wMonth - 1;
- // timeinfo.tm_yday = ...;
- timeinfo.tm_year = stUTC.wYear - 1900;
-
- time_t retVal = mktime(&timeinfo) - _timezone;
- return retVal;
-}
+int poll(struct pollfd *ufds, unsigned long nfds, int timeout);
-#ifdef _MSC_VER
- #define stat(filename, struct) emu_stat (filename, struct)
- #define lstat(filename, struct) emu_stat (filename, struct)
- #define fstat(handle, struct) emu_fstat(handle, struct)
-#else
- inline int stat(const char* filename, struct stat* stat)
- {
- return emu_stat(filename, stat);
- }
- inline int lstat(const char* filename, struct stat* stat)
- {
- return emu_stat(filename, stat);
- }
- inline int fstat(HANDLE handle, struct stat* stat)
- {
- return emu_fstat(handle, stat);
- }
-#endif
+struct iovec {
+ void *iov_base; /* Starting address */
+ size_t iov_len; /* Number of bytes */
+};
+
+int readv (int filedes, const struct iovec *vector, size_t count);
+int writev(int filedes, const struct iovec *vector, size_t count);
+
+// The following functions are not emulations, but utilities for other
+// parts of the code where Windows API is used or windows-specific stuff
+// is needed, like codepage conversion.
-int poll(struct pollfd *ufds, unsigned long nfds, int timeout);
bool EnableBackupRights( void );
+bool ConvertEncoding (const std::string& rSource, int sourceCodePage,
+ std::string& rDest, int destCodePage);
+bool ConvertToUtf8 (const std::string& rSource, std::string& rDest,
+ int sourceCodePage);
+bool ConvertFromUtf8 (const std::string& rSource, std::string& rDest,
+ int destCodePage);
bool ConvertUtf8ToConsole(const char* pString, std::string& rDest);
bool ConvertConsoleToUtf8(const char* pString, std::string& rDest);
-//
-// MessageId: MSG_ERR_EXIST
-// MessageText:
-// Box Backup.
-//
-#define MSG_ERR_EXIST ((DWORD)0xC0000004L)
+// Utility function which returns a default config file name,
+// based on the path of the current executable.
+std::string GetDefaultConfigFilePath(const std::string& rName);
+
+// GetErrorMessage() returns a system error message, like strerror()
+// but for Windows error codes.
+std::string GetErrorMessage(DWORD errorCode);
-// replacement for _cgetws which requires a relatively recent C runtime lib
+// console_read() is a replacement for _cgetws which requires a
+// relatively recent C runtime lib
int console_read(char* pBuffer, size_t BufferSize);
+#ifdef _MSC_VER
+ /* disable certain compiler warnings to be able to actually see the show-stopper ones */
+ #pragma warning(disable:4101) // unreferenced local variable
+ #pragma warning(disable:4244) // conversion, possible loss of data
+ #pragma warning(disable:4267) // conversion, possible loss of data
+ #pragma warning(disable:4311) // pointer truncation
+ #pragma warning(disable:4700) // uninitialized local variable used (hmmmmm...)
+ #pragma warning(disable:4805) // unsafe mix of type and type 'bool' in operation
+ #pragma warning(disable:4800) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning(disable:4996) // POSIX name for this item is deprecated
+#endif // _MSC_VER
+
#endif // !EMU_INCLUDE && WIN32
diff --git a/lib/win32/getopt.h b/lib/win32/getopt.h
new file mode 100755
index 00000000..0d133477
--- /dev/null
+++ b/lib/win32/getopt.h
@@ -0,0 +1,136 @@
+// 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.
+//
+//
+//
+/* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */
+/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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 advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+// copied from: http://www.la.utexas.edu/lab/software/devtool/gnu/libtool/C_header_files.html
+
+/* __BEGIN_DECLS should be used at the beginning of your declarations,
+ so that C++ compilers don't mangle their names. Use __END_DECLS at
+ the end of C declarations. */
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS /* empty */
+# define __END_DECLS /* empty */
+#endif
+
+/*
+ * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions
+ */
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+struct option {
+ /* name of long option */
+ const char *name;
+ /*
+ * one of no_argument, required_argument, and optional_argument:
+ * whether option takes an argument
+ */
+ int has_arg;
+ /* if not NULL, set *flag to val when option found */
+ int *flag;
+ /* if flag not NULL, value to set *flag to; else return value */
+ int val;
+};
+
+__BEGIN_DECLS
+int getopt_long(int, char * const *, const char *,
+ const struct option *, int *);
+int getopt_long_only(int, char * const *, const char *,
+ const struct option *, int *);
+#ifndef _GETOPT_DEFINED_
+#define _GETOPT_DEFINED_
+int getopt(int, char * const *, const char *);
+int getsubopt(char **, char * const *, char **);
+
+extern char *optarg; /* getopt(3) external variables */
+extern int opterr;
+extern int optind;
+extern int optopt;
+extern int optreset;
+extern char *suboptarg; /* getsubopt(3) external variable */
+#endif
+__END_DECLS
+
+#endif /* !_GETOPT_H_ */
diff --git a/lib/win32/getopt_long.cxx b/lib/win32/getopt_long.cxx
new file mode 100755
index 00000000..a24930aa
--- /dev/null
+++ b/lib/win32/getopt_long.cxx
@@ -0,0 +1,550 @@
+/* $OpenBSD: getopt_long.c,v 1.20 2005/10/25 15:49:37 jmc Exp $ */
+/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
+// Adapted for Box Backup by Chris Wilson <chris+boxbackup@qwirx.com>
+
+/*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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 advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+// #include "Box.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "getopt.h"
+
+#if defined _MSC_VER || defined __MINGW32__
+#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
+#endif
+
+#ifdef REPLACE_GETOPT
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+#endif
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+static void warnx(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+ char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **) nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * parse_long_options --
+ * Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int short_too)
+{
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, match;
+
+ current_argv = place;
+ match = -1;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* partial match */
+ match = i;
+ else {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return (BADARG);
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ } else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ } else
+ return (long_options[match].val);
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx, int flags)
+{
+ const char * oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ */
+ if (posixly_correct == -1)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ else if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+ if (*place == '-')
+ place++; /* --foo long option */
+ else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ optchar == (int)'-' && *place != '\0' ||
+ (oli = strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else /* white space */
+ place = nargv[optind];
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = place;
+ /* XXX: disable test for :: if PC? (GNU doesn't) */
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ } else
+ optarg = nargv[optind];
+ } else if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If permutation is disabled, we can accept an
+ * optional arg separated by whitespace so long
+ * as it does not start with a dash (-).
+ */
+ if (optind + 1 < nargc && *nargv[optind + 1] != '-')
+ optarg = nargv[++optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+ const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE|FLAG_LONGONLY));
+}
+
diff --git a/lib/win32/messages.h b/lib/win32/messages.h
new file mode 100755
index 00000000..3a0b032b
--- /dev/null
+++ b/lib/win32/messages.h
@@ -0,0 +1,95 @@
+// 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.
+//
+//
+//
+ // Message source file, to be compiled to a resource file with
+ // Microsoft Message Compiler (MC), to an object file with a Resource
+ // Compiler, and linked into the application.
+
+ // The main reason for this file is to work around Windows' stupid
+ // messages in the Event Log, which say:
+
+ // The description for Event ID ( 4 ) in Source ( Box Backup (bbackupd) )
+ // cannot be found. The local computer may not have the necessary
+ // registry information or message DLL files to display messages from a
+ // remote computer. The following information is part of the event:
+ // Message definitions follow
+//
+// Values are 32 bit values layed out as follows:
+//
+// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +---+-+-+-----------------------+-------------------------------+
+// |Sev|C|R| Facility | Code |
+// +---+-+-+-----------------------+-------------------------------+
+//
+// where
+//
+// Sev - is the severity code
+//
+// 00 - Success
+// 01 - Informational
+// 10 - Warning
+// 11 - Error
+//
+// C - is the Customer code flag
+//
+// R - is a reserved bit
+//
+// Facility - is the facility code
+//
+// Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+
+
+//
+// Define the severity codes
+//
+
+
+//
+// MessageId: MSG_ERR
+//
+// MessageText:
+//
+// %1
+//
+#define MSG_ERR ((DWORD)0x40000001L)
+
diff --git a/lib/win32/messages.mc b/lib/win32/messages.mc
new file mode 100644
index 00000000..75f17b0f
--- /dev/null
+++ b/lib/win32/messages.mc
@@ -0,0 +1,22 @@
+; // Message source file, to be compiled to a resource file with
+; // Microsoft Message Compiler (MC), to an object file with a Resource
+; // Compiler, and linked into the application.
+;
+; // The main reason for this file is to work around Windows' stupid
+; // messages in the Event Log, which say:
+;
+; // The description for Event ID ( 4 ) in Source ( Box Backup (bbackupd) )
+; // cannot be found. The local computer may not have the necessary
+; // registry information or message DLL files to display messages from a
+; // remote computer. The following information is part of the event:
+
+MessageIdTypedef = DWORD
+
+; // Message definitions follow
+
+MessageId = 0x1
+Severity = Informational
+SymbolicName = MSG_ERR
+Language = English
+%1
+.
diff --git a/lib/win32/messages.rc b/lib/win32/messages.rc
new file mode 100755
index 00000000..116522b7
--- /dev/null
+++ b/lib/win32/messages.rc
@@ -0,0 +1,2 @@
+LANGUAGE 0x9,0x1
+1 11 MSG00001.bin
diff --git a/modules.txt b/modules.txt
index ab2171f4..e08c6c6a 100644
--- a/modules.txt
+++ b/modules.txt
@@ -9,49 +9,35 @@
# Generic support code and modules
-OMIT:mingw32
-OMIT:CYGWIN
lib/raidfile
-END-OMIT
-
lib/crypto
lib/server
-lib/win32 lib/server
lib/compress
-test/common lib/win32
-test/crypto lib/crypto lib/win32
-test/compress lib/compress lib/win32
+lib/intercept
-OMIT:mingw32
-test/basicserver lib/server lib/win32
-OMIT:CYGWIN
-test/raidfile lib/raidfile
-END-OMIT
+test/common
+test/crypto lib/crypto
+test/compress lib/compress
+test/raidfile lib/raidfile lib/intercept
+test/basicserver lib/server
# Backup system
lib/backupclient lib/server lib/crypto lib/compress
-
-OMIT:mingw32
-OMIT:CYGWIN
lib/backupstore lib/server lib/raidfile lib/backupclient
-bin/bbstored lib/raidfile lib/server lib/backupstore lib/backupclient lib/win32
-bin/bbstoreaccounts lib/raidfile lib/backupstore lib/win32
-bin/bbackupobjdump lib/backupclient lib/backupstore lib/win32
-END-OMIT
-bin/bbackupd lib/server lib/backupclient lib/win32
-bin/bbackupquery lib/server lib/backupclient lib/win32
-bin/bbackupctl lib/server lib/backupclient lib/win32
+bin/bbackupobjdump lib/backupclient lib/backupstore
+bin/bbstored lib/raidfile lib/server lib/backupstore lib/backupclient
+bin/bbstoreaccounts lib/raidfile lib/backupstore
+bin/bbackupd lib/server lib/backupclient
+bin/bbackupquery lib/server lib/backupclient
+bin/bbackupctl lib/server lib/backupclient
-OMIT:mingw32
-OMIT:CYGWIN
test/backupstore bin/bbstored bin/bbstoreaccounts lib/server lib/backupstore lib/backupclient lib/raidfile
-test/backupstorefix bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile bin/bbackupquery bin/bbackupd
+test/backupstorefix bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile bin/bbackupquery bin/bbackupd bin/bbackupctl
test/backupstorepatch bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile
test/backupdiff lib/backupclient
-test/bbackupd bin/bbackupd bin/bbstored bin/bbstoreaccounts bin/bbackupquery bin/bbackupctl lib/server lib/backupstore lib/backupclient
-END-OMIT
+test/bbackupd bin/bbackupd bin/bbstored bin/bbstoreaccounts bin/bbackupquery bin/bbackupctl lib/server lib/backupstore lib/backupclient lib/intercept
diff --git a/notes/win32_build_on_cygwin_using_mingw.txt b/notes/win32_build_on_cygwin_using_mingw.txt
index c35764bb..e71b5764 100644
--- a/notes/win32_build_on_cygwin_using_mingw.txt
+++ b/notes/win32_build_on_cygwin_using_mingw.txt
@@ -1,13 +1,20 @@
How to build Box Backup on Win32 using Cygwin and MinGW
-By Chris Wilson, 2005-12-07
+By Chris Wilson, 2007-05-26
+
+(To read this document online with better formatting, browse to:
+http://bbdev.fluffy.co.uk/trac/wiki/CompileWithMinGW)
+
+Start by installing Cygwin on your Windows machine [http://www.cygwin.org].
+Make sure to select the following packages during installation:
-Install Cygwin on your Windows box [http://www.cygwin.org]
-Make sure to include the following packages:
* Devel/gcc-mingw
* Devel/gcc-mingw-core
* Devel/gcc-mingw-g++
* Mingw/mingw-zlib
+If you already have Cygwin installed, please re-run the installer and
+ensure that those packages are installed.
+
Download OpenSSL from
[http://www.openssl.org/source/openssl-0.9.7i.tar.gz]
@@ -35,20 +42,12 @@ Configure PCRE for MinGW compilation, and build and install it:
export CFLAGS="-mno-cygwin"
./configure
make winshared
- cp .libs/pcreposix.dll /bin
- cp .libs/pcreposix.dll.a /usr/i686-pc-mingw32/lib
- cp pcreposix.h /usr/i686-pc-mingw32/include/regex.h
+ cp .libs/libpcre.a .libs/libpcreposix.a /usr/lib/mingw
+ cp pcreposix.h /usr/include/mingw
Now unpack the Box Backup sources, enter the source directory,
and configure like this:
- 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 you don't have a "configure" file, run "./bootstrap")
- ./configure --target=i686-pc-mingw32
+ ./infrastructure/mingw/configure.sh
make
diff --git a/notes/win32_build_on_linux_using_mingw.txt b/notes/win32_build_on_linux_using_mingw.txt
index a3243a50..407096b1 100644
--- a/notes/win32_build_on_linux_using_mingw.txt
+++ b/notes/win32_build_on_linux_using_mingw.txt
@@ -7,6 +7,11 @@ Install the MinGW cross-compiler for Windows:
- Fedora and SuSE users can download RPM packages from
[http://mirzam.it.vu.nl/mingw/]
+You will need to know the prefix used by the cross-compiler executables.
+It will usually be something like "ix86-mingw32*-". All the binaries in the
+cross-compiler package will start with this prefix. The documentation below
+assumes that it is "i386-mingw32-". Adjust to taste.
+
Download Zlib from [http://www.zlib.net/], unpack and enter source directory:
export CC=i386-mingw32-gcc
@@ -16,7 +21,34 @@ Download Zlib from [http://www.zlib.net/], unpack and enter source directory:
make
make install prefix=/usr/local/i386-mingw32
-Download OpenSSL 0.9.7 from
+Download OpenSSL 0.9.8b from
+[http://www.openssl.org/source/openssl-0.9.8b.tar.gz]
+
+Unpack and configure:
+
+ tar xzvf openssl-0.9.8b.tar.gz
+ cd openssl-0.9.8b
+ ./Configure --prefix=/usr/local/i386-mingw32 mingw
+ make makefile.one
+ wget http://bbdev.fluffy.co.uk/svn/box/chris/win32/support/openssl-0.9.8b-mingw-cross.patch
+ patch -p1 < openssl-0.9.8b-mingw-cross.patch
+ make -f makefile.one
+ make -f makefile.one install
+
+Download PCRE from
+[http://prdownloads.sourceforge.net/pcre/pcre-6.3.tar.bz2?download]
+
+Unpack:
+
+ tar xjvf pcre-6.3.tar.bz2
+ cd pcre-6.3
+
+Configure and make:
+
+ ./configure --host=i586-mingw32msvc --prefix=/usr/i386-mingw32/
+ make winshared wininstall
+ cp .libs/libpcreposix.a /usr/i386-pc-mingw32/lib
+ cp pcreposix.h /usr/i386-pc-mingw32/include/regex.h
Configure Box with:
@@ -27,5 +59,6 @@ Configure Box with:
export CXXFLAGS="-mthreads"
export LDFLAGS="-mthreads"
export LIBS="-lcrypto -lws2_32 -lgdi32"
+ (if you don't have a "configure" file, run "./bootstrap")
./configure --target=i386-mingw32
- make CXX="$CXX" AR="$AR" RANLIB="$RANLIB"
+ make CXX="$CXX" AR="$AR" RANLIB="$RANLIB" WINDRES="i386-mingw32-windres"
diff --git a/parcels.txt b/parcels.txt
index 13328e55..06e41613 100644
--- a/parcels.txt
+++ b/parcels.txt
@@ -8,24 +8,23 @@ backup-client
bin bbackupquery
bin bbackupctl
script bin/bbackupd/bbackupd-config
+ script LICENSE.txt
-ONLY:mingw32
+ONLY:mingw32,mingw32msvc
script bin/bbackupd/win32/installer.iss
- script bin/bbackupd/win32/ReadMe.txt
script bin/bbackupd/win32/bbackupd.conf
+ script bin/bbackupd/win32/NotifySysAdmin.vbs
+END-ONLY
+
+ONLY:mingw32
script /bin/mgwz.dll
script /bin/mingwm10.dll
optional script /bin/pcreposix.dll
END-ONLY
-OMIT:mingw32
-OMIT:CYGWIN
-
backup-server
bin bbstored
bin bbstoreaccounts
script bin/bbstored/bbstored-certs
script bin/bbstored/bbstored-config
script lib/raidfile/raidfile-config
-
-END-OMIT
diff --git a/runtest.pl.in b/runtest.pl.in
new file mode 100755
index 00000000..0d4381a6
--- /dev/null
+++ b/runtest.pl.in
@@ -0,0 +1,123 @@
+#!@PERL@
+
+use strict;
+use warnings;
+
+use lib 'infrastructure';
+use BoxPlatform;
+
+my ($test_name,$test_mode) = @ARGV;
+
+$test_mode = 'debug' if not defined $test_mode or $test_mode eq '';
+
+if($test_name eq '' || ($test_mode ne 'debug' && $test_mode ne 'release'))
+{
+ print <<__E;
+Run Test utility -- bad usage.
+
+runtest.pl (test|ALL) [release|debug]
+
+Mode defaults to debug.
+
+__E
+ exit(2);
+}
+
+my @results;
+my $exit_code = 0;
+
+if($test_name ne 'ALL')
+{
+ # run one or more specified test
+ if ($test_name =~ m/,/)
+ {
+ foreach my $test (split m/,/, $test_name)
+ {
+ runtest($test);
+ }
+ }
+ else
+ {
+ runtest($test_name);
+ }
+}
+else
+{
+ # run all tests
+ my @tests;
+ open MODULES,'modules.txt' or die "Can't open modules file";
+ while(<MODULES>)
+ {
+ # omit bits on some platforms?
+ next if m/\AEND-OMIT/;
+ if(m/\AOMIT:(.+)/)
+ {
+ if($1 eq $build_os or $1 eq $target_os)
+ {
+ while(<MODULES>)
+ {
+ last if m/\AEND-OMIT/;
+ }
+ }
+ next;
+ }
+ push @tests,$1 if m~\Atest/(\w+)\s~;
+ }
+ close MODULES;
+
+ runtest($_) for(@tests)
+}
+
+# report results
+print "--------\n",join("\n",@results),"\n";
+
+exit $exit_code;
+
+sub runtest
+{
+ my ($t) = @_;
+
+ # attempt to make this test
+ my $flag = ($test_mode eq 'release')?(BoxPlatform::make_flag('RELEASE')):'';
+ my $make_res = system("cd test/$t ; $make_command $flag");
+ if($make_res != 0)
+ {
+ push @results,"$t: make failed";
+ $exit_code = 2;
+ return;
+ }
+
+ my $logfile = "test-$t.log";
+
+ # run it
+ my $test_res = system("cd $test_mode/test/$t ; ./t 2>&1 " .
+ "| tee ../../../$logfile");
+
+ # open test results
+ if(open RESULTS, $logfile)
+ {
+ my $last;
+ while(<RESULTS>)
+ {
+ $last = $_ if m/\w/;
+ }
+ close RESULTS;
+
+ chomp $last;
+ push @results, "$t: $last";
+
+ if ($last ne "PASSED")
+ {
+ $exit_code = 1;
+ }
+ }
+ else
+ {
+ push @results,
+ "$t: failed to open test log file: $logfile: $!";
+ }
+
+ # delete test results
+ # unlink $logfile;
+}
+
diff --git a/test/backupdiff/difftestfiles.cpp b/test/backupdiff/difftestfiles.cpp
index cf28fab1..40e5da52 100644
--- a/test/backupdiff/difftestfiles.cpp
+++ b/test/backupdiff/difftestfiles.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/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp
index bab6c941..09b4875e 100644
--- a/test/backupdiff/testbackupdiff.cpp
+++ b/test/backupdiff/testbackupdiff.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.
@@ -104,22 +104,26 @@ bool files_identical(const char *file1, const char *file2)
void make_file_of_zeros(const char *filename, size_t size)
{
- static const size_t bs = 0x10000;
- size_t remSize = size;
- void *b = malloc(bs);
- memset(b, 0, bs);
- FILE *f = fopen(filename, "wb");
-
- // Using largish blocks like this is much faster, while not consuming too much RAM
- while(remSize > bs)
+ #ifdef WIN32
+ HANDLE handle = openfile(filename, O_WRONLY | O_CREAT | O_EXCL, 0);
+ TEST_THAT(handle != INVALID_HANDLE_VALUE);
+ TEST_THAT(SetFilePointer(handle, size, NULL, FILE_BEGIN)
+ != INVALID_SET_FILE_POINTER);
+ TEST_THAT(GetLastError() == NO_ERROR);
+ BOOL result = SetEndOfFile(handle);
+ if (result != TRUE)
{
- fwrite(b, bs, 1, f);
- remSize -= bs;
+ printf("Error %u\n", GetLastError());
}
- fwrite(b, remSize, 1, f);
-
- fclose(f);
- free(b);
+ TEST_THAT(result == TRUE);
+ TEST_THAT(CloseHandle(handle) == TRUE);
+ #else
+ int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600);
+ if (fd < 0) perror(filename);
+ TEST_THAT(fd >= 0);
+ TEST_THAT(ftruncate(fd, size) == 0);
+ TEST_THAT(close(fd) == 0);
+ #endif
TEST_THAT((size_t)TestGetFileSize(filename) == size);
}
@@ -156,12 +160,20 @@ void check_encoded_file(const char *filename, int64_t OtherFileID, int new_block
if(s > 0)
{
nnew++;
+ #ifdef WIN32
+ TRACE2("%8I64d this s=%8I64d", b, s);
+ #else
TRACE2("%8lld this s=%8lld", b, s);
+ #endif
}
else
{
nold++;
+ #ifdef WIN32
+ TRACE2("%8I64d other i=%8I64d", b, 0 - s);
+ #else
TRACE2("%8lld other i=%8lld", b, 0 - s);
+ #endif
}
// Decode the rest
uint64_t iv = box_ntoh64(hdr.mEntryIVBase);
@@ -245,10 +257,18 @@ void test_diff(int from, int to, int new_blocks_expected, int old_blocks_expecte
}
else
{
+#ifdef WIN32
+ // Emulate the above stage!
+ char src[256], dst[256];
+ sprintf(src, "testfiles\\f%d.diff", to);
+ sprintf(dst, "testfiles\\f%d.encoded", to);
+ TEST_THAT(CopyFile(src, dst, FALSE) != 0)
+#else
// Emulate the above stage!
char cmd[256];
sprintf(cmd, "cp testfiles/f%d.diff testfiles/f%d.encoded", to, to);
::system(cmd);
+#endif
}
// Decode it
@@ -393,8 +413,10 @@ int test(int argc, const char *argv[])
{
// Want to trace out all the details
#ifndef NDEBUG
+ #ifndef WIN32
BackupStoreFile::TraceDetailsOfDiffProcess = true;
#endif
+ #endif
// Create all the test files
create_test_files();
@@ -408,6 +430,7 @@ int test(int argc, const char *argv[])
FileStream out("testfiles/f0.encoded", O_WRONLY | O_CREAT | O_EXCL);
std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/f0", 1 /* dir ID */, f0name));
encoded->CopyStreamTo(out);
+ out.Close();
check_encoded_file("testfiles/f0.encoded", 0, 33, 0);
}
@@ -468,6 +491,7 @@ int test(int argc, const char *argv[])
FileStream out("testfiles/f9.zerotest", O_WRONLY | O_CREAT | O_EXCL);
std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFile("testfiles/f9", 1 /* dir ID */, fn));
encoded->CopyStreamTo(out);
+ out.Close();
check_encoded_file("testfiles/f9.zerotest", 0, 0, 0);
}
{
@@ -478,6 +502,7 @@ int test(int argc, const char *argv[])
}
}
+#ifndef WIN32
// Check that symlinks aren't diffed
TEST_THAT(::symlink("f2", "testfiles/f2.symlink") == 0)
// And go and diff it against the previous encoded file
@@ -505,8 +530,10 @@ int test(int argc, const char *argv[])
TEST_THAT(completelyDifferent == true);
check_encoded_file("testfiles/f2.symlink.diff", 0, 0, 0);
}
+#endif
- // Check that diffing against a file which isn't "complete" and referes another isn't allowed
+ // Check that diffing against a file which isn't "complete" and
+ // references another isn't allowed
{
FileStream blockindex("testfiles/f1.diff");
BackupStoreFile::MoveStreamPositionToBlockIndex(blockindex);
@@ -518,10 +545,19 @@ int test(int argc, const char *argv[])
0, 0), BackupStoreException, CannotDiffAnIncompleteStoreFile);
}
- // Found a nasty case where files of lots of the same thing sock up lots of processor
- // time -- because of lots of matches found. Check this out!
+ // Found a nasty case where files of lots of the same thing
+ // suck up lots of processor time -- because of lots of matches
+ // found. Check this out!
+
+ #ifdef WIN32
+ ::fprintf(stdout, "Testing diffing two large streams, "
+ "may take a while!\n");
+ ::fflush(stdout);
+ #endif
+
make_file_of_zeros("testfiles/zero.0", 20*1024*1024);
make_file_of_zeros("testfiles/zero.1", 200*1024*1024);
+
// Generate a first encoded file
{
BackupStoreFilenameClear f0name("zero.0");
@@ -541,7 +577,14 @@ int test(int argc, const char *argv[])
2000 /* object ID of the file diffing from */, blockindex, IOStream::TimeOutInfinite,
0, 0));
encoded->CopyStreamTo(out);
+
+ printf("Time taken: %d seconds\n", (int)(time(0) - beginTime));
+
+ #ifdef WIN32
+ TEST_THAT(time(0) < (beginTime + 300));
+ #else
TEST_THAT(time(0) < (beginTime + 40));
+ #endif
}
// Remove zero-files to save disk space
remove("testfiles/zero.0");
diff --git a/test/backupdiff/testextra b/test/backupdiff/testextra
index 6f5f4473..8a493f53 100644
--- a/test/backupdiff/testextra
+++ b/test/backupdiff/testextra
@@ -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/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp
index 593ae121..46c74bd0 100644
--- a/test/backupstore/testbackupstore.cpp
+++ b/test/backupstore/testbackupstore.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.
@@ -71,6 +71,7 @@
#include "MemBlockStream.h"
#include "BackupClientFileAttributes.h"
#include "BackupClientCryptoKeys.h"
+#include "ServerControl.h"
#include "MemLeakFindOn.h"
@@ -463,7 +464,8 @@ void test_test_file(int t, IOStream &rStream)
}
free(data);
- unlink("testfiles/test_download");
+ in.Close();
+ TEST_THAT(unlink("testfiles/test_download") == 0);
}
void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID)
@@ -968,6 +970,7 @@ int test_server(const char *hostname)
// Check marker is 0
TEST_THAT(loginConf->GetClientStoreMarker() == 0);
+#ifndef WIN32
// Check that we can't open a new connection which requests write permissions
{
SocketStreamTLS conn;
@@ -979,10 +982,12 @@ int test_server(const char *hostname)
ConnectionException, Conn_Protocol_UnexpectedReply);
protocol.QueryFinished();
}
+#endif
// Set the client store marker
protocol.QuerySetClientStoreMarker(0x8732523ab23aLL);
+#ifndef WIN32
// Open a new connection which is read only
SocketStreamTLS connReadOnly;
connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED);
@@ -1001,10 +1006,12 @@ int test_server(const char *hostname)
// Check client store marker
TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL);
}
+#else // WIN32
+ BackupProtocolClient& protocolReadOnly(protocol);
+#endif
test_server_1(protocol, protocolReadOnly);
-
// Create and upload some test files
int64_t maxID = 0;
for(int t = 0; t < UPLOAD_NUM; ++t)
@@ -1242,6 +1249,7 @@ int test_server(const char *hostname)
StreamableMemBlock attr(attr1, sizeof(attr1));
TEST_THAT(dir.GetAttributes() == attr);
}
+
// Check that we don't get attributes if we don't ask for them
{
// Command
@@ -1255,6 +1263,10 @@ int test_server(const char *hostname)
dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
TEST_THAT(!dir.HasAttributes());
}
+
+ // sleep to ensure that the timestamp on the file will change
+ ::safe_sleep(1);
+
// Change attributes on the directory
{
MemBlockStream attrnew(attr2, sizeof(attr2));
@@ -1293,6 +1305,7 @@ int test_server(const char *hostname)
subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName));
TEST_THAT(rep->GetObjectID() == uploads[UPLOAD_FILE_TO_MOVE].allocated_objid);
}
+
// Try some dodgy renames
{
BackupStoreFilenameClear newName("moved-files");
@@ -1305,6 +1318,10 @@ int test_server(const char *hostname)
subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName),
ConnectionException, Conn_Protocol_UnexpectedReply);
}
+
+ // sleep to ensure that the timestamp on the file will change
+ ::safe_sleep(1);
+
// Rename within a directory
{
BackupStoreFilenameClear newName("moved-files-x");
@@ -1312,6 +1329,7 @@ int test_server(const char *hostname)
subdirid,
subdirid, BackupProtocolClientMoveObject::Flags_MoveAllWithSameName, newName);
}
+
// Check it's all gone from the root directory...
{
// Command
@@ -1331,6 +1349,7 @@ int test_server(const char *hostname)
TEST_THAT(en->GetName() != uploads[UPLOAD_FILE_TO_MOVE].name);
}
}
+
// Check the old and new versions are in the other directory
{
BackupStoreFilenameClear lookFor("moved-files-x");
@@ -1360,6 +1379,7 @@ int test_server(const char *hostname)
TEST_THAT(foundCurrent);
TEST_THAT(foundOld);
}
+
// make a little bit more of a thing to look at
int64_t subsubdirid = 0;
int64_t subsubfileid = 0;
@@ -1383,6 +1403,7 @@ int test_server(const char *hostname)
upload));
subsubfileid = stored->GetObjectID();
}
+
// Query names -- test that invalid stuff returns not found OK
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(3248972347823478927LL, subsubdirid));
@@ -1400,6 +1421,7 @@ int test_server(const char *hostname)
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(BackupProtocolClientGetObjectName::ObjectID_DirectoryOnly, 2234342378424LL));
TEST_THAT(nameRep->GetNumNameElements() == 0);
}
+
// Query names... first, get info for the file
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(subsubfileid, subsubdirid));
@@ -1417,6 +1439,7 @@ int test_server(const char *hostname)
TEST_THAT(fn.GetClearFilename() == testnames[l]);
}
}
+
// Query names... secondly, for the directory
{
std::auto_ptr<BackupProtocolClientObjectName> nameRep(protocol.QueryGetObjectName(BackupProtocolClientGetObjectName::ObjectID_DirectoryOnly, subsubdirid));
@@ -1476,11 +1499,15 @@ int test_server(const char *hostname)
}
// Finish the connections
+#ifndef WIN32
protocolReadOnly.QueryFinished();
+#endif
protocol.QueryFinished();
// Close logs
+#ifndef WIN32
::fclose(protocolReadOnlyLog);
+#endif
::fclose(protocolLog);
}
@@ -1639,6 +1666,7 @@ int test3(int argc, const char *argv[])
TEST_THAT(decoded->GetNumBlocks() == 3);
}
+#ifndef WIN32 // no symlinks on Win32
// Try out doing this on a symlink
{
TEST_THAT(::symlink("does/not/exist", "testfiles/testsymlink") == 0);
@@ -1652,6 +1680,7 @@ int test3(int argc, const char *argv[])
// Decode it
BackupStoreFile::DecodeFile(b, "testfiles/testsymlink_2", IOStream::TimeOutInfinite);
}
+#endif
}
// Store info
@@ -1709,7 +1738,11 @@ int test3(int argc, const char *argv[])
"testfiles/clientTrustedCAs.pem");
// First, try logging in without an account having been created... just make sure login fails.
- int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+
+ std::string cmd = BBSTORED " " + bbstored_args +
+ " testfiles/bbstored.conf";
+ int pid = LaunchServer(cmd.c_str(), "testfiles/bbstored.pid");
+
TEST_THAT(pid != -1 && pid != 0);
if(pid > 0)
{
@@ -1738,12 +1771,17 @@ int test3(int argc, const char *argv[])
}
// Create an account for the test client
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf create 01234567 0 "
+ "10000B 20000B") == 0);
+
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
+
TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567"));
TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567"));
TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567"));
- TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8); // make sure something is written to it
+ TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8);
+ // make sure something is written to it
TEST_THAT(ServerIsAlive(pid));
@@ -1763,15 +1801,22 @@ int test3(int argc, const char *argv[])
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
+#ifndef WIN32
TestRemoteProcessMemLeaks("bbstored.memleaks");
+#endif
- // Set a new limit on the account -- leave the hard limit high to make sure the target for
- // freeing space is the soft limit.
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0);
+ // Set a new limit on the account -- leave the hard limit
+ // high to make sure the target for freeing space is the
+ // soft limit.
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf setlimit 01234567 "
+ "10B 20000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Start things up
- pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+ pid = LaunchServer(BBSTORED " testfiles/bbstored.conf",
+ "testfiles/bbstored.pid");
+
::sleep(1);
TEST_THAT(ServerIsAlive(pid));
@@ -1787,8 +1832,9 @@ int test3(int argc, const char *argv[])
// Count the objects again
recursive_count_objects_results after = {0,0,0};
- recursive_count_objects("localhost", BackupProtocolClientListDirectory::RootDirectory, after);
-printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after.deleted, after.old);
+ recursive_count_objects("localhost",
+ BackupProtocolClientListDirectory::RootDirectory,
+ after);
// If these tests fail then try increasing the timeout above
TEST_THAT(after.objectsNotDel == before.objectsNotDel);
@@ -1796,7 +1842,9 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after
TEST_THAT(after.old == 0);
// Set a really small hard limit
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf setlimit 01234567 "
+ "10B 20B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Try to upload a file and create a directory, and check an error is generated
@@ -1846,7 +1894,10 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
+
+#ifndef WIN32
TestRemoteProcessMemLeaks("bbstored.memleaks");
+#endif
}
return 0;
@@ -1857,11 +1908,16 @@ int multi_server()
printf("Starting server for connection from remote machines...\n");
// Create an account for the test client
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf create 01234567 0 "
+ "30000B 40000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// First, try logging in without an account having been created... just make sure login fails.
- int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid");
+
+ int pid = LaunchServer(BBSTORED " testfiles/bbstored_multi.conf",
+ "testfiles/bbstored.pid");
+
TEST_THAT(pid != -1 && pid != 0);
if(pid > 0)
{
@@ -1878,15 +1934,58 @@ int multi_server()
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
+#ifndef WIN32
TestRemoteProcessMemLeaks("bbstored.memleaks");
+#endif
}
return 0;
}
+#ifdef WIN32
+WCHAR* ConvertUtf8ToWideString(const char* pString);
+std::string ConvertPathToAbsoluteUnicode(const char *pFileName);
+#endif
+
int test(int argc, const char *argv[])
{
+#ifdef WIN32
+ // this had better work, or bbstored will die when combining diffs
+ char* file = "foo";
+ std::string abs = ConvertPathToAbsoluteUnicode(file);
+ WCHAR* wfile = ConvertUtf8ToWideString(abs.c_str());
+
+ DWORD accessRights = FILE_READ_ATTRIBUTES |
+ FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_WRITE_ATTRIBUTES |
+ FILE_WRITE_DATA | FILE_WRITE_EA /*| FILE_ALL_ACCESS*/;
+ DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+ HANDLE h1 = CreateFileW(wfile, accessRights, shareMode,
+ NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ assert(h1 != INVALID_HANDLE_VALUE);
+ TEST_THAT(h1 != INVALID_HANDLE_VALUE);
+
+ accessRights = FILE_READ_ATTRIBUTES |
+ FILE_LIST_DIRECTORY | FILE_READ_EA;
+
+ HANDLE h2 = CreateFileW(wfile, accessRights, shareMode,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ assert(h2 != INVALID_HANDLE_VALUE);
+ TEST_THAT(h2 != INVALID_HANDLE_VALUE);
+
+ CloseHandle(h2);
+ CloseHandle(h1);
+ delete [] wfile;
+
+ h1 = openfile("foo", O_CREAT | O_RDWR, 0);
+ TEST_THAT(h1 != INVALID_HANDLE_VALUE);
+ h2 = openfile("foo", O_RDWR, 0);
+ TEST_THAT(h2 != INVALID_HANDLE_VALUE);
+ CloseHandle(h2);
+ CloseHandle(h1);
+#endif
+
// SSL library
SSLLib::Initialise();
@@ -1905,14 +2004,19 @@ int test(int argc, const char *argv[])
// for seeing what's going on.
BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys");
- // encode in some filenames -- can't do static initialisation because the key won't be set up when these are initialised
- for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l)
+ // encode in some filenames -- can't do static initialisation
+ // because the key won't be set up when these are initialised
{
- ens[l].fn = BackupStoreFilenameClear(ens_filenames[l]);
- }
- for(unsigned int l = 0; l < sizeof(uploads_filenames) / sizeof(uploads_filenames[0]); ++l)
- {
- uploads[l].name = BackupStoreFilenameClear(uploads_filenames[l]);
+ MEMLEAKFINDER_NO_LEAKS
+
+ for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l)
+ {
+ ens[l].fn = BackupStoreFilenameClear(ens_filenames[l]);
+ }
+ for(unsigned int l = 0; l < sizeof(uploads_filenames) / sizeof(uploads_filenames[0]); ++l)
+ {
+ uploads[l].name = BackupStoreFilenameClear(uploads_filenames[l]);
+ }
}
// Trace errors out
diff --git a/test/backupstore/testextra b/test/backupstore/testextra
index ad7dd552..85783cca 100644
--- a/test/backupstore/testextra
+++ b/test/backupstore/testextra
@@ -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/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp
index 62d098b1..66e6bd94 100644
--- a/test/backupstorefix/testbackupstorefix.cpp
+++ b/test/backupstorefix/testbackupstorefix.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,7 @@
#include "RaidFileException.h"
#include "StoreStructure.h"
#include "BackupStoreFileWire.h"
+#include "ServerControl.h"
#include "MemLeakFindOn.h"
@@ -80,7 +81,7 @@ make some BackupDirectoryStore objects, CheckAndFix(), then verify
- all old flags
delete store info
-add suprious file
+add spurious file
delete directory (should appear again)
change container ID of directory
delete a file
@@ -103,22 +104,8 @@ std::map<std::string, int32_t> nameToID;
std::map<int32_t, bool> objectIsDir;
#define RUN_CHECK \
- ::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf check 01234567"); \
- ::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf check 01234567 fix");
-
-// Wait a given number of seconds for something to complete
-void wait_for_operation(int seconds)
-{
- printf("waiting: ");
- fflush(stdout);
- for(int l = 0; l < seconds; ++l)
- {
- sleep(1);
- printf(".");
- fflush(stdout);
- }
- printf("\n");
-}
+ ::system(BBSTOREACCOUNTS " -c testfiles/bbstored.conf check 01234567"); \
+ ::system(BBSTOREACCOUNTS " -c testfiles/bbstored.conf check 01234567 fix");
// Get ID of an object given a filename
int32_t getID(const char *name)
@@ -176,6 +163,7 @@ void CorruptObject(const char *name, int start, const char *rubbish)
w.Write(rubbish, rubbish_len);
// Copy rest of file
r->CopyStreamTo(w);
+ r->Close();
// Commit
w.Commit(true /* convert now */);
}
@@ -240,9 +228,12 @@ void check_dir_dep(BackupStoreDirectory &dir, checkdepinfoen *ck)
void test_dir_fixing()
{
- fnames[0].SetAsClearFilename("x1");
- fnames[1].SetAsClearFilename("x2");
- fnames[2].SetAsClearFilename("x3");
+ {
+ MEMLEAKFINDER_NO_LEAKS;
+ fnames[0].SetAsClearFilename("x1");
+ fnames[1].SetAsClearFilename("x2");
+ fnames[2].SetAsClearFilename("x3");
+ }
{
BackupStoreDirectory dir;
@@ -313,7 +304,7 @@ void test_dir_fixing()
TEST_THAT(dir.CheckAndFix() == false);
check_dir_dep(dir, c1);
- // Check that a suprious depends older ref is undone
+ // Check that a spurious depends older ref is undone
e2->SetDependsOlder(1);
TEST_THAT(dir.CheckAndFix() == true);
TEST_THAT(dir.CheckAndFix() == false);
@@ -338,37 +329,57 @@ int test(int argc, const char *argv[])
rcontroller.Initialise("testfiles/raidfile.conf");
// Create an account
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf "
+ "create 01234567 0 10000B 20000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Start the bbstored server
- int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+ int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf",
+ "testfiles/bbstored.pid");
TEST_THAT(pid != -1 && pid != 0);
+
if(pid > 0)
{
::sleep(1);
TEST_THAT(ServerIsAlive(pid));
// Run the perl script to create the initial directories
- TEST_THAT_ABORTONFAIL(::system("perl testfiles/testbackupstorefix.pl init") == 0);
+ TEST_THAT_ABORTONFAIL(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl init") == 0);
- int bbackupd_pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid");
+ std::string cmd = BBACKUPD " " + bbackupd_args +
+ " testfiles/bbackupd.conf";
+ int bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
+
if(bbackupd_pid > 0)
{
- ::sleep(1);
+ ::safe_sleep(1);
TEST_THAT(ServerIsAlive(bbackupd_pid));
-
- // Create a nice store directory
- wait_for_operation(30);
- // That'll do nicely, stop the server
- TEST_THAT(KillServer(bbackupd_pid));
- TestRemoteProcessMemLeaks("bbackupd.memleaks");
+ // Wait 4 more seconds for the files to be old enough
+ // to upload
+ ::safe_sleep(4);
+
+ // Upload files to create a nice store directory
+ ::sync_and_wait();
+
+ // Stop bbackupd
+ #ifdef WIN32
+ terminate_bbackupd(bbackupd_pid);
+ // implicit check for memory leaks
+ #else
+ TEST_THAT(KillServer(bbackupd_pid));
+ TestRemoteProcessMemLeaks("bbackupd.memleaks");
+ #endif
}
// Generate a list of all the object IDs
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf \"list -r\" quit > testfiles/initial-listing.txt") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf \"list -r\" quit "
+ "> testfiles/initial-listing.txt") == 0);
+
// And load it in
{
FILE *f = ::fopen("testfiles/initial-listing.txt", "r");
@@ -379,9 +390,11 @@ int test(int argc, const char *argv[])
char name[256];
while(::fgets(line, sizeof(line), f) != 0)
{
- TEST_THAT(::sscanf(line, "%x %s %s", &id, flags, name) == 3);
+ TEST_THAT(::sscanf(line, "%x %s %s", &id,
+ flags, name) == 3);
bool isDir = (::strcmp(flags, "-d---") == 0);
//TRACE3("%x,%d,%s\n", id, isDir, name);
+ MEMLEAKFINDER_NO_LEAKS;
nameToID[std::string(name)] = id;
objectIsDir[id] = isDir;
}
@@ -396,19 +409,24 @@ int test(int argc, const char *argv[])
del.Delete();
}
{
- // Add a suprious file
- RaidFileWrite random(discSetNum, storeRoot + "randomfile");
+ // Add a spurious file
+ RaidFileWrite random(discSetNum,
+ storeRoot + "randomfile");
random.Open();
random.Write("test", 4);
random.Commit(true);
}
+
// Fix it
RUN_CHECK
+
// Check everything is as it was
- TEST_THAT(::system("perl testfiles/testbackupstorefix.pl check 0") == 0);
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 0") == 0);
// Check the random file doesn't exist
{
- TEST_THAT(!RaidFileRead::FileExists(discSetNum, storeRoot + "01/randomfile"));
+ TEST_THAT(!RaidFileRead::FileExists(discSetNum,
+ storeRoot + "01/randomfile"));
}
// ------------------------------------------------------------------------------------------------
@@ -448,6 +466,8 @@ int test(int argc, const char *argv[])
file_BlockIndexEntry e[2];
} h;
TEST_THAT(file->Read(&h, sizeof(h)) == sizeof(h));
+ file->Close();
+
// Modify
TEST_THAT(box_ntoh64(h.hdr.mOtherFileID) == 0);
TEST_THAT(box_ntoh64(h.hdr.mNumBlocks) >= 2);
@@ -463,14 +483,16 @@ int test(int argc, const char *argv[])
// Fix it
RUN_CHECK
// Check
- TEST_THAT(::system("perl testfiles/testbackupstorefix.pl check 1") == 0);
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 1")
+ == 0);
// Check the modified file doesn't exist
TEST_THAT(!RaidFileRead::FileExists(discSetNum, fn));
}
// ------------------------------------------------------------------------------------------------
- ::printf(" === Delete directory, change container ID of another, duplicate entry in dir, supurious file size, delete file\n");
+ ::printf(" === Delete directory, change container ID of another, duplicate entry in dir, spurious file size, delete file\n");
{
BackupStoreDirectory dir;
LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
@@ -478,7 +500,7 @@ int test(int argc, const char *argv[])
SaveDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
}
int64_t duplicatedID = 0;
- int64_t notSupriousFileSize = 0;
+ int64_t notSpuriousFileSize = 0;
{
BackupStoreDirectory dir;
LoadDirectory("Test1/cannes/ict/peep", dir);
@@ -496,7 +518,7 @@ int test(int argc, const char *argv[])
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File);
TEST_THAT(en != 0);
- notSupriousFileSize = en->GetSizeInBlocks();
+ notSpuriousFileSize = en->GetSizeInBlocks();
en->SetSizeInBlocks(3473874);
TEST_THAT(en->GetSizeInBlocks() == 3473874);
}
@@ -509,7 +531,8 @@ int test(int argc, const char *argv[])
// Fix it
RUN_CHECK
// Check everything is as it should be
- TEST_THAT(::system("perl testfiles/testbackupstorefix.pl check 2") == 0);
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 2") == 0);
{
BackupStoreDirectory dir;
LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
@@ -535,7 +558,7 @@ int test(int argc, const char *argv[])
BackupStoreDirectory::Iterator i(dir);
BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File);
TEST_THAT(en != 0);
- TEST_THAT(en->GetSizeInBlocks() == notSupriousFileSize);
+ TEST_THAT(en->GetSizeInBlocks() == notSpuriousFileSize);
}
}
@@ -565,7 +588,8 @@ int test(int argc, const char *argv[])
// Fix it
RUN_CHECK
// Check everything is as it should be
- TEST_THAT(::system("perl testfiles/testbackupstorefix.pl check 3") == 0);
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 3") == 0);
{
BackupStoreDirectory dir;
LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir);
@@ -579,18 +603,22 @@ int test(int argc, const char *argv[])
// Fix it
RUN_CHECK
// Check everything is where it is predicted to be
- TEST_THAT(::system("perl testfiles/testbackupstorefix.pl check 4") == 0);
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 4") == 0);
// ------------------------------------------------------------------------------------------------
::printf(" === Corrupt file and dir\n");
// File
- CorruptObject("Test1/foreomizes/stemptinevidate/algoughtnerge", 33, "34i729834298349283479233472983sdfhasgs");
+ CorruptObject("Test1/foreomizes/stemptinevidate/algoughtnerge",
+ 33, "34i729834298349283479233472983sdfhasgs");
// Dir
- CorruptObject("Test1/cannes/imulatrougge/foreomizes", 23, "dsf32489sdnadf897fd2hjkesdfmnbsdfcsfoisufio2iofe2hdfkjhsf");
+ CorruptObject("Test1/cannes/imulatrougge/foreomizes",23,
+ "dsf32489sdnadf897fd2hjkesdfmnbsdfcsfoisufio2iofe2hdfkjhsf");
// Fix it
RUN_CHECK
// Check everything is where it should be
- TEST_THAT(::system("perl testfiles/testbackupstorefix.pl check 5") == 0);
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl check 5") == 0);
// ------------------------------------------------------------------------------------------------
::printf(" === Overwrite root with a file\n");
@@ -604,13 +632,16 @@ int test(int argc, const char *argv[])
// Fix it
RUN_CHECK
// Check everything is where it should be
- TEST_THAT(::system("perl testfiles/testbackupstorefix.pl reroot 6") == 0);
+ TEST_THAT(::system(PERL_EXECUTABLE
+ " testfiles/testbackupstorefix.pl reroot 6") == 0);
// ------------------------------------------------------------------------------------------------
// Stop server
TEST_THAT(KillServer(pid));
- TestRemoteProcessMemLeaks("bbstored.memleaks");
+ #ifndef WIN32
+ TestRemoteProcessMemLeaks("bbstored.memleaks");
+ #endif
}
return 0;
diff --git a/test/backupstorefix/testextra b/test/backupstorefix/testextra
index d55200d6..a9c53bb9 100644
--- a/test/backupstorefix/testextra
+++ b/test/backupstorefix/testextra
@@ -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/test/backupstorefix/testfiles/testbackupstorefix.pl b/test/backupstorefix/testfiles/testbackupstorefix.pl
index b2b111c9..0094b1ae 100755
--- a/test/backupstorefix/testfiles/testbackupstorefix.pl
+++ b/test/backupstorefix/testfiles/testbackupstorefix.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.
@@ -92,7 +92,7 @@ elsif($ARGV[0] eq 'check')
open INITIAL,'testfiles/initial-listing.txt' or die "Can't open original listing";
while(<INITIAL>)
{
- chomp;
+ chomp; s/\r//;
$expected{$_} = 1;
m/\A(.+?) .+? (.+)\Z/;
$filenames{$2} = $_;
@@ -137,7 +137,7 @@ elsif($ARGV[0] eq 'check')
while(<LISTING>)
{
print LISTING_COPY;
- chomp;
+ chomp; s/\r//;
s/\[FILENAME NOT ENCRYPTED\]//;
if(exists $expected{$_})
{
diff --git a/test/backupstorefix/testfiles/testbackupstorefix.pl.in b/test/backupstorefix/testfiles/testbackupstorefix.pl.in
new file mode 100755
index 00000000..e64474f0
--- /dev/null
+++ b/test/backupstorefix/testfiles/testbackupstorefix.pl.in
@@ -0,0 +1,213 @@
+#!@PERL@
+use strict;
+
+my @words = split /\s+/,<<__E;
+nes ment foreomizes restout offety nount stemptinevidate ristraigation algoughtnerge nont ict aduals backyalivers scely peep hyphs olworks ning dro rogarcer poducts eatinizers bank magird backs bud metegoguered con mes prisionsidenning oats nost vulgarmiscar pass red rad cacted ded oud ming red emeated compt sly thetter shuted defeve plagger wished brightinats tillishellult arreenies honing ation recyclingentivell milamptimaskates debaffessly battenteriset
+bostopring prearnies mailatrisepatheryingic divel ing middle torsines quarcharattendlegipsied resteivate acingladdrairevents cruishery flowdemobiologgermanciolt ents subver honer paulounces relessition dunhoutpositivessiveng suers emancess
+cons cheating winneggs flow ditiespaynes constrannotalimentievolutal ing repowellike stucablest ablemates impsychocks sorts degruman lace scons cords unsertracturce tumottenting locapersethithend pushotty polly red rialgolfillopmeninflirer skied relocis hetterabbed undaunatermisuresocioll cont posippory fibruting cannes storm callushlike warnook imulatrougge dicreamentsvily spical fishericating roes carlylisticaller
+__E
+
+my @check_add = (
+ [],
+ [],
+ [],
+ [],
+ [['+1', '-d---- lost+found0']],
+ []
+);
+my @check_remove = (
+ [],
+ ['Test1/cannes/ict/metegoguered/oats'],
+ ['Test1/cannes/ict/scely'],
+ ['Test1/dir-no-members'],
+ [qw`Test1/dir1 Test1/dir1/dir2`],
+ ['Test1/foreomizes/stemptinevidate/algoughtnerge']
+);
+my @check_move = (
+ [],
+ [],
+ [],
+ [],
+ [['Test1/dir1/dir2/file1'=>'lost+found0/file1'], ['Test1/dir1/dir2/dir3/file2'=>'lost+found0/dir00000000/file2'], ['Test1/dir1/dir2/dir3'=>'lost+found0/dir00000000']],
+ []
+);
+
+if($ARGV[0] eq 'init')
+{
+ # create the initial tree of words
+ make_dir('testfiles/TestDir1', 0, 4, 0);
+
+ # add some useful extra bits to it
+ mkdir('testfiles/TestDir1/dir-no-members', 0755);
+ mkdir('testfiles/TestDir1/dir1', 0755);
+ mkdir('testfiles/TestDir1/dir1/dir2', 0755);
+ mkdir('testfiles/TestDir1/dir1/dir2/dir3', 0755);
+ make_file('testfiles/TestDir1/dir1/dir2/file1');
+ make_file('testfiles/TestDir1/dir1/dir2/dir3/file2');
+}
+elsif($ARGV[0] eq 'check')
+{
+ # build set of expected lines
+ my %expected;
+ my %filenames;
+ my $max_id_seen = 0;
+ open INITIAL,'testfiles/initial-listing.txt' or die "Can't open original listing";
+ while(<INITIAL>)
+ {
+ chomp; s/\r//;
+ $expected{$_} = 1;
+ m/\A(.+?) .+? (.+)\Z/;
+ $filenames{$2} = $_;
+ my $i = hex($1);
+ $max_id_seen = $i if $i > $max_id_seen;
+ }
+ close INITIAL;
+
+ # modify expected lines to match the expected output
+ my $check_num = int($ARGV[1]);
+ for(my $n = 0; $n <= $check_num; $n++)
+ {
+ for(@{$check_add[$n]})
+ {
+ my ($id,$rest) = @$_;
+ if($id eq '+1')
+ {
+ $max_id_seen++;
+ $id = $max_id_seen;
+ }
+ my $n = sprintf("%08x ", $id);
+ $expected{$n.$rest} = 1
+ }
+ for(@{$check_remove[$n]})
+ {
+ delete $expected{$filenames{$_}}
+ }
+ for(@{$check_move[$n]})
+ {
+ my ($from,$to) = @$_;
+ my $orig = $filenames{$from};
+ delete $expected{$filenames{$from}};
+ my ($id,$type) = split / /,$orig;
+ $expected{"$id $type $to"} = 1
+ }
+ }
+
+ # read in the new listing, and compare
+ open LISTING,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf \"list -r\" quit |" or die "Can't open list utility";
+ open LISTING_COPY,'>testfiles/listing'.$ARGV[1].'.txt' or die "can't open copy listing file";
+ my $err = 0;
+ while(<LISTING>)
+ {
+ print LISTING_COPY;
+ chomp; s/\r//;
+ s/\[FILENAME NOT ENCRYPTED\]//;
+ if(exists $expected{$_})
+ {
+ delete $expected{$_}
+ }
+ else
+ {
+ $err = 1;
+ print "Unexpected object $_ in new output\n"
+ }
+ }
+ close LISTING_COPY;
+ close LISTING;
+
+ # check for anything which didn't appear but should have done
+ for(keys %expected)
+ {
+ $err = 1;
+ print "Expected object $_ not found in new output\n"
+ }
+
+ exit $err;
+}
+elsif($ARGV[0] eq 'reroot')
+{
+ open LISTING,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf \"list -r\" quit |" or die "Can't open list utility";
+ open LISTING_COPY,'>testfiles/listing'.$ARGV[1].'.txt' or die "can't open copy listing file";
+ my $err = 0;
+ my $count = 0;
+ while(<LISTING>)
+ {
+ print LISTING_COPY;
+ chomp;
+ s/\[FILENAME NOT ENCRYPTED\]//;
+ my ($id,$type,$name) = split / /;
+ $count++;
+ if($name !~ /\Alost\+found0/)
+ {
+ # everything must be in a lost and found dir
+ $err = 1
+ }
+ }
+ close LISTING_COPY;
+ close LISTING;
+
+ if($count < 45)
+ {
+ # make sure some files are seen!
+ $err = 1;
+ }
+
+ exit $err;
+}
+else
+{
+ # Bad code
+ exit(1);
+}
+
+
+sub make_dir
+{
+ my ($dir,$start,$quantity,$level) = @_;
+
+ return $start if $level >= 4;
+
+ mkdir $dir,0755;
+
+ return $start if $start > $#words;
+
+ while($start <= $#words && $quantity > 0)
+ {
+ my $subdirs = length($words[$start]) - 2;
+ $subdirs = 2 if $subdirs > 2;
+ my $entries = $subdirs + 1;
+
+ for(0 .. ($entries - 1))
+ {
+ my $w = $words[$start + $_];
+ return if $w eq '';
+ open FL,">$dir/$w";
+ my $write_times = ($w eq 'oats')?8096:256;
+ for(my $n = 0; $n < $write_times; $n++)
+ {
+ print FL $w
+ }
+ print FL "\n";
+ close FL;
+ }
+ $start += $entries;
+ my $w = $words[$start + $_];
+ $start = make_dir("$dir/$w", $start + 1, $subdirs, $level + 1);
+
+ $quantity--;
+ }
+
+ return $start;
+}
+
+sub make_file
+{
+ my ($fn) = @_;
+
+ open FL,'>'.$fn or die "can't open $fn for writing";
+ for(0 .. 255)
+ {
+ print FL $fn
+ }
+ close FL;
+}
+
diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp
index 9edd427b..57a28ec0 100644
--- a/test/backupstorepatch/testbackupstorepatch.cpp
+++ b/test/backupstorepatch/testbackupstorepatch.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.
@@ -73,6 +73,7 @@
#include "MemBlockStream.h"
#include "BackupClientFileAttributes.h"
#include "BackupClientCryptoKeys.h"
+#include "ServerControl.h"
#include "MemLeakFindOn.h"
@@ -347,7 +348,9 @@ int test(int argc, const char *argv[])
"testfiles/clientTrustedCAs.pem");
// Create an account
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
+ " -c testfiles/bbstored.conf "
+ "create 01234567 0 30000B 40000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Create test files
@@ -357,7 +360,8 @@ int test(int argc, const char *argv[])
test_depends_in_dirs();
// First, try logging in without an account having been created... just make sure login fails.
- int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+ int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf",
+ "testfiles/bbstored.pid");
TEST_THAT(pid != -1 && pid != 0);
if(pid > 0)
{
@@ -435,7 +439,13 @@ int test(int argc, const char *argv[])
// Store details
test_files[f].IDOnServer = stored->GetObjectID();
test_files[f].IsCompletelyDifferent = isCompletelyDifferent;
- printf("ID %lld, completely different: %s\n", test_files[f].IDOnServer,
+
+#ifdef WIN32
+ printf("ID %I64d, completely different: %s\n",
+#else
+ printf("ID %lld, completely different: %s\n",
+#endif
+ test_files[f].IDOnServer,
test_files[f].IsCompletelyDifferent?"yes":"no");
}
else
@@ -603,9 +613,18 @@ int test(int argc, const char *argv[])
writedir.Commit(true);
}
- // Send the server a restart signal, so it does housekeeping immedaitely, and wait for it to happen
- ::sleep(1); // wait for old connections to terminate
+#ifdef WIN32
+ // Cannot signal bbstored to do housekeeping now,
+ // so just wait until we're sure it's done
+ wait_for_operation(12);
+#else
+ // Send the server a restart signal, so it does
+ // housekeeping immediately, and wait for it to happen
+ // Wait for old connections to terminate
+ ::sleep(1);
::kill(pid, SIGHUP);
+#endif
+
// Get the revision number of the info file
int64_t first_revision = 0;
RaidFileRead::FileExists(0, "backup/01234567/o01", &first_revision);
@@ -649,7 +668,10 @@ int test(int argc, const char *argv[])
// Kill store server
TEST_THAT(KillServer(pid));
TEST_THAT(!ServerIsAlive(pid));
+
+ #ifndef WIN32
TestRemoteProcessMemLeaks("bbstored.memleaks");
+ #endif
}
::free(buffer);
diff --git a/test/backupstorepatch/testextra b/test/backupstorepatch/testextra
index be970ffa..4929c1be 100644
--- a/test/backupstorepatch/testextra
+++ b/test/backupstorepatch/testextra
@@ -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/test/basicserver/Makefile.extra b/test/basicserver/Makefile.extra
index 51280db9..3feda961 100644
--- a/test/basicserver/Makefile.extra
+++ b/test/basicserver/Makefile.extra
@@ -6,16 +6,16 @@ GEN_CMD_CLI = $(MAKEPROTOCOL) Client testprotocol.txt
# AUTOGEN SEEDING
autogen_TestProtocolServer.cpp: $(MAKEPROTOCOL) testprotocol.txt
- perl $(GEN_CMD_SRV)
+ $(PERL) $(GEN_CMD_SRV)
autogen_TestProtocolServer.h: $(MAKEPROTOCOL) testprotocol.txt
- perl $(GEN_CMD_SRV)
+ $(PERL) $(GEN_CMD_SRV)
# AUTOGEN SEEDING
autogen_TestProtocolClient.cpp: $(MAKEPROTOCOL) testprotocol.txt
- perl $(GEN_CMD_CLI)
+ $(PERL) $(GEN_CMD_CLI)
autogen_TestProtocolClient.h: $(MAKEPROTOCOL) testprotocol.txt
- perl $(GEN_CMD_CLI)
+ $(PERL) $(GEN_CMD_CLI)
diff --git a/test/basicserver/TestCommands.cpp b/test/basicserver/TestCommands.cpp
index d879ff9d..09626238 100644
--- a/test/basicserver/TestCommands.cpp
+++ b/test/basicserver/TestCommands.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.
@@ -39,7 +39,9 @@
#include "Box.h"
+#ifdef HAVE_SYSLOG_H
#include <syslog.h>
+#endif
#include "autogen_TestProtocolServer.h"
#include "CollectInBufferStream.h"
diff --git a/test/basicserver/TestContext.cpp b/test/basicserver/TestContext.cpp
index 8c99dde7..042c4d78 100644
--- a/test/basicserver/TestContext.cpp
+++ b/test/basicserver/TestContext.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/test/basicserver/TestContext.h b/test/basicserver/TestContext.h
index 27663e95..c606c72a 100644
--- a/test/basicserver/TestContext.h
+++ b/test/basicserver/TestContext.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/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp
index 9045b34b..90d4bb79 100644
--- a/test/basicserver/testbasicserver.cpp
+++ b/test/basicserver/testbasicserver.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,10 +66,10 @@
#include "TestContext.h"
#include "autogen_TestProtocolClient.h"
#include "autogen_TestProtocolServer.h"
+#include "ServerControl.h"
#include "MemLeakFindOn.h"
-
#define SERVER_LISTEN_PORT 2003
// in ms
@@ -100,10 +100,14 @@ void basicdaemon::Run()
void testservers_pause_before_reply()
{
- struct timespec t;
- t.tv_sec = 0;
- t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000; // convert to ns
- ::nanosleep(&t, NULL);
+#ifdef WIN32
+ Sleep(COMMS_SERVER_WAIT_BEFORE_REPLYING);
+#else
+ struct timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000; // convert to ns
+ ::nanosleep(&t, NULL);
+#endif
}
#define LARGE_DATA_BLOCK_SIZE 19870
@@ -160,6 +164,25 @@ void testservers_connection(SocketStream &rStream)
total += r;
}
TEST_THAT(total == LARGE_DATA_SIZE);
+ if (total != LARGE_DATA_SIZE)
+ {
+ BOX_ERROR("Expected " <<
+ LARGE_DATA_SIZE << " bytes " <<
+ "but was " << total);
+ return;
+ }
+ }
+ {
+ // Send lots of data again
+ char data[LARGE_DATA_BLOCK_SIZE];
+ for(unsigned int y = 0; y < sizeof(data); y++)
+ {
+ data[y] = y & 0xff;
+ }
+ for(int s = 0; s < (LARGE_DATA_SIZE / LARGE_DATA_BLOCK_SIZE); ++s)
+ {
+ rStream.Write(data, sizeof(data));
+ }
}
// next!
@@ -379,6 +402,18 @@ void Srv2TestConversations(const std::vector<IOStream *> &conns)
conns[c]->Write(data, sizeof(data));
}
}
+ for(unsigned int c = 0; c < conns.size(); ++c)
+ {
+ // Receive lots of data again
+ char buf[1024];
+ int total = 0;
+ int r = 0;
+ while(total < LARGE_DATA_SIZE && (r = conns[c]->Read(buf, sizeof(buf))) != 0)
+ {
+ total += r;
+ }
+ TEST_THAT(total == LARGE_DATA_SIZE);
+ }
for(unsigned int c = 0; c < conns.size(); ++c)
{
@@ -441,108 +476,184 @@ int test(int argc, const char *argv[])
// Server launching stuff
if(argc >= 2)
{
- if(strcmp(argv[1], "srv1") == 0)
+ // this is a quick hack to allow passing some options
+ // to the daemon
+
+ const char* mode = argv[1];
+
+ if (test_args.length() > 0)
+ {
+ argv[1] = test_args.c_str();
+ }
+ else
+ {
+ argc--;
+ argv++;
+ }
+
+ if(strcmp(mode, "srv1") == 0)
{
// Run very basic daemon
basicdaemon daemon;
- return daemon.Main("doesnotexist", argc - 1, argv + 1);
+ return daemon.Main("doesnotexist", argc, argv);
}
- else if(strcmp(argv[1], "srv2") == 0)
+ else if(strcmp(mode, "srv2") == 0)
{
// Run daemon which accepts connections
testserver daemon;
- return daemon.Main("doesnotexist", argc - 1, argv + 1);
+ return daemon.Main("doesnotexist", argc, argv);
}
- else if(strcmp(argv[1], "srv3") == 0)
+ else if(strcmp(mode, "srv3") == 0)
{
testTLSserver daemon;
- return daemon.Main("doesnotexist", argc - 1, argv + 1);
+ return daemon.Main("doesnotexist", argc, argv);
}
- else if(strcmp(argv[1], "srv4") == 0)
+ else if(strcmp(mode, "srv4") == 0)
{
testProtocolServer daemon;
- return daemon.Main("doesnotexist", argc - 1, argv + 1);
+ return daemon.Main("doesnotexist", argc, argv);
}
}
-//printf("SKIPPING TESTS------------------------\n");
-//goto protocolserver;
+ //printf("SKIPPING TESTS------------------------\n");
+ //goto protocolserver;
// Launch a basic server
{
- int pid = LaunchServer("./test srv1 testfiles/srv1.conf", "testfiles/srv1.pid");
+ std::string cmd = "./test --test-daemon-args=";
+ cmd += test_args;
+ cmd += " srv1 testfiles/srv1.conf";
+ int pid = LaunchServer(cmd, "testfiles/srv1.pid");
+
TEST_THAT(pid != -1 && pid != 0);
if(pid > 0)
{
// Check that it's written the expected file
- TEST_THAT(TestFileExists("testfiles/srv1.test1"));
+ TEST_THAT(TestFileExists("testfiles"
+ DIRECTORY_SEPARATOR "srv1.test1"));
TEST_THAT(ServerIsAlive(pid));
+
// Move the config file over
- TEST_THAT(::rename("testfiles/srv1b.conf", "testfiles/srv1.conf") != -1);
- // Get it to reread the config file
- TEST_THAT(HUPServer(pid));
- ::sleep(1);
- TEST_THAT(ServerIsAlive(pid));
- // Check that new file exists
- TEST_THAT(TestFileExists("testfiles/srv1.test2"));
+ #ifdef WIN32
+ TEST_THAT(::unlink("testfiles"
+ DIRECTORY_SEPARATOR "srv1.conf") != -1);
+ #endif
+
+ TEST_THAT(::rename(
+ "testfiles" DIRECTORY_SEPARATOR "srv1b.conf",
+ "testfiles" DIRECTORY_SEPARATOR "srv1.conf")
+ != -1);
+
+ #ifndef WIN32
+ // Get it to reread the config file
+ TEST_THAT(HUPServer(pid));
+ ::sleep(1);
+ TEST_THAT(ServerIsAlive(pid));
+ // Check that new file exists
+ TEST_THAT(TestFileExists("testfiles"
+ DIRECTORY_SEPARATOR "srv1.test2"));
+ #endif // !WIN32
+
// Kill it off
TEST_THAT(KillServer(pid));
- TestRemoteProcessMemLeaks("generic-daemon.memleaks");
+
+ #ifndef WIN32
+ TestRemoteProcessMemLeaks(
+ "generic-daemon.memleaks");
+ #endif // !WIN32
}
}
// Launch a test forking server
{
- int pid = LaunchServer("./test srv2 testfiles/srv2.conf", "testfiles/srv2.pid");
+ std::string cmd = "./test --test-daemon-args=";
+ cmd += test_args;
+ cmd += " srv2 testfiles/srv2.conf";
+ int pid = LaunchServer(cmd, "testfiles/srv2.pid");
+
TEST_THAT(pid != -1 && pid != 0);
+
if(pid > 0)
{
// Will it restart?
TEST_THAT(ServerIsAlive(pid));
- TEST_THAT(HUPServer(pid));
- ::sleep(1);
- TEST_THAT(ServerIsAlive(pid));
+
+ #ifndef WIN32
+ TEST_THAT(HUPServer(pid));
+ ::sleep(1);
+ TEST_THAT(ServerIsAlive(pid));
+ #endif // !WIN32
+
// Make some connections
{
SocketStream conn1;
conn1.Open(Socket::TypeINET, "localhost", 2003);
- SocketStream conn2;
- conn2.Open(Socket::TypeUNIX, "testfiles/srv2.sock");
- SocketStream conn3;
- conn3.Open(Socket::TypeINET, "localhost", 2003);
+
+ #ifndef WIN32
+ SocketStream conn2;
+ conn2.Open(Socket::TypeUNIX,
+ "testfiles/srv2.sock");
+ SocketStream conn3;
+ conn3.Open(Socket::TypeINET,
+ "localhost", 2003);
+ #endif // !WIN32
+
// Quick check that reconnections fail
- TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX, "testfiles/srv2.sock");, ServerException, SocketAlreadyOpen);
+ TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX,
+ "testfiles/srv2.sock");,
+ ServerException, SocketAlreadyOpen);
+
// Stuff some data around
std::vector<IOStream *> conns;
conns.push_back(&conn1);
- conns.push_back(&conn2);
- conns.push_back(&conn3);
+
+ #ifndef WIN32
+ conns.push_back(&conn2);
+ conns.push_back(&conn3);
+ #endif // !WIN32
+
Srv2TestConversations(conns);
// Implicit close
}
- // HUP again
- TEST_THAT(HUPServer(pid));
- ::sleep(1);
- TEST_THAT(ServerIsAlive(pid));
+
+ #ifndef WIN32
+ // HUP again
+ TEST_THAT(HUPServer(pid));
+ ::sleep(1);
+ TEST_THAT(ServerIsAlive(pid));
+ #endif // !WIN32
+
// Kill it
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
- TestRemoteProcessMemLeaks("test-srv2.memleaks");
+
+ #ifndef WIN32
+ TestRemoteProcessMemLeaks("test-srv2.memleaks");
+ #endif // !WIN32
}
}
// Launch a test SSL server
{
- int pid = LaunchServer("./test srv3 testfiles/srv3.conf", "testfiles/srv3.pid");
+ std::string cmd = "./test --test-daemon-args=";
+ cmd += test_args;
+ cmd += " srv3 testfiles/srv3.conf";
+ int pid = LaunchServer(cmd, "testfiles/srv3.pid");
+
TEST_THAT(pid != -1 && pid != 0);
+
if(pid > 0)
{
// Will it restart?
TEST_THAT(ServerIsAlive(pid));
- TEST_THAT(HUPServer(pid));
- ::sleep(1);
- TEST_THAT(ServerIsAlive(pid));
+
+ #ifndef WIN32
+ TEST_THAT(HUPServer(pid));
+ ::sleep(1);
+ TEST_THAT(ServerIsAlive(pid));
+ #endif
+
// Make some connections
{
// SSL library
@@ -557,37 +668,62 @@ int test(int argc, const char *argv[])
SocketStreamTLS conn1;
conn1.Open(context, Socket::TypeINET, "localhost", 2003);
- SocketStreamTLS conn2;
- conn2.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock");
- SocketStreamTLS conn3;
- conn3.Open(context, Socket::TypeINET, "localhost", 2003);
+ #ifndef WIN32
+ SocketStreamTLS conn2;
+ conn2.Open(context, Socket::TypeUNIX,
+ "testfiles/srv3.sock");
+ SocketStreamTLS conn3;
+ conn3.Open(context, Socket::TypeINET,
+ "localhost", 2003);
+ #endif
+
// Quick check that reconnections fail
- TEST_CHECK_THROWS(conn1.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock");, ServerException, SocketAlreadyOpen);
+ TEST_CHECK_THROWS(conn1.Open(context,
+ Socket::TypeUNIX,
+ "testfiles/srv3.sock");,
+ ServerException, SocketAlreadyOpen);
+
// Stuff some data around
std::vector<IOStream *> conns;
conns.push_back(&conn1);
- conns.push_back(&conn2);
- conns.push_back(&conn3);
+
+ #ifndef WIN32
+ conns.push_back(&conn2);
+ conns.push_back(&conn3);
+ #endif
+
Srv2TestConversations(conns);
// Implicit close
}
- // HUP again
- TEST_THAT(HUPServer(pid));
- ::sleep(1);
- TEST_THAT(ServerIsAlive(pid));
+
+ #ifndef WIN32
+ // HUP again
+ TEST_THAT(HUPServer(pid));
+ ::sleep(1);
+ TEST_THAT(ServerIsAlive(pid));
+ #endif
+
// Kill it
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
- TestRemoteProcessMemLeaks("test-srv3.memleaks");
+
+ #ifndef WIN32
+ TestRemoteProcessMemLeaks("test-srv3.memleaks");
+ #endif
}
}
//protocolserver:
// Launch a test protocol handling server
{
- int pid = LaunchServer("./test srv4 testfiles/srv4.conf", "testfiles/srv4.pid");
+ std::string cmd = "./test --test-daemon-args=";
+ cmd += test_args;
+ cmd += " srv4 testfiles/srv4.conf";
+ int pid = LaunchServer(cmd, "testfiles/srv4.pid");
+
TEST_THAT(pid != -1 && pid != 0);
+
if(pid > 0)
{
::sleep(1);
@@ -595,7 +731,11 @@ int test(int argc, const char *argv[])
// Open a connection to it
SocketStream conn;
- conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock");
+ #ifdef WIN32
+ conn.Open(Socket::TypeINET, "localhost", 2003);
+ #else
+ conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock");
+ #endif
// Create a protocol
TestProtocolClient protocol(conn);
@@ -658,7 +798,10 @@ int test(int argc, const char *argv[])
TEST_THAT(KillServer(pid));
::sleep(1);
TEST_THAT(!ServerIsAlive(pid));
- TestRemoteProcessMemLeaks("test-srv4.memleaks");
+
+ #ifndef WIN32
+ TestRemoteProcessMemLeaks("test-srv4.memleaks");
+ #endif
}
}
diff --git a/test/basicserver/testfiles/srv4.conf b/test/basicserver/testfiles/srv4.conf
index b4c5627c..f05dff75 100644
--- a/test/basicserver/testfiles/srv4.conf
+++ b/test/basicserver/testfiles/srv4.conf
@@ -1,6 +1,6 @@
Server
{
PidFile = testfiles/srv4.pid
- ListenAddresses = unix:testfiles/srv4.sock
+ ListenAddresses = unix:testfiles/srv4.sock,inet:localhost
}
diff --git a/test/bbackupd/Makefile.extra b/test/bbackupd/Makefile.extra
new file mode 100644
index 00000000..1d3f5103
--- /dev/null
+++ b/test/bbackupd/Makefile.extra
@@ -0,0 +1 @@
+link-extra: ../../bin/bbackupd/autogen_ClientException.o ../../bin/bbackupd/BackupClientContext.o ../../bin/bbackupd/BackupClientDeleteList.o ../../bin/bbackupd/BackupClientDirectoryRecord.o ../../bin/bbackupd/Win32BackupService.o ../../bin/bbackupd/BackupClientInodeToIDMap.o ../../bin/bbackupd/Win32ServiceFunctions.o ../../bin/bbackupd/BackupDaemon.o
diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp
index a085a96c..0447bc9c 100644
--- a/test/bbackupd/testbbackupd.cpp
+++ b/test/bbackupd/testbbackupd.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,38 +47,65 @@
#include "Box.h"
+// do not include MinGW's dirent.h on Win32,
+// as we override some of it in lib/win32.
+
+#ifndef WIN32
+ #include <dirent.h>
+#endif
+
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
-#include <sys/wait.h>
#include <unistd.h>
+
+#ifdef HAVE_SYS_WAIT_H
+ #include <sys/wait.h>
+#endif
+
#ifdef HAVE_SYS_XATTR_H
-#include <cerrno>
-#include <sys/xattr.h>
+ #include <cerrno>
+ #include <sys/xattr.h>
#endif
+
#include <map>
-#include "Test.h"
+#ifdef HAVE_SYSCALL
+ #include <sys/syscall.h>
+#endif
+
+#include "BackupClientCryptoKeys.h"
#include "BackupClientFileAttributes.h"
-#include "CommonException.h"
+#include "BackupClientRestore.h"
+#include "BackupDaemon.h"
+#include "BackupDaemonConfigVerify.h"
+#include "BackupStoreConstants.h"
+#include "BackupStoreDirectory.h"
#include "BackupStoreException.h"
+#include "BoxPortsAndFiles.h"
+#include "BoxTime.h"
+#include "BoxTimeToUnix.h"
+#include "CollectInBufferStream.h"
+#include "CommonException.h"
+#include "Configuration.h"
#include "FileModificationTime.h"
-#include "autogen_BackupProtocolClient.h"
+#include "FileStream.h"
+#include "IOStreamGetLine.h"
+#include "LocalProcessStream.h"
#include "SSLLib.h"
-#include "TLSContext.h"
-#include "SocketStreamTLS.h"
-#include "BoxPortsAndFiles.h"
-#include "BackupStoreConstants.h"
+#include "ServerControl.h"
#include "Socket.h"
-#include "BackupClientRestore.h"
-#include "BackupStoreDirectory.h"
-#include "BackupClientCryptoKeys.h"
-#include "CollectInBufferStream.h"
+#include "SocketStreamTLS.h"
+#include "TLSContext.h"
+#include "Test.h"
+#include "Timer.h"
#include "Utils.h"
-#include "BoxTime.h"
-#include "BoxTimeToUnix.h"
+
+#include "autogen_BackupProtocolClient.h"
+#include "intercept.h"
+#include "ServerControl.h"
#include "MemLeakFindOn.h"
@@ -90,20 +117,34 @@
// two cycles and a bit
#define TIME_TO_WAIT_FOR_BACKUP_OPERATION 12
+// utility macro for comparing two strings in a line
+#define TEST_EQUAL(expected, found, line) \
+{ \
+ std::string exp_str = expected; \
+ std::string found_str = found; \
+ TEST_THAT(exp_str == found_str); \
+ if(exp_str != found_str) \
+ { \
+ printf("Expected <%s> but found <%s> in <%s>\n", \
+ exp_str.c_str(), found_str.c_str(), line.c_str()); \
+ } \
+}
+
+// utility macro for testing a line
+#define TEST_LINE(condition, line) \
+ TEST_THAT(condition); \
+ if (!(condition)) \
+ { \
+ printf("Test failed on <%s>\n", line.c_str()); \
+ }
+
void wait_for_backup_operation(int seconds = TIME_TO_WAIT_FOR_BACKUP_OPERATION)
{
- printf("waiting: ");
- fflush(stdout);
- for(int l = 0; l < seconds; ++l)
- {
- sleep(1);
- printf(".");
- fflush(stdout);
- }
- printf("\n");
+ wait_for_operation(seconds);
}
int bbstored_pid = 0;
+int bbackupd_pid = 0;
#ifdef HAVE_SYS_XATTR_H
bool readxattr_into_map(const char *filename, std::map<std::string,std::string> &rOutput)
@@ -290,6 +331,9 @@ bool attrmatch(const char *f1, const char *f2)
// if link, just make sure other file is a link too, and that the link to names match
if((s1.st_mode & S_IFMT) == S_IFLNK)
{
+#ifdef WIN32
+ TEST_FAIL_WITH_MESSAGE("No symlinks on win32!")
+#else
if((s2.st_mode & S_IFMT) != S_IFLNK) return false;
char p1[PATH_MAX], p2[PATH_MAX];
@@ -300,6 +344,7 @@ bool attrmatch(const char *f1, const char *f2)
p1[p1l] = '\0';
p2[p2l] = '\0';
return strcmp(p1, p2) == 0;
+#endif
}
// modification times
@@ -318,12 +363,15 @@ int test_basics()
BackupClientFileAttributes t1;
t1.ReadAttributes("testfiles/test1");
TEST_THAT(!t1.IsSymLink());
+
+#ifndef WIN32
BackupClientFileAttributes t2;
t2.ReadAttributes("testfiles/test2");
TEST_THAT(t2.IsSymLink());
// Check that it's actually been encrypted (search for symlink name encoded in it)
void *te = ::memchr(t2.GetBuffer(), 't', t2.GetSize() - 3);
TEST_THAT(te == 0 || ::memcmp(te, "test", 4) != 0);
+#endif
BackupClientFileAttributes t3;
TEST_CHECK_THROWS(t3.ReadAttributes("doesn't exist"), CommonException, OSFileError);
@@ -336,13 +384,20 @@ int test_basics()
// Apply attributes to these new files
t1.WriteAttributes("testfiles/test1_n");
+#ifdef WIN32
+ t1.WriteAttributes("testfiles/test2_n");
+#else
t2.WriteAttributes("testfiles/test2_n");
+#endif
+
+#ifndef WIN32
TEST_CHECK_THROWS(t1.WriteAttributes("testfiles/test1_nXX"), CommonException, OSFileError);
TEST_CHECK_THROWS(t3.WriteAttributes("doesn't exist"), BackupStoreException, AttributesNotLoaded);
- // Test that atttributes are vaguely similar
+ // Test that attributes are vaguely similar
TEST_THAT(attrmatch("testfiles/test1", "testfiles/test1_n"));
TEST_THAT(attrmatch("testfiles/test2", "testfiles/test2_n"));
+#endif
// Check encryption, and recovery from encryption
// First, check that two attributes taken from the same thing have different encrypted values (think IV)
@@ -415,18 +470,22 @@ int test_basics()
int test_setupaccount()
{
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 1000B 2000B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
+ "testfiles/bbstored.conf create 01234567 0 1000B 2000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
return 0;
}
int test_run_bbstored()
{
- bbstored_pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid");
+ std::string cmd = BBSTORED + bbstored_args + " testfiles/bbstored.conf";
+ bbstored_pid = LaunchServer(cmd, "testfiles/bbstored.pid");
+
TEST_THAT(bbstored_pid != -1 && bbstored_pid != 0);
+
if(bbstored_pid > 0)
{
- ::sleep(1);
+ ::safe_sleep(1);
TEST_THAT(ServerIsAlive(bbstored_pid));
return 0; // success
}
@@ -437,9 +496,13 @@ int test_run_bbstored()
int test_kill_bbstored()
{
TEST_THAT(KillServer(bbstored_pid));
- ::sleep(1);
+ ::safe_sleep(1);
TEST_THAT(!ServerIsAlive(bbstored_pid));
- TestRemoteProcessMemLeaks("bbstored.memleaks");
+
+ #ifndef WIN32
+ TestRemoteProcessMemLeaks("bbstored.memleaks");
+ #endif
+
return 0;
}
@@ -475,6 +538,7 @@ void terminate_on_alarm(int sigraised)
abort();
}
+#ifndef WIN32
void do_interrupted_restore(const TLSContext &context, int64_t restoredirid)
{
int pid = 0;
@@ -537,12 +601,242 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid)
}
}
}
+#endif // !WIN32
+
+#ifdef WIN32
+bool set_file_time(const char* filename, FILETIME creationTime,
+ FILETIME lastModTime, FILETIME lastAccessTime)
+{
+ HANDLE handle = openfile(filename, O_RDWR, 0);
+ TEST_THAT(handle != INVALID_HANDLE_VALUE);
+ if (handle == INVALID_HANDLE_VALUE) return false;
+
+ BOOL success = SetFileTime(handle, &creationTime, &lastAccessTime,
+ &lastModTime);
+ TEST_THAT(success);
+
+ TEST_THAT(CloseHandle(handle));
+ return success;
+}
+#endif
+
+void intercept_setup_delay(const char *filename, unsigned int delay_after,
+ int delay_ms, int syscall_to_delay);
+bool intercept_triggered();
+
+int64_t SearchDir(BackupStoreDirectory& rDir,
+ const std::string& rChildName)
+{
+ BackupStoreDirectory::Iterator i(rDir);
+ BackupStoreFilenameClear child(rChildName.c_str());
+ BackupStoreDirectory::Entry *en = i.FindMatchingClearName(child);
+ if (en == 0) return 0;
+ int64_t id = en->GetObjectID();
+ TEST_THAT(id > 0);
+ TEST_THAT(id != BackupProtocolClientListDirectory::RootDirectory);
+ return id;
+}
+
+SocketStreamTLS sSocket;
+
+std::auto_ptr<BackupProtocolClient> Connect(TLSContext& rContext, int flags)
+{
+ sSocket.Open(rContext, Socket::TypeINET,
+ "localhost", BOX_PORT_BBSTORED);
+ std::auto_ptr<BackupProtocolClient> connection;
+ connection.reset(new BackupProtocolClient(sSocket));
+ connection->Handshake();
+ std::auto_ptr<BackupProtocolClientVersion>
+ serverVersion(connection->QueryVersion(
+ BACKUP_STORE_SERVER_VERSION));
+ if(serverVersion->GetVersion() !=
+ BACKUP_STORE_SERVER_VERSION)
+ {
+ THROW_EXCEPTION(BackupStoreException,
+ WrongServerVersion);
+ }
+ connection->QueryLogin(0x01234567, flags);
+ return connection;
+}
+
+std::auto_ptr<BackupStoreDirectory> ReadDirectory
+(
+ BackupProtocolClient& rClient,
+ int64_t id
+)
+{
+ std::auto_ptr<BackupProtocolClientSuccess> dirreply(
+ rClient.QueryListDirectory(id, false, 0, false));
+ std::auto_ptr<IOStream> dirstream(rClient.ReceiveStream());
+ std::auto_ptr<BackupStoreDirectory> apDir(new BackupStoreDirectory());
+ apDir->ReadFromStream(*dirstream, rClient.GetTimeout());
+ return apDir;
+}
+
+int start_internal_daemon()
+{
+ // ensure that no child processes end up running tests!
+ int own_pid = getpid();
+
+ // this is a quick hack to allow passing some options to the daemon
+ const char* argv[] = {
+ "dummy",
+ bbackupd_args.c_str(),
+ };
+
+ BackupDaemon daemon;
+ int result;
+
+ if (bbackupd_args.size() > 0)
+ {
+ result = daemon.Main("testfiles/bbackupd.conf", 2, argv);
+ }
+ else
+ {
+ result = daemon.Main("testfiles/bbackupd.conf", 1, argv);
+ }
+
+ TEST_THAT(result == 0);
+ if (result != 0)
+ {
+ printf("Daemon exited with code %d\n", result);
+ }
+
+ // ensure that no child processes end up running tests!
+ TEST_THAT(getpid() == own_pid);
+ if (getpid() != own_pid)
+ {
+ // abort!
+ _exit(1);
+ }
+
+ TEST_THAT(TestFileExists("testfiles/bbackupd.pid"));
+
+ printf("Waiting for backup daemon to start: ");
+ int pid = -1;
+
+ for (int i = 0; i < 30; i++)
+ {
+ printf(".");
+ fflush(stdout);
+ safe_sleep(1);
+
+ if (TestFileExists("testfiles/bbackupd.pid"))
+ {
+ pid = ReadPidFile("testfiles/bbackupd.pid");
+ }
+
+ if (pid > 0)
+ {
+ break;
+ }
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+
+ TEST_THAT(pid > 0);
+ return pid;
+}
+
+bool stop_internal_daemon(int pid)
+{
+ bool killed_server = KillServer(pid);
+ TEST_THAT(killed_server);
+ return killed_server;
+
+ /*
+ int status;
+ TEST_THAT(waitpid(pid, &status, 0) == pid);
+ TEST_THAT(WIFEXITED(status));
+
+ if (WIFEXITED(status))
+ {
+ TEST_THAT(WEXITSTATUS(status) == 0);
+ }
+ */
+}
+
+static struct dirent readdir_test_dirent;
+static int readdir_test_counter = 0;
+static int readdir_stop_time = 0;
+static char stat_hook_filename[512];
+
+// First test hook, during the directory scanning stage, returns empty.
+// This will not match the directory on the store, so a sync will start.
+// We set up the next intercept for the same directory by passing NULL.
+
+struct dirent *readdir_test_hook_2(DIR *dir);
+
+#ifdef LINUX_WEIRD_LSTAT
+int lstat_test_hook(int ver, const char *file_name, struct stat *buf);
+#else
+int lstat_test_hook(const char *file_name, struct stat *buf);
+#endif
+
+struct dirent *readdir_test_hook_1(DIR *dir)
+{
+#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ intercept_setup_readdir_hook(NULL, readdir_test_hook_2);
+#endif
+ return NULL;
+}
+
+// Second test hook, during the directory sync stage, keeps returning
+// new filenames until the timer expires, then disables the intercept.
+
+struct dirent *readdir_test_hook_2(DIR *dir)
+{
+ if (time(NULL) >= readdir_stop_time)
+ {
+#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ intercept_setup_readdir_hook(NULL, NULL);
+ intercept_setup_lstat_hook (NULL, NULL);
+ // we will not be called again.
+#endif
+ }
+
+ // fill in the struct dirent appropriately
+ memset(&readdir_test_dirent, 0, sizeof(readdir_test_dirent));
+
+ #ifdef HAVE_STRUCT_DIRENT_D_INO
+ readdir_test_dirent.d_ino = ++readdir_test_counter;
+ #endif
+
+ snprintf(readdir_test_dirent.d_name,
+ sizeof(readdir_test_dirent.d_name),
+ "test.%d", readdir_test_counter);
+
+ // ensure that when bbackupd stats the file, it gets the
+ // right answer
+ snprintf(stat_hook_filename, sizeof(stat_hook_filename),
+ "testfiles/TestDir1/spacetest/d1/test.%d",
+ readdir_test_counter);
+
+#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ intercept_setup_lstat_hook(stat_hook_filename, lstat_test_hook);
+#endif
+
+ return &readdir_test_dirent;
+}
+#ifdef LINUX_WEIRD_LSTAT
+int lstat_test_hook(int ver, const char *file_name, struct stat *buf)
+#else
+int lstat_test_hook(const char *file_name, struct stat *buf)
+#endif
+{
+ // TRACE1("lstat hook triggered for %s", file_name);
+ memset(buf, 0, sizeof(*buf));
+ buf->st_mode = S_IFREG;
+ return 0;
+}
int test_bbackupd()
{
-// // First, wait for a normal period to make sure the last changes attributes are within a normal backup timeframe.
-// wait_for_backup_operation();
+ // First, wait for a normal period to make sure the last changes
+ // attributes are within a normal backup timeframe.
+ // wait_for_backup_operation();
// Connection gubbins
TLSContext context;
@@ -553,39 +847,553 @@ int test_bbackupd()
// unpack the files for the initial test
TEST_THAT(::system("rm -rf testfiles/TestDir1") == 0);
- TEST_THAT(::system("mkdir testfiles/TestDir1") == 0);
- TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0);
+ TEST_THAT(::mkdir("testfiles/TestDir1", 0777) == 0);
+
+ #ifdef WIN32
+ TEST_THAT(::system("tar xzvf testfiles/spacetest1.tgz "
+ "-C testfiles/TestDir1") == 0);
+ #else
+ TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz "
+ "| ( cd testfiles/TestDir1 && tar xf - )") == 0);
+ #endif
+
+#ifdef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ printf("\n==== Skipping intercept-based KeepAlive tests "
+ "on this platform.\n");
+#else
+ printf("\n==== Testing SSL KeepAlive messages\n");
- int pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid");
- TEST_THAT(pid != -1 && pid != 0);
- if(pid > 0)
{
- ::sleep(1);
- TEST_THAT(ServerIsAlive(pid));
+ #ifdef WIN32
+ #error TODO: implement threads on Win32, or this test \
+ will not finish properly
+ #endif
+
+ // bbackupd daemon will try to initialise timers itself
+ Timers::Cleanup();
+
+ // something to diff against (empty file doesn't work)
+ int fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+
+ char buffer[10000];
+ memset(buffer, 0, sizeof(buffer));
+
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ int pid = start_internal_daemon();
+ wait_for_backup_operation();
+ TEST_THAT(stop_internal_daemon(pid));
+
+ // two-second delay on the first read() of f1
+ // should mean that a single keepalive is sent,
+ // and diff does not abort.
+ intercept_setup_delay("testfiles/TestDir1/spacetest/f1",
+ 0, 2000, SYS_read, 1);
+ TEST_THAT(unlink("testfiles/bbackupd.log") == 0);
+
+ pid = start_internal_daemon();
+
+ fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ wait_for_backup_operation();
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ TEST_THAT(stop_internal_daemon(pid));
+
+ // check that keepalive was written to logs, and
+ // diff was not aborted, i.e. upload was a diff
+ FileStream fs("testfiles/bbackupd.log", O_RDONLY);
+ IOStreamGetLine reader(fs);
+ bool found1 = false;
+
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
+ {
+ found1 = true;
+ break;
+ }
+ }
+
+ TEST_THAT(found1);
+ if (found1)
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ std::string comp = "Receive Success(0x";
+ TEST_EQUAL(comp, line.substr(0, comp.size()), line);
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Receiving stream, size 124", line, line);
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Send GetIsAlive()", line, line);
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Receive IsAlive()", line, line);
+
+ TEST_THAT(reader.GetLine(line));
+ comp = "Send StoreFile(0x3,";
+ TEST_EQUAL(comp, line.substr(0, comp.size()), line);
+ comp = ",\"f1\")";
+ std::string sub = line.substr(line.size() - comp.size());
+ TEST_EQUAL(comp, sub, line);
+ std::string comp2 = ",0x0,";
+ sub = line.substr(line.size() - comp.size() -
+ comp2.size() + 1, comp2.size());
+ TEST_LINE(comp2 != sub, line);
+ }
+
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ Timers::Init();
+ return 1;
+ }
+
+ // four-second delay on first read() of f1
+ // should mean that no keepalives were sent,
+ // because diff was immediately aborted
+ // before any matching blocks could be found.
+ intercept_setup_delay("testfiles/TestDir1/spacetest/f1",
+ 0, 4000, SYS_read, 1);
+ pid = start_internal_daemon();
+
+ fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ wait_for_backup_operation();
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ TEST_THAT(stop_internal_daemon(pid));
+
+ // check that the diff was aborted, i.e. upload was not a diff
+ found1 = false;
+
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
+ {
+ found1 = true;
+ break;
+ }
+ }
+
+ TEST_THAT(found1);
+ if (found1)
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ std::string comp = "Receive Success(0x";
+ TEST_THAT(line.substr(0, comp.size()) == comp);
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receiving stream, size 124");
+
+ // delaying for 4 seconds in one step means that
+ // the diff timer and the keepalive timer will
+ // both expire, and the diff timer is honoured first,
+ // so there will be no keepalives.
+
+ TEST_THAT(reader.GetLine(line));
+ comp = "Send StoreFile(0x3,";
+ TEST_EQUAL(comp, line.substr(0, comp.size()), line);
+ comp = ",0x0,\"f1\")";
+ std::string sub = line.substr(line.size() - comp.size());
+ TEST_EQUAL(comp, sub, line);
+ }
+
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ Timers::Init();
+ return 1;
+ }
+
+ intercept_setup_delay("testfiles/TestDir1/spacetest/f1",
+ 0, 1000, SYS_read, 3);
+ pid = start_internal_daemon();
+
+ fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
+
+ wait_for_backup_operation();
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ TEST_THAT(stop_internal_daemon(pid));
+
+ // check that the diff was aborted, i.e. upload was not a diff
+ found1 = false;
+
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send GetBlockIndexByName(0x3,\"f1\")")
+ {
+ found1 = true;
+ break;
+ }
+ }
+
+ TEST_THAT(found1);
+ if (found1)
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ std::string comp = "Receive Success(0x";
+ TEST_THAT(line.substr(0, comp.size()) == comp);
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receiving stream, size 124");
+
+ // delaying for 3 seconds in steps of 1 second
+ // means that the keepalive timer will expire 3 times,
+ // and on the 3rd time the diff timer will expire too.
+ // The diff timer is honoured first, so there will be
+ // only two keepalives.
+
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Send GetIsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive IsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Send GetIsAlive()");
+ TEST_THAT(reader.GetLine(line));
+ TEST_THAT(line == "Receive IsAlive()");
+
+ // but two matching blocks should have been found
+ // already, so the upload should be a diff.
+
+ TEST_THAT(reader.GetLine(line));
+ comp = "Send StoreFile(0x3,";
+ TEST_EQUAL(comp, line.substr(0, comp.size()), line);
+ comp = ",\"f1\")";
+ std::string sub = line.substr(line.size() - comp.size());
+ TEST_EQUAL(comp, sub, line);
+ std::string comp2 = ",0x0,";
+ sub = line.substr(line.size() - comp.size() -
+ comp2.size() + 1, comp2.size());
+ TEST_LINE(comp2 != sub, line);
+ }
+
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ Timers::Init();
+ return 1;
+ }
+
+ intercept_setup_readdir_hook("testfiles/TestDir1/spacetest/d1",
+ readdir_test_hook_1);
+
+ // time for at least two keepalives
+ readdir_stop_time = time(NULL) + 12 + 2;
+
+ pid = start_internal_daemon();
+
+ std::string touchfile =
+ "testfiles/TestDir1/spacetest/d1/touch-me";
+
+ fd = open(touchfile.c_str(), O_CREAT | O_WRONLY);
+ TEST_THAT(fd > 0);
+ // write again, to update the file's timestamp
+ TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd) == 0);
- // First, check storage space handling -- wait for file to be uploaded
wait_for_backup_operation();
- //TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf info 01234567") == 0);
+ // can't test whether intercept was triggered, because
+ // it's in a different process.
+ // TEST_THAT(intercept_triggered());
+ TEST_THAT(stop_internal_daemon(pid));
+
+ // check that keepalives were sent during the dir search
+ found1 = false;
+
+ // skip to next login
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send ListDirectory(0x3,0xffffffff,0xc,true)")
+ {
+ found1 = true;
+ break;
+ }
+ }
+
+ TEST_THAT(found1);
+ if (found1)
+ {
+ found1 = false;
+
+ while (!reader.IsEOF())
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ if (line == "Send ListDirectory(0x3,0xffffffff,0xc,true)")
+ {
+ found1 = true;
+ break;
+ }
+ }
+ }
+
+ if (found1)
+ {
+ std::string line;
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Receive Success(0x3)", line, line);
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Receiving stream, size 425", line, line);
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Send GetIsAlive()", line, line);
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Receive IsAlive()", line, line);
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Send GetIsAlive()", line, line);
+ TEST_THAT(reader.GetLine(line));
+ TEST_EQUAL("Receive IsAlive()", line, line);
+ }
+
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ Timers::Init();
+ return 1;
+ }
+
+ TEST_THAT(unlink(touchfile.c_str()) == 0);
+
+ // restore timers for rest of tests
+ Timers::Init();
+ }
+#endif // PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+
+ std::string cmd = BBACKUPD " " + bbackupd_args +
+ " testfiles/bbackupd-temploc.conf";
+
+ bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
+ TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
+ ::safe_sleep(1);
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Testing that absolute symlinks are not followed "
+ "during restore\n");
+
+ {
+ #define SYM_DIR "testfiles" DIRECTORY_SEPARATOR "TestDir1" \
+ DIRECTORY_SEPARATOR "symlink_test"
+
+ TEST_THAT(::mkdir(SYM_DIR, 0777) == 0);
+ TEST_THAT(::mkdir(SYM_DIR DIRECTORY_SEPARATOR "a", 0777) == 0);
+ TEST_THAT(::mkdir(SYM_DIR DIRECTORY_SEPARATOR "a"
+ DIRECTORY_SEPARATOR "subdir", 0777) == 0);
+ TEST_THAT(::mkdir(SYM_DIR DIRECTORY_SEPARATOR "b", 0777) == 0);
+
+ FILE* fp = fopen(SYM_DIR DIRECTORY_SEPARATOR "a"
+ DIRECTORY_SEPARATOR "subdir"
+ DIRECTORY_SEPARATOR "content", "w");
+ TEST_THAT(fp != NULL);
+ fputs("before\n", fp);
+ fclose(fp);
+
+ char buf[PATH_MAX];
+ TEST_THAT(getcwd(buf, sizeof(buf)) != NULL);
+ std::string path = buf;
+ path += DIRECTORY_SEPARATOR SYM_DIR
+ DIRECTORY_SEPARATOR "a"
+ DIRECTORY_SEPARATOR "subdir";
+ TEST_THAT(symlink(path.c_str(), SYM_DIR
+ DIRECTORY_SEPARATOR "b"
+ DIRECTORY_SEPARATOR "link") == 0);
+
+ ::wait_for_operation(4);
+ ::sync_and_wait();
+
+ // Check that the backup was successful, i.e. no differences
+ int compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query1.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // now stop bbackupd and update the test file,
+ // make the original directory unreadable
+ terminate_bbackupd(bbackupd_pid);
+
+ fp = fopen(SYM_DIR DIRECTORY_SEPARATOR "a"
+ DIRECTORY_SEPARATOR "subdir"
+ DIRECTORY_SEPARATOR "content", "w");
+ TEST_THAT(fp != NULL);
+ fputs("after\n", fp);
+ fclose(fp);
+
+ TEST_THAT(chmod(SYM_DIR, 0) == 0);
+
+ // check that we can restore it
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-q \"restore Test1 testfiles/restore-symlink\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 0);
+
+ // make it accessible again
+ TEST_THAT(chmod(SYM_DIR, 0755) == 0);
+
+ // check that the original file was not overwritten
+ FileStream fs(SYM_DIR "/a/subdir/content");
+ IOStreamGetLine gl(fs);
+ std::string line;
+ TEST_THAT(gl.GetLine(line));
+ TEST_THAT(line != "before");
+ TEST_THAT(line == "after");
+
+ #undef SYM_DIR
+
+ bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
+ TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
+ ::safe_sleep(1);
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+ }
+
+ printf("\n==== Testing that redundant locations are deleted on time\n");
+
+ {
+ std::auto_ptr<BackupProtocolClient> client = Connect(
+ context,
+ BackupProtocolClientLogin::Flags_ReadOnly);
+
+ std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory(
+ *client,
+ BackupProtocolClientListDirectory::RootDirectory);
+
+ // int64_t testDirId = SearchDir(*dir, "Test2");
+ // TEST_THAT(testDirId == 0);
+
+ sync_and_wait();
+
+ dir = ReadDirectory(*client,
+ BackupProtocolClientListDirectory::RootDirectory);
+ int64_t testDirId = SearchDir(*dir, "Test2");
+ TEST_THAT(testDirId != 0);
+
+ // Kill the daemon
+ terminate_bbackupd(bbackupd_pid);
+
+ cmd = BBACKUPD " " + bbackupd_args +
+ " testfiles/bbackupd.conf";
+ bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
+
+ TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
+
+ ::safe_sleep(1);
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // Test2 should be deleted after 10 seconds (4 runs)
+ wait_for_sync_end();
+ wait_for_sync_end();
+ wait_for_sync_end();
+
+ dir = ReadDirectory(*client,
+ BackupProtocolClientListDirectory::RootDirectory);
+ testDirId = SearchDir(*dir, "Test2");
+ TEST_THAT(testDirId != 0);
+
+ wait_for_sync_end();
+
+ dir = ReadDirectory(*client,
+ BackupProtocolClientListDirectory::RootDirectory);
+ testDirId = SearchDir(*dir, "Test2");
+ TEST_THAT(testDirId != 0);
+
+ BackupStoreDirectory::Iterator i(*dir);
+ BackupStoreFilenameClear dirname("Test2");
+ BackupStoreDirectory::Entry *en = i.FindMatchingClearName(dirname);
+ TEST_THAT(en != 0);
+ int16_t en_flags = en->GetFlags();
+ TEST_THAT(en_flags && BackupStoreDirectory::Entry::Flags_Deleted);
+
+ // Log out.
+ client->QueryFinished();
+ sSocket.Close();
+ }
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ if(bbackupd_pid > 0)
+ {
+ printf("\n==== Testing that backup pauses when store is full\n");
+
+ // wait for files to be uploaded
+ wait_for_backup_operation();
+
// Set limit to something very small
- // About 28 blocks will be used at this point. bbackupd will only pause if the size used is
- // greater than soft limit + 1/3 of (hard - soft). Set small values for limits accordingly.
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 40B") == 0);
+ // About 28 blocks will be used at this point. bbackupd
+ // will only pause if the size used is greater than
+ // soft limit + 1/3 of (hard - soft). Set small values
+ // for limits accordingly.
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
+ "testfiles/bbstored.conf setlimit 01234567 9B 10B")
+ == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Unpack some more files
- TEST_THAT(::system("gzip -d < testfiles/spacetest2.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0);
+ #ifdef WIN32
+ TEST_THAT(::system("tar xzvf testfiles/spacetest2.tgz "
+ "-C testfiles/TestDir1") == 0);
+ #else
+ TEST_THAT(::system("gzip -d < testfiles/spacetest2.tgz "
+ "| ( cd testfiles/TestDir1 && tar xf - )") == 0);
+ #endif
+
// Delete a file and a directory
TEST_THAT(::unlink("testfiles/TestDir1/spacetest/d1/f3") == 0);
TEST_THAT(::system("rm -rf testfiles/TestDir1/spacetest/d3/d4") == 0);
wait_for_backup_operation();
// Make sure there are some differences
- int compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query0a.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 2*256);
+ int compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query0a.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 2);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
// Put the limit back
- TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 1000B 2000B") == 0);
+ TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c "
+ "testfiles/bbstored.conf setlimit 01234567 "
+ "1000B 2000B") == 0);
TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
// Check that the notify script was run
@@ -594,185 +1402,1069 @@ int test_bbackupd()
TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2"));
// unpack the initial files again
- TEST_THAT(::system("gzip -d < testfiles/test_base.tgz | ( cd testfiles && tar xf - )") == 0);
+ #ifdef WIN32
+ TEST_THAT(::system("tar xzvf testfiles/test_base.tgz "
+ "-C testfiles") == 0);
+ #else
+ TEST_THAT(::system("gzip -d < testfiles/test_base.tgz "
+ "| ( cd testfiles && tar xf - )") == 0);
+ #endif
// wait for it to do it's stuff
wait_for_backup_operation();
- // Check that the contents of the store are the same as the contents
- // of the disc (-a = all, -c = give result in return code)
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query1.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ // Check that the contents of the store are the same
+ // as the contents of the disc
+ // (-a = all, -c = give result in return code)
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query1.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+
+ printf("\n==== Check that read-only directories and "
+ "their contents can be restored.\n");
+
+ {
+ #ifdef WIN32
+ TEST_THAT(::system("chmod 0555 testfiles/"
+ "TestDir1/x1") == 0);
+ #else
+ TEST_THAT(chmod("testfiles/TestDir1/x1",
+ 0555) == 0);
+ #endif
+
+ wait_for_sync_end(); // too new
+ wait_for_sync_end(); // should be backed up now
+
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-q \"compare -cEQ Test1 testfiles/TestDir1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // check that we can restore it
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-q \"restore Test1 testfiles/restore1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 0);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // check that it restored properly
+ compareReturnValue = ::system(BBACKUPQUERY " "
+ "-c testfiles/bbackupd.conf "
+ "-q \"compare -cEQ Test1 testfiles/restore1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // put the permissions back to sensible values
+ #ifdef WIN32
+ TEST_THAT(::system("chmod 0755 testfiles/"
+ "TestDir1/x1") == 0);
+ #else
+ TEST_THAT(chmod("testfiles/TestDir1/x1",
+ 0755) == 0);
+ #endif
+
+ }
+
+#ifdef WIN32
+ printf("\n==== Check that filenames in UTF-8 "
+ "can be backed up\n");
+
+ // We have no guarantee that a random Unicode string can be
+ // represented in the user's character set, so we go the
+ // other way, taking three random characters from the
+ // character set and converting them to Unicode.
+ //
+ // We hope that these characters are valid in most
+ // character sets, but they probably are not in multibyte
+ // character sets such as Shift-JIS, GB2312, etc. This test
+ // will probably fail if your system locale is set to
+ // Chinese, Japanese, etc. where one of these character
+ // sets is used by default. You can check the character
+ // set for your system in Control Panel -> Regional
+ // Options -> General -> Language Settings -> Set Default
+ // (System Locale). Because bbackupquery converts from
+ // system locale to UTF-8 via the console code page
+ // (which you can check from the Command Prompt with "chcp")
+ // they must also be valid in your code page (850 for
+ // Western Europe).
+ //
+ // In ISO-8859-1 (Danish locale) they are three Danish
+ // accented characters, which are supported in code page
+ // 850. Depending on your locale, YYMV (your yak may vomit).
+
+ std::string foreignCharsNative("\x91\x9b\x86");
+ std::string foreignCharsUnicode;
+ TEST_THAT(ConvertConsoleToUtf8(foreignCharsNative.c_str(),
+ foreignCharsUnicode));
+
+ std::string basedir("testfiles/TestDir1");
+ std::string dirname("test" + foreignCharsUnicode + "testdir");
+ std::string dirpath(basedir + "/" + dirname);
+ TEST_THAT(mkdir(dirpath.c_str(), 0) == 0);
+
+ std::string filename("test" + foreignCharsUnicode + "testfile");
+ std::string filepath(dirpath + "/" + filename);
+
+ char cwdbuf[1024];
+ TEST_THAT(getcwd(cwdbuf, sizeof(cwdbuf)) == cwdbuf);
+ std::string cwd = cwdbuf;
+
+ // Test that our emulated chdir() works properly
+ // with relative and absolute paths
+ TEST_THAT(::chdir(dirpath.c_str()) == 0);
+ TEST_THAT(::chdir("../../..") == 0);
+ TEST_THAT(::chdir(cwd.c_str()) == 0);
+
+ // Check that it can be converted to the system encoding
+ // (which is what is needed on the command line)
+ std::string systemDirName;
+ TEST_THAT(ConvertEncoding(dirname.c_str(), CP_UTF8,
+ systemDirName, CP_ACP));
+
+ std::string systemFileName;
+ TEST_THAT(ConvertEncoding(filename.c_str(), CP_UTF8,
+ systemFileName, CP_ACP));
+
+ // Check that it can be converted to the console encoding
+ // (which is what we will see in the output)
+ std::string consoleDirName;
+ TEST_THAT(ConvertUtf8ToConsole(dirname.c_str(),
+ consoleDirName));
+
+ std::string consoleFileName;
+ TEST_THAT(ConvertUtf8ToConsole(filename.c_str(),
+ consoleFileName));
+
+ // test that bbackupd will let us lcd into the local
+ // directory using a relative path
+ std::string command = BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "\"lcd testfiles/TestDir1/" + systemDirName + "\" "
+ "quit";
+ compareReturnValue = ::system(command.c_str());
+ TEST_RETURN(compareReturnValue, 0);
+
+ // and back out again
+ command = BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "\"lcd testfiles/TestDir1/" + systemDirName + "\" "
+ "\"lcd ..\" quit";
+ compareReturnValue = ::system(command.c_str());
+ TEST_RETURN(compareReturnValue, 0);
+
+ // and using an absolute path
+ command = BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "\"lcd " + cwd + "/testfiles/TestDir1/" +
+ systemDirName + "\" quit";
+ compareReturnValue = ::system(command.c_str());
+ TEST_RETURN(compareReturnValue, 0);
+
+ // and back out again
+ command = BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "\"lcd " + cwd + "/testfiles/TestDir1/" +
+ systemDirName + "\" "
+ "\"lcd ..\" quit";
+ compareReturnValue = ::system(command.c_str());
+ TEST_RETURN(compareReturnValue, 0);
+
+ {
+ FileStream fs(filepath.c_str(), O_CREAT | O_RDWR);
+
+ std::string data("hello world\n");
+ fs.Write(data.c_str(), data.size());
+ TEST_THAT(fs.GetPosition() == 12);
+ fs.Close();
+ }
+
+ wait_for_backup_operation();
+ // Compare to check that the file was uploaded
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf \"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // Check that we can find it in directory listing
+ {
+ std::auto_ptr<BackupProtocolClient> client =
+ Connect(context, 0);
+
+ std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory(
+ *client,
+ BackupProtocolClientListDirectory::RootDirectory);
+
+ int64_t baseDirId = SearchDir(*dir, "Test1");
+ TEST_THAT(baseDirId != 0);
+ dir = ReadDirectory(*client, baseDirId);
+
+ int64_t testDirId = SearchDir(dir, dirname.c_str());
+ TEST_THAT(testDirId != 0);
+ dir = ReadDirectory(*client, testDirId);
- printf("Delete file and update another, create symlink.\n");
+ TEST_THAT(SearchDir(dir, filename.c_str()) != 0);
+ // Log out
+ client->QueryFinished();
+ sSocket.Close();
+ }
+
+
+ // Check that bbackupquery shows the dir in console encoding
+ command = BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-q \"list Test1\" quit";
+ pid_t bbackupquery_pid;
+ std::auto_ptr<IOStream> queryout;
+ queryout = LocalProcessStream(command.c_str(),
+ bbackupquery_pid);
+ TEST_THAT(queryout.get() != NULL);
+ TEST_THAT(bbackupquery_pid != -1);
+
+ IOStreamGetLine reader(*queryout);
+ std::string line;
+ bool found = false;
+ while (!reader.IsEOF())
+ {
+ TEST_THAT(reader.GetLine(line));
+ if (line.find(consoleDirName) != std::string::npos)
+ {
+ found = true;
+ }
+ }
+ TEST_THAT(!(queryout->StreamDataLeft()));
+ TEST_THAT(reader.IsEOF());
+ TEST_THAT(found);
+ queryout->Close();
+
+ // Check that bbackupquery can list the dir when given
+ // on the command line in system encoding, and shows
+ // the file in console encoding
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
+ "-q \"list Test1/" + systemDirName + "\" quit";
+ queryout = LocalProcessStream(command.c_str(),
+ bbackupquery_pid);
+ TEST_THAT(queryout.get() != NULL);
+ TEST_THAT(bbackupquery_pid != -1);
+
+ IOStreamGetLine reader2(*queryout);
+ found = false;
+ while (!reader2.IsEOF())
+ {
+ TEST_THAT(reader2.GetLine(line));
+ if (line.find(consoleFileName) != std::string::npos)
+ {
+ found = true;
+ }
+ }
+ TEST_THAT(!(queryout->StreamDataLeft()));
+ TEST_THAT(reader2.IsEOF());
+ TEST_THAT(found);
+ queryout->Close();
+
+ // Check that bbackupquery can compare the dir when given
+ // on the command line in system encoding.
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
+ "-q \"compare -cEQ Test1/" + systemDirName +
+ " testfiles/TestDir1/" + systemDirName + "\" quit";
+
+ compareReturnValue = ::system(command.c_str());
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_RETURN(compareReturnValue, 1);
+
+ // Check that bbackupquery can restore the dir when given
+ // on the command line in system encoding.
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
+ "-q \"restore Test1/" + systemDirName +
+ " testfiles/restore-" + systemDirName + "\" quit";
+
+ compareReturnValue = ::system(command.c_str());
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_RETURN(compareReturnValue, 0);
+
+ // Compare to make sure it was restored properly.
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
+ "-q \"compare -cEQ Test1/" + systemDirName +
+ " testfiles/restore-" + systemDirName + "\" quit";
+
+ compareReturnValue = ::system(command.c_str());
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_RETURN(compareReturnValue, 1);
+
+ std::string fileToUnlink = "testfiles/restore-" +
+ dirname + "/" + filename;
+ TEST_THAT(::unlink(fileToUnlink.c_str()) == 0);
+
+ // Check that bbackupquery can get the file when given
+ // on the command line in system encoding.
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
+ "-q \"get Test1/" + systemDirName + "/" +
+ systemFileName + " " + "testfiles/restore-" +
+ systemDirName + "/" + systemFileName + "\" quit";
+
+ compareReturnValue = ::system(command.c_str());
+ TEST_RETURN(compareReturnValue, 0);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // And after changing directory to a relative path
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf -q "
+ "\"lcd testfiles\" "
+ "\"cd Test1/" + systemDirName + "\" " +
+ "\"get " + systemFileName + "\" quit";
+
+ compareReturnValue = ::system(command.c_str());
+ TEST_RETURN(compareReturnValue, 0);
+ TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks");
+
+ // cannot overwrite a file that exists, so delete it
+ std::string tmp = "testfiles/" + filename;
+ TEST_THAT(::unlink(tmp.c_str()) == 0);
+
+ // And after changing directory to an absolute path
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf -q "
+ "\"lcd " + cwd + "/testfiles\" "
+ "\"cd Test1/" + systemDirName + "\" " +
+ "\"get " + systemFileName + "\" quit";
+
+ compareReturnValue = ::system(command.c_str());
+ TEST_RETURN(compareReturnValue, 0);
+ TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks");
+
+ // Compare to make sure it was restored properly.
+ // The Get command does not restore attributes, so
+ // we must compare without them (-A) to succeed.
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
+ "-q \"compare -cAEQ Test1/" + systemDirName +
+ " testfiles/restore-" + systemDirName + "\" quit";
+
+ compareReturnValue = ::system(command.c_str());
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_RETURN(compareReturnValue, 1);
+
+ // Compare without attributes. This should fail.
+ command = BBACKUPQUERY " -c testfiles/bbackupd.conf "
+ "-q \"compare -cEQ Test1/" + systemDirName +
+ " testfiles/restore-" + systemDirName + "\" quit";
+
+ compareReturnValue = ::system(command.c_str());
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_RETURN(compareReturnValue, 2);
+#endif // WIN32
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Check that SyncAllowScript is executed and can "
+ "pause backup\n");
+ fflush(stdout);
+
+ {
+ wait_for_sync_end();
+ // we now have 3 seconds before bbackupd
+ // runs the SyncAllowScript again.
+
+ char* sync_control_file = "testfiles"
+ DIRECTORY_SEPARATOR "syncallowscript.control";
+ int fd = open(sync_control_file,
+ O_CREAT | O_EXCL | O_WRONLY, 0700);
+ if (fd <= 0)
+ {
+ perror(sync_control_file);
+ }
+ TEST_THAT(fd > 0);
+
+ char* control_string = "10\n";
+ TEST_THAT(write(fd, control_string,
+ strlen(control_string)) ==
+ (int)strlen(control_string));
+ close(fd);
+
+ // this will pause backups, bbackupd will check
+ // every 10 seconds to see if they are allowed again.
+
+ char* new_test_file = "testfiles"
+ DIRECTORY_SEPARATOR "TestDir1"
+ DIRECTORY_SEPARATOR "Added_During_Pause";
+ fd = open(new_test_file,
+ O_CREAT | O_EXCL | O_WRONLY, 0700);
+ if (fd <= 0)
+ {
+ perror(new_test_file);
+ }
+ TEST_THAT(fd > 0);
+ close(fd);
+
+ struct stat st;
+
+ // next poll should happen within the next
+ // 5 seconds (normally about 3 seconds)
+
+ safe_sleep(1); // 2 seconds before
+ TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
+ "syncallowscript.notifyran.1", &st) != 0);
+ safe_sleep(4); // 2 seconds after
+ TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
+ "syncallowscript.notifyran.1", &st) == 0);
+ TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
+ "syncallowscript.notifyran.2", &st) != 0);
+
+ // next poll should happen within the next
+ // 10 seconds (normally about 8 seconds)
+
+ safe_sleep(6); // 2 seconds before
+ TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
+ "syncallowscript.notifyran.2", &st) != 0);
+ safe_sleep(4); // 2 seconds after
+ TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR
+ "syncallowscript.notifyran.2", &st) == 0);
+
+ // bbackupquery compare might take a while
+ // on slow machines, so start the timer now
+ long start_time = time(NULL);
+
+ // check that no backup has run (compare fails)
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 2);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(unlink(sync_control_file) == 0);
+ wait_for_sync_start();
+ long end_time = time(NULL);
+
+ long wait_time = end_time - start_time + 2;
+ // should be about 10 seconds
+ printf("Waited for %ld seconds, should have been %s",
+ wait_time, control_string);
+ TEST_THAT(wait_time >= 8);
+ TEST_THAT(wait_time <= 12);
+
+ wait_for_sync_end();
+ // check that backup has run (compare succeeds)
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3a.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ if (failures > 0)
+ {
+ // stop early to make debugging easier
+ return 1;
+ }
+ }
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Delete file and update another, "
+ "create symlink.\n");
// Delete a file
TEST_THAT(::unlink("testfiles/TestDir1/x1/dsfdsfs98.fd") == 0);
- // New symlink
- TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/symlink-to-dir") == 0);
-
+
+ #ifndef WIN32
+ // New symlink
+ TEST_THAT(::symlink("does-not-exist",
+ "testfiles/TestDir1/symlink-to-dir") == 0);
+ #endif
+
// Update a file (will be uploaded as a diff)
{
- // Check that the file is over the diffing threshold in the bbstored.conf file
- TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") > 1024);
+ // Check that the file is over the diffing
+ // threshold in the bbackupd.conf file
+ TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df")
+ > 1024);
// Add a bit to the end
FILE *f = ::fopen("testfiles/TestDir1/f45.df", "a");
TEST_THAT(f != 0);
::fprintf(f, "EXTRA STUFF");
::fclose(f);
- TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") > 1024);
+ TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df")
+ > 1024);
}
// wait for backup daemon to do it's stuff, and compare again
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query2.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query2.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
// Try a quick compare, just for fun
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query2q.log \"compare -acq\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query2q.log "
+ "\"compare -acqQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // Check that store errors are reported neatly
+ printf("\n==== Create store error\n");
+ TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf",
+ "testfiles/0_0/backup/01234567/info.rf.bak") == 0);
+ TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf",
+ "testfiles/0_1/backup/01234567/info.rf.bak") == 0);
+ TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf",
+ "testfiles/0_2/backup/01234567/info.rf.bak") == 0);
+ // Create a file to trigger an upload
+ {
+ int fd1 = open("testfiles/TestDir1/force-upload",
+ O_CREAT | O_EXCL | O_WRONLY, 0700);
+ TEST_THAT(fd1 > 0);
+ TEST_THAT(write(fd1, "just do it", 10) == 10);
+ TEST_THAT(close(fd1) == 0);
+ wait_for_backup_operation(4);
+ }
+ // Wait and test...
+ wait_for_backup_operation();
+ // Check that it was reported correctly
+ TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.1"));
+ // Check that the error was only reported once
+ TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.2"));
+ // Fix the store
+ TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf.bak",
+ "testfiles/0_0/backup/01234567/info.rf") == 0);
+ TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf.bak",
+ "testfiles/0_1/backup/01234567/info.rf") == 0);
+ TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf.bak",
+ "testfiles/0_2/backup/01234567/info.rf") == 0);
+
+ // Check that we DO get errors on compare
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3b.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 2);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // Wait until bbackupd recovers from the exception
+ wait_for_backup_operation(100);
+
+ // Ensure that the force-upload file gets uploaded,
+ // meaning that bbackupd recovered
+ sync_and_wait();
+
+ // Check that it did get uploaded, and we have no more errors
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3b.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
// Bad case: delete a file/symlink, replace it with a directory
- printf("Replace symlink with directory, add new directory\n");
- TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir") == 0);
- TEST_THAT(::mkdir("testfiles/TestDir1/symlink-to-dir", 0755) == 0);
- TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) == 0);
- // NOTE: create a file within the directory to avoid deletion by the housekeeping process later
- TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents") == 0);
+ printf("\n==== Replace symlink with directory, "
+ "add new directory\n");
+
+ #ifndef WIN32
+ TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir")
+ == 0);
+ #endif
+
+ TEST_THAT(::mkdir("testfiles/TestDir1/symlink-to-dir", 0755)
+ == 0);
+ TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755)
+ == 0);
+
+ // NOTE: create a file within the directory to
+ // avoid deletion by the housekeeping process later
+
+ #ifndef WIN32
+ TEST_THAT(::symlink("does-not-exist",
+ "testfiles/TestDir1/x1/dir-to-file/contents")
+ == 0);
+ #endif
+
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3c.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
// And the inverse, replace a directory with a file/symlink
- printf("Replace directory with symlink\n");
- TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents") == 0);
+ printf("\n==== Replace directory with symlink\n");
+
+ #ifndef WIN32
+ TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file"
+ "/contents") == 0);
+ #endif
+
TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0);
- TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0);
+
+ #ifndef WIN32
+ TEST_THAT(::symlink("does-not-exist",
+ "testfiles/TestDir1/x1/dir-to-file") == 0);
+ #endif
+
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3d.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
// And then, put it back to how it was before.
- printf("Replace symlink with directory (which was a symlink)\n");
- TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file") == 0);
- TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) == 0);
- TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents2") == 0);
+ printf("\n==== Replace symlink with directory "
+ "(which was a symlink)\n");
+
+ #ifndef WIN32
+ TEST_THAT(::unlink("testfiles/TestDir1/x1"
+ "/dir-to-file") == 0);
+ #endif
+
+ TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file",
+ 0755) == 0);
+
+ #ifndef WIN32
+ TEST_THAT(::symlink("does-not-exist",
+ "testfiles/TestDir1/x1/dir-to-file/contents2")
+ == 0);
+ #endif
+
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3e.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
- // And finally, put it back to how it was before it was put back to how it was before
- // This gets lots of nasty things in the store with directories over other old directories.
- printf("Put it all back to how it was\n");
- TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents2") == 0);
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // And finally, put it back to how it was before
+ // it was put back to how it was before
+ // This gets lots of nasty things in the store with
+ // directories over other old directories.
+ printf("\n==== Put it all back to how it was\n");
+
+ #ifndef WIN32
+ TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file"
+ "/contents2") == 0);
+ #endif
+
TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0);
- TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0);
+
+ #ifndef WIN32
+ TEST_THAT(::symlink("does-not-exist",
+ "testfiles/TestDir1/x1/dir-to-file") == 0);
+ #endif
+
+ wait_for_backup_operation();
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3f.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // rename an untracked file over an
+ // existing untracked file
+ printf("\n==== Rename over existing untracked file\n");
+ int fd1 = open("testfiles/TestDir1/untracked-1",
+ O_CREAT | O_EXCL | O_WRONLY, 0700);
+ int fd2 = open("testfiles/TestDir1/untracked-2",
+ O_CREAT | O_EXCL | O_WRONLY, 0700);
+ TEST_THAT(fd1 > 0);
+ TEST_THAT(fd2 > 0);
+ TEST_THAT(write(fd1, "hello", 5) == 5);
+ TEST_THAT(close(fd1) == 0);
+ safe_sleep(1);
+ TEST_THAT(write(fd2, "world", 5) == 5);
+ TEST_THAT(close(fd2) == 0);
+ TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-1"));
+ TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-2"));
+ wait_for_operation(5);
+ // back up both files
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3g.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
- // case which went wrong: rename a tracked file over a deleted file
- printf("Rename an existing file over a deleted file\n");
- TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0);
+ #ifdef WIN32
+ TEST_THAT(::unlink("testfiles/TestDir1/untracked-2")
+ == 0);
+ #endif
+
+ TEST_THAT(::rename("testfiles/TestDir1/untracked-1",
+ "testfiles/TestDir1/untracked-2") == 0);
+ TEST_THAT(!TestFileExists("testfiles/TestDir1/untracked-1"));
+ TEST_THAT( TestFileExists("testfiles/TestDir1/untracked-2"));
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3g.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // case which went wrong: rename a tracked file over an
+ // existing tracked file
+ printf("\n==== Rename over existing tracked file\n");
+ fd1 = open("testfiles/TestDir1/tracked-1",
+ O_CREAT | O_EXCL | O_WRONLY, 0700);
+ fd2 = open("testfiles/TestDir1/tracked-2",
+ O_CREAT | O_EXCL | O_WRONLY, 0700);
+ TEST_THAT(fd1 > 0);
+ TEST_THAT(fd2 > 0);
+ char buffer[1024];
+ TEST_THAT(write(fd1, "hello", 5) == 5);
+ TEST_THAT(write(fd1, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd1) == 0);
+ safe_sleep(1);
+ TEST_THAT(write(fd2, "world", 5) == 5);
+ TEST_THAT(write(fd2, buffer, sizeof(buffer)) == sizeof(buffer));
+ TEST_THAT(close(fd2) == 0);
+ TEST_THAT(TestFileExists("testfiles/TestDir1/tracked-1"));
+ TEST_THAT(TestFileExists("testfiles/TestDir1/tracked-2"));
+ wait_for_operation(5);
+ // back up both files
+ wait_for_backup_operation();
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3h.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ #ifdef WIN32
+ TEST_THAT(::unlink("testfiles/TestDir1/tracked-2")
+ == 0);
+ #endif
+
+ TEST_THAT(::rename("testfiles/TestDir1/tracked-1",
+ "testfiles/TestDir1/tracked-2") == 0);
+ TEST_THAT(!TestFileExists("testfiles/TestDir1/tracked-1"));
+ TEST_THAT( TestFileExists("testfiles/TestDir1/tracked-2"));
+ wait_for_backup_operation();
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3i.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // case which went wrong: rename a tracked file
+ // over a deleted file
+ printf("\n==== Rename an existing file over a deleted file\n");
+ TEST_THAT(!TestFileExists("testfiles/TestDir1/x1/dsfdsfs98.fd"));
+ TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf",
+ "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0);
- printf("Add files with old times, update attributes of one to latest time\n");
+ wait_for_backup_operation();
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3j.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Add files with old times, update "
+ "attributes of one to latest time\n");
// Move that file back
- TEST_THAT(::rename("testfiles/TestDir1/x1/dsfdsfs98.fd", "testfiles/TestDir1/df9834.dsf") == 0);
+ TEST_THAT(::rename("testfiles/TestDir1/x1/dsfdsfs98.fd",
+ "testfiles/TestDir1/df9834.dsf") == 0);
// Add some more files
- // Because the 'm' option is not used, these files will look very old to the daemon.
+ // Because the 'm' option is not used, these files will
+ // look very old to the daemon.
// Lucky it'll upload them then!
- TEST_THAT(::system("gzip -d < testfiles/test2.tgz | ( cd testfiles && tar xf - )") == 0);
- ::chmod("testfiles/TestDir1/sub23/dhsfdss/blf.h", 0415);
+ #ifdef WIN32
+ TEST_THAT(::system("tar xzvf testfiles/test2.tgz "
+ "-C testfiles") == 0);
+ #else
+ TEST_THAT(::system("gzip -d < testfiles/test2.tgz "
+ "| ( cd testfiles && tar xf - )") == 0);
+ ::chmod("testfiles/TestDir1/sub23/dhsfdss/blf.h", 0415);
+ #endif
// Wait and test
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3k.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
- // Check that modifying files with old timestamps still get added
- printf("Modify existing file, but change timestamp to rather old\n");
- // Time critical, so sync
- TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0);
- TestRemoteProcessMemLeaks("bbackupctl.memleaks");
- // Then wait a second, to make sure the scan is complete
- ::sleep(1);
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // Check that modifying files with old timestamps
+ // still get added
+ printf("\n==== Modify existing file, but change timestamp "
+ "to rather old\n");
+ wait_for_sync_end();
+
// Then modify an existing file
{
- chmod("testfiles/TestDir1/sub23/rand.h", 0777); // in the archive, it's read only
- FILE *f = fopen("testfiles/TestDir1/sub23/rand.h", "w+");
+ // in the archive, it's read only
+ #ifdef WIN32
+ TEST_THAT(::system("chmod 0777 testfiles"
+ "/TestDir1/sub23/rand.h") == 0);
+ #else
+ TEST_THAT(chmod("testfiles/TestDir1/sub23"
+ "/rand.h", 0777) == 0);
+ #endif
+
+ FILE *f = fopen("testfiles/TestDir1/sub23/rand.h",
+ "w+");
+
+ if (f == 0)
+ {
+ perror("Failed to open");
+ }
+
TEST_THAT(f != 0);
- fprintf(f, "MODIFIED!\n");
- fclose(f);
+
+ if (f != 0)
+ {
+ fprintf(f, "MODIFIED!\n");
+ fclose(f);
+ }
+
// and then move the time backwards!
struct timeval times[2];
- BoxTimeToTimeval(SecondsToBoxTime((time_t)(365*24*60*60)), times[1]);
+ BoxTimeToTimeval(SecondsToBoxTime(
+ (time_t)(365*24*60*60)), times[1]);
times[0] = times[1];
- TEST_THAT(::utimes("testfiles/TestDir1/sub23/rand.h", times) == 0);
+ TEST_THAT(::utimes("testfiles/TestDir1/sub23/rand.h",
+ times) == 0);
}
+
// Wait and test
- wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ wait_for_sync_end(); // files too new
+ wait_for_sync_end(); // should (not) be backed up this time
+
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3l.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
// Add some files and directories which are marked as excluded
- printf("Add files and dirs for exclusion test\n");
- TEST_THAT(::system("gzip -d < testfiles/testexclude.tgz | ( cd testfiles && tar xf - )") == 0);
+ printf("\n==== Add files and dirs for exclusion test\n");
+ #ifdef WIN32
+ TEST_THAT(::system("tar xzvf testfiles/testexclude.tgz "
+ "-C testfiles") == 0);
+ #else
+ TEST_THAT(::system("gzip -d < "
+ "testfiles/testexclude.tgz "
+ "| ( cd testfiles && tar xf - )") == 0);
+ #endif
+
// Wait and test
- wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3c.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ wait_for_sync_end();
+ wait_for_sync_end();
+
+ // compare with exclusions, should not find differences
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3m.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3d.log \"compare -acE\" quit");
- TEST_THAT(compareReturnValue == 2*256); // should find differences
+
+ // compare without exclusions, should find differences
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3n.log "
+ "\"compare -acEQ\" quit");
+ TEST_RETURN(compareReturnValue, 2);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // check that the excluded files did not make it
+ // into the store, and the included files did
+ printf("\n==== Check that exclude/alwaysinclude commands "
+ "actually work\n");
+
+ {
+ std::auto_ptr<BackupProtocolClient> client = Connect(
+ context,
+ BackupProtocolClientLogin::Flags_ReadOnly);
+
+ std::auto_ptr<BackupStoreDirectory> dir = ReadDirectory(
+ *client,
+ BackupProtocolClientListDirectory::RootDirectory);
+
+ int64_t testDirId = SearchDir(*dir, "Test1");
+ TEST_THAT(testDirId != 0);
+ dir = ReadDirectory(*client, testDirId);
+
+ TEST_THAT(!SearchDir(*dir, "excluded_1"));
+ TEST_THAT(!SearchDir(*dir, "excluded_2"));
+ TEST_THAT(!SearchDir(*dir, "exclude_dir"));
+ TEST_THAT(!SearchDir(*dir, "exclude_dir_2"));
+ // xx_not_this_dir_22 should not be excluded by
+ // ExcludeDirsRegex, because it's a file
+ TEST_THAT(SearchDir (*dir, "xx_not_this_dir_22"));
+ TEST_THAT(!SearchDir(*dir, "zEXCLUDEu"));
+ TEST_THAT(SearchDir (*dir, "dont.excludethis"));
+ TEST_THAT(SearchDir (*dir, "xx_not_this_dir_ALWAYSINCLUDE"));
+
+ int64_t sub23id = SearchDir(*dir, "sub23");
+ TEST_THAT(sub23id != 0);
+ dir = ReadDirectory(*client, sub23id);
+
+ TEST_THAT(!SearchDir(*dir, "xx_not_this_dir_22"));
+ TEST_THAT(!SearchDir(*dir, "somefile.excludethis"));
+ client->QueryFinished();
+ sSocket.Close();
+ }
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+#ifndef WIN32
// These tests only work as non-root users.
if(::getuid() != 0)
{
// Check that read errors are reported neatly
- printf("Add unreadable files\n");
+ printf("\n==== Add unreadable files\n");
+
{
// Dir and file which can't be read
- TEST_THAT(::mkdir("testfiles/TestDir1/sub23/read-fail-test-dir", 0000) == 0);
- int fd = ::open("testfiles/TestDir1/read-fail-test-file", O_CREAT | O_WRONLY, 0000);
+ TEST_THAT(::mkdir("testfiles/TestDir1/sub23"
+ "/read-fail-test-dir", 0000) == 0);
+ int fd = ::open("testfiles/TestDir1"
+ "/read-fail-test-file",
+ O_CREAT | O_WRONLY, 0000);
TEST_THAT(fd != -1);
::close(fd);
}
+
// Wait and test...
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 2*256); // should find differences
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3o.log "
+ "\"compare -acQ\" quit");
+
+ // should find differences
+ TEST_RETURN(compareReturnValue, 3);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
// Check that it was reported correctly
TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1"));
+
+ // Check that the error was only reported once
TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2"));
- // Set permissions on file and dir to stop errors in the future
- ::chmod("testfiles/TestDir1/sub23/read-fail-test-dir", 0770);
- ::chmod("testfiles/TestDir1/read-fail-test-file", 0770);
+
+ // Set permissions on file and dir to stop
+ // errors in the future
+ TEST_THAT(::chmod("testfiles/TestDir1/sub23"
+ "/read-fail-test-dir", 0770) == 0);
+ TEST_THAT(::chmod("testfiles/TestDir1"
+ "/read-fail-test-file", 0770) == 0);
}
+#endif
- printf("Continuously update file, check isn't uploaded\n");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Continuously update file, "
+ "check isn't uploaded\n");
- // Make sure everything happens at the same point in the sync cycle: wait until exactly the start of a sync
- TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -c testfiles/bbackupd.conf wait-for-sync") == 0);
- TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+ // Make sure everything happens at the same point in the
+ // sync cycle: wait until exactly the start of a sync
+ wait_for_sync_start();
+
// Then wait a second, to make sure the scan is complete
- ::sleep(1);
+ ::safe_sleep(1);
{
// Open a file, then save something to it every second
@@ -782,39 +2474,54 @@ int test_bbackupd()
TEST_THAT(f != 0);
fprintf(f, "Loop iteration %d\n", l);
fflush(f);
- sleep(1);
+ fclose(f);
+
printf(".");
fflush(stdout);
- ::fclose(f);
+ safe_sleep(1);
}
printf("\n");
+ fflush(stdout);
// Check there's a difference
- compareReturnValue = ::system("testfiles/extcheck1.pl");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system("perl testfiles/"
+ "extcheck1.pl");
+
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
- printf("Keep on continuously updating file, check it is uploaded eventually\n");
+ printf("\n==== Keep on continuously updating file, "
+ "check it is uploaded eventually\n");
for(int l = 0; l < 28; ++l)
{
- FILE *f = ::fopen("testfiles/TestDir1/continousupdate", "w+");
+ FILE *f = ::fopen("testfiles/TestDir1/"
+ "continousupdate", "w+");
TEST_THAT(f != 0);
fprintf(f, "Loop 2 iteration %d\n", l);
fflush(f);
- sleep(1);
+ fclose(f);
+
printf(".");
fflush(stdout);
- ::fclose(f);
+ safe_sleep(1);
}
printf("\n");
+ fflush(stdout);
- compareReturnValue = ::system("testfiles/extcheck2.pl");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system("perl testfiles/"
+ "extcheck2.pl");
+
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
}
- printf("Delete directory, change attributes\n");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Delete directory, change attributes\n");
// Delete a directory
TEST_THAT(::system("rm -rf testfiles/TestDir1/x1") == 0);
@@ -823,109 +2530,284 @@ int test_bbackupd()
// Wait and test
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query4.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
- printf("Restore files and directories\n");
+ printf("\n==== Restore files and directories\n");
int64_t deldirid = 0;
int64_t restoredirid = 0;
{
// connect and log in
- SocketStreamTLS conn;
- conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED);
- BackupProtocolClient protocol(conn);
- protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION);
- std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly));
+ std::auto_ptr<BackupProtocolClient> client = Connect(
+ context,
+ BackupProtocolClientLogin::Flags_ReadOnly);
// Find the ID of the Test1 directory
- restoredirid = GetDirID(protocol, "Test1", BackupProtocolClientListDirectory::RootDirectory);
+ restoredirid = GetDirID(*client, "Test1",
+ BackupProtocolClientListDirectory::RootDirectory);
TEST_THAT(restoredirid != 0);
// Test the restoration
- TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-Test1", true /* print progress dots */) == Restore_Complete);
+ TEST_THAT(BackupClientRestore(*client, restoredirid,
+ "testfiles/restore-Test1",
+ true /* print progress dots */)
+ == Restore_Complete);
- // Compare it
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query10.log \"compare -cE Test1 testfiles/restore-Test1\" quit");
- TEST_THAT(compareReturnValue == 1*256);
- TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ // On Win32 we can't open another connection
+ // to the server, so we'll compare later.
// Make sure you can't restore a restored directory
- TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-Test1", true /* print progress dots */) == Restore_TargetExists);
+ TEST_THAT(BackupClientRestore(*client, restoredirid,
+ "testfiles/restore-Test1",
+ true /* print progress dots */)
+ == Restore_TargetExists);
+
+ // Make sure you can't restore to a nonexistant path
+ printf("Try to restore to a path that doesn't exist\n");
+ TEST_THAT(BackupClientRestore(*client, restoredirid,
+ "testfiles/no-such-path/subdir",
+ true /* print progress dots */)
+ == Restore_TargetPathNotFound);
// Find ID of the deleted directory
- deldirid = GetDirID(protocol, "x1", restoredirid);
+ deldirid = GetDirID(*client, "x1", restoredirid);
TEST_THAT(deldirid != 0);
- // Just check it doesn't bomb out -- will check this properly later (when bbackupd is stopped)
- TEST_THAT(BackupClientRestore(protocol, deldirid, "testfiles/restore-Test1-x1", true /* print progress dots */, true /* deleted files */) == Restore_Complete);
+ // Just check it doesn't bomb out -- will check this
+ // properly later (when bbackupd is stopped)
+ TEST_THAT(BackupClientRestore(*client, deldirid,
+ "testfiles/restore-Test1-x1",
+ true /* print progress dots */,
+ true /* deleted files */)
+ == Restore_Complete);
// Log out
- protocol.QueryFinished();
+ client->QueryFinished();
+ sSocket.Close();
}
- printf("Add files with current time\n");
+ // Compare the restored files
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10.log "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+#ifdef WIN32
+ // make one of the files read-only, expect a compare failure
+ compareReturnValue = ::system("attrib +r "
+ "testfiles\\restore-Test1\\f1.dat");
+ TEST_RETURN(compareReturnValue, 0);
+
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 2);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // set it back, expect no failures
+ compareReturnValue = ::system("attrib -r "
+ "testfiles\\restore-Test1\\f1.dat");
+ TEST_RETURN(compareReturnValue, 0);
+
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf -l testfiles/query10a.log "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // change the timestamp on a file, expect a compare failure
+ char* testfile = "testfiles\\restore-Test1\\f1.dat";
+ HANDLE handle = openfile(testfile, O_RDWR, 0);
+ TEST_THAT(handle != INVALID_HANDLE_VALUE);
+
+ FILETIME creationTime, lastModTime, lastAccessTime;
+ TEST_THAT(GetFileTime(handle, &creationTime, &lastAccessTime,
+ &lastModTime) != 0);
+ TEST_THAT(CloseHandle(handle));
+
+ FILETIME dummyTime = lastModTime;
+ dummyTime.dwHighDateTime -= 100;
+
+ // creation time is backed up, so changing it should cause
+ // a compare failure
+ TEST_THAT(set_file_time(testfile, dummyTime, lastModTime,
+ lastAccessTime));
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 2);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // last access time is not backed up, so it cannot be compared
+ TEST_THAT(set_file_time(testfile, creationTime, lastModTime,
+ dummyTime));
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // last write time is backed up, so changing it should cause
+ // a compare failure
+ TEST_THAT(set_file_time(testfile, creationTime, dummyTime,
+ lastAccessTime));
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 2);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // set back to original values, check that compare succeeds
+ TEST_THAT(set_file_time(testfile, creationTime, lastModTime,
+ lastAccessTime));
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query10a.log "
+ "\"compare -cEQ Test1 testfiles/restore-Test1\" "
+ "quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+#endif // WIN32
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Add files with current time\n");
// Add some more files and modify others
// Use the m flag this time so they have a recent modification time
- TEST_THAT(::system("gzip -d < testfiles/test3.tgz | ( cd testfiles && tar xmf - )") == 0);
+ #ifdef WIN32
+ TEST_THAT(::system("tar xzvmf testfiles/test3.tgz "
+ "-C testfiles") == 0);
+ #else
+ TEST_THAT(::system("gzip -d < testfiles/test3.tgz "
+ "| ( cd testfiles && tar xmf - )") == 0);
+ #endif
// Wait and test
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query5.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query5.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
// Rename directory
- printf("Rename directory\n");
- TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", "testfiles/TestDir1/renamed-dir") == 0);
+ printf("\n==== Rename directory\n");
+ TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss",
+ "testfiles/TestDir1/renamed-dir") == 0);
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query6.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
// and again, but with quick flag
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6q.log \"compare -acq\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query6q.log "
+ "\"compare -acqQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
// Rename some files -- one under the threshold, others above
- printf("Rename files\n");
- TEST_THAT(rename("testfiles/TestDir1/continousupdate", "testfiles/TestDir1/continousupdate-ren") == 0);
- TEST_THAT(rename("testfiles/TestDir1/df324", "testfiles/TestDir1/df324-ren") == 0);
- TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", "testfiles/TestDir1/find2perl-ren") == 0);
+ printf("\n==== Rename files\n");
+ TEST_THAT(rename("testfiles/TestDir1/continousupdate",
+ "testfiles/TestDir1/continousupdate-ren") == 0);
+ TEST_THAT(rename("testfiles/TestDir1/df324",
+ "testfiles/TestDir1/df324-ren") == 0);
+ TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl",
+ "testfiles/TestDir1/find2perl-ren") == 0);
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query6.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
- // Check that modifying files with madly in the future timestamps still get added
- printf("Create a file with timestamp to way ahead in the future\n");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ // Check that modifying files with madly in the future
+ // timestamps still get added
+ printf("\n==== Create a file with timestamp way ahead "
+ "in the future\n");
+
// Time critical, so sync
- TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0);
- TestRemoteProcessMemLeaks("bbackupctl.memleaks");
+ wait_for_sync_start();
+
// Then wait a second, to make sure the scan is complete
- ::sleep(1);
+ ::safe_sleep(1);
+
// Then modify an existing file
{
- FILE *f = fopen("testfiles/TestDir1/sub23/in-the-future", "w");
+ FILE *f = fopen("testfiles/TestDir1/sub23/"
+ "in-the-future", "w");
TEST_THAT(f != 0);
fprintf(f, "Back to the future!\n");
fclose(f);
// and then move the time forwards!
struct timeval times[2];
- BoxTimeToTimeval(GetCurrentBoxTime() + SecondsToBoxTime((time_t)(365*24*60*60)), times[1]);
+ BoxTimeToTimeval(GetCurrentBoxTime() +
+ SecondsToBoxTime((time_t)(365*24*60*60)),
+ times[1]);
times[0] = times[1];
- TEST_THAT(::utimes("testfiles/TestDir1/sub23/in-the-future", times) == 0);
+ TEST_THAT(::utimes("testfiles/TestDir1/sub23/"
+ "in-the-future", times) == 0);
}
+
// Wait and test
wait_for_backup_operation();
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query3e.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
- printf("Change client store marker\n");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Change client store marker\n");
- // Then... connect to the server, and change the client store marker. See what that does!
+ // Then... connect to the server, and change the
+ // client store marker. See what that does!
{
bool done = false;
int tries = 4;
@@ -934,7 +2816,8 @@ int test_bbackupd()
try
{
SocketStreamTLS conn;
- conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED);
+ conn.Open(context, Socket::TypeINET,
+ "localhost", BOX_PORT_BBSTORED);
BackupProtocolClient protocol(conn);
protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION);
std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write
@@ -958,10 +2841,15 @@ int test_bbackupd()
TEST_THAT(done);
}
- printf("Check change of store marker pauses daemon\n");
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Check change of store marker pauses daemon\n");
- // Make a change to a file, to detect whether or not it's hanging around
- // waiting to retry.
+ // Make a change to a file, to detect whether or not
+ // it's hanging around waiting to retry.
{
FILE *f = ::fopen("testfiles/TestDir1/fileaftermarker", "w");
TEST_THAT(f != 0);
@@ -970,56 +2858,105 @@ int test_bbackupd()
}
// Wait and test that there *are* differences
- wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); // little bit longer than usual
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 2*256);
+ wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION *
+ 3) / 2); // little bit longer than usual
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query6.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 2);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
-
- printf("Interrupted restore\n");
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Waiting for bbackupd to recover\n");
+ // 100 seconds - (12*3/2)
+ wait_for_operation(82);
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+#ifndef WIN32
+ printf("\n==== Interrupted restore\n");
{
do_interrupted_restore(context, restoredirid);
int64_t resumesize = 0;
- TEST_THAT(FileExists("testfiles/restore-interrupt.boxbackupresume", &resumesize));
- TEST_THAT(resumesize > 16); // make sure it has recorded something to resume
+ TEST_THAT(FileExists("testfiles/"
+ "restore-interrupt.boxbackupresume",
+ &resumesize));
+ // make sure it has recorded something to resume
+ TEST_THAT(resumesize > 16);
- printf("\nResume restore\n");
+ printf("\n==== Resume restore\n");
- SocketStreamTLS conn;
- conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED);
- BackupProtocolClient protocol(conn);
- protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION);
- std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write
+ std::auto_ptr<BackupProtocolClient> client = Connect(
+ context,
+ BackupProtocolClientLogin::Flags_ReadOnly);
- // Check that the restore fn returns resume possible, rather than doing anything
- TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-interrupt", true /* print progress dots */) == Restore_ResumePossible);
+ // Check that the restore fn returns resume possible,
+ // rather than doing anything
+ TEST_THAT(BackupClientRestore(*client, restoredirid,
+ "testfiles/restore-interrupt",
+ true /* print progress dots */)
+ == Restore_ResumePossible);
// Then resume it
- TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-interrupt", true /* print progress dots */, false /* deleted files */, false /* undelete server */, true /* resume */) == Restore_Complete);
+ TEST_THAT(BackupClientRestore(*client, restoredirid,
+ "testfiles/restore-interrupt",
+ true /* print progress dots */,
+ false /* deleted files */,
+ false /* undelete server */,
+ true /* resume */)
+ == Restore_Complete);
- protocol.QueryFinished();
+ client->QueryFinished();
+ sSocket.Close();
// Then check it has restored the correct stuff
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query14.log \"compare -cE Test1 testfiles/restore-interrupt\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query14.log "
+ "\"compare -cEQ Test1 "
+ "testfiles/restore-interrupt\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
}
+#endif // !WIN32
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ printf("\n==== Check restore deleted files\n");
- printf("Check restore deleted files\n");
{
- SocketStreamTLS conn;
- conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED);
- BackupProtocolClient protocol(conn);
- protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION);
- std::auto_ptr<BackupProtocolClientLoginConfirmed> loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write
+ std::auto_ptr<BackupProtocolClient> client = Connect(
+ context, 0 /* read-write */);
// Do restore and undelete
- TEST_THAT(BackupClientRestore(protocol, deldirid, "testfiles/restore-Test1-x1-2", true /* print progress dots */, true /* deleted files */, true /* undelete on server */) == Restore_Complete);
+ TEST_THAT(BackupClientRestore(*client, deldirid,
+ "testfiles/restore-Test1-x1-2",
+ true /* print progress dots */,
+ true /* deleted files */,
+ true /* undelete on server */)
+ == Restore_Complete);
- protocol.QueryFinished();
+ client->QueryFinished();
+ sSocket.Close();
// Do a compare with the now undeleted files
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query11.log \"compare -cE Test1/x1 testfiles/restore-Test1-x1-2\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query11.log "
+ "\"compare -cEQ Test1/x1 "
+ "testfiles/restore-Test1-x1-2\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
}
@@ -1027,39 +2964,125 @@ int test_bbackupd()
TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2"));
TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2"));
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+#ifdef WIN32
+ printf("\n==== Testing locked file behaviour:\n");
+
+ // Test that locked files cannot be backed up,
+ // and the appropriate error is reported.
+ // Wait for the sync to finish, so that we have time to work
+ wait_for_sync_start();
+ // Now we have about three seconds to work
+
+ handle = openfile("testfiles/TestDir1/lockedfile",
+ O_CREAT | O_EXCL | O_LOCK, 0);
+ TEST_THAT(handle != INVALID_HANDLE_VALUE);
+
+ if (handle != 0)
+ {
+ // first sync will ignore the file, it's too new
+ wait_for_sync_end();
+ TEST_THAT(!TestFileExists("testfiles/"
+ "notifyran.read-error.1"));
+
+ // this sync should try to back up the file,
+ // and fail, because it's locked
+ wait_for_sync_end();
+ TEST_THAT(TestFileExists("testfiles/"
+ "notifyran.read-error.1"));
+ TEST_THAT(!TestFileExists("testfiles/"
+ "notifyran.read-error.2"));
+
+ // now close the file and check that it is
+ // backed up on the next run.
+ CloseHandle(handle);
+ wait_for_sync_end();
+ TEST_THAT(!TestFileExists("testfiles/"
+ "notifyran.read-error.2"));
+
+ // compare, and check that it works
+ // reports the correct error message (and finishes)
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query15a.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // open the file again, compare and check that compare
+ // reports the correct error message (and finishes)
+ handle = openfile("testfiles/TestDir1/lockedfile",
+ O_LOCK, 0);
+ TEST_THAT(handle != INVALID_HANDLE_VALUE);
+
+ compareReturnValue = ::system(BBACKUPQUERY
+ " -q -c testfiles/bbackupd.conf "
+ "-l testfiles/query15.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 3);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+
+ // close the file again, check that compare
+ // works again
+ CloseHandle(handle);
+
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query15a.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
+ TestRemoteProcessMemLeaks("bbackupquery.memleaks");
+ }
+#endif
+
// Kill the daemon
- TEST_THAT(KillServer(pid));
- ::sleep(1);
- TEST_THAT(!ServerIsAlive(pid));
- TestRemoteProcessMemLeaks("bbackupd.memleaks");
+ terminate_bbackupd(bbackupd_pid);
// Start it again
- pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid");
- TEST_THAT(pid != -1 && pid != 0);
- if(pid != -1 && pid != 0)
+ cmd = BBACKUPD " " + bbackupd_args +
+ " testfiles/bbackupd.conf";
+ bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid");
+
+ TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0);
+
+ TEST_THAT(ServerIsAlive(bbackupd_pid));
+ TEST_THAT(ServerIsAlive(bbstored_pid));
+ if (!ServerIsAlive(bbackupd_pid)) return 1;
+ if (!ServerIsAlive(bbstored_pid)) return 1;
+
+ if(bbackupd_pid != -1 && bbackupd_pid != 0)
{
- // Wait and comapre
- wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); // little bit longer than usual
- compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit");
- TEST_THAT(compareReturnValue == 1*256);
+ // Wait and compare (a little bit longer than usual)
+ wait_for_backup_operation(
+ (TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2);
+ compareReturnValue = ::system(BBACKUPQUERY " -q "
+ "-c testfiles/bbackupd.conf "
+ "-l testfiles/query4a.log "
+ "\"compare -acQ\" quit");
+ TEST_RETURN(compareReturnValue, 1);
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
// Kill it again
- TEST_THAT(KillServer(pid));
- ::sleep(1);
- TEST_THAT(!ServerIsAlive(pid));
- TestRemoteProcessMemLeaks("bbackupd.memleaks");
+ terminate_bbackupd(bbackupd_pid);
}
}
// List the files on the server
- ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/queryLIST.log \"list -rotdh\" quit");
+ ::system(BBACKUPQUERY " -q -c testfiles/bbackupd.conf "
+ "-l testfiles/queryLIST.log \"list -rotdh\" quit");
TestRemoteProcessMemLeaks("bbackupquery.memleaks");
-
- if(::getuid() == 0)
- {
- ::printf("WARNING: This test was run as root. Some tests have been omitted.\n");
- }
+
+ #ifndef WIN32
+ if(::getuid() == 0)
+ {
+ ::printf("WARNING: This test was run as root. "
+ "Some tests have been omitted.\n");
+ }
+ #endif
return 0;
}
@@ -1073,7 +3096,13 @@ int test(int argc, const char *argv[])
BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys");
// Initial files
- TEST_THAT(::system("gzip -d < testfiles/test_base.tgz | ( cd testfiles && tar xf - )") == 0);
+ #ifdef WIN32
+ TEST_THAT(::system("tar xzvf testfiles/test_base.tgz "
+ "-C testfiles") == 0);
+ #else
+ TEST_THAT(::system("gzip -d < testfiles/test_base.tgz "
+ "| ( cd testfiles && tar xf - )") == 0);
+ #endif
// Do the tests
@@ -1087,10 +3116,14 @@ int test(int argc, const char *argv[])
if(r != 0) return r;
r = test_bbackupd();
- if(r != 0) return r;
+ if(r != 0)
+ {
+ KillServer(bbackupd_pid);
+ KillServer(bbstored_pid);
+ return r;
+ }
test_kill_bbstored();
return 0;
}
-
diff --git a/test/bbackupd/testextra b/test/bbackupd/testextra
index ad7dd552..85783cca 100644
--- a/test/bbackupd/testextra
+++ b/test/bbackupd/testextra
@@ -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/test/bbackupd/testfiles/bbackupd-temploc.conf b/test/bbackupd/testfiles/bbackupd-temploc.conf
new file mode 100644
index 00000000..86901298
--- /dev/null
+++ b/test/bbackupd/testfiles/bbackupd-temploc.conf
@@ -0,0 +1,54 @@
+
+CertificateFile = testfiles/clientCerts.pem
+PrivateKeyFile = testfiles/clientPrivKey.pem
+TrustedCAsFile = testfiles/clientTrustedCAs.pem
+
+KeysFile = testfiles/bbackupd.keys
+
+DataDirectory = testfiles/bbackupd-data
+
+StoreHostname = localhost
+AccountNumber = 0x01234567
+
+UpdateStoreInterval = 3
+MinimumFileAge = 4
+MaxUploadWait = 24
+
+FileTrackingSizeThreshold = 1024
+DiffingUploadSizeThreshold = 1024
+
+MaximumDiffingTime = 3
+KeepAliveTime = 1
+
+ExtendedLogging = no
+ExtendedLogFile = testfiles/bbackupd.log
+
+CommandSocket = testfiles/bbackupd.sock
+
+Server
+{
+ PidFile = testfiles/bbackupd.pid
+}
+
+BackupLocations
+{
+ Test1
+ {
+ Path = testfiles/TestDir1
+
+ ExcludeFile = testfiles/TestDir1/excluded_1
+ ExcludeFile = testfiles/TestDir1/excluded_2
+ ExcludeFilesRegex = \.excludethis$
+ ExcludeFilesRegex = EXCLUDE
+ AlwaysIncludeFile = testfiles/TestDir1/dont.excludethis
+ ExcludeDir = testfiles/TestDir1/exclude_dir
+ ExcludeDir = testfiles/TestDir1/exclude_dir_2
+ ExcludeDirsRegex = not_this_dir
+ AlwaysIncludeDirsRegex = ALWAYSINCLUDE
+ }
+ Test2
+ {
+ Path = testfiles/TestDir1
+ }
+}
+
diff --git a/test/bbackupd/testfiles/bbackupd.conf b/test/bbackupd/testfiles/bbackupd.conf
index c25b4eab..643978f2 100644..100755
--- a/test/bbackupd/testfiles/bbackupd.conf
+++ b/test/bbackupd/testfiles/bbackupd.conf
@@ -13,17 +13,21 @@ AccountNumber = 0x01234567
UpdateStoreInterval = 3
MinimumFileAge = 4
MaxUploadWait = 24
+DeleteRedundantLocationsAfter = 10
FileTrackingSizeThreshold = 1024
DiffingUploadSizeThreshold = 1024
-MaximumDiffingTime = 8
+MaximumDiffingTime = 3
+KeepAliveTime = 1
-ExtendedLogging = yes
+ExtendedLogging = no
+ExtendedLogFile = testfiles/bbackupd.log
CommandSocket = testfiles/bbackupd.sock
-NotifyScript = perl testfiles/notifyscript.pl
+NotifyScript = /usr/bin/perl testfiles/notifyscript.pl
+SyncAllowScript = /usr/bin/perl testfiles/syncallowscript.pl
Server
{
diff --git a/test/bbackupd/testfiles/bbackupd.conf.in b/test/bbackupd/testfiles/bbackupd.conf.in
new file mode 100644
index 00000000..aecb3884
--- /dev/null
+++ b/test/bbackupd/testfiles/bbackupd.conf.in
@@ -0,0 +1,54 @@
+
+CertificateFile = testfiles/clientCerts.pem
+PrivateKeyFile = testfiles/clientPrivKey.pem
+TrustedCAsFile = testfiles/clientTrustedCAs.pem
+
+KeysFile = testfiles/bbackupd.keys
+
+DataDirectory = testfiles/bbackupd-data
+
+StoreHostname = localhost
+AccountNumber = 0x01234567
+
+UpdateStoreInterval = 3
+MinimumFileAge = 4
+MaxUploadWait = 24
+DeleteRedundantLocationsAfter = 10
+
+FileTrackingSizeThreshold = 1024
+DiffingUploadSizeThreshold = 1024
+
+MaximumDiffingTime = 3
+KeepAliveTime = 1
+
+ExtendedLogging = no
+ExtendedLogFile = testfiles/bbackupd.log
+
+CommandSocket = testfiles/bbackupd.sock
+
+NotifyScript = @TARGET_PERL@ testfiles/notifyscript.pl
+SyncAllowScript = @TARGET_PERL@ testfiles/syncallowscript.pl
+
+Server
+{
+ PidFile = testfiles/bbackupd.pid
+}
+
+BackupLocations
+{
+ Test1
+ {
+ Path = testfiles/TestDir1
+
+ ExcludeFile = testfiles/TestDir1/excluded_1
+ ExcludeFile = testfiles/TestDir1/excluded_2
+ ExcludeFilesRegex = \.excludethis$
+ ExcludeFilesRegex = EXCLUDE
+ AlwaysIncludeFile = testfiles/TestDir1/dont.excludethis
+ ExcludeDir = testfiles/TestDir1/exclude_dir
+ ExcludeDir = testfiles/TestDir1/exclude_dir_2
+ ExcludeDirsRegex = not_this_dir
+ AlwaysIncludeDirsRegex = ALWAYSINCLUDE
+ }
+}
+
diff --git a/test/bbackupd/testfiles/extcheck1.pl b/test/bbackupd/testfiles/extcheck1.pl
index 8bd5b91d..fe7f5caa 100755
--- a/test/bbackupd/testfiles/extcheck1.pl
+++ b/test/bbackupd/testfiles/extcheck1.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.
@@ -39,7 +39,9 @@
#
use strict;
-unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit|")
+my $flags = $ARGV[0] or "";
+
+unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit 2>&1 |")
{
print "Couldn't open compare utility\n";
exit 2;
@@ -53,14 +55,23 @@ while(<IN>)
next unless m/\S/;
if(m/continousupdate/)
{
- $ret = 2 unless m/exists/;
+ unless (/exists/)
+ {
+ print "FAIL: continousupdate line does not match\n";
+ $ret = 2;
+ }
$seen = 1;
}
else
{
- $ret = 2 unless m/\AWARNING/ || m/\ADifferences/ || /might be reason/ || /probably due to file mod/;
+ unless (/\AWARNING/ or /\ADifferences/ or /might be reason/
+ or /probably due to file mod/)
+ {
+ print "FAIL: Summary line does not match\n";
+ $ret = 2;
+ }
}
- print;
+ print "READ: $_";
}
close IN;
diff --git a/test/bbackupd/testfiles/extcheck1.pl.in b/test/bbackupd/testfiles/extcheck1.pl.in
new file mode 100755
index 00000000..2a7c0e9a
--- /dev/null
+++ b/test/bbackupd/testfiles/extcheck1.pl.in
@@ -0,0 +1,44 @@
+#!@PERL@
+use strict;
+
+my $flags = $ARGV[0] or "";
+
+unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit 2>&1 |")
+{
+ print "Couldn't open compare utility\n";
+ exit 2;
+}
+
+my $ret = 1;
+my $seen = 0;
+
+while(<IN>)
+{
+ next unless m/\S/;
+ if(m/continousupdate/)
+ {
+ unless (/exists/)
+ {
+ print "FAIL: continousupdate line does not match\n";
+ $ret = 2;
+ }
+ $seen = 1;
+ }
+ else
+ {
+ unless (/\AWARNING/ or /\ADifferences/ or /might be reason/
+ or /probably due to file mod/)
+ {
+ print "FAIL: Summary line does not match\n";
+ $ret = 2;
+ }
+ }
+ print "READ: $_";
+}
+
+close IN;
+
+$ret = 2 unless $seen;
+
+exit $ret;
+
diff --git a/test/bbackupd/testfiles/extcheck2.pl b/test/bbackupd/testfiles/extcheck2.pl
index abf63ba9..4c2733a2 100755
--- a/test/bbackupd/testfiles/extcheck2.pl
+++ b/test/bbackupd/testfiles/extcheck2.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.
@@ -39,7 +39,9 @@
#
use strict;
-unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit|")
+my $flags = $ARGV[0] or "";
+
+unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit 2>&1 |")
{
print "Couldn't open compare utility\n";
exit 2;
@@ -52,13 +54,23 @@ while(<IN>)
next unless m/\S/;
if(m/continousupdate/)
{
- $ret = 2 unless m/contents/ || m/attributes/;
+ unless (m/contents/ or m/attributes/)
+ {
+ print "FAIL: continuousupdate line does not match\n";
+ $ret = 2;
+ }
}
else
{
- $ret = 2 unless m/\AWARNING/ || m/\ADifferences/ || /might be reason/ || /probably due to file mod/;
+ unless (/\AWARNING/ or /\ADifferences/ or /might be reason/
+ or /probably due to file mod/)
+ {
+ print "FAIL: summary line does not match\n";
+ $ret = 2;
+ }
}
- print;
+
+ print "READ: $_";
}
close IN;
diff --git a/test/bbackupd/testfiles/extcheck2.pl.in b/test/bbackupd/testfiles/extcheck2.pl.in
new file mode 100755
index 00000000..c79bf414
--- /dev/null
+++ b/test/bbackupd/testfiles/extcheck2.pl.in
@@ -0,0 +1,41 @@
+#!@PERL@
+use strict;
+
+my $flags = $ARGV[0] or "";
+
+unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit 2>&1 |")
+{
+ print "Couldn't open compare utility\n";
+ exit 2;
+}
+
+my $ret = 1;
+
+while(<IN>)
+{
+ next unless m/\S/;
+ if(m/continousupdate/)
+ {
+ unless (m/contents/ or m/attributes/)
+ {
+ print "FAIL: continuousupdate line does not match\n";
+ $ret = 2;
+ }
+ }
+ else
+ {
+ unless (/\AWARNING/ or /\ADifferences/ or /might be reason/
+ or /probably due to file mod/)
+ {
+ print "FAIL: summary line does not match\n";
+ $ret = 2;
+ }
+ }
+
+ print "READ: $_";
+}
+
+close IN;
+
+exit $ret;
+
diff --git a/test/bbackupd/testfiles/notifyscript.pl b/test/bbackupd/testfiles/notifyscript.pl
index deadadb9..b35c6573 100755
--- a/test/bbackupd/testfiles/notifyscript.pl
+++ b/test/bbackupd/testfiles/notifyscript.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/test/bbackupd/testfiles/notifyscript.pl.in b/test/bbackupd/testfiles/notifyscript.pl.in
new file mode 100755
index 00000000..89741e46
--- /dev/null
+++ b/test/bbackupd/testfiles/notifyscript.pl.in
@@ -0,0 +1,15 @@
+#!@TARGET_PERL@
+
+
+my $f = 'testfiles/notifyran.'.$ARGV[0].'.';
+my $n = 1;
+
+while(-e $f.$n)
+{
+ $n ++;
+}
+
+open FL,'>'.$f.$n;
+print FL localtime();
+close FL;
+
diff --git a/runtest.pl b/test/bbackupd/testfiles/syncallowscript.pl
index 5b4b1689..d06ff238 100755
--- a/runtest.pl
+++ b/test/bbackupd/testfiles/syncallowscript.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.
@@ -38,97 +38,34 @@
#
#
-use lib 'infrastructure';
-use BoxPlatform;
+use strict;
+use warnings;
-my ($test_name,$test_mode) = @ARGV;
-
-$test_mode = 'debug' if $test_mode eq '';
-
-if($test_name eq '' || ($test_mode ne 'debug' && $test_mode ne 'release'))
+my $control_file = 'testfiles/syncallowscript.control';
+if (! -r $control_file)
{
- print <<__E;
-Run Test utility -- bad usage.
-
-runtest.pl (test|ALL) [release|debug]
-
-Mode defaults to debug.
-
-__E
- exit(0);
+ print "now\n";
+ exit 0;
}
-my @results;
+my $control_state;
+open CONTROL, "< $control_file" or die "$control_file: $!";
+$control_state = <CONTROL>;
+defined $control_state or die "$control_file: read failed: $!";
+close CONTROL;
-if($test_name ne 'ALL')
-{
- # run one test
- runtest($test_name);
-}
-else
-{
- # run all tests
- my @tests;
- open MODULES,'modules.txt' or die "Can't open modules file";
- while(<MODULES>)
- {
- # omit bits on some platforms?
- next if m/\AEND-OMIT/;
- if(m/\AOMIT:(.+)/)
- {
- if($1 eq $build_os or $1 eq $target_os)
- {
- while(<MODULES>)
- {
- last if m/\AEND-OMIT/;
- }
- }
- next;
- }
- push @tests,$1 if m~\Atest/(\w+)\s~;
- }
- close MODULES;
-
- runtest($_) for(@tests)
-}
-
-# report results
-print "--------\n",join("\n",@results),"\n";
+my $marker_file_root = 'testfiles/syncallowscript.notifyran.';
+my $n = 1;
+my $marker_file;
-sub runtest
+while($marker_file = $marker_file_root.$n and -e $marker_file)
{
- my ($t) = @_;
-
- # attempt to make this test
- my $flag = ($test_mode eq 'release')?(BoxPlatform::make_flag('RELEASE')):'';
- my $make_res = system("cd test/$t ; $make_command $flag");
- if($make_res != 0)
- {
- push @results,"$t: make failed";
- return;
- }
-
- # run it
- my $test_res = system("cd $test_mode/test/$t ; ./t | tee ../../../temp.runtest");
-
- # open test results
- if(open RESULTS,'temp.runtest')
- {
- my $last;
- while(<RESULTS>)
- {
- $last = $_ if m/\w/;
- }
- close RESULTS;
- chomp $last;
- push @results,"$t: $last";
- }
- else
- {
- push @results,"$t: output not found";
- }
-
- # delete test results
- unlink 'temp.runtest';
+ $n ++;
}
+open FL,'>'.$marker_file or die "$marker_file: $!";
+print FL localtime();
+close FL;
+
+print $control_state;
+exit 0;
diff --git a/test/bbackupd/testfiles/syncallowscript.pl.in b/test/bbackupd/testfiles/syncallowscript.pl.in
new file mode 100755
index 00000000..f2ef1171
--- /dev/null
+++ b/test/bbackupd/testfiles/syncallowscript.pl.in
@@ -0,0 +1,33 @@
+#!@TARGET_PERL@
+
+use strict;
+use warnings;
+
+my $control_file = 'testfiles/syncallowscript.control';
+if (! -r $control_file)
+{
+ print "now\n";
+ exit 0;
+}
+
+my $control_state;
+open CONTROL, "< $control_file" or die "$control_file: $!";
+$control_state = <CONTROL>;
+defined $control_state or die "$control_file: read failed: $!";
+close CONTROL;
+
+my $marker_file_root = 'testfiles/syncallowscript.notifyran.';
+my $n = 1;
+my $marker_file;
+
+while($marker_file = $marker_file_root.$n and -e $marker_file)
+{
+ $n ++;
+}
+
+open FL,'>'.$marker_file or die "$marker_file: $!";
+print FL localtime();
+close FL;
+
+print $control_state;
+exit 0;
diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp
index ac388b33..cba8b692 100644
--- a/test/common/testcommon.cpp
+++ b/test/common/testcommon.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,13 +47,16 @@
#include "Box.h"
+#include <errno.h>
#include <stdio.h>
+#include <time.h>
#include "Test.h"
#include "Configuration.h"
#include "FdGetLine.h"
#include "Guards.h"
#include "FileStream.h"
+#include "InvisibleTempFileStream.h"
#include "IOStreamGetLine.h"
#include "NamedLock.h"
#include "ReadGatherStream.h"
@@ -62,6 +65,12 @@
#include "CommonException.h"
#include "Conversion.h"
#include "autogen_ConversionException.h"
+#include "CollectInBufferStream.h"
+#include "Archive.h"
+#include "Timer.h"
+#include "Logging.h"
+#include "ZeroStream.h"
+#include "PartialReadStream.h"
#include "MemLeakFindOn.h"
@@ -168,11 +177,139 @@ ConfigurationVerify verify =
0
};
+class TestLogger : public Logger
+{
+ private:
+ bool mTriggered;
+ Log::Level mTargetLevel;
+
+ public:
+ TestLogger(Log::Level targetLevel)
+ : mTriggered(false), mTargetLevel(targetLevel)
+ {
+ Logging::Add(this);
+ }
+ ~TestLogger()
+ {
+ Logging::Remove(this);
+ }
+
+ bool IsTriggered() { return mTriggered; }
+ void Reset() { mTriggered = false; }
+
+ virtual bool Log(Log::Level level, const std::string& rFile,
+ int line, std::string& rMessage)
+ {
+ if (level == mTargetLevel)
+ {
+ mTriggered = true;
+ }
+ return true;
+ }
+
+ virtual const char* GetType() { return "Test"; }
+ virtual void SetProgramName(const std::string& rProgramName) { }
+};
+
int test(int argc, const char *argv[])
{
- // Test memory leak detection
+ // Test PartialReadStream and ReadGatherStream handling of files
+ // over 2GB (refs #2)
+ {
+ char buffer[8];
+
+ ZeroStream zero(0x80000003);
+ zero.Seek(0x7ffffffe, IOStream::SeekType_Absolute);
+ TEST_THAT(zero.GetPosition() == 0x7ffffffe);
+ TEST_THAT(zero.Read(buffer, 8) == 5);
+ TEST_THAT(zero.GetPosition() == 0x80000003);
+ TEST_THAT(zero.Read(buffer, 8) == 0);
+ zero.Seek(0, IOStream::SeekType_Absolute);
+ TEST_THAT(zero.GetPosition() == 0);
+
+ char* buffer2 = new char [0x1000000];
+ TEST_THAT(buffer2 != NULL);
+
+ PartialReadStream part(zero, 0x80000002);
+ for (int i = 0; i < 0x80; i++)
+ {
+ int read = part.Read(buffer2, 0x1000000);
+ TEST_THAT(read == 0x1000000);
+ }
+ TEST_THAT(part.Read(buffer, 8) == 2);
+ TEST_THAT(part.Read(buffer, 8) == 0);
+
+ delete [] buffer2;
+
+ ReadGatherStream gather(false);
+ zero.Seek(0, IOStream::SeekType_Absolute);
+ int component = gather.AddComponent(&zero);
+ gather.AddBlock(component, 0x80000002);
+ TEST_THAT(gather.Read(buffer, 8) == 8);
+ }
+
+ // Test self-deleting temporary file streams
+ {
+ std::string tempfile("testfiles/tempfile");
+ TEST_CHECK_THROWS(InvisibleTempFileStream fs(tempfile.c_str()),
+ CommonException, OSFileOpenError);
+ InvisibleTempFileStream fs(tempfile.c_str(), O_CREAT);
+
+ #ifdef WIN32
+ // file is still visible under Windows
+ TEST_THAT(TestFileExists(tempfile.c_str()));
+
+ // opening it again should work
+ InvisibleTempFileStream fs2(tempfile.c_str());
+ TEST_THAT(TestFileExists(tempfile.c_str()));
+
+ // opening it to create should work
+ InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT);
+ TEST_THAT(TestFileExists(tempfile.c_str()));
+
+ // opening it to create exclusively should fail
+ TEST_CHECK_THROWS(InvisibleTempFileStream fs4(tempfile.c_str(),
+ O_CREAT | O_EXCL), CommonException, OSFileOpenError);
+
+ fs2.Close();
+ #else
+ // file is not visible under Unix
+ TEST_THAT(!TestFileExists(tempfile.c_str()));
+
+ // opening it again should fail
+ TEST_CHECK_THROWS(InvisibleTempFileStream fs2(tempfile.c_str()),
+ CommonException, OSFileOpenError);
+
+ // opening it to create should work
+ InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT);
+ TEST_THAT(!TestFileExists(tempfile.c_str()));
+
+ // opening it to create exclusively should work
+ InvisibleTempFileStream fs4(tempfile.c_str(), O_CREAT | O_EXCL);
+ TEST_THAT(!TestFileExists(tempfile.c_str()));
+
+ fs4.Close();
+ #endif
+
+ fs.Close();
+ fs3.Close();
+
+ // now that it's closed, it should be invisible on all platforms
+ TEST_THAT(!TestFileExists(tempfile.c_str()));
+ }
+
+ // Test that memory leak detection doesn't crash
+ {
+ char *test = new char[1024];
+ delete [] test;
+ MemBlockStream *s = new MemBlockStream(test,12);
+ delete s;
+ }
+
#ifdef BOX_MEMORY_LEAK_TESTING
{
+ Timers::Cleanup();
+
TEST_THAT(memleakfinder_numleaks() == 0);
void *block = ::malloc(12);
TEST_THAT(memleakfinder_numleaks() == 1);
@@ -188,9 +325,85 @@ int test(int argc, const char *argv[])
TEST_THAT(memleakfinder_numleaks() == 1);
delete [] test;
TEST_THAT(memleakfinder_numleaks() == 0);
+
+ Timers::Init();
}
#endif // BOX_MEMORY_LEAK_TESTING
+
+ // test main() initialises timers for us, so uninitialise them
+ Timers::Cleanup();
+
+ // Check that using timer methods without initialisation
+ // throws an assertion failure. Can only do this in debug mode
+ #ifndef NDEBUG
+ TEST_CHECK_THROWS(Timers::Add(*(Timer*)NULL),
+ CommonException, AssertFailed);
+ TEST_CHECK_THROWS(Timers::Remove(*(Timer*)NULL),
+ CommonException, AssertFailed);
+ #endif
+
+ // TEST_CHECK_THROWS(Timers::Signal(), CommonException, AssertFailed);
+ #ifndef NDEBUG
+ TEST_CHECK_THROWS(Timers::Cleanup(), CommonException,
+ AssertFailed);
+ #endif
+
+ // Check that we can initialise the timers
+ Timers::Init();
+
+ // Check that double initialisation throws an exception
+ #ifndef NDEBUG
+ TEST_CHECK_THROWS(Timers::Init(), CommonException,
+ AssertFailed);
+ #endif
+
+ // Check that we can clean up the timers
+ Timers::Cleanup();
+
+ // Check that double cleanup throws an exception
+ #ifndef NDEBUG
+ TEST_CHECK_THROWS(Timers::Cleanup(), CommonException,
+ AssertFailed);
+ #endif
+
+ Timers::Init();
+
+ Timer t0(0); // should never expire
+ Timer t1(1);
+ Timer t2(2);
+ Timer t3(3);
+ TEST_THAT(!t0.HasExpired());
+ TEST_THAT(!t1.HasExpired());
+ TEST_THAT(!t2.HasExpired());
+ TEST_THAT(!t3.HasExpired());
+
+ safe_sleep(1);
+ TEST_THAT(!t0.HasExpired());
+ TEST_THAT(t1.HasExpired());
+ TEST_THAT(!t2.HasExpired());
+ TEST_THAT(!t3.HasExpired());
+
+ safe_sleep(1);
+ TEST_THAT(!t0.HasExpired());
+ TEST_THAT(t1.HasExpired());
+ TEST_THAT(t2.HasExpired());
+ TEST_THAT(!t3.HasExpired());
+
+ t1 = Timer(1);
+ t2 = Timer(2);
+ TEST_THAT(!t0.HasExpired());
+ TEST_THAT(!t1.HasExpired());
+ TEST_THAT(!t2.HasExpired());
+
+ safe_sleep(1);
+ TEST_THAT(!t0.HasExpired());
+ TEST_THAT(t1.HasExpired());
+ TEST_THAT(!t2.HasExpired());
+ TEST_THAT(t3.HasExpired());
+
+ // Leave timers initialised for rest of test.
+ // Test main() will cleanup after test finishes.
static char *testfilelines[] =
{
@@ -575,7 +788,7 @@ int test(int argc, const char *argv[])
TEST_THAT(elist.SizeOfDefiniteList() == 4);
// Add regex entries
- #ifdef HAVE_REGEX_H
+ #ifdef HAVE_REGEX_SUPPORT
elist.AddRegexEntries(std::string("[a-d]+\\.reg$" "\x01" "EXCLUDE" "\x01" "^exclude$"));
elist.AddRegexEntries(std::string(""));
TEST_CHECK_THROWS(elist.AddRegexEntries(std::string("[:not_valid")), CommonException, BadRegularExpression);
@@ -584,24 +797,123 @@ int test(int argc, const char *argv[])
TEST_CHECK_THROWS(elist.AddRegexEntries(std::string("[a-d]+\\.reg$" "\x01" "EXCLUDE" "\x01" "^exclude$")), CommonException, RegexNotSupportedOnThisPlatform);
TEST_THAT(elist.SizeOfRegexList() == 0);
#endif
+
+ #ifdef WIN32
+ #define CASE_SENSITIVE false
+ #else
+ #define CASE_SENSITIVE true
+ #endif
+
// Try some matches!
TEST_THAT(elist.IsExcluded(std::string("Definite1")) == true);
TEST_THAT(elist.IsExcluded(std::string("/dir/DefNumberTwo")) == true);
TEST_THAT(elist.IsExcluded(std::string("ThingDefThree")) == true);
TEST_THAT(elist.IsExcluded(std::string("AnotherDef")) == true);
TEST_THAT(elist.IsExcluded(std::string("dir/DefNumberTwo")) == false);
- #ifdef HAVE_REGEX_H
+
+ // Try some case insensitive matches,
+ // that should pass on Win32 and fail elsewhere
+ TEST_THAT(elist.IsExcluded("DEFINITe1")
+ == !CASE_SENSITIVE);
+ TEST_THAT(elist.IsExcluded("/Dir/DefNumberTwo")
+ == !CASE_SENSITIVE);
+ TEST_THAT(elist.IsExcluded("thingdefthree")
+ == !CASE_SENSITIVE);
+
+ #ifdef HAVE_REGEX_SUPPORT
TEST_THAT(elist.IsExcluded(std::string("b.reg")) == true);
+ TEST_THAT(elist.IsExcluded(std::string("B.reg")) == !CASE_SENSITIVE);
+ TEST_THAT(elist.IsExcluded(std::string("b.Reg")) == !CASE_SENSITIVE);
TEST_THAT(elist.IsExcluded(std::string("e.reg")) == false);
- TEST_THAT(elist.IsExcluded(std::string("b.Reg")) == false);
- TEST_THAT(elist.IsExcluded(std::string("DEfinite1")) == false);
+ TEST_THAT(elist.IsExcluded(std::string("e.Reg")) == false);
+ TEST_THAT(elist.IsExcluded(std::string("DEfinite1")) == !CASE_SENSITIVE);
TEST_THAT(elist.IsExcluded(std::string("DEXCLUDEfinite1")) == true);
- TEST_THAT(elist.IsExcluded(std::string("DEfinitexclude1")) == false);
+ TEST_THAT(elist.IsExcluded(std::string("DEfinitexclude1")) == !CASE_SENSITIVE);
TEST_THAT(elist.IsExcluded(std::string("exclude")) == true);
+ TEST_THAT(elist.IsExcluded(std::string("ExcludE")) == !CASE_SENSITIVE);
#endif
+
+ #undef CASE_SENSITIVE
+
+ TestLogger logger(Log::WARNING);
+ TEST_THAT(!logger.IsTriggered());
+ elist.AddDefiniteEntries(std::string("/foo"));
+ TEST_THAT(!logger.IsTriggered());
+ elist.AddDefiniteEntries(std::string("/foo/"));
+ TEST_THAT(logger.IsTriggered());
+ logger.Reset();
+ elist.AddDefiniteEntries(std::string("/foo"
+ DIRECTORY_SEPARATOR));
+ TEST_THAT(logger.IsTriggered());
+ logger.Reset();
+ elist.AddDefiniteEntries(std::string("/foo"
+ DIRECTORY_SEPARATOR "bar\x01/foo"));
+ TEST_THAT(!logger.IsTriggered());
+ elist.AddDefiniteEntries(std::string("/foo"
+ DIRECTORY_SEPARATOR "bar\x01/foo"
+ DIRECTORY_SEPARATOR));
+ TEST_THAT(logger.IsTriggered());
}
test_conversions();
+ // test that we can use Archive and CollectInBufferStream
+ // to read and write arbitrary types to a memory buffer
+
+ {
+ CollectInBufferStream buffer;
+ ASSERT(buffer.GetPosition() == 0);
+
+ {
+ Archive archive(buffer, 0);
+ ASSERT(buffer.GetPosition() == 0);
+
+ archive.Write((bool) true);
+ archive.Write((bool) false);
+ archive.Write((int) 0x12345678);
+ archive.Write((int) 0x87654321);
+ archive.Write((int64_t) 0x0badfeedcafebabeLL);
+ archive.Write((uint64_t) 0xfeedfacedeadf00dLL);
+ archive.Write((uint8_t) 0x01);
+ archive.Write((uint8_t) 0xfe);
+ archive.Write(std::string("hello world!"));
+ archive.Write(std::string("goodbye cruel world!"));
+ }
+
+ CollectInBufferStream buf2;
+ buf2.Write(buffer.GetBuffer(), buffer.GetSize());
+ TEST_THAT(buf2.GetPosition() == buffer.GetSize());
+
+ buf2.SetForReading();
+ TEST_THAT(buf2.GetPosition() == 0);
+
+ {
+ Archive archive(buf2, 0);
+ TEST_THAT(buf2.GetPosition() == 0);
+
+ bool b;
+ archive.Read(b); TEST_THAT(b == true);
+ archive.Read(b); TEST_THAT(b == false);
+
+ int i;
+ archive.Read(i); TEST_THAT(i == 0x12345678);
+ archive.Read(i); TEST_THAT((unsigned int)i == 0x87654321);
+
+ uint64_t i64;
+ archive.Read(i64); TEST_THAT(i64 == 0x0badfeedcafebabeLL);
+ archive.Read(i64); TEST_THAT(i64 == 0xfeedfacedeadf00dLL);
+
+ uint8_t i8;
+ archive.Read(i8); TEST_THAT(i8 == 0x01);
+ archive.Read(i8); TEST_THAT(i8 == 0xfe);
+
+ std::string s;
+ archive.Read(s); TEST_THAT(s == "hello world!");
+ archive.Read(s); TEST_THAT(s == "goodbye cruel world!");
+
+ TEST_THAT(!buf2.StreamDataLeft());
+ }
+ }
+
return 0;
}
diff --git a/test/compress/testcompress.cpp b/test/compress/testcompress.cpp
index a7ea1298..a8367722 100644
--- a/test/compress/testcompress.cpp
+++ b/test/compress/testcompress.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/test/crypto/testcrypto.cpp b/test/crypto/testcrypto.cpp
index f3e9fb50..0dd7debb 100644
--- a/test/crypto/testcrypto.cpp
+++ b/test/crypto/testcrypto.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/test/raidfile/testextra b/test/raidfile/testextra
index 7b0bd613..1d668dd1 100644
--- a/test/raidfile/testextra
+++ b/test/raidfile/testextra
@@ -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/test/raidfile/testraidfile.cpp b/test/raidfile/testraidfile.cpp
index 04b5b454..1e5715af 100644
--- a/test/raidfile/testraidfile.cpp
+++ b/test/raidfile/testraidfile.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,7 +50,10 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+
+#ifdef HAVE_SYSCALL
#include <sys/syscall.h>
+#endif
#include <string.h>
@@ -245,16 +248,24 @@ void testReadingFileContents(int set, const char *filename, void *data, int data
bytesread += r;
}
TEST_THAT(!readstream4.StreamDataLeft()); // check IOStream interface is correct
+ pread.reset();
// Be nasty, and create some errors for the RAID stuff to recover from...
if(TestRAIDProperties)
{
char stripe1fn[256], stripe1fnRename[256];
- sprintf(stripe1fn, "testfiles/%d_%d/%s.rf", set, startDisc, filename);
- sprintf(stripe1fnRename, "testfiles/%d_%d/%s.rf-REMOVED", set, startDisc, filename);
+ sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename);
+ sprintf(stripe1fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, startDisc,
+ filename);
char stripe2fn[256], stripe2fnRename[256];
- sprintf(stripe2fn, "testfiles/%d_%d/%s.rf", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename);
- sprintf(stripe2fnRename, "testfiles/%d_%d/%s.rf-REMOVED", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename);
+ sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rf", set,
+ (startDisc + 1) % RAID_NUMBER_DISCS, filename);
+ sprintf(stripe2fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rf-REMOVED", set,
+ (startDisc + 1) % RAID_NUMBER_DISCS, filename);
// Read with stripe1 + parity
TEST_THAT(::rename(stripe2fn, stripe2fnRename) == 0);
@@ -290,9 +301,15 @@ void testReadingFileContents(int set, const char *filename, void *data, int data
}
mungefilename[m++] = '\0';
char stripe1munge[256];
- sprintf(stripe1munge, "testfiles/%d_%d/.raidfile-unreadable/%s", set, startDisc, mungefilename);
+ sprintf(stripe1munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR ".raidfile-unreadable"
+ DIRECTORY_SEPARATOR "%s", set, startDisc,
+ mungefilename);
char stripe2munge[256];
- sprintf(stripe2munge, "testfiles/%d_%d/.raidfile-unreadable/%s", set, (startDisc + 1) % RAID_NUMBER_DISCS, mungefilename);
+ sprintf(stripe2munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR ".raidfile-unreadable"
+ DIRECTORY_SEPARATOR "%s", set,
+ (startDisc + 1) % RAID_NUMBER_DISCS, mungefilename);
#ifdef TRF_CAN_INTERCEPT
@@ -397,10 +414,12 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize
write4.Write(data, datasize);
// This time, don't discard and transform it to a RAID File
char writefnPre[256];
- sprintf(writefnPre, "testfiles/%d_%d/%s.rfwX", set, startDisc, filename);
+ sprintf(writefnPre, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rfwX", set, startDisc, filename);
TEST_THAT(TestFileExists(writefnPre));
char writefn[256];
- sprintf(writefn, "testfiles/%d_%d/%s.rfw", set, startDisc, filename);
+ sprintf(writefn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rfw", set, startDisc, filename);
int usageInBlocks = write4.GetDiscUsageInBlocks();
write4.Commit(DoTransform);
// Check that files are nicely done...
@@ -428,14 +447,19 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize
fs1 = ((fullblocks / 2)+1) * RAID_BLOCK_SIZE;
}
char stripe1fn[256];
- sprintf(stripe1fn, "testfiles/%d_%d/%s.rf", set, startDisc, filename);
+ sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename);
TEST_THAT(TestGetFileSize(stripe1fn) == fs1);
char stripe2fn[256];
- sprintf(stripe2fn, "testfiles/%d_%d/%s.rf", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename);
+ sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rf", set,
+ (startDisc + 1) % RAID_NUMBER_DISCS, filename);
TEST_THAT(TestGetFileSize(stripe2fn) == (int)(datasize - fs1));
// Parity file size
char parityfn[256];
- sprintf(parityfn, "testfiles/%d_%d/%s.rf", set, (startDisc + 2) % RAID_NUMBER_DISCS, filename);
+ sprintf(parityfn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
+ DIRECTORY_SEPARATOR "%s.rf", set,
+ (startDisc + 2) % RAID_NUMBER_DISCS, filename);
// Mildly complex calculation
unsigned int blocks = datasize / RAID_BLOCK_SIZE;
unsigned int bytesOver = datasize % RAID_BLOCK_SIZE;
@@ -474,14 +498,16 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize
if(datasize > (3*1024))
{
int f;
- TEST_THAT((f = ::open(stripe1fn, O_RDONLY, 0)) != -1);
+ TEST_THAT((f = ::open(stripe1fn, O_RDONLY | O_BINARY,
+ 0)) != -1);
TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock)));
for(unsigned int q = 0; q < sizeof(testblock); ++q)
{
TEST_THAT(testblock[q] == ((char*)data)[q]);
}
::close(f);
- TEST_THAT((f = ::open(stripe2fn, O_RDONLY, 0)) != -1);
+ TEST_THAT((f = ::open(stripe2fn, O_RDONLY | O_BINARY,
+ 0)) != -1);
TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock)));
for(unsigned int q = 0; q < sizeof(testblock); ++q)
{
@@ -574,7 +600,9 @@ void test_overwrites()
// Generate a random pre-existing write file (and ensure that it doesn't exist already)
int f;
- TEST_THAT((f = ::open("testfiles/0_2/overwrite_B.rfwX", O_WRONLY | O_CREAT | O_EXCL, 0755)) != -1);
+ TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
+ DIRECTORY_SEPARATOR "overwrite_B.rfwX",
+ O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0755)) != -1);
TEST_THAT(::write(f, "TESTTEST", 8) == 8);
::close(f);
@@ -595,7 +623,7 @@ int test(int argc, const char *argv[])
// Initialise the controller
RaidFileController &rcontroller = RaidFileController::GetController();
- rcontroller.Initialise("testfiles/raidfile.conf");
+ rcontroller.Initialise("testfiles" DIRECTORY_SEPARATOR "raidfile.conf");
// some data
char data[TEST_DATA_SIZE];
@@ -612,9 +640,12 @@ int test(int argc, const char *argv[])
// Try creating a directory
RaidFileWrite::CreateDirectory(0, "test-dir");
- TEST_THAT(TestDirExists("testfiles/0_0/test-dir"));
- TEST_THAT(TestDirExists("testfiles/0_1/test-dir"));
- TEST_THAT(TestDirExists("testfiles/0_2/test-dir"));
+ TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_0"
+ DIRECTORY_SEPARATOR "test-dir"));
+ TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_1"
+ DIRECTORY_SEPARATOR "test-dir"));
+ TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_2"
+ DIRECTORY_SEPARATOR "test-dir"));
TEST_THAT(RaidFileRead::DirectoryExists(0, "test-dir"));
TEST_THAT(!RaidFileRead::DirectoryExists(0, "test-dir-not"));
@@ -646,9 +677,12 @@ int test(int argc, const char *argv[])
// Before it's deleted, check to see the contents are as expected
int f;
- TEST_THAT((f = ::open("testfiles/0_2/test1.rfwX", O_RDONLY, 0)) >= 0);
+ TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
+ DIRECTORY_SEPARATOR "test1.rfwX", O_RDONLY | O_BINARY, 0))
+ >= 0);
char buffer[sizeof(data)];
- TEST_THAT(::read(f, buffer, sizeof(buffer)) == sizeof(buffer));
+ int bytes_read = ::read(f, buffer, sizeof(buffer));
+ TEST_THAT(bytes_read == sizeof(buffer));
for(unsigned int l = 0; l < 1024; ++l)
{
TEST_THAT(buffer[l] == data[l]);
@@ -662,7 +696,8 @@ int test(int argc, const char *argv[])
TEST_THAT(buffer[l+2048+sizeof(data2)] == data2[l]);
}
TEST_THAT(::lseek(f, sizeof(data), SEEK_SET) == sizeof(buffer));
- TEST_THAT(::read(f, buffer, sizeof(buffer)) == sizeof(buffer));
+ bytes_read = ::read(f, buffer, sizeof(buffer));
+ TEST_THAT(bytes_read == sizeof(buffer));
for(unsigned int l = 0; l < 1024; ++l)
{
TEST_THAT(buffer[l] == data[l]);
@@ -673,7 +708,9 @@ int test(int argc, const char *argv[])
// Commit the data
write1.Commit();
- TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) >= 0);
+ TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
+ DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0))
+ >= 0);
::close(f);
// Now try and read it
@@ -725,7 +762,9 @@ int test(int argc, const char *argv[])
write2.Write(data, sizeof(data));
// This time, discard it
write2.Discard();
- TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) == -1);
+ TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
+ DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0))
+ == -1);
// And leaving it there...
RaidFileWrite writeLeave(0, "test1");
@@ -733,7 +772,9 @@ int test(int argc, const char *argv[])
writeLeave.Write(data, sizeof(data));
// This time, commit it
writeLeave.Commit();
- TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) != -1);
+ TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
+ DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0))
+ != -1);
::close(f);
// Then check that the thing will refuse to open it again.
@@ -750,7 +791,8 @@ int test(int argc, const char *argv[])
write3b.Write(data + 3, sizeof(data) - 3);
write3b.Commit();
// Test it
- testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false /*TestRAIDProperties*/);
+ testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false
+ /* TestRAIDProperties */);
// And once again, but this time making it a raid file
RaidFileWrite write3c(0, "test1");
@@ -759,7 +801,8 @@ int test(int argc, const char *argv[])
write3c.Write(data + 7, sizeof(data) - 7);
write3c.Commit(true); // make RAID
// Test it
- testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false /*TestRAIDProperties*/);
+ testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false
+ /*TestRAIDProperties*/);
// Test opening a file which doesn't exist
TEST_CHECK_THROWS(
@@ -774,20 +817,23 @@ int test(int argc, const char *argv[])
w.Commit(true);
// Try removing the parity file
- TEST_THAT(::rename("testfiles/0_0/damage.rf", "testfiles/0_0/damage.rf-NT") == 0);
+ TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0"
+ DIRECTORY_SEPARATOR "damage.rf",
+ "testfiles" DIRECTORY_SEPARATOR "0_0"
+ DIRECTORY_SEPARATOR "damage.rf-NT") == 0);
{
std::auto_ptr<RaidFileRead> pr0 = RaidFileRead::Open(0, "damage");
pr0->Read(buffer, sizeof(data));
}
- TEST_THAT(::rename("testfiles/0_0/damage.rf-NT", "testfiles/0_0/damage.rf") == 0);
-
+ TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf-NT", "testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0);
+
// Delete one of the files
- TEST_THAT(::unlink("testfiles/0_1/damage.rf") == 0); // stripe 1
+ TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "damage.rf") == 0); // stripe 1
#ifdef TRF_CAN_INTERCEPT
// Open it and read...
{
- intercept_setup_error("testfiles/0_2/damage.rf", 0, EIO, SYS_read); // stripe 2
+ intercept_setup_error("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "damage.rf", 0, EIO, SYS_read); // stripe 2
std::auto_ptr<RaidFileRead> pr1 = RaidFileRead::Open(0, "damage");
TEST_CHECK_THROWS(
pr1->Read(buffer, sizeof(data)),
@@ -799,7 +845,7 @@ int test(int argc, const char *argv[])
#endif //TRF_CAN_INTERCEPT
// Delete another
- TEST_THAT(::unlink("testfiles/0_0/damage.rf") == 0); // parity
+ TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0); // parity
TEST_CHECK_THROWS(
std::auto_ptr<RaidFileRead> pread2 = RaidFileRead::Open(0, "damage"),
@@ -810,22 +856,22 @@ int test(int argc, const char *argv[])
{
RaidFileWrite::CreateDirectory(0, "dirread");
// Make some contents
- RaidFileWrite::CreateDirectory(0, "dirread/dfsdf1");
- RaidFileWrite::CreateDirectory(0, "dirread/ponwq2");
+ RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "dfsdf1");
+ RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "ponwq2");
{
- RaidFileWrite w(0, "dirread/sdf9873241");
+ RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "sdf9873241");
w.Open();
w.Write(data, sizeof(data));
w.Commit(true);
}
{
- RaidFileWrite w(0, "dirread/fsdcxjni3242");
+ RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "fsdcxjni3242");
w.Open();
w.Write(data, sizeof(data));
w.Commit(true);
}
{
- RaidFileWrite w(0, "dirread/cskjnds3");
+ RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "cskjnds3");
w.Open();
w.Write(data, sizeof(data));
w.Commit(false);
@@ -841,15 +887,15 @@ int test(int argc, const char *argv[])
TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_DirsOnly, names));
TEST_THAT(list_matches(names, dir_list1));
// Delete things
- TEST_THAT(::unlink("testfiles/0_0/dirread/sdf9873241.rf") == 0);
+ TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
TEST_THAT(list_matches(names, file_list1));
// Delete something else so that it's not recoverable
- TEST_THAT(::unlink("testfiles/0_1/dirread/sdf9873241.rf") == 0);
+ TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
TEST_THAT(false == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
TEST_THAT(list_matches(names, file_list1));
// And finally...
- TEST_THAT(::unlink("testfiles/0_2/dirread/sdf9873241.rf") == 0);
+ TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
TEST_THAT(list_matches(names, file_list2));
}
diff --git a/test/win32/testlibwin32.cpp b/test/win32/testlibwin32.cpp
index 02dfd5b5..62670cac 100644
--- a/test/win32/testlibwin32.cpp
+++ b/test/win32/testlibwin32.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.
@@ -44,12 +44,214 @@
#ifdef WIN32
+#include <assert.h>
+#include <AccCtrl.h>
+#include <Aclapi.h>
+
#include "../../bin/bbackupd/BackupDaemon.h"
#include "BoxPortsAndFiles.h"
#include "emu.h"
int main(int argc, char* argv[])
{
+ // ACL tests
+ char* exename = getenv("WINDIR");
+
+ PSID psidOwner;
+ PSID psidGroup;
+ PACL pDacl;
+ PSECURITY_DESCRIPTOR pSecurityDesc;
+
+ DWORD result = GetNamedSecurityInfo(
+ exename, // pObjectName
+ SE_FILE_OBJECT, // ObjectType
+ DACL_SECURITY_INFORMATION | // SecurityInfo
+ GROUP_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION,
+ &psidOwner, // ppsidOwner,
+ &psidGroup, // ppsidGroup,
+ &pDacl, // ppDacl,
+ NULL, // ppSacl,
+ &pSecurityDesc // ppSecurityDescriptor
+ );
+ if (result != ERROR_SUCCESS)
+ {
+ printf("Error getting security info for '%s': error %d",
+ exename, result);
+ }
+ assert(result == ERROR_SUCCESS);
+
+ char namebuf[1024];
+ char domainbuf[1024];
+ SID_NAME_USE nametype;
+ DWORD namelen = sizeof(namebuf);
+ DWORD domainlen = sizeof(domainbuf);
+
+ assert(LookupAccountSid(NULL, psidOwner, namebuf, &namelen,
+ domainbuf, &domainlen, &nametype));
+
+ printf("Owner:\n");
+ printf("User name: %s\n", namebuf);
+ printf("Domain name: %s\n", domainbuf);
+ printf("Name type: %d\n", nametype);
+ printf("\n");
+
+ namelen = sizeof(namebuf);
+ domainlen = sizeof(domainbuf);
+
+ assert(LookupAccountSid(NULL, psidGroup, namebuf, &namelen,
+ domainbuf, &domainlen, &nametype));
+
+ printf("Group:\n");
+ printf("User name: %s\n", namebuf);
+ printf("Domain name: %s\n", domainbuf);
+ printf("Name type: %d\n", nametype);
+ printf("\n");
+
+ ULONG numEntries;
+ PEXPLICIT_ACCESS pEntries;
+ result = GetExplicitEntriesFromAcl
+ (
+ pDacl, // pAcl
+ &numEntries, // pcCountOfExplicitEntries,
+ &pEntries // pListOfExplicitEntries
+ );
+ assert(result == ERROR_SUCCESS);
+
+ printf("Found %lu explicit DACL entries for '%s'\n\n",
+ (unsigned long)numEntries, exename);
+
+ for (ULONG i = 0; i < numEntries; i++)
+ {
+ EXPLICIT_ACCESS* pEntry = &(pEntries[i]);
+ printf("DACL entry %lu:\n", (unsigned long)i);
+
+ DWORD perms = pEntry->grfAccessPermissions;
+ printf(" Access permissions: ", perms);
+
+ #define PRINT_PERM(name) \
+ if (perms & name) \
+ { \
+ printf(#name " "); \
+ perms &= ~name; \
+ }
+
+ PRINT_PERM(FILE_ADD_FILE);
+ PRINT_PERM(FILE_ADD_SUBDIRECTORY);
+ PRINT_PERM(FILE_ALL_ACCESS);
+ PRINT_PERM(FILE_APPEND_DATA);
+ PRINT_PERM(FILE_CREATE_PIPE_INSTANCE);
+ PRINT_PERM(FILE_DELETE_CHILD);
+ PRINT_PERM(FILE_EXECUTE);
+ PRINT_PERM(FILE_LIST_DIRECTORY);
+ PRINT_PERM(FILE_READ_ATTRIBUTES);
+ PRINT_PERM(FILE_READ_DATA);
+ PRINT_PERM(FILE_READ_EA);
+ PRINT_PERM(FILE_TRAVERSE);
+ PRINT_PERM(FILE_WRITE_ATTRIBUTES);
+ PRINT_PERM(FILE_WRITE_DATA);
+ PRINT_PERM(FILE_WRITE_EA);
+ PRINT_PERM(STANDARD_RIGHTS_READ);
+ PRINT_PERM(STANDARD_RIGHTS_WRITE);
+ PRINT_PERM(SYNCHRONIZE);
+ PRINT_PERM(DELETE);
+ PRINT_PERM(READ_CONTROL);
+ PRINT_PERM(WRITE_DAC);
+ PRINT_PERM(WRITE_OWNER);
+ PRINT_PERM(MAXIMUM_ALLOWED);
+ PRINT_PERM(GENERIC_ALL);
+ PRINT_PERM(GENERIC_EXECUTE);
+ PRINT_PERM(GENERIC_WRITE);
+ PRINT_PERM(GENERIC_READ);
+ printf("\n");
+
+ if (perms)
+ {
+ printf(" Bits left over: %08x\n", perms);
+ }
+ assert(!perms);
+
+ printf(" Access mode: ");
+ switch(pEntry->grfAccessMode)
+ {
+ case NOT_USED_ACCESS:
+ printf("NOT_USED_ACCESS\n"); break;
+ case GRANT_ACCESS:
+ printf("GRANT_ACCESS\n"); break;
+ case DENY_ACCESS:
+ printf("DENY_ACCESS\n"); break;
+ case REVOKE_ACCESS:
+ printf("REVOKE_ACCESS\n"); break;
+ case SET_AUDIT_SUCCESS:
+ printf("SET_AUDIT_SUCCESS\n"); break;
+ case SET_AUDIT_FAILURE:
+ printf("SET_AUDIT_FAILURE\n"); break;
+ default:
+ printf("Unknown (%08x)\n", pEntry->grfAccessMode);
+ }
+
+ printf(" Trustee: ");
+ assert(pEntry->Trustee.pMultipleTrustee == NULL);
+ assert(pEntry->Trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE);
+ switch(pEntry->Trustee.TrusteeForm)
+ {
+ case TRUSTEE_IS_SID:
+ {
+ PSID trusteeSid = (PSID)(pEntry->Trustee.ptstrName);
+
+ namelen = sizeof(namebuf);
+ domainlen = sizeof(domainbuf);
+
+ assert(LookupAccountSid(NULL, trusteeSid, namebuf, &namelen,
+ domainbuf, &domainlen, &nametype));
+
+ printf("SID of %s\\%s (%d)\n", domainbuf, namebuf, nametype);
+ }
+ break;
+ case TRUSTEE_IS_NAME:
+ printf("Name\n"); break;
+ case TRUSTEE_BAD_FORM:
+ printf("Bad form\n"); assert(0);
+ case TRUSTEE_IS_OBJECTS_AND_SID:
+ printf("Objects and SID\n"); break;
+ case TRUSTEE_IS_OBJECTS_AND_NAME:
+ printf("Objects and name\n"); break;
+ default:
+ printf("Unknown form\n"); assert(0);
+ }
+
+ printf(" Trustee type: ");
+ switch(pEntry->Trustee.TrusteeType)
+ {
+ case TRUSTEE_IS_UNKNOWN:
+ printf("Unknown type.\n"); break;
+ case TRUSTEE_IS_USER:
+ printf("User\n"); break;
+ case TRUSTEE_IS_GROUP:
+ printf("Group\n"); break;
+ case TRUSTEE_IS_DOMAIN:
+ printf("Domain\n"); break;
+ case TRUSTEE_IS_ALIAS:
+ printf("Alias\n"); break;
+ case TRUSTEE_IS_WELL_KNOWN_GROUP:
+ printf("Well-known group\n"); break;
+ case TRUSTEE_IS_DELETED:
+ printf("Deleted account\n"); break;
+ case TRUSTEE_IS_INVALID:
+ printf("Invalid trustee type\n"); break;
+ case TRUSTEE_IS_COMPUTER:
+ printf("Computer\n"); break;
+ default:
+ printf("Unknown type %d\n", pEntry->Trustee.TrusteeType);
+ assert(0);
+ }
+
+ printf("\n");
+ }
+
+ assert(LocalFree((HLOCAL)pEntries) == 0);
+ assert(LocalFree((HLOCAL)pSecurityDesc) == 0);
+
chdir("c:\\tmp");
openfile("test", O_CREAT, 0);
struct stat ourfs;
@@ -63,12 +265,11 @@ int main(int argc, char* argv[])
do
{
info = readdir(ourDir);
- if ( info ) printf("File/Dir name is : %s\r\n", info->d_name);
-
- }while ( info != NULL );
+ if (info) printf("File/Dir name is : %s\r\n", info->d_name);
+ }
+ while (info != NULL);
closedir(ourDir);
-
}
std::string diry("C:\\Projects\\boxbuild\\testfiles\\");
@@ -79,12 +280,12 @@ int main(int argc, char* argv[])
do
{
info = readdir(ourDir);
- if ( info == NULL ) break;
+ if (info == NULL) break;
std::string file(diry + info->d_name);
stat(file.c_str(), &ourfs);
- if ( info ) printf("File/Dir name is : %s\r\n", info->d_name);
-
- }while ( info != NULL );
+ if (info) printf("File/Dir name is : %s\r\n", info->d_name);
+ }
+ while ( info != NULL );
closedir(ourDir);
@@ -92,47 +293,70 @@ int main(int argc, char* argv[])
stat("c:\\windows", &ourfs);
stat("c:\\autoexec.bat", &ourfs);
- printf("Finished dir read");
-#if 0
- //remove - sleepycat include a version of getopt - mine never REALLY worked !
- //test our getopt function
- std::string commline("-q -c fgfgfg -f -l hello");
+ printf("Finished dir read\n");
- int c;
- while((c = getopt(commline.size(), (char * const *)commline.c_str(), "qwc:l:")) != -1)
+ //test our getopt function
+ char * test_argv[] =
{
- printf("switch = %c, param is %s\r\n", c, optarg);
- }
-#endif
+ "foobar.exe",
+ "-qwc",
+ "-",
+ "-c",
+ "fgfgfg",
+ "-f",
+ "-l",
+ "hello",
+ "-",
+ "force-sync",
+ NULL
+ };
+ int test_argc;
+ for (test_argc = 0; test_argv[test_argc]; test_argc++) { }
+ const char* opts = "qwc:l:";
+
+ assert(getopt(test_argc, test_argv, opts) == 'q');
+ assert(getopt(test_argc, test_argv, opts) == 'w');
+ assert(getopt(test_argc, test_argv, opts) == 'c');
+ assert(strcmp(optarg, "-") == 0);
+ assert(getopt(test_argc, test_argv, opts) == 'c');
+ assert(strcmp(optarg, "fgfgfg") == 0);
+ assert(getopt(test_argc, test_argv, opts) == '?');
+ assert(optopt == 'f');
+ assert(getopt(test_argc, test_argv, opts) == 'l');
+ assert(strcmp(optarg, "hello") == 0);
+ assert(getopt(test_argc, test_argv, opts) == -1);
+ // assert(optopt == 0); // no more options
+ assert(strcmp(test_argv[optind], "-") == 0);
+ assert(strcmp(test_argv[optind+1], "force-sync") == 0);
//end of getopt test
//now test our statfs funct
stat("c:\\cert.cer", &ourfs);
-
-
char *timee;
timee = ctime(&ourfs.st_mtime);
- if ( S_ISREG(ourfs.st_mode))
+ if (S_ISREG(ourfs.st_mode))
{
- printf("is a normal file");
+ printf("is a normal file\n");
}
else
{
- printf("is a directory?");
+ printf("is a directory?\n");
+ exit(1);
}
- lstat("c:\\windows", &ourfs);
+ lstat(getenv("WINDIR"), &ourfs);
if ( S_ISDIR(ourfs.st_mode))
{
- printf("is a directory");
+ printf("is a directory\n");
}
else
{
- printf("is a file?");
+ printf("is a file?\n");
+ exit(1);
}
//test the syslog functions
@@ -143,6 +367,7 @@ int main(int argc, char* argv[])
closelog();
+ /*
//first off get the path name for the default
char buf[MAX_PATH];
@@ -150,7 +375,7 @@ int main(int argc, char* argv[])
std::string buffer(buf);
std::string conf("-c " + buffer.substr(0,(buffer.find("win32test.exe"))) + "bbackupd.conf");
//std::string conf( "-c " + buffer.substr(0,(buffer.find("bbackupd.exe"))) + "bbackupd.conf");
-
+ */
return 0;
}
diff --git a/test/win32/timezone.cpp b/test/win32/timezone.cpp
index 0a336206..04e0a202 100644
--- a/test/win32/timezone.cpp
+++ b/test/win32/timezone.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.