summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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.cpp585
-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
205 files changed, 10004 insertions, 1658 deletions
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/lib/intercept/intercept.cpp b/lib/intercept/intercept.cpp
new file mode 100644
index 00000000..b608db0b
--- /dev/null
+++ b/lib/intercept/intercept.cpp
@@ -0,0 +1,585 @@
+// 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.cpp
+// Purpose: Syscall interception code for the raidfile test
+// Created: 2003/07/22
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include "intercept.h"
+
+#ifdef HAVE_SYS_SYSCALL_H
+ #include <sys/syscall.h>
+#endif
+#include <sys/types.h>
+#include <unistd.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)
+ #define PLATFORM_NO_SYSCALL
+#endif
+
+#ifdef PLATFORM_NO_SYSCALL
+ // For some reason, syscall just doesn't work on Darwin
+ // so instead, we build functions using assembler in a varient
+ // of the technique used in the Darwin Libc
+ extern "C" int
+ TEST_open(const char *path, int flags, mode_t mode);
+ extern "C" int
+ TEST_close(int d);
+ extern "C" ssize_t
+ TEST_write(int d, const void *buf, size_t nbytes);
+ extern "C" ssize_t
+ TEST_read(int d, void *buf, size_t nbytes);
+ extern "C" ssize_t
+ TEST_readv(int d, const struct iovec *iov, int iovcnt);
+ extern "C" off_t
+ TEST_lseek(int fildes, off_t offset, int whence);
+#else
+ #ifdef HAVE___SYSCALL_NEED_DEFN
+ // Need this, not declared in syscall.h nor unistd.h
+ extern "C" off_t __syscall(quad_t number, ...);
+ #endif
+ #ifndef HAVE_SYSCALL
+ #undef syscall
+ #define syscall __syscall
+ #endif
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "MemLeakFindOn.h"
+
+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_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_count == 0;
+}
+
+void intercept_setup_error(const char *filename, unsigned int errorafter, int errortoreturn, int syscalltoerror)
+{
+ 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)
+{
+ ASSERT(intercept_count > 0)
+
+ if (intercept_filedes == -1)
+ {
+ 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) { }
+ }
+
+ 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()
+{
+ int err = intercept_errno;
+ intercept_clear_setup();
+ return err;
+}
+
+#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_count > 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_filename != NULL &&
+ intercept_count > 0 &&
+ intercept_filedes == -1)
+ {
+ // Right file?
+ if(strcmp(intercept_filename, path) == 0)
+ {
+ intercept_filedes = r;
+ //printf("Found file to intercept, h = %d\n", r);
+ }
+ }
+
+ return r;
+}
+
+extern "C" int
+open64(const char *path, int flags, mode_t mode)
+{
+ // With _FILE_OFFSET_BITS set to 64 this should really use (flags |
+ // O_LARGEFILE) here, but not actually necessary for the tests and not
+ // worth the trouble finding O_LARGEFILE
+ return open(path, flags, mode);
+}
+
+extern "C" int
+close(int d)
+{
+ CHECK_FOR_FAKE_ERROR_COND(d, SIZE_ALWAYS_ERROR, SYS_close, -1);
+#ifdef PLATFORM_NO_SYSCALL
+ int r = TEST_close(d);
+#else
+ int r = syscall(SYS_close, d);
+#endif
+ if(r == 0)
+ {
+ if(d == intercept_filedes)
+ {
+ intercept_filedes = -1;
+ }
+ }
+ return r;
+}
+
+extern "C" ssize_t
+write(int d, const void *buf, size_t nbytes)
+{
+ CHECK_FOR_FAKE_ERROR_COND(d, nbytes, SYS_write, -1);
+#ifdef PLATFORM_NO_SYSCALL
+ int r = TEST_write(d, buf, nbytes);
+#else
+ int r = syscall(SYS_write, d, buf, nbytes);
+#endif
+ if(r != -1)
+ {
+ intercept_filepos += r;
+ }
+ return r;
+}
+
+extern "C" ssize_t
+read(int d, void *buf, size_t nbytes)
+{
+ CHECK_FOR_FAKE_ERROR_COND(d, nbytes, SYS_read, -1);
+#ifdef PLATFORM_NO_SYSCALL
+ int r = TEST_read(d, buf, nbytes);
+#else
+ int r = syscall(SYS_read, d, buf, nbytes);
+#endif
+ if(r != -1)
+ {
+ intercept_filepos += r;
+ }
+ return r;
+}
+
+extern "C" ssize_t
+readv(int d, const struct iovec *iov, int iovcnt)
+{
+ // how many bytes?
+ int nbytes = 0;
+ for(int b = 0; b < iovcnt; ++b)
+ {
+ nbytes += iov[b].iov_len;
+ }
+
+ CHECK_FOR_FAKE_ERROR_COND(d, nbytes, SYS_readv, -1);
+#ifdef PLATFORM_NO_SYSCALL
+ int r = TEST_readv(d, iov, iovcnt);
+#else
+ int r = syscall(SYS_readv, d, iov, iovcnt);
+#endif
+ if(r != -1)
+ {
+ intercept_filepos += r;
+ }
+ return r;
+}
+
+extern "C" off_t
+lseek(int fildes, off_t offset, int whence)
+{
+ // random magic for lseek syscall, see /usr/src/lib/libc/sys/lseek.c
+ CHECK_FOR_FAKE_ERROR_COND(fildes, 0, SYS_lseek, -1);
+#ifdef PLATFORM_NO_SYSCALL
+ int r = TEST_lseek(fildes, offset, whence);
+#else
+ #ifdef HAVE_LSEEK_DUMMY_PARAM
+ off_t r = syscall(SYS_lseek, fildes, 0 /* extra 0 required here! */, offset, whence);
+ #elif defined(_FILE_OFFSET_BITS)
+ // Don't bother trying to call SYS__llseek on 32 bit since it is
+ // fiddly and not needed for the tests
+ off_t r = syscall(SYS_lseek, fildes, (uint32_t)offset, whence);
+ #else
+ off_t r = syscall(SYS_lseek, fildes, offset, whence);
+ #endif
+#endif
+ if(r != -1)
+ {
+ intercept_filepos = r;
+ }
+ 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