-- cgit v1.2.3 From c7662795f519d2b6797e4b1ac7fa4a22afa26310 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 Jul 2006 23:18:35 +0000 Subject: * merge - This is my current patch queue. I think that all of these are safe to apply. This is just under half of the pending changes in chris/general (the easy half). --- bin/bbackupctl/bbackupctl.cpp | 104 +++++++- bin/bbackupd/BackupClientContext.cpp | 2 +- bin/bbackupd/BackupClientDirectoryRecord.cpp | 98 +++++-- bin/bbackupd/BackupDaemon.cpp | 282 +++++++++++++++------ bin/bbackupd/BackupDaemon.h | 14 +- bin/bbackupd/Win32BackupService.cpp | 47 ++-- bin/bbackupd/Win32BackupService.h | 2 +- bin/bbackupd/Win32ServiceFunctions.cpp | 184 ++++++++++---- bin/bbackupd/Win32ServiceFunctions.h | 6 +- bin/bbackupd/bbackupd.cpp | 56 ++-- bin/bbackupquery/BackupQueries.cpp | 168 +++++++++--- bin/bbackupquery/BackupQueries.h | 2 + bin/bbackupquery/documentation.txt | 1 + bin/bbstored/BBStoreDHousekeeping.cpp | 174 ++++++++----- bin/bbstored/BackupCommands.cpp | 33 ++- bin/bbstored/BackupContext.cpp | 20 +- bin/bbstored/BackupStoreDaemon.cpp | 19 +- bin/bbstored/BackupStoreDaemon.h | 13 + bin/bbstored/HousekeepStoreAccount.cpp | 7 + configure.ac | 15 +- docs/backup/win32_build_on_linux_using_mingw.txt | 21 +- infrastructure/BoxPlatform.pm.in | 64 ++++- infrastructure/buildenv-testmain-template.cpp | 7 +- infrastructure/makebuildenv.pl.in | 144 ++++++++--- infrastructure/msvc/2003/boxbackup.ncb | Bin 650240 -> 0 bytes infrastructure/msvc/2003/boxbackup.suo | Bin 22528 -> 0 bytes lib/backupclient/BackupClientFileAttributes.cpp | 2 + lib/backupclient/BackupStoreFile.cpp | 2 + lib/backupclient/BackupStoreObjectDump.cpp | 8 +- lib/backupstore/BackupStoreAccounts.cpp | 5 +- lib/backupstore/BackupStoreCheck.cpp | 7 +- lib/common/BoxPlatform.h | 9 +- lib/common/FdGetLine.h | 4 + lib/common/Guards.h | 2 +- lib/common/UnixUser.cpp | 4 + lib/common/makeexception.pl.in | 11 +- lib/raidfile/RaidFileRead.cpp | 31 ++- lib/raidfile/RaidFileWrite.cpp | 69 ++++- lib/server/Daemon.cpp | 50 +++- lib/server/ServerStream.h | 18 +- lib/server/SocketStream.cpp | 47 +++- lib/server/SocketStream.h | 2 + lib/server/SocketStreamTLS.cpp | 8 +- lib/server/makeprotocol.pl.in | 18 +- runtest.pl.in | 31 ++- test/backupdiff/testbackupdiff.cpp | 75 ++++-- test/backupstore/testbackupstore.cpp | 177 +++++++++++-- .../testfiles/testbackupstorefix.pl.in | 4 +- test/backupstorepatch/testbackupstorepatch.cpp | 35 ++- test/basicserver/TestCommands.cpp | 2 + test/basicserver/testbasicserver.cpp | 99 +++++++- test/bbackupd/testbbackupd.cpp | 2 +- test/bbackupd/testfiles/bbackupd.conf | 50 ---- test/bbackupd/testfiles/bbackupd.conf.in | 50 ++++ test/bbackupd/testfiles/extcheck1.pl.in | 19 +- test/bbackupd/testfiles/extcheck2.pl.in | 20 +- test/common/testcommon.cpp | 60 +++++ test/raidfile/intercept.cpp | 4 + test/raidfile/testraidfile.cpp | 126 ++++++--- test/win32/testlibwin32.cpp | 279 ++++++++++++++++++-- win32.bat | 4 +- 61 files changed, 2179 insertions(+), 638 deletions(-) delete mode 100644 infrastructure/msvc/2003/boxbackup.ncb delete mode 100644 infrastructure/msvc/2003/boxbackup.suo delete mode 100644 test/bbackupd/testfiles/bbackupd.conf create mode 100644 test/bbackupd/testfiles/bbackupd.conf.in diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index dfadc37d..37d5c377 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -32,12 +32,14 @@ void PrintUsageAndExit() { printf("Usage: bbackupctl [-q] [-c config_file] \n" "Commands are:\n" - " sync -- start a syncronisation run now\n" - " force-sync -- force the start of a syncronisation run, " + " sync -- start a synchronisation (backup) run now\n" + " force-sync -- force the start of a synchronisation run, " "even if SyncAllowScript says no\n" " reload -- reload daemon configuration\n" " terminate -- terminate daemon now\n" " wait-for-sync -- wait until the next sync starts, then exit\n" + " wait-for-end -- wait until the next sync finishes, then exit\n" + " sync-and-wait -- start sync, wait until it finishes, then exit\n" ); exit(1); } @@ -107,7 +109,10 @@ int main(int argc, const char *argv[]) // Check there's a socket defined in the config file if(!conf.KeyExists("CommandSocket")) { - printf("Daemon isn't using a control socket, could not execute command.\nAdd a CommandSocket declaration to the bbackupd.conf file.\n"); + printf("Daemon isn't using a control socket, " + "could not execute command.\n" + "Add a CommandSocket declaration to the " + "bbackupd.conf file.\n"); return 1; } @@ -188,27 +193,74 @@ int main(int argc, const char *argv[]) // Print summary? if(!quiet) { - printf("Daemon configuration summary:\n" \ - " AutomaticBackup = %s\n" \ - " UpdateStoreInterval = %d seconds\n" \ - " MinimumFileAge = %d seconds\n" \ - " MaxUploadWait = %d seconds\n", - autoBackup?"true":"false", updateStoreInterval, minimumFileAge, maxUploadWait); + printf("Daemon configuration summary:\n" + " AutomaticBackup = %s\n" + " UpdateStoreInterval = %d seconds\n" + " MinimumFileAge = %d seconds\n" + " MaxUploadWait = %d seconds\n", + autoBackup?"true":"false", updateStoreInterval, + minimumFileAge, maxUploadWait); + } + + std::string stateLine; + if(!getLine.GetLine(stateLine) || getLine.IsEOF()) + { +#if defined WIN32 && ! defined NDEBUG + syslog(LOG_ERR, "Failed to receive state line from daemon"); +#else + printf("Failed to receive state line from daemon\n"); +#endif + return 1; + } + + // Decode it + int currentState; + if(::sscanf(stateLine.c_str(), "state %d", ¤tState) != 1) + { + printf("State line didn't decode\n"); + return 1; } // Is the command the "wait for sync to start" command? bool areWaitingForSync = false; - if(::strcmp(argv[0], "wait-for-sync") == 0) + bool areWaitingForSyncEnd = false; + + if(::strcmp(argv[0], "wait-for-sync") == 0 || + ::strcmp(argv[0], "wait-for-end") == 0) { - // Check that it's not in non-automatic mode, because then it'll never start + // Check that it's not in non-automatic mode, + // because then it'll never start if(!autoBackup) { - printf("ERROR: Daemon is not in automatic mode -- sync will never start!\n"); + printf("ERROR: Daemon is not in automatic mode -- " + "sync will never start!\n"); return 1; } - // Yes... set the flag so we know what we're waiting for a sync to start - areWaitingForSync = true; + // Yes... set the flag so we know that + // we're waiting for a sync to start/end + if(::strcmp(argv[0], "wait-for-sync") == 0) + { + areWaitingForSync = true; + } + else if (::strcmp(argv[0], "wait-for-end") == 0) + { + areWaitingForSyncEnd = true; + } + } + else if (::strcmp(argv[0], "sync-and-wait") == 0) + { + // send a sync command + std::string cmd("force-sync\n"); + connection.Write(cmd.c_str(), cmd.size()); + connection.WriteAllBuffered(); + areWaitingForSyncEnd = true; + + if (currentState != 0) + { + printf("Waiting for current sync/error state " + "to finish...\n"); + } } else { @@ -220,6 +272,8 @@ int main(int argc, const char *argv[]) // Read the response std::string line; + bool syncIsRunning = false; + while(!getLine.IsEOF() && getLine.GetLine(line)) { if(areWaitingForSync) @@ -234,6 +288,28 @@ int main(int argc, const char *argv[]) break; } } + else if(areWaitingForSyncEnd) + { + if(line == "start-sync") + { + if (!quiet) printf("Sync started...\n"); + syncIsRunning = true; + } + else if(line == "finish-sync" && syncIsRunning) + { + if (!quiet) printf("Sync finished.\n"); + // Send a quit command to finish nicely + connection.Write("quit\n", 5); + + // And we're done + break; + } + else if(line == "finish-sync") + { + if (!quiet) printf("Previous sync finished.\n"); + } + // daemon must still be busy + } else { // Is this an OK or error line? diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index 25852b19..4b84fecb 100644 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -176,7 +176,7 @@ BackupProtocolClient &BackupClientContext::GetConnection() // no -- flag so only things like deletions happen mStorageLimitExceeded = true; // Log - ::syslog(LOG_INFO, "Exceeded storage limits on server -- not uploading changes to files"); + ::syslog(LOG_WARNING, "Exceeded storage limits on server -- not uploading changes to files"); } } catch(...) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 5a566d84..37bd3fea 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -645,34 +645,75 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP // Need to update? // // Condition for upload: - // modifiction time within sync period + // modification time within sync period // if it's been seen before but not uploaded, is the time from this first sight longer than the MaxUploadWait // and if we know about it from a directory listing, that it hasn't got the same upload time as on the store - if( - ( - // Check the file modified within the acceptable time period we're checking - // If the file isn't on the server, the acceptable time starts at zero. - // Check pDirOnStore and en, because if we didn't download a directory listing, - // pDirOnStore will be zero, but we know it's on the server. - ( ((pDirOnStore != 0 && en == 0) || (modTime >= rParams.mSyncPeriodStart)) && modTime < rParams.mSyncPeriodEnd) - - // However, just in case things are continually modified, we check the first seen time. - // The two compares of syncPeriodEnd and pendingFirstSeenTime are because the values are unsigned. - || (pendingFirstSeenTime != 0 && - (rParams.mSyncPeriodEnd > pendingFirstSeenTime) - && ((rParams.mSyncPeriodEnd - pendingFirstSeenTime) > rParams.mMaxUploadWait)) - - // Then make sure that if files are added with a time less than the sync period start - // (which can easily happen on file server), it gets uploaded. The directory contents checksum - // will pick up the fact it has been added, so the store listing will be available when this happens. - || ((modTime <= rParams.mSyncPeriodStart) && (en != 0) && (en->GetModificationTime() != modTime)) - - // And just to catch really badly off clocks in the future for file server clients, - // just upload the file if it's madly in the future. - || (modTime > rParams.mUploadAfterThisTimeInTheFuture) - ) - // But even then, only upload it if the mod time locally is different to that on the server. - && (en == 0 || en->GetModificationTime() != modTime)) + + bool doUpload = false; + + // Only upload a file if the mod time locally is + // different to that on the server. + + if (en == 0 || en->GetModificationTime() != modTime) + { + // Check the file modified within the acceptable time period we're checking + // If the file isn't on the server, the acceptable time starts at zero. + // Check pDirOnStore and en, because if we didn't download a directory listing, + // pDirOnStore will be zero, but we know it's on the server. + if (modTime < rParams.mSyncPeriodEnd) + { + if (pDirOnStore != 0 && en == 0) + { + doUpload = true; + } + else if (modTime >= rParams.mSyncPeriodStart) + { + doUpload = true; + } + } + + // However, just in case things are continually + // modified, we check the first seen time. + // The two compares of syncPeriodEnd and + // pendingFirstSeenTime are because the values + // are unsigned. + + if (!doUpload && + pendingFirstSeenTime != 0 && + rParams.mSyncPeriodEnd > pendingFirstSeenTime && + (rParams.mSyncPeriodEnd - pendingFirstSeenTime) + > rParams.mMaxUploadWait) + { + doUpload = true; + } + + // Then make sure that if files are added with a + // time less than the sync period start + // (which can easily happen on file server), it + // gets uploaded. The directory contents checksum + // will pick up the fact it has been added, so the + // store listing will be available when this happens. + + if (!doUpload && + modTime <= rParams.mSyncPeriodStart && + en != 0 && + en->GetModificationTime() != modTime) + { + doUpload = true; + } + + // And just to catch really badly off clocks in + // the future for file server clients, + // just upload the file if it's madly in the future. + + if (!doUpload && modTime > + rParams.mUploadAfterThisTimeInTheFuture) + { + doUpload = true; + } + } + + if (doUpload) { // Make sure we're connected -- must connect here so we know whether // the storage limit has been exceeded, and hence whether or not @@ -1022,7 +1063,10 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP BackupClientDirectoryRecord *rec = e->second; mSubDirectories.erase(e); delete rec; - TRACE2("Deleted directory record for %s/%s\n", rLocalPath.c_str(), dirname.GetClearFilename().c_str()); + TRACE2("Deleted directory record for " + "%s" DIRECTORY_SEPARATOR "%s\n", + rLocalPath.c_str(), + dirname.GetClearFilename().c_str()); } } } diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index ebf5a1ea..e2d7c5e7 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -125,6 +125,29 @@ BackupDaemon::BackupDaemon() } #ifdef WIN32 + // Create the event object to signal from main thread to worker + // when new messages are queued to be sent to the command socket. + mhMessageToSendEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (mhMessageToSendEvent == INVALID_HANDLE_VALUE) + { + syslog(LOG_ERR, "Failed to create event object: error %d", + GetLastError); + exit(1); + } + + // Create the event object to signal from worker to main thread + // when a command has been received on the command socket. + mhCommandReceivedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (mhCommandReceivedEvent == INVALID_HANDLE_VALUE) + { + syslog(LOG_ERR, "Failed to create event object: error %d", + GetLastError); + exit(1); + } + + // Create the critical section to protect the message queue + InitializeCriticalSection(&mMessageQueueLock); + // Create a thread to handle the named pipe HANDLE hThread; unsigned int dwThreadId; @@ -263,15 +286,34 @@ void BackupDaemon::DeleteAllLocations() void BackupDaemon::RunHelperThread(void) { mpCommandSocketInfo = new CommandSocketInfo; - this->mReceivedCommandConn = false; + WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); // loop until the parent process exits - while (TRUE) + while (!IsTerminateWanted()) { try { - mpCommandSocketInfo->mListeningSocket.Accept( - BOX_NAMED_PIPE_NAME); + rSocket.Accept(BOX_NAMED_PIPE_NAME); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to open command socket: %s", + e.what()); + SetTerminateWanted(); + break; // this is fatal + } + catch (...) + { + ::syslog(LOG_ERR, "Failed to open command socket: " + "unknown error"); + SetTerminateWanted(); + break; // this is fatal + } + + try + { + // Errors here do not kill the thread, + // only the current connection. // This next section comes from Ben's original function // Log @@ -289,17 +331,72 @@ void BackupDaemon::RunHelperThread(void) conf.GetKeyValueInt("MaxUploadWait"), mState); - mpCommandSocketInfo->mListeningSocket.Write(summary, summarySize); - mpCommandSocketInfo->mListeningSocket.Write("ping\n", 5); + rSocket.Write(summary, summarySize); + rSocket.Write("ping\n", 5); + + // old queued messages are not useful + EnterCriticalSection(&mMessageQueueLock); + mMessageList.clear(); + ResetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); - IOStreamGetLine readLine(mpCommandSocketInfo->mListeningSocket); + IOStreamGetLine readLine(rSocket); std::string command; - while (mpCommandSocketInfo->mListeningSocket.IsConnected() && - readLine.GetLine(command) ) + while (rSocket.IsConnected() && !IsTerminateWanted()) { - TRACE1("Receiving command '%s' over " - "command socket\n", command.c_str()); + HANDLE handles[2]; + handles[0] = mhMessageToSendEvent; + handles[1] = rSocket.GetReadableEvent(); + + DWORD result = WaitForMultipleObjects( + sizeof(handles)/sizeof(*handles), + handles, FALSE, 1000); + + if (result == 0) + { + ResetEvent(mhMessageToSendEvent); + + EnterCriticalSection(&mMessageQueueLock); + try + { + while (mMessageList.size() > 0) + { + std::string message = *(mMessageList.begin()); + mMessageList.erase(mMessageList.begin()); + printf("Sending '%s' to waiting client... ", message.c_str()); + message += "\n"; + rSocket.Write(message.c_str(), + message.length()); + + printf("done.\n"); + } + } + catch (...) + { + LeaveCriticalSection(&mMessageQueueLock); + throw; + } + LeaveCriticalSection(&mMessageQueueLock); + continue; + } + else if (result == WAIT_TIMEOUT) + { + continue; + } + else if (result != 1) + { + ::syslog(LOG_ERR, "WaitForMultipleObjects returned invalid result %d", result); + continue; + } + + if (!readLine.GetLine(command)) + { + ::syslog(LOG_ERR, "Failed to read line"); + continue; + } + + printf("Received command '%s' from client\n", command.c_str()); bool sendOK = false; bool sendResponse = true; @@ -338,12 +435,18 @@ void BackupDaemon::RunHelperThread(void) SetTerminateWanted(); sendOK = true; } + else + { + ::syslog(LOG_ERR, "Received unknown command '%s' from client", command.c_str()); + sendResponse = true; + sendOK = false; + } // Send a response back? if (sendResponse) { const char* response = sendOK ? "ok\n" : "error\n"; - mpCommandSocketInfo->mListeningSocket.Write( + rSocket.Write( response, strlen(response)); } @@ -352,10 +455,10 @@ void BackupDaemon::RunHelperThread(void) break; } - this->mReceivedCommandConn = true; + // this->mReceivedCommandConn = true; } - mpCommandSocketInfo->mListeningSocket.Close(); + rSocket.Close(); } catch (BoxException &e) { @@ -504,8 +607,8 @@ void BackupDaemon::Run2() BackupClientContext::ClientStoreMarker_NotKnown; // haven't contacted the store yet - bool deserialised = DeserializeStoreObjectInfo(clientStoreMarker, - lastSyncTime, nextSyncTime); + bool deleteStoreObjectInfoFile = DeserializeStoreObjectInfo( + clientStoreMarker, lastSyncTime, nextSyncTime); // -------------------------------------------------------------------------------------------- @@ -611,7 +714,8 @@ void BackupDaemon::Run2() // Delete the serialised store object file, // so that we don't try to reload it after a // partially completed backup - if(deserialised && !DeleteStoreObjectInfo()) + if(deleteStoreObjectInfoFile && + !DeleteStoreObjectInfo()) { ::syslog(LOG_ERR, "Failed to delete the " "StoreObjectInfoFile, backup cannot " @@ -621,6 +725,11 @@ void BackupDaemon::Run2() ::sleep(60); continue; } + + // In case the backup throws an exception, + // we should not try to delete the store info + // object file again. + deleteStoreObjectInfoFile = false; // Do sync bool errorOccurred = false; @@ -729,8 +838,14 @@ void BackupDaemon::Run2() // -------------------------------------------------------------------------------------------- - // We had a successful backup, save the store info - SerializeStoreObjectInfo(clientStoreMarker, lastSyncTime, nextSyncTime); + // We had a successful backup, save the store + // info. If we save successfully, we must + // delete the file next time we start a backup + + deleteStoreObjectInfoFile = + SerializeStoreObjectInfo( + clientStoreMarker, + lastSyncTime, nextSyncTime); // -------------------------------------------------------------------------------------------- } @@ -902,25 +1017,27 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut) { #ifdef WIN32 - // Really could use some interprocess protection, mutex etc - // any side effect should be too bad???? :) - DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay); + DWORD requiredDelayMs = BoxTimeToMilliSeconds(RequiredDelay); - while ( this->mReceivedCommandConn == false ) - { - Sleep(1); + DWORD result = WaitForSingleObject(mhCommandReceivedEvent, + (DWORD)requiredDelayMs); - if ( timeout == 0 ) - { - DoSyncFlagOut = false; - SyncIsForcedOut = false; - return; - } - timeout--; + if (result == WAIT_OBJECT_0) + { + DoSyncFlagOut = this->mDoSyncFlagOut; + SyncIsForcedOut = this->mSyncIsForcedOut; + ResetEvent(mhCommandReceivedEvent); + } + else if (result == WAIT_TIMEOUT) + { + DoSyncFlagOut = false; + SyncIsForcedOut = false; + } + else + { + ::syslog(LOG_ERR, "Unexpected result from " + "WaitForSingleObject: error %d", GetLastError()); } - this->mReceivedCommandConn = false; - DoSyncFlagOut = this->mDoSyncFlagOut; - SyncIsForcedOut = this->mSyncIsForcedOut; return; #else // ! WIN32 @@ -953,7 +1070,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla { #ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET bool uidOK = true; - ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)"); + ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credentials of peers connecting to the command socket. (bbackupctl)"); #else // Security check -- does the process connecting to this socket have // the same UID as this process? @@ -1023,8 +1140,13 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla while(mpCommandSocketInfo->mpGetLine != 0 && !mpCommandSocketInfo->mpGetLine->IsEOF() && mpCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout)) { - TRACE1("Receiving command '%s' over command socket\n", command.c_str()); - + TRACE1("Receiving command '%s' over command socket\n", + command.c_str()); + + #ifdef WIN32 + SetEvent(mhCommandReceivedEvent); + #endif + bool sendOK = false; bool sendResponse = true; @@ -1137,12 +1259,8 @@ void BackupDaemon::CloseCommandConnection() // -------------------------------------------------------------------------- void BackupDaemon::SendSyncStartOrFinish(bool SendStart) { - // The bbackupctl program can't rely on a state change, because it may never - // change if the server doesn't need to be contacted. - -#ifdef __MINGW32__ -#warning race condition: what happens if socket is closed? -#endif + // The bbackupctl program can't rely on a state change, because it + // may never change if the server doesn't need to be contacted. if (mpCommandSocketInfo != NULL && #ifdef WIN32 @@ -1152,15 +1270,18 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) #endif ) { - const char* message = SendStart ? "start-sync\n" : "finish-sync\n"; + std::string message = SendStart ? "start-sync" : "finish-sync"; try { #ifdef WIN32 - mpCommandSocketInfo->mListeningSocket.Write(message, - (int)strlen(message)); + EnterCriticalSection(&mMessageQueueLock); + mMessageList.push_back(message); + SetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); #else - mpCommandSocketInfo->mpConnectedSocket->Write(message, - strlen(message)); + message += "\n"; + mpCommandSocketInfo->mpConnectedSocket->Write( + message.c_str(), message.size()); #endif } catch(...) @@ -1756,39 +1877,36 @@ void BackupDaemon::SetState(int State) // command socket if there's an error char newState[64]; - char newStateSize = sprintf(newState, "state %d\n", State); + sprintf(newState, "state %d", State); + std::string message = newState; #ifdef WIN32 - #ifndef _MSC_VER - #warning FIX ME: race condition - #endif + EnterCriticalSection(&mMessageQueueLock); + mMessageList.push_back(newState); + SetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); +#else + message += "\n"; - // what happens if the socket is closed by the other thread before - // we can write to it? Null pointer deref at best. - if (mpCommandSocketInfo && - mpCommandSocketInfo->mListeningSocket.IsConnected()) + if(mpCommandSocketInfo == 0) { - try - { - mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize); - } - catch(...) - { - CloseCommandConnection(); - } + return; } -#else - if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0) + + if (mpCommandSocketInfo->mpConnectedSocket.get() == 0) { - // Something connected to the command socket, tell it about the new state - try - { - mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize); - } - catch(...) - { - CloseCommandConnection(); - } + return; + } + + // Something connected to the command socket, tell it about the new state + try + { + mpCommandSocketInfo->mpConnectedSocket->Write(message.c_str(), + message.length()); + } + catch(...) + { + CloseCommandConnection(); } #endif } @@ -2173,11 +2291,11 @@ static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F; static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE"; static const int STOREOBJECTINFO_VERSION = 1; -void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const +bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const { if(!GetConfiguration().KeyExists("StoreObjectInfoFile")) { - return; + return false; } std::string StoreObjectInfoFile = @@ -2185,13 +2303,17 @@ void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time if (StoreObjectInfoFile.size() <= 0) { - return; + return false; } + bool created = false; + try { FileStream aFile(StoreObjectInfoFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC); + created = true; + Archive anArchive(aFile, 0); anArchive.Write(STOREOBJECTINFO_MAGIC_ID_VALUE); @@ -2236,6 +2358,8 @@ void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time "not accessible or could not be created", StoreObjectInfoFile.c_str()); } + + return created; } // -------------------------------------------------------------------------- diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 3bd15fad..94a142f5 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -46,9 +46,12 @@ public: ~BackupDaemon(); private: - // methods below do partial (specialized) serialization of client state only - void SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const; - bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime); + // methods below do partial (specialized) serialization of + // client state only + bool SerializeStoreObjectInfo(int64_t aClientStoreMarker, + box_time_t theLastSyncTime, box_time_t theNextSyncTime) const; + bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, + box_time_t & theLastSyncTime, box_time_t & theNextSyncTime); bool DeleteStoreObjectInfo() const; BackupDaemon(const BackupDaemon &); public: @@ -182,7 +185,10 @@ private: void RunHelperThread(void); private: - bool mDoSyncFlagOut, mSyncIsForcedOut, mReceivedCommandConn; + bool mDoSyncFlagOut, mSyncIsForcedOut; + HANDLE mhMessageToSendEvent, mhCommandReceivedEvent; + CRITICAL_SECTION mMessageQueueLock; + std::vector mMessageList; #endif }; diff --git a/bin/bbackupd/Win32BackupService.cpp b/bin/bbackupd/Win32BackupService.cpp index aa3bf55c..7cbf4828 100644 --- a/bin/bbackupd/Win32BackupService.cpp +++ b/bin/bbackupd/Win32BackupService.cpp @@ -12,40 +12,51 @@ #include "Win32BackupService.h" -Win32BackupService gDaemonService; +Win32BackupService* gpDaemonService = NULL; extern HANDLE gStopServiceEvent; unsigned int WINAPI RunService(LPVOID lpParameter) { - DWORD retVal = gDaemonService.WinService(); - SetEvent( gStopServiceEvent ); + DWORD retVal = gpDaemonService->WinService((const char*) lpParameter); + SetEvent(gStopServiceEvent); return retVal; } void TerminateService(void) { - gDaemonService.SetTerminateWanted(); + gpDaemonService->SetTerminateWanted(); } -DWORD Win32BackupService::WinService(void) +DWORD Win32BackupService::WinService(const char* pConfigFileName) { - int argc = 2; - //first off get the path name for the default - char buf[MAX_PATH]; - - GetModuleFileName(NULL, buf, sizeof(buf)); - std::string buffer(buf); - std::string conf( "-c"); - std::string cfile(buffer.substr(0,(buffer.find("bbackupd.exe"))) - + "bbackupd.conf"); + char exepath[MAX_PATH]; + GetModuleFileName(NULL, exepath, sizeof(exepath)); - const char *argv[] = {conf.c_str(), cfile.c_str()}; + std::string configfile; + + if (pConfigFileName != NULL) + { + configfile = pConfigFileName; + } + else + { + // make the default config file name, + // based on the program path + configfile = exepath; + configfile = configfile.substr(0, + configfile.rfind(DIRECTORY_SEPARATOR_ASCHAR)); + configfile += DIRECTORY_SEPARATOR "bbackupd.conf"; + } + + const char *argv[] = {exepath, "-c", configfile.c_str()}; + int argc = sizeof(argv) / sizeof(*argv); + DWORD ret; MAINHELPER_START - - return this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); - + ret = this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); MAINHELPER_END + + return ret; } #endif // WIN32 diff --git a/bin/bbackupd/Win32BackupService.h b/bin/bbackupd/Win32BackupService.h index 38cebacc..e7f077f2 100644 --- a/bin/bbackupd/Win32BackupService.h +++ b/bin/bbackupd/Win32BackupService.h @@ -12,7 +12,7 @@ class BackupDaemon; class Win32BackupService : public BackupDaemon { public: - DWORD WinService(void); + DWORD WinService(const char* pConfigFileName); }; #endif // WIN32 diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index b74c7e09..1b50a7fa 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -93,28 +93,30 @@ void WINAPI ServiceControlHandler( DWORD controlCode ) // It also returns on any error because the // service cannot start if there is an eror. +static char* spConfigFileName; + VOID ServiceMain(DWORD argc, LPTSTR *argv) { - // initialise service status - gServiceStatus.dwServiceType = SERVICE_WIN32; - gServiceStatus.dwCurrentState = SERVICE_STOPPED; - gServiceStatus.dwControlsAccepted = 0; - gServiceStatus.dwWin32ExitCode = NO_ERROR; - gServiceStatus.dwServiceSpecificExitCode = NO_ERROR; - gServiceStatus.dwCheckPoint = 0; - gServiceStatus.dwWaitHint = 0; - - gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName, - ServiceControlHandler); - - if (gServiceStatusHandle) - { - // service is starting - gServiceStatus.dwCurrentState = SERVICE_START_PENDING; - SetServiceStatus(gServiceStatusHandle, &gServiceStatus); - - // do initialisation here - gStopServiceEvent = CreateEvent( 0, TRUE, FALSE, 0 ); + // initialise service status + gServiceStatus.dwServiceType = SERVICE_WIN32; + gServiceStatus.dwCurrentState = SERVICE_STOPPED; + gServiceStatus.dwControlsAccepted = 0; + gServiceStatus.dwWin32ExitCode = NO_ERROR; + gServiceStatus.dwServiceSpecificExitCode = NO_ERROR; + gServiceStatus.dwCheckPoint = 0; + gServiceStatus.dwWaitHint = 0; + + gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName, + ServiceControlHandler); + + if (gServiceStatusHandle) + { + // service is starting + gServiceStatus.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(gServiceStatusHandle, &gServiceStatus); + + // do initialisation here + gStopServiceEvent = CreateEvent(0, TRUE, FALSE, 0); if (!gStopServiceEvent) { gServiceStatus.dwControlsAccepted &= @@ -129,7 +131,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) NULL, 0, RunService, - 0, + spConfigFileName, CREATE_SUSPENDED, NULL); @@ -138,7 +140,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) // we are now running so tell the SCM gServiceStatus.dwControlsAccepted |= - (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); gServiceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(gServiceStatusHandle, &gServiceStatus); @@ -156,11 +158,13 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); gServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(gServiceStatusHandle, &gServiceStatus); - } + } } -void OurService(void) +void OurService(char* pConfigFileName) { + spConfigFileName = pConfigFileName; + SERVICE_TABLE_ENTRY serviceTable[] = { { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain }, @@ -179,28 +183,52 @@ void OurService(void) } } -void InstallService(void) +int InstallService(const char* pConfigFileName) { - SC_HANDLE newService, scm; + if (pConfigFileName != NULL) + { + struct stat st; - scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + if (emu_stat(pConfigFileName, &st) != 0) + { + syslog(LOG_ERR, "Failed to open configuration file: " + "%s: %s", pConfigFileName, strerror(errno)); + return 1; + } + + if (! st.st_mode & S_IFREG) + { + + syslog(LOG_ERR, "Failed to open configuration file: " + "%s: not a file", pConfigFileName); + return 1; + } + } + + SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); if (!scm) { syslog(LOG_ERR, "Failed to open service control manager: " "error %d", GetLastError()); - return; + return 1; } char cmd[MAX_PATH]; GetModuleFileName(NULL, cmd, sizeof(cmd)-1); cmd[sizeof(cmd)-1] = 0; - char cmd_args[MAX_PATH]; - _snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd); - cmd_args[sizeof(cmd_args)-1] = 0; + std::string cmdWithArgs(cmd); + cmdWithArgs += " --service"; - newService = CreateService( + if (pConfigFileName != NULL) + { + cmdWithArgs += " \""; + cmdWithArgs += pConfigFileName; + cmdWithArgs += "\""; + } + + SC_HANDLE newService = CreateService( scm, SERVICE_NAME, "Box Backup", @@ -208,14 +236,36 @@ void InstallService(void) SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - cmd_args, + cmdWithArgs.c_str(), 0,0,0,0,0); + DWORD err = GetLastError(); + CloseServiceHandle(scm); + if (!newService) { - ::syslog(LOG_ERR, "Failed to create Box Backup service: " - "error %d", GetLastError()); - return; + if (err == ERROR_SERVICE_EXISTS) + { + ::syslog(LOG_ERR, "Failed to create Box Backup " + "service: it already exists"); + } + else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) + { + ::syslog(LOG_ERR, "Failed to create Box Backup " + "service: it is waiting to be deleted"); + } + else if (err == ERROR_DUPLICATE_SERVICE_NAME) + { + ::syslog(LOG_ERR, "Failed to create Box Backup " + "service: a service with this name " + "already exists"); + } + else + { + ::syslog(LOG_ERR, "Failed to create Box Backup " + "service: error %d", err); + } + return 1; } ::syslog(LOG_INFO, "Created Box Backup service"); @@ -231,45 +281,75 @@ void InstallService(void) } CloseServiceHandle(newService); - CloseServiceHandle(scm); + + return 0; } -void RemoveService(void) +int RemoveService(void) { - SC_HANDLE service, scm; - SERVICE_STATUS status; - - scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); if (!scm) { syslog(LOG_ERR, "Failed to open service control manager: " "error %d", GetLastError()); - return; + return 1; } - service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE); - ControlService(service, SERVICE_CONTROL_STOP, &status); + SC_HANDLE service = OpenService(scm, SERVICE_NAME, + SERVICE_ALL_ACCESS|DELETE); + DWORD err = GetLastError(); + CloseServiceHandle(scm); if (!service) { - syslog(LOG_ERR, "Failed to open Box Backup service: " - "error %d", GetLastError()); - return; + if (err == ERROR_SERVICE_DOES_NOT_EXIST || + err == ERROR_IO_PENDING) + // hello microsoft? anyone home? + { + syslog(LOG_ERR, "Failed to open Box Backup service: " + "not installed or not found"); + } + else + { + syslog(LOG_ERR, "Failed to open Box Backup service: " + "error %d", err); + } + return 1; } - if (DeleteService(service)) + SERVICE_STATUS status; + if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) + { + err = GetLastError(); + if (err != ERROR_SERVICE_NOT_ACTIVE) + { + syslog(LOG_WARNING, "Failed to stop Box Backup " + "service: error %d", err); + } + } + + BOOL deleted = DeleteService(service); + err = GetLastError(); + CloseServiceHandle(service); + + if (deleted) { syslog(LOG_INFO, "Box Backup service deleted"); + return 0; + } + else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) + { + syslog(LOG_ERR, "Failed to remove Box Backup service: " + "it is already being deleted"); } else { syslog(LOG_ERR, "Failed to remove Box Backup service: " - "error %d", GetLastError()); + "error %d", err); } - CloseServiceHandle(service); - CloseServiceHandle(scm); + return 1; } #endif // WIN32 diff --git a/bin/bbackupd/Win32ServiceFunctions.h b/bin/bbackupd/Win32ServiceFunctions.h index 72f65479..3fe77187 100644 --- a/bin/bbackupd/Win32ServiceFunctions.h +++ b/bin/bbackupd/Win32ServiceFunctions.h @@ -12,8 +12,8 @@ #ifndef WIN32SERVICEFUNCTIONS_H #define WIN32SERVICEFUNCTIONS_H -void RemoveService(void); -void InstallService(void); -void OurService(void); +int RemoveService(void); +int InstallService(const char* pConfigFilePath); +void OurService(char* pConfigFileName); #endif diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index 089b2d09..e00d3628 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -19,7 +19,7 @@ #include "Win32ServiceFunctions.h" #include "Win32BackupService.h" - extern Win32BackupService gDaemonService; + extern Win32BackupService* gpDaemonService; #endif int main(int argc, const char *argv[]) @@ -28,7 +28,7 @@ int main(int argc, const char *argv[]) #ifdef WIN32 - ::openlog("Box Backup (bbackupd)", 0, 0); + ::openlog("Box Backup (bbackupd)", LOG_PID, LOG_LOCAL6); if(argc == 2 && (::strcmp(argv[1], "--help") == 0 || @@ -40,32 +40,25 @@ int main(int argc, const char *argv[]) } if(argc == 2 && ::strcmp(argv[1], "-r") == 0) { - RemoveService(); - return 0; + return RemoveService(); } - if(argc == 2 && ::strcmp(argv[1], "-i") == 0) + if((argc == 2 || argc == 3) && ::strcmp(argv[1], "-i") == 0) { - InstallService(); - return 0; + const char* config = NULL; + if (argc == 3) + { + config = argv[2]; + } + return InstallService(config); } bool runAsWin32Service = false; - if (argc == 2 && ::strcmp(argv[1], "--service") == 0) + if (argc >= 2 && ::strcmp(argv[1], "--service") == 0) { runAsWin32Service = true; } - - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - if (WSAStartup(0x0101, &info) == SOCKET_ERROR) - { - // box backup will not run without sockets - ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); - THROW_EXCEPTION(BackupStoreException, Internal) - } + gpDaemonService = new Win32BackupService(); EnableBackupRights(); @@ -73,20 +66,33 @@ int main(int argc, const char *argv[]) if (runAsWin32Service) { - syslog(LOG_INFO,"Starting Box Backup Service"); - OurService(); + syslog(LOG_INFO, "Box Backup service starting"); + + char* config = NULL; + if (argc >= 3) + { + config = strdup(argv[2]); + } + + OurService(config); + + if (config) + { + free(config); + } + + syslog(LOG_INFO, "Box Backup service shut down"); } else { - ExitCode = gDaemonService.Main( + ExitCode = gpDaemonService->Main( BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); } - // Clean up our sockets - WSACleanup(); - ::closelog(); + delete gpDaemonService; + return ExitCode; #else // !WIN32 diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index b7207720..05e34b7e 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -70,7 +70,11 @@ BackupQueries::BackupQueries(BackupProtocolClient &rConnection, const Configurat mWarnedAboutOwnerAttributes(false), mReturnCode(0) // default return code { + #ifdef WIN32 + mRunningAsRoot = TRUE; + #else mRunningAsRoot = (::geteuid() == 0); + #endif } // -------------------------------------------------------------------------- @@ -85,6 +89,12 @@ BackupQueries::~BackupQueries() { } +typedef struct cmd_info +{ + const char* name; + const char* opts; +} cmd_info_t; + // -------------------------------------------------------------------------- // // Function @@ -162,8 +172,24 @@ void BackupQueries::DoCommand(const char *Command) } // Data about commands - static const char *commandNames[] = {"quit", "exit", "list", "pwd", "cd", "lcd", "sh", "getobject", "get", "compare", "restore", "help", "usage", "undelete", 0}; - static const char *validOptions[] = {"", "", "rodIFtsh", "", "od", "", "", "", "i", "alcqE", "dri", "", "", "", 0}; + static cmd_info_t commands[] = + { + { "quit", "" }, + { "exit", "" }, + { "list", "rodIFtTsh", }, + { "pwd", "" }, + { "cd", "od" }, + { "lcd", "" }, + { "sh", "" }, + { "getobject", "" }, + { "get", "i" }, + { "compare", "alcqAE" }, + { "restore", "dri" }, + { "help", "" }, + { "usage", "" }, + { "undelete", "" }, + { NULL, NULL } + }; #define COMMAND_Quit 0 #define COMMAND_Exit 1 #define COMMAND_List 2 @@ -183,11 +209,11 @@ void BackupQueries::DoCommand(const char *Command) // Work out which command it is... int cmd = 0; - while(commandNames[cmd] != 0 && ::strcmp(cmdElements[0].c_str(), commandNames[cmd]) != 0) + while(commands[cmd].name != 0 && ::strcmp(cmdElements[0].c_str(), commands[cmd].name) != 0) { cmd++; } - if(commandNames[cmd] == 0) + if(commands[cmd].name == 0) { // Check for aliases int a; @@ -222,9 +248,10 @@ void BackupQueries::DoCommand(const char *Command) while(*c != 0) { // Valid option? - if(::strchr(validOptions[cmd], *c) == NULL) + if(::strchr(commands[cmd].opts, *c) == NULL) { - printf("Invalid option '%c' for command %s\n", *c, commandNames[cmd]); + printf("Invalid option '%c' for command %s\n", + *c, commands[cmd].name); return; } opts[(int)*c] = true; @@ -319,8 +346,9 @@ void BackupQueries::CommandList(const std::vector &args, const bool #define LIST_OPTION_ALLOWOLD 'o' #define LIST_OPTION_ALLOWDELETED 'd' #define LIST_OPTION_NOOBJECTID 'I' - #define LIST_OPTION_NOFLAGS 'F' - #define LIST_OPTION_TIMES 't' + #define LIST_OPTION_NOFLAGS 'F' + #define LIST_OPTION_TIMES_LOCAL 't' + #define LIST_OPTION_TIMES_UTC 'T' #define LIST_OPTION_SIZEINBLOCKS 's' #define LIST_OPTION_DISPLAY_HASH 'h' @@ -362,7 +390,7 @@ void BackupQueries::CommandList(const std::vector &args, const bool // -------------------------------------------------------------------------- // // Function -// Name: BackupQueries::CommandList2(int64_t, const std::string &, const bool *) +// Name: BackupQueries::List(int64_t, const std::string &, const bool *, bool) // Purpose: Do the actual listing of directories and files // Created: 2003/10/10 // @@ -437,9 +465,9 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool } } - if(opts[LIST_OPTION_TIMES]) + if(opts[LIST_OPTION_TIMES_LOCAL]) { - // Show times... + // Show local times... std::string time = BoxTimeToISO8601String( en->GetModificationTime()); printf("%s ", time.c_str()); @@ -844,13 +872,44 @@ void BackupQueries::CommandGet(const std::vector &args, const bool } // Find object ID somehow - int64_t id; + int64_t fileId; + int64_t dirId = GetCurrentDirectoryID(); std::string localName; + // BLOCK { +#ifdef WIN32 + std::string fileName; + if(!ConvertConsoleToUtf8(args[0].c_str(), fileName)) + return; +#else + std::string fileName(args[0]); +#endif + + if(!opts['i']) + { + // does this remote filename include a path? + std::string::size_type index = fileName.rfind('/'); + if(index != std::string::npos) + { + std::string dirName(fileName.substr(0, index)); + fileName = fileName.substr(index + 1); + + dirId = FindDirectoryObjectID(dirName); + if(dirId == 0) + { + printf("Directory '%s' not found\n", + dirName.c_str()); + return; + } + } + } + + BackupStoreFilenameClear fn(fileName); + // Need to look it up in the current directory mrConnection.QueryListDirectory( - GetCurrentDirectoryID(), + dirId, BackupProtocolClientListDirectory::Flags_File, // just files (opts['i'])?(BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING):(BackupProtocolClientListDirectory::Flags_OldVersion | BackupProtocolClientListDirectory::Flags_Deleted), // only current versions false /* don't want attributes */); @@ -863,17 +922,23 @@ void BackupQueries::CommandGet(const std::vector &args, const bool if(opts['i']) { // Specified as ID. - id = ::strtoll(args[0].c_str(), 0, 16); - if(id == std::numeric_limits::min() || id == std::numeric_limits::max() || id == 0) + fileId = ::strtoll(args[0].c_str(), 0, 16); + if(fileId == std::numeric_limits::min() || + fileId == std::numeric_limits::max() || + fileId == 0) { printf("Not a valid object ID (specified in hex)\n"); return; } // Check that the item is actually in the directory - if(dir.FindEntryByID(id) == 0) + if(dir.FindEntryByID(fileId) == 0) { - printf("ID '%08llx' not found in current directory on store.\n(You can only download objects by ID from the current directory.)\n", id); + printf("ID '%08llx' not found in current " + "directory on store.\n" + "(You can only download objects by ID " + "from the current directory.)\n", + fileId); return; } @@ -884,26 +949,22 @@ void BackupQueries::CommandGet(const std::vector &args, const bool { // Specified by name, find the object in the directory to get the ID BackupStoreDirectory::Iterator i(dir); -#ifdef WIN32 - std::string fileName; - if(!ConvertConsoleToUtf8(args[0].c_str(), fileName)) - return; - BackupStoreFilenameClear fn(fileName); -#else - BackupStoreFilenameClear fn(args[0]); -#endif BackupStoreDirectory::Entry *en = i.FindMatchingClearName(fn); if(en == 0) { - printf("Filename '%s' not found in current directory on store.\n(Subdirectories in path not searched.)\n", args[0].c_str()); + printf("Filename '%s' not found in current " + "directory on store.\n" + "(Subdirectories in path not " + "searched.)\n", args[0].c_str()); return; } - id = en->GetObjectID(); + fileId = en->GetObjectID(); - // Local name is the last argument, which is either the looked up filename, or - // a filename specified by the user. + // Local name is the last argument, which is either + // the looked up filename, or a filename specified + // by the user. localName = args[args.size() - 1]; } } @@ -920,7 +981,7 @@ void BackupQueries::CommandGet(const std::vector &args, const bool try { // Request object - mrConnection.QueryGetFile(GetCurrentDirectoryID(), id); + mrConnection.QueryGetFile(dirId, fileId); // Stream containing encoded file std::auto_ptr objectStream(mrConnection.ReceiveStream()); @@ -929,7 +990,7 @@ void BackupQueries::CommandGet(const std::vector &args, const bool BackupStoreFile::DecodeFile(*objectStream, localName.c_str(), mrConnection.GetTimeout()); // Done. - printf("Object ID %08llx fetched sucessfully.\n", id); + printf("Object ID %08llx fetched sucessfully.\n", fileId); } catch(...) { @@ -950,8 +1011,10 @@ void BackupQueries::CommandGet(const std::vector &args, const bool BackupQueries::CompareParams::CompareParams() : mQuickCompare(false), mIgnoreExcludes(false), + mIgnoreAttributes(false), mDifferences(0), mDifferencesExplainedByModTime(0), + mUncheckedFiles(0), mExcludedDirs(0), mExcludedFiles(0), mpExcludeFiles(0), @@ -1012,6 +1075,7 @@ void BackupQueries::CommandCompare(const std::vector &args, const b BackupQueries::CompareParams params; params.mQuickCompare = opts['q']; params.mIgnoreExcludes = opts['E']; + params.mIgnoreAttributes = opts['A']; // Try and work out the time before which all files should be on the server { @@ -1074,13 +1138,29 @@ void BackupQueries::CommandCompare(const std::vector &args, const b return; } - printf("\n[ %d (of %d) differences probably due to file modifications after the last upload ]\nDifferences: %d (%d dirs excluded, %d files excluded)\n", - params.mDifferencesExplainedByModTime, params.mDifferences, params.mDifferences, params.mExcludedDirs, params.mExcludedFiles); + printf("\n[ %d (of %d) differences probably due to file " + "modifications after the last upload ]\n" + "Differences: %d (%d dirs excluded, %d files excluded, " + "%d files not checked)\n", + params.mDifferencesExplainedByModTime, params.mDifferences, + params.mDifferences, params.mExcludedDirs, + params.mExcludedFiles, params.mUncheckedFiles); // Set return code? if(opts['c']) { - SetReturnCode((params.mDifferences == 0)?COMPARE_RETURN_SAME:COMPARE_RETURN_DIFFERENT); + if (params.mUncheckedFiles != 0) + { + SetReturnCode(COMPARE_RETURN_ERROR); + } + else if (params.mDifferences != 0) + { + SetReturnCode(COMPARE_RETURN_DIFFERENT); + } + else + { + SetReturnCode(COMPARE_RETURN_SAME); + } } } @@ -1214,11 +1294,13 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s "(compared to server directory '%s')\n", localDirDisplay.c_str(), storeDirDisplay.c_str()); + rParams.mDifferences ++; } else { printf("ERROR: stat on local dir '%s'\n", localDirDisplay.c_str()); + rParams.mUncheckedFiles ++; } return; } @@ -1268,6 +1350,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s { printf("ERROR: opendir on local dir '%s'\n", localDirDisplay.c_str()); + rParams.mUncheckedFiles ++; return; } try @@ -1455,11 +1538,12 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s } // Compare attributes - BackupClientFileAttributes localAttr; box_time_t fileModTime = 0; + BackupClientFileAttributes localAttr; localAttr.ReadAttributes(localPath.c_str(), false /* don't zero mod times */, &fileModTime); modifiedAfterLastSync = (fileModTime > rParams.mLatestFileUploadTime); - if(!localAttr.Compare(fileOnServerStream->GetAttributes(), + if(!rParams.mIgnoreAttributes && + !localAttr.Compare(fileOnServerStream->GetAttributes(), true /* ignore attr mod time */, fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */)) { @@ -1554,10 +1638,12 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s e.GetType(), e.GetSubType(), storePathDisplay.c_str()); + rParams.mUncheckedFiles ++; } catch(...) - { + { printf("ERROR: (unknown) during file fetch and comparison for '%s'\n", storePathDisplay.c_str()); + rParams.mUncheckedFiles ++; } // Remove from set so that we know it's been compared @@ -1793,6 +1879,14 @@ void BackupQueries::CommandRestore(const std::vector &args, const b printf("The target directory exists. You cannot restore over an existing directory.\n"); break; + #ifdef WIN32 + case Restore_TargetPathNotFound: + printf("The target directory path does not exist.\n" + "To restore to a directory whose parent " + "does not exist, create the parent first.\n"); + break; + #endif + default: printf("ERROR: Unknown restore result.\n"); break; diff --git a/bin/bbackupquery/BackupQueries.h b/bin/bbackupquery/BackupQueries.h index e84de6ab..42fd54fe 100644 --- a/bin/bbackupquery/BackupQueries.h +++ b/bin/bbackupquery/BackupQueries.h @@ -68,8 +68,10 @@ private: void DeleteExcludeLists(); bool mQuickCompare; bool mIgnoreExcludes; + bool mIgnoreAttributes; int mDifferences; int mDifferencesExplainedByModTime; + int mUncheckedFiles; int mExcludedDirs; int mExcludedFiles; const ExcludeList *mpExcludeFiles; diff --git a/bin/bbackupquery/documentation.txt b/bin/bbackupquery/documentation.txt index 429caabe..0fb0bacb 100644 --- a/bin/bbackupquery/documentation.txt +++ b/bin/bbackupquery/documentation.txt @@ -104,6 +104,7 @@ compare -c -- set return code -q -- quick compare. Only checks file contents against checksums, doesn't do a full download + -A -- ignore attribute differences -E -- ignore exclusion settings Comparing with the root directory is an error, use -a option instead. diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp index d3656630..86b2468b 100644 --- a/bin/bbstored/BBStoreDHousekeeping.cpp +++ b/bin/bbstored/BBStoreDHousekeeping.cpp @@ -10,7 +10,10 @@ #include "Box.h" #include + +#ifdef HAVE_SYSLOG_H #include +#endif #include "BackupStoreDaemon.h" #include "BackupStoreAccountDatabase.h" @@ -29,95 +32,128 @@ // Created: 11/12/03 // // -------------------------------------------------------------------------- +void BackupStoreDaemon::HousekeepingInit() +{ + + mLastHousekeepingRun = 0; +} + +#ifndef WIN32 void BackupStoreDaemon::HousekeepingProcess() { + HousekeepingInit(); + // Get the time between housekeeping runs const Configuration &rconfig(GetConfiguration()); int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping")); - - int64_t lastHousekeepingRun = 0; while(!StopRun()) { - // Time now + RunHousekeepingIfNeeded(); + + // Calculate how long should wait before doing the next housekeeping run int64_t timeNow = GetCurrentBoxTime(); - // Do housekeeping if the time interval has elapsed since the last check - if((timeNow - lastHousekeepingRun) >= housekeepingInterval) - { - // Store the time - lastHousekeepingRun = timeNow; - ::syslog(LOG_INFO, "Starting housekeeping"); + time_t secondsToGo = BoxTimeToSeconds((mLastHousekeepingRun + housekeepingInterval) - timeNow); + if(secondsToGo < 1) secondsToGo = 1; + if(secondsToGo > 60) secondsToGo = 60; + int32_t millisecondsToGo = ((int)secondsToGo) * 1000; + + // Check to see if there's any message pending + CheckForInterProcessMsg(0 /* no account */, millisecondsToGo); + } +} +#endif - // Get the list of accounts - std::vector accounts; - if(mpAccountDatabase) - { - mpAccountDatabase->GetAllAccountIDs(accounts); - } +void BackupStoreDaemon::RunHousekeepingIfNeeded() +{ + // Get the time between housekeeping runs + const Configuration &rconfig(GetConfiguration()); + int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping")); + + // Time now + int64_t timeNow = GetCurrentBoxTime(); + // Do housekeeping if the time interval has elapsed since the last check + if((timeNow - mLastHousekeepingRun) < housekeepingInterval) + { + return; + } + + // Store the time + mLastHousekeepingRun = timeNow; + ::syslog(LOG_INFO, "Starting housekeeping"); + + // Get the list of accounts + std::vector accounts; + if(mpAccountDatabase) + { + mpAccountDatabase->GetAllAccountIDs(accounts); + } - SetProcessTitle("housekeeping, active"); + SetProcessTitle("housekeeping, active"); - // Check them all - for(std::vector::const_iterator i = accounts.begin(); i != accounts.end(); ++i) + // Check them all + for(std::vector::const_iterator i = accounts.begin(); i != accounts.end(); ++i) + { + try + { + if(mpAccounts) { - try - { - if(mpAccounts) - { - // Get the account root - std::string rootDir; - int discSet = 0; - mpAccounts->GetAccountRoot(*i, rootDir, discSet); - - // Do housekeeping on this account - HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); - housekeeping.DoHousekeeping(); - } - } - catch(BoxException &e) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account", - *i, e.what(), e.GetType(), e.GetSubType()); - } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account", - *i, e.what()); - } - catch(...) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account", - *i); - } + // Get the account root + std::string rootDir; + int discSet = 0; + mpAccounts->GetAccountRoot(*i, rootDir, discSet); - // Check to see if there's any message pending - CheckForInterProcessMsg(0 /* no account */); - - // Stop early? - if(StopRun()) - { - break; - } + // Do housekeeping on this account + HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); + housekeeping.DoHousekeeping(); } - - ::syslog(LOG_INFO, "Finished housekeeping"); } - - // Placed here for accuracy, if StopRun() is true, for example. - SetProcessTitle("housekeeping, idle"); - - // Calculate how long should wait before doing the next housekeeping run - timeNow = GetCurrentBoxTime(); - time_t secondsToGo = BoxTimeToSeconds((lastHousekeepingRun + housekeepingInterval) - timeNow); - if(secondsToGo < 1) secondsToGo = 1; - if(secondsToGo > 60) secondsToGo = 60; - int32_t millisecondsToGo = ((int)secondsToGo) * 1000; + catch(BoxException &e) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account", + *i, e.what(), e.GetType(), e.GetSubType()); + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account", + *i, e.what()); + } + catch(...) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account", + *i); + } +#ifndef WIN32 // Check to see if there's any message pending - CheckForInterProcessMsg(0 /* no account */, millisecondsToGo); + CheckForInterProcessMsg(0 /* no account */); +#endif + + // Stop early? + if(StopRun()) + { + break; + } } + + ::syslog(LOG_INFO, "Finished housekeeping"); + + // Placed here for accuracy, if StopRun() is true, for example. + SetProcessTitle("housekeeping, idle"); } +#ifdef WIN32 +void BackupStoreDaemon::OnIdle() +{ + if (!mHousekeepingInited) + { + HousekeepingInit(); + mHousekeepingInited = true; + } + + RunHousekeepingIfNeeded(); +} +#endif // -------------------------------------------------------------------------- // @@ -128,6 +164,7 @@ void BackupStoreDaemon::HousekeepingProcess() // Created: 11/12/03 // // -------------------------------------------------------------------------- +#ifndef WIN32 bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitTime) { // First, check to see if it's EOF -- this means something has gone wrong, and the housekeeping should terminate. @@ -171,5 +208,6 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT return false; } +#endif diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index 35bc095d..845903b2 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -9,7 +9,12 @@ #include "Box.h" +#ifdef HAVE_SYSLOG_H #include +#endif + +#include +#include #include "autogen_BackupProtocolServer.h" #include "BackupConstants.h" @@ -327,8 +332,15 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto std::auto_ptr diff2(rContext.OpenObject(patchID)); // Choose a temporary filename for the result of the combination - std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", - p + 16 /* rotate which disc it's on */)); +#ifdef WIN32 + std::ostringstream fs(rContext.GetStoreRoot()); + fs << ".recombinetemp."; + fs << p; + std::string tempFn(fs.str()); + tempFn = RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), tempFn, p + 16); +#else + std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", p + 16 /* rotate which disc it's on */)); +#endif // Open the temporary file std::auto_ptr combined; @@ -336,14 +348,23 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto { { // Write nastily to allow this to work with gcc 2.x +#ifdef WIN32 + combined.reset(new FileStream( + tempFn.c_str(), + O_RDWR | O_CREAT | O_EXCL | + O_BINARY | O_TRUNC)); +#else std::auto_ptr t(new FileStream(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL)); combined = t; +#endif } +#ifndef WIN32 // Unlink immediately as it's a temporary file if(::unlink(tempFn.c_str()) != 0) { THROW_EXCEPTION(CommonException, OSFileError); } +#endif } catch(...) { @@ -359,6 +380,9 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto combined->Seek(0, IOStream::SeekType_Absolute); // Then shuffle round for the next go +#ifdef WIN32 + if (from.get()) from->Close(); +#endif from = combined; } @@ -396,8 +420,9 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto stream = t; } - // Object will be deleted when the stream is deleted, so can release the object auto_ptr here to - // avoid premature deletiong + // Object will be deleted when the stream is deleted, + // so can release the object auto_ptr here to avoid + // premature deletion object.release(); } diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp index c796c13a..cd17812c 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupContext.cpp @@ -132,6 +132,7 @@ bool BackupContext::AttemptToGetWriteLock() // Request the lock bool gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */); +#ifndef WIN32 if(!gotLock) { // The housekeeping process might have the thing open -- ask it to stop @@ -150,6 +151,7 @@ bool BackupContext::AttemptToGetWriteLock() } while(!gotLock && tries > 0); } +#endif if(gotLock) { @@ -453,13 +455,21 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod try { // Open it twice +#ifdef WIN32 + FileStream diff(tempFn.c_str(), + O_RDWR | O_CREAT | O_BINARY); + FileStream diff2(tempFn.c_str(), + O_RDWR | O_BINARY); +#else FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL); FileStream diff2(tempFn.c_str(), O_RDONLY); - // Unlink it immediately, so it definately goes away + + // Unlink it immediately, so it definitely goes away if(::unlink(tempFn.c_str()) != 0) { THROW_EXCEPTION(CommonException, OSFileError); } +#endif // Stream the incoming diff to this temporary file if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT)) @@ -508,6 +518,14 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod ::unlink(tempFn.c_str()); throw; } + +#ifdef WIN32 + // we can't delete the file while it's open, above + if(::unlink(tempFn.c_str()) != 0) + { + THROW_EXCEPTION(CommonException, OSFileError); + } +#endif } // Get the blocks used diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 2752893a..24a81ceb 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -11,9 +11,12 @@ #include #include -#include #include +#ifdef HAVE_SYSLOG_H +#include +#endif + #include "BackupContext.h" #include "BackupStoreDaemon.h" #include "BackupStoreConfigVerify.h" @@ -39,7 +42,11 @@ BackupStoreDaemon::BackupStoreDaemon() mExtendedLogging(false), mHaveForkedHousekeeping(false), mIsHousekeepingProcess(false), +#ifdef WIN32 + mHousekeepingInited(false) +#else mInterProcessComms(mInterProcessCommsSocket) +#endif { } @@ -156,6 +163,7 @@ void BackupStoreDaemon::Run() const Configuration &config(GetConfiguration()); mExtendedLogging = config.GetKeyValueBool("ExtendedLogging"); +#ifndef WIN32 // Fork off housekeeping daemon -- must only do this the first time Run() is called if(!mHaveForkedHousekeeping) { @@ -219,9 +227,11 @@ void BackupStoreDaemon::Run() } else { +#endif // !WIN32 // In server process -- use the base class to do the magic ServerTLS::Run(); +#ifndef WIN32 // Why did it stop? Tell the housekeeping process to do the same if(IsReloadConfigWanted()) { @@ -232,6 +242,7 @@ void BackupStoreDaemon::Run() mInterProcessCommsSocket.Write("t\n", 2); } } +#endif } @@ -297,6 +308,8 @@ void BackupStoreDaemon::LogConnectionStats(const char *commonName, // Log the amount of data transferred ::syslog(LOG_INFO, "Connection statistics for %s: " "IN=%lld OUT=%lld TOTAL=%lld\n", commonName, - s.GetBytesRead(), s.GetBytesWritten(), - s.GetBytesRead() + s.GetBytesWritten()); + (long long)s.GetBytesRead(), + (long long)s.GetBytesWritten(), + (long long)s.GetBytesRead() + + (long long)s.GetBytesWritten()); } diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index 2fbe486d..857a9356 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -38,11 +38,13 @@ private: BackupStoreDaemon(const BackupStoreDaemon &rToCopy); public: +#ifndef WIN32 // For BackupContext to comminicate with housekeeping process void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) { mInterProcessCommsSocket.Write(Msg, MsgLen); } +#endif protected: @@ -57,9 +59,11 @@ protected: const ConfigurationVerify *GetConfigVerify() const; +#ifndef WIN32 // Housekeeping functions void HousekeepingProcess(); bool CheckForInterProcessMsg(int AccountNum = 0, int MaximumWaitTime = 0); +#endif void LogConnectionStats(const char *commonName, const SocketStreamTLS &s); @@ -70,8 +74,17 @@ private: bool mHaveForkedHousekeeping; bool mIsHousekeepingProcess; +#ifdef WIN32 + virtual void OnIdle(); + bool mHousekeepingInited; +#else SocketStream mInterProcessCommsSocket; IOStreamGetLine mInterProcessComms; +#endif + + void HousekeepingInit(); + void RunHousekeepingIfNeeded(); + int64_t mLastHousekeepingRun; }; diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp index 4aa1999e..91945306 100644 --- a/bin/bbstored/HousekeepStoreAccount.cpp +++ b/bin/bbstored/HousekeepStoreAccount.cpp @@ -225,6 +225,7 @@ void HousekeepStoreAccount::MakeObjectFilename(int64_t ObjectID, std::string &rF // -------------------------------------------------------------------------- bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -235,6 +236,7 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) return false; } } +#endif // Get the filename std::string objectFilename; @@ -251,6 +253,7 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) // Read the directory in BackupStoreDirectory dir; dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite); + dirStream->Close(); // Is it empty? if(dir.GetNumberOfEntries() == 0) @@ -485,6 +488,7 @@ bool HousekeepStoreAccount::DeleteFiles() // (there is likely to be more in the set than should be actually deleted). for(std::set::iterator i(mPotentialDeletions.begin()); i != mPotentialDeletions.end(); ++i) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -495,6 +499,7 @@ bool HousekeepStoreAccount::DeleteFiles() return true; } } +#endif // Load up the directory it's in // Get the filename @@ -729,6 +734,7 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() // Go through list for(std::vector::const_iterator i(mEmptyDirectories.begin()); i != mEmptyDirectories.end(); ++i) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -739,6 +745,7 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() return true; } } +#endif // Do not delete the root directory if(*i == BACKUPSTORE_ROOT_DIRECTORY_ID) diff --git a/configure.ac b/configure.ac index 2c4300c7..f3fe26b1 100644 --- a/configure.ac +++ b/configure.ac @@ -44,7 +44,7 @@ AC_CHECK_LIB([z], [zlibVersion],, [AC_MSG_ERROR([[cannot find zlib]])]) VL_LIB_READLINE([have_libreadline=yes], [have_libreadline=no]) ## Check for Berkely DB. Restrict to certain versions -AX_PATH_BDB(, [ +AX_PATH_BDB([1.x or 4.1], [ LIBS="$BDB_LIBS $LIBS" LDFLAGS="$BDB_LDFLAGS $LDFLAGS" CPPFLAGS="$CPPFLAGS $BDB_CPPFLAGS" @@ -89,7 +89,7 @@ AC_CHECK_HEADERS([execinfo.h process.h pwd.h regex.h signal.h]) AC_CHECK_HEADERS([syslog.h time.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h]) -AC_CHECK_HEADERS([sys/xattr.h]) +AC_CHECK_HEADERS([sys/uio.h sys/xattr.h]) if test "$ac_cv_header_regex_h" = "yes"; then AC_SEARCH_LIBS([regcomp], [pcreposix]) @@ -116,6 +116,7 @@ AC_CHECK_MEMBERS([struct sockaddr_in.sin_len],,, [[ ]]) AC_CHECK_DECLS([INFTIM],,, [[#include ]]) AC_CHECK_DECLS([SO_PEERCRED],,, [[#include ]]) +AC_CHECK_DECLS([O_BINARY],,,) AC_HEADER_TIME AC_STRUCT_TM AX_CHECK_DIRENT_D_TYPE @@ -124,14 +125,14 @@ AX_CHECK_DEFINE_PRAGMA if test "x$ac_cv_c_bigendian" != "xyes"; then AX_BSWAP64 fi + if test "$target_os" != "mingw32"; then AX_RANDOM_DEVICE -fi -AX_CHECK_MOUNT_POINT(,[ - if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then + AX_CHECK_MOUNT_POINT(,[ AC_MSG_ERROR([[cannot work out how to discover mount points on your platform]]) - fi ]) +fi + AX_CHECK_MALLOC_WORKAROUND @@ -220,6 +221,7 @@ AX_CONFIG_SCRIPTS([bin/bbackupd/bbackupd-config lib/server/makeprotocol.pl runtest.pl test/backupstorefix/testfiles/testbackupstorefix.pl + test/bbackupd/testfiles/bbackupd.conf test/bbackupd/testfiles/extcheck1.pl test/bbackupd/testfiles/extcheck2.pl test/bbackupd/testfiles/notifyscript.pl]) @@ -237,6 +239,7 @@ A summary of the build configuration is below. Box Backup will function without these features, but will work better where they are present. Refer to the documentation for more information on each feature. +Regular expressions: $ac_cv_header_regex_h Large files: $have_large_file_support Berkeley DB: $ax_path_bdb_ok Readline: $have_libreadline diff --git a/docs/backup/win32_build_on_linux_using_mingw.txt b/docs/backup/win32_build_on_linux_using_mingw.txt index a3243a50..12261d51 100644 --- a/docs/backup/win32_build_on_linux_using_mingw.txt +++ b/docs/backup/win32_build_on_linux_using_mingw.txt @@ -7,6 +7,11 @@ Install the MinGW cross-compiler for Windows: - Fedora and SuSE users can download RPM packages from [http://mirzam.it.vu.nl/mingw/] +You will need to know the prefix used by the cross-compiler executables. +It will usually be something like "ix86-mingw32*-". All the binaries in the +cross-compiler package will start with this prefix. The documentation below +assumes that it is "i386-mingw32-". Adjust to taste. + Download Zlib from [http://www.zlib.net/], unpack and enter source directory: export CC=i386-mingw32-gcc @@ -16,7 +21,18 @@ Download Zlib from [http://www.zlib.net/], unpack and enter source directory: make make install prefix=/usr/local/i386-mingw32 -Download OpenSSL 0.9.7 from +Download OpenSSL 0.9.8b from +[http://www.openssl.org/source/openssl-0.9.8b.tar.gz] + +Unpack and configure: + + tar xzvf openssl-0.9.8b.tar.gz + cd openssl-0.9.8b + ./Configure mingw + make makefile.one + wget http://bbdev.fluffy.co.uk/svn/box/chris/win32/support/openssl-0.9.8b-mingw-cross.patch + patch -p1 < openssl-0.9.8b-mingw-cross.patch + make -f makefile.one Configure Box with: @@ -27,5 +43,6 @@ Configure Box with: export CXXFLAGS="-mthreads" export LDFLAGS="-mthreads" export LIBS="-lcrypto -lws2_32 -lgdi32" + (if you don't have a "configure" file, run "./bootstrap") ./configure --target=i386-mingw32 - make CXX="$CXX" AR="$AR" RANLIB="$RANLIB" + make CXX="$CXX" AR="$AR" RANLIB="$RANLIB" WINDRES="i386-mingw32-windres" diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in index 04e6cda4..8297b93b 100644 --- a/infrastructure/BoxPlatform.pm.in +++ b/infrastructure/BoxPlatform.pm.in @@ -1,16 +1,30 @@ package BoxPlatform; use Exporter; @ISA = qw/Exporter/; -@EXPORT = qw/$build_os $build_cpu $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext/; +@EXPORT = qw/$build_os $build_cpu $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows update_if_changed/; BEGIN { # which OS are we building under? - $build_os = `uname`; - chomp $build_os; - $build_cpu = `uname -p`; - chomp $build_cpu; + $target_os = '@target_os@'; + $target_windows = 0; + $target_windows = 1 if $target_os =~ m'^mingw32' + or $target_os eq "winnt"; + + if ($^O eq "MSWin32" and not -x "/usr/bin/uname") + { + $build_os = "winnt"; + $build_cpu = "ix86"; + } + else + { + $build_os = `uname`; + chomp $build_os; + $build_cpu = `uname -m`; + chomp $build_cpu; + } + # Cygwin Builds usually something like CYGWIN_NT-5.0, CYGWIN_NT-5.1 # Box Backup tried on Win2000,XP only :) @@ -24,11 +38,18 @@ BEGIN $platform_compile_line_extra =~ s/ -O2//; $platform_link_line_extra = '@LDFLAGS@'; $platform_lib_files = '@LIBS@'; - $target_os = '@target_os@'; $platform_exe_ext = '@EXEEXT@'; # get version - open VERSION,"VERSION.txt" or die "VERSION.txt: $!"; + if (! -r "VERSION.txt" and -r "../../VERSION.txt") + { + open VERSION,"../../VERSION.txt" or die "../../VERSION.txt: $!"; + } + else + { + open VERSION,"VERSION.txt" or die "VERSION.txt: $!"; + } + $product_version = ; chomp $product_version; $product_name = ; @@ -89,5 +110,34 @@ sub make_flag return $_[0].'=1'; } +sub update_if_changed ($) +{ + my ($file) = @_; + die "$file.new: not found" unless -r "$file.new"; + + if (-r $file) + { + die "$file.new: not found" unless -r "$file.new"; + if (system("diff --brief $file $file.new") == 0) + { + unlink "$file.new"; + return; + } + } + + if (system("cp $file.new $file") != 0) + { + die "failed to copy $file.new to $file"; + } + + if (system("diff --brief $file $file.new") != 0) + { + die "$file and $file.new are still different"; + } + + unlink "$file.new"; + return; +} + 1; diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index f95f01e6..c64c1fa5 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -41,6 +41,8 @@ int test(int argc, const char *argv[]); #endif int failures = 0; +int first_fail_line; +std::string first_fail_file; int filedes_open_at_beginning = -1; @@ -128,7 +130,10 @@ int main(int argc, const char *argv[]) } if(failures > 0) { - printf("FAILED: %d tests failed\n", failures); + printf("FAILED: %d tests failed (first at " + "%s:%d)\n", failures, + first_fail_file.c_str(), + first_fail_line); } else { diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index f70321a7..9306a8c1 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -14,8 +14,7 @@ $|=1; print "Box build environment setup.\n\n"; - -my $implicit_dep = 'lib/common'; +my @implicit_deps = ('lib/common'); # work out platform variables use lib 'infrastructure'; @@ -38,11 +37,15 @@ unless(-d 'local') # flags about the environment my %env_flags; -my $windows_include_path = "-I../../lib/win32 "; -if ($target_os ne "mingw32" && $target_os ne "winnt") +my $windows_include_path = ""; +if ($target_windows) +{ + $module_dependency{"lib/common"} = ["lib/win32"]; + push @implicit_deps, "lib/win32"; +} +else { - $windows_include_path = ""; - $env_flags{'IGNORE_lib/win32'} = 1; + # $env_flags{'IGNORE_lib/win32'} = 1; } # print "Flag: $_\n" for(keys %env_flags); @@ -111,7 +114,7 @@ close FINDAUTOGEN; print "done\n\n"; -# open test mail program template file +# open test main program template file my $test_template_file = 'infrastructure/buildenv-testmain-template.cpp'; open FL,$test_template_file or die "Can't open test template file\n"; my $test_template; @@ -271,7 +274,7 @@ for(@modules_files) push @md,$_ unless ignore_module($_) } } - $module_dependency{$mod} = [$implicit_dep,@md]; + $module_dependency{$mod} = [@implicit_deps,@md]; $module_library_link_opts{$mod} = [@lo]; # make directories, but not if we're using an external library and this a library module @@ -286,17 +289,21 @@ for(@modules_files) } # make dirs for implicit dep -mkdir "release/$implicit_dep",0755; -mkdir "debug/$implicit_dep",0755; +foreach my $dep (@implicit_deps) +{ + mkdir "release/$dep",0755; + mkdir "debug/$dep",0755; +} # write a list of all the modules we've configured to use -open CONFIGURED_MODS,'>local/modules.h' or die "Can't write configured modules list"; +open CONFIGURED_MODS,'>local/modules.h.new' or die + "Can't write configured modules list"; print CONFIGURED_MODS <<__E; // automatically generated file, do not edit #ifndef _CONFIGURED_MODULES__H #define _CONFIGURED_MODULES__H __E -for($implicit_dep,@modules) +for(@implicit_deps,@modules) { my $m = $_; $m =~ s~/~_~; @@ -306,11 +313,11 @@ print CONFIGURED_MODS <<__E; #endif // _CONFIGURED_MODULES__H __E close CONFIGURED_MODS; - +update_if_changed("local/modules.h"); # now make a list of all the .h files we can find, recording which module they're in my %hfiles; -for my $mod (@modules, $implicit_dep) +for my $mod (@modules, @implicit_deps) { opendir DIR,$mod; my @items = readdir DIR; @@ -347,7 +354,7 @@ for my $mod (@modules, $implicit_dep) } } -for my $mod (@modules, $implicit_dep) +for my $mod (@modules, @implicit_deps) { opendir DIR,$mod; for my $h (grep /\.h\Z/i, readdir DIR) @@ -373,9 +380,10 @@ for my $mod (@modules, $implicit_dep) print "done\n\nGenerating Makefiles...\n"; +my %module_resources_win32; # Then write a makefile for each module -for my $mod (@modules, $implicit_dep) +for my $mod (@implicit_deps, @modules) { print $mod,"\n"; @@ -386,15 +394,19 @@ for my $mod (@modules, $implicit_dep) { my $testmain = $test_template; $testmain =~ s/TEST_NAME/$name/g; - open TESTMAIN,">$mod/_main.cpp" or die "Can't open test main file for $mod for writing\n"; + open TESTMAIN,">$mod/_main.cpp.new" or die + "Can't open test main file for $mod for writing\n"; print TESTMAIN $testmain; close TESTMAIN; + update_if_changed("$mod/_main.cpp"); # test file... sub writetestfile { my ($filename,$runcmd,$module) = @_; - open TESTFILE,">$filename" or die "Can't open test script file for $module for writing\n"; + open TESTFILE,">$filename.new" or die + "Can't open test script file for $module " . + "for writing\n"; print TESTFILE "#!/bin/sh\necho TEST: $module\n"; if(-d "$module/testfiles") { @@ -413,12 +425,13 @@ __E } print TESTFILE "$runcmd\n"; close TESTFILE; + update_if_changed($filename); } writetestfile("$mod/_t", - './test' . $platform_exe_ext . '$1 $2 $3 $4 $5', $mod); + './test' . $platform_exe_ext . ' $1 $2 $3 $4 $5', $mod); writetestfile("$mod/_t-gdb", - 'gdb ./test ' . $platform_exe_ext, $mod); + 'gdb ./test' . $platform_exe_ext, $mod); } @@ -441,14 +454,14 @@ __E add_mod_deps(\@deps_raw, $mod); # and then dedup and reorder them my %d_done; - for(my $a = $#deps_raw; $a >= 0; $a--) + foreach my $dep (reverse @deps_raw) { - if(!exists $d_done{$deps_raw[$a]}) + if(!exists $d_done{$dep}) { # insert - push @all_deps_for_module, $deps_raw[$a]; + push @all_deps_for_module, $dep; # mark as done - $d_done{$deps_raw[$a]} = 1; + $d_done{$dep} = 1; } } } @@ -480,11 +493,12 @@ __E # start the makefile my $mk_name_extra = ($bsd_make)?'':'X'; - open MAKE,">$mod/Makefile".$mk_name_extra or die "Can't open Makefile for $mod\n"; + open MAKE,">$mod/Makefile".$mk_name_extra.".new" or die + "Can't open Makefile for $mod\n"; my $debug_link_extra = ($target_is_library)?'':'../../debug/lib/debug/debug.a'; my $release_flags = "-O2"; - if ($target_os eq "mingw32") + if ($target_windows) { $release_flags = "-O0 -g"; } @@ -499,6 +513,7 @@ CXX = g++ AR = ar RANLIB = ranlib PERL = "@PERL@" +WINDRES = windres .ifdef RELEASE CXXFLAGS = -DNDEBUG $release_flags -Wall $include_paths $extra_platform_defines -DBOX_VERSION="\\"$product_version\\"" OUTBASE = ../../release @@ -546,7 +561,7 @@ __E @items = (@items, @autogen_items); } - # first, obtain a list of depenencies within the .h files + # first, obtain a list of dependencies within the .h files my %headers; for my $h (grep /\.h\Z/i, @items) { @@ -566,19 +581,30 @@ __E # then... do the cpp files... my @obj_base; - for my $cpp (@items) + for my $file (@items) { - next unless $cpp =~ m/\A(.+)\.cpp\Z/i; - next if $cpp =~ /\A\._/; # Temp Mac OS Resource hack + my $is_cpp = $file =~ m/\A(.+)\.cpp\Z/i; + my $is_rc = $file =~ m/\A(.+)\.rc\Z/i; + my $base = $1; + + if ($target_windows) + { + next if not $is_cpp and not $is_rc; + } + else + { + next if not $is_cpp; + } + + next if $file =~ /\A\._/; # Temp Mac OS Resource hack # store for later - my $base = $1; push @obj_base,$base; # get the file... - open FL,"$mod/$cpp"; + open FL,"$mod/$file"; my $f; - read FL,$f,-s "$mod/$cpp"; + read FL,$f,-s "$mod/$file"; close FL; my %dep; @@ -592,10 +618,29 @@ __E my $out_name = '$(OUTDIR)/'.$base.'.o'; # write the line for this cpp file - $make .= $out_name.': '.join(' ',$cpp,map - { ($hfiles{$_} eq $mod)?$_:'../../'.$hfiles{$_}."/$_" } keys %dep)."\n"; - $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra -c $cpp -o $out_name\n\n"; + my @dep_paths = map + { + ($hfiles{$_} eq $mod) + ? $_ + : '../../'.$hfiles{$_}."/$_" + } + keys %dep; + $make .= $out_name.': '.join(' ',$file,@dep_paths)."\n"; + + if ($is_cpp) + { + $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra ". + "-c $file -o $out_name\n\n"; + } + elsif ($is_rc) + { + $make .= "\t\$(WINDRES) $file $out_name\n\n"; + my $res_list = $module_resources_win32{$mod}; + $res_list ||= []; + push @$res_list, $base.'.o'; + $module_resources_win32{$mod} = $res_list; + } } my $has_deps = ($#{$module_dependency{$mod}} >= 0); @@ -647,11 +692,28 @@ __E additional_objects_from_make_fragment("$mod/Makefile.extra.$build_os", \@objs, \@makefile_includes); my $o_file_list = join(' ',map {'$(OUTDIR)/'.$_.'.o'} @objs); + + if ($has_deps and not $bsd_make) + { + print MAKE ".PHONY: all\n" . + "all: dep_modules $end_target\n\n"; + } + print MAKE $end_target,': ',$o_file_list; - print MAKE ' dep_modules' if $has_deps and not $bsd_make; print MAKE " ",$lib_files unless $target_is_library; print MAKE "\n"; + if ($target_windows) + { + foreach my $dep (@all_deps_for_module) + { + my $res_list = $module_resources_win32{$dep}; + next unless $res_list; + $o_file_list .= ' '.join(' ', + map {'$(OUTBASE)/'.$dep."/$_"} @$res_list); + } + } + # stuff to make the final target... if($target_is_library) { @@ -730,8 +792,8 @@ __E if(!$bsd_make) { # need to post process this into a GNU makefile - open MAKE,">$mod/Makefile"; - open MAKEB,"$mod/MakefileX"; + open MAKE,">$mod/Makefile.new" or die $!; + open MAKEB,"$mod/MakefileX.new" or die $!; while() { @@ -743,8 +805,10 @@ __E close MAKEB; close MAKE; - unlink "$mod/MakefileX"; + unlink "$mod/MakefileX.new"; } + + update_if_changed("$mod/Makefile"); } print "\nType 'cd ; $make_command' to build a module\n\n"; diff --git a/infrastructure/msvc/2003/boxbackup.ncb b/infrastructure/msvc/2003/boxbackup.ncb deleted file mode 100644 index 8aacb715..00000000 Binary files a/infrastructure/msvc/2003/boxbackup.ncb and /dev/null differ diff --git a/infrastructure/msvc/2003/boxbackup.suo b/infrastructure/msvc/2003/boxbackup.suo deleted file mode 100644 index c461ff26..00000000 Binary files a/infrastructure/msvc/2003/boxbackup.suo and /dev/null differ diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp index 974db3c9..ace72cf8 100644 --- a/lib/backupclient/BackupClientFileAttributes.cpp +++ b/lib/backupclient/BackupClientFileAttributes.cpp @@ -642,6 +642,7 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const } // If working as root, set user IDs + #ifndef WIN32 if(::geteuid() == 0) { #ifndef HAVE_LCHOWN @@ -661,6 +662,7 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const } #endif } + #endif if(static_cast(xattrOffset+sizeof(u_int32_t))<=mpClearAttributes->GetSize()) { diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp index f5a55207..278bf50a 100644 --- a/lib/backupclient/BackupStoreFile.cpp +++ b/lib/backupclient/BackupStoreFile.cpp @@ -289,6 +289,8 @@ void BackupStoreFile::DecodeFile(IOStream &rEncodedFile, const char *DecodedFile // Copy it out to the file stream->CopyStreamTo(out); } + + out.Close(); // Write the attributes stream->GetAttributes().WriteAttributes(DecodedFilename); diff --git a/lib/backupclient/BackupStoreObjectDump.cpp b/lib/backupclient/BackupStoreObjectDump.cpp index b4ccc731..d3d9cc17 100644 --- a/lib/backupclient/BackupStoreObjectDump.cpp +++ b/lib/backupclient/BackupStoreObjectDump.cpp @@ -113,7 +113,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/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 36d9cad3..eb10b385 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -141,8 +141,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/BackupStoreCheck.cpp b/lib/backupstore/BackupStoreCheck.cpp index fb48c3da..16d397a2 100644 --- a/lib/backupstore/BackupStoreCheck.cpp +++ b/lib/backupstore/BackupStoreCheck.cpp @@ -328,7 +328,8 @@ 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" @@ -377,7 +378,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":""); + ::printf("Spurious file %s" DIRECTORY_SEPARATOR "%s " + "found%s\n", dirName.c_str(), (*i).c_str(), + mFixErrors?", deleting":""); ++mNumberErrorsFound; if(mFixErrors) { diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h index b766706a..cb83f7a9 100644 --- a/lib/common/BoxPlatform.h +++ b/lib/common/BoxPlatform.h @@ -40,8 +40,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 @@ -138,6 +138,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 diff --git a/lib/common/FdGetLine.h b/lib/common/FdGetLine.h index fecb0371..a18007a3 100644 --- a/lib/common/FdGetLine.h +++ b/lib/common/FdGetLine.h @@ -14,6 +14,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/Guards.h b/lib/common/Guards.h index 17d73b3f..b1bca0fa 100644 --- a/lib/common/Guards.h +++ b/lib/common/Guards.h @@ -24,7 +24,7 @@ #include "MemLeakFindOn.h" -template +template class FileHandleGuard { public: diff --git a/lib/common/UnixUser.cpp b/lib/common/UnixUser.cpp index df2d0ddd..d0fd337b 100644 --- a/lib/common/UnixUser.cpp +++ b/lib/common/UnixUser.cpp @@ -75,6 +75,7 @@ UnixUser::UnixUser(uid_t UID, gid_t GID) // -------------------------------------------------------------------------- UnixUser::~UnixUser() { +#ifndef WIN32 if(mRevertOnDestruction) { // Revert to "real" user and group id of the process @@ -84,6 +85,7 @@ UnixUser::~UnixUser() THROW_EXCEPTION(CommonException, CouldNotRestoreProcessUser) } } +#endif } @@ -98,6 +100,7 @@ UnixUser::~UnixUser() // -------------------------------------------------------------------------- void UnixUser::ChangeProcessUser(bool Temporary) { +#ifndef WIN32 if(Temporary) { // Change temporarily (change effective only) @@ -119,6 +122,7 @@ void UnixUser::ChangeProcessUser(bool Temporary) THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser) } } +#endif } diff --git a/lib/common/makeexception.pl.in b/lib/common/makeexception.pl.in index 1564b75b..c03b8277 100755 --- a/lib/common/makeexception.pl.in +++ b/lib/common/makeexception.pl.in @@ -1,9 +1,11 @@ #!@PERL@ +use lib "../../infrastructure"; +use BoxPlatform; + # global exception list file my $global_list = '../../ExceptionCodes.txt'; - my @exception; my @exception_desc; my $class; @@ -46,8 +48,8 @@ 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"; +open CPP,">autogen_${class}Exception.cpp.new" or die "Can't open cpp file for writing"; +open H,">autogen_${class}Exception.h.new" or die "Can't open h file for writing"; # write header file my $guardname = uc 'AUTOGEN_'.$class.'EXCEPTION_H'; @@ -200,6 +202,9 @@ __E close H; close CPP; +update_if_changed("autogen_${class}Exception.cpp"); +update_if_changed("autogen_${class}Exception.h"); + # update the global exception list my $list_before; my $list_after; diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp index d60936fc..bc728113 100644 --- a/lib/raidfile/RaidFileRead.cpp +++ b/lib/raidfile/RaidFileRead.cpp @@ -14,10 +14,20 @@ #include #include #include + +#ifdef HAVE_SYS_UIO_H #include +#endif + +#ifdef HAVE_SYSLOG_H #include +#endif + #include + +#ifdef HAVE_DIRENT_H #include +#endif #include #include @@ -583,7 +593,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) @@ -1017,7 +1028,8 @@ std::auto_ptr 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) @@ -1055,13 +1067,15 @@ std::auto_ptr 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; @@ -1169,7 +1183,8 @@ std::auto_ptr 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) @@ -1178,14 +1193,16 @@ std::auto_ptr 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/RaidFileWrite.cpp b/lib/raidfile/RaidFileWrite.cpp index e30162fa..b3c98701 100644 --- a/lib/raidfile/RaidFileWrite.cpp +++ b/lib/raidfile/RaidFileWrite.cpp @@ -104,7 +104,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) { @@ -115,7 +116,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; @@ -123,6 +124,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. @@ -242,23 +246,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) @@ -292,8 +319,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) } @@ -388,13 +422,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... @@ -530,6 +564,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/server/Daemon.cpp b/lib/server/Daemon.cpp index 2f902473..2131bdcb 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -23,6 +23,10 @@ #include #endif +#ifdef WIN32 + #include +#endif + #include "Daemon.h" #include "Configuration.h" #include "ServerException.h" @@ -142,7 +146,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) { fprintf(stderr, "%s: failed to start: " "failed to open configuration file: " - "%s", DaemonName(), + "%s\n", DaemonName(), mConfigFileName.c_str()); #ifdef WIN32 ::syslog(LOG_ERR, "%s: failed to start: " @@ -189,6 +193,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) { THROW_EXCEPTION(ServerException, DaemoniseFailed) } +#endif // !WIN32 // Server configuration const Configuration &serverConfig( @@ -197,7 +202,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")) { @@ -267,20 +273,25 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // open the log ::openlog(DaemonName(), LOG_PID, LOG_LOCAL6); + // Log the start message ::syslog(LOG_INFO, "Starting daemon (config: %s) (version " BOX_VERSION ")", mConfigFileName.c_str()); -#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"); THROW_EXCEPTION(ServerException, DaemoniseFailed) } -#endif // Set up memory leak reporting #ifdef BOX_MEMORY_LEAK_TESTING @@ -352,6 +363,22 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) #endif 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 + ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); + THROW_EXCEPTION(CommonException, Internal) + } +#endif + + int retcode = 0; // Main Daemon running try @@ -381,7 +408,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) mConfigFileName.c_str(), errors.c_str()); // And give up - return 1; + retcode = 1; + break; } // delete old configuration @@ -409,22 +437,26 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) ::syslog(LOG_ERR, "%s: terminating due to exception %s " "(%d/%d)", DaemonName(), e.what(), e.GetType(), e.GetSubType()); - return 1; + retcode = 1; } catch(std::exception &e) { ::syslog(LOG_ERR, "%s: terminating due to exception %s", DaemonName(), e.what()); - return 1; + retcode = 1; } catch(...) { ::syslog(LOG_ERR, "%s: terminating due to unknown exception", DaemonName()); - return 1; + retcode = 1; } + +#ifdef WIN32 + WSACleanup(); +#endif - return 0; + return retcode; } // -------------------------------------------------------------------------- diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h index 8dafccae..745c3ccb 100644 --- a/lib/server/ServerStream.h +++ b/lib/server/ServerStream.h @@ -56,6 +56,10 @@ public: return "generic-stream-server"; } + #ifdef WIN32 + virtual void OnIdle() { } + #endif + virtual void Run() { // Set process title as appropraite @@ -215,6 +219,7 @@ public: if(connection.get()) { // Since this is a template parameter, the if() will be optimised out by the compiler + #ifndef WIN32 // no fork on Win32 if(ForkToHandleRequests) { pid_t pid = ::fork(); @@ -255,14 +260,20 @@ public: } else { + #endif // !WIN32 // Just handle in this connection SetProcessTitle("handling"); HandleConnection(*connection); SetProcessTitle("idle"); + #ifndef WIN32 } + #endif // !WIN32 } } - + + #ifdef WIN32 + OnIdle(); + #else // !WIN32 // Clean up child processes (if forking daemon) if(ForkToHandleRequests) { @@ -277,6 +288,7 @@ public: } } while(p > 0); } + #endif // !WIN32 } } catch(...) @@ -301,7 +313,11 @@ protected: // depends on the forking model in case someone changes it later. bool WillForkToHandleRequests() { + #ifdef WIN32 + return false; + #else return ForkToHandleRequests; + #endif // WIN32 } private: diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp index aa3825bf..61d3846f 100644 --- a/lib/server/SocketStream.cpp +++ b/lib/server/SocketStream.cpp @@ -36,7 +36,7 @@ // // -------------------------------------------------------------------------- SocketStream::SocketStream() - : mSocketHandle(-1), + : mSocketHandle(INVALID_SOCKET_VALUE), mReadClosed(false), mWriteClosed(false), mBytesRead(0), @@ -85,7 +85,7 @@ SocketStream::SocketStream(const SocketStream &rToCopy) { THROW_EXCEPTION(ServerException, BadSocketHandle); } - if(mSocketHandle == -1) + if(mSocketHandle == INVALID_SOCKET_VALUE) { THROW_EXCEPTION(ServerException, DupError); } @@ -101,7 +101,7 @@ SocketStream::SocketStream(const SocketStream &rToCopy) // -------------------------------------------------------------------------- SocketStream::~SocketStream() { - if(mSocketHandle != -1) + if(mSocketHandle != INVALID_SOCKET_VALUE) { Close(); } @@ -117,7 +117,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(); @@ -134,7 +137,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; @@ -144,7 +150,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) } @@ -158,7 +164,7 @@ void SocketStream::Open(int Type, const char *Name, int Port) #else ::close(mSocketHandle); #endif - mSocketHandle = -1; + mSocketHandle = INVALID_SOCKET_VALUE; THROW_EXCEPTION(ConnectionException, Conn_SocketConnectError) } ResetCounters(); @@ -174,7 +180,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) { @@ -247,7 +256,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); @@ -311,7 +323,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 @@ -320,7 +335,7 @@ void SocketStream::Close() { THROW_EXCEPTION(ServerException, SocketCloseError) } - mSocketHandle = -1; + mSocketHandle = INVALID_SOCKET_VALUE; } // -------------------------------------------------------------------------- @@ -333,7 +348,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; @@ -388,7 +406,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 7f1cb741..ca07434e 100644 --- a/lib/server/SocketStream.h +++ b/lib/server/SocketStream.h @@ -14,8 +14,10 @@ #ifdef WIN32 typedef SOCKET tOSSocketHandle; + #define INVALID_SOCKET_VALUE (tOSSocketHandle)(-1) #else typedef int tOSSocketHandle; + #define INVALID_SOCKET_VALUE -1 #endif // -------------------------------------------------------------------------- diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp index 94aa3868..af4ad460 100644 --- a/lib/server/SocketStreamTLS.cpp +++ b/lib/server/SocketStreamTLS.cpp @@ -137,8 +137,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 @@ -309,7 +313,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/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in index 3dce6118..efe6519d 100755 --- a/lib/server/makeprotocol.pl.in +++ b/lib/server/makeprotocol.pl.in @@ -1,6 +1,9 @@ #!@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) @@ -167,8 +170,8 @@ 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"; +open CPP,'>autogen_'.$protocol_name.'Protocol'.$type.'.cpp.new'; +open H,">$h_filename.new"; print CPP <<__E; @@ -912,6 +915,8 @@ __E close H; close CPP; +update_if_changed('autogen_'.$protocol_name.'Protocol'.$type.'.cpp'); +update_if_changed($h_filename); sub obj_is_type { @@ -981,8 +986,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 diff --git a/runtest.pl.in b/runtest.pl.in index f2b70a14..db58726d 100755 --- a/runtest.pl.in +++ b/runtest.pl.in @@ -1,11 +1,14 @@ #!@PERL@ +use strict; +use warnings; + use lib 'infrastructure'; use BoxPlatform; my ($test_name,$test_mode) = @ARGV; -$test_mode = 'debug' if $test_mode eq ''; +$test_mode = 'debug' if not defined $test_mode or $test_mode eq ''; if($test_name eq '' || ($test_mode ne 'debug' && $test_mode ne 'release')) { @@ -17,15 +20,26 @@ runtest.pl (test|ALL) [release|debug] Mode defaults to debug. __E - exit(0); + exit(2); } my @results; +my $exit_code = 0; if($test_name ne 'ALL') { - # run one test - runtest($test_name); + # run one or more specified test + if ($test_name =~ m/,/) + { + foreach my $test (split m/,/, $test_name) + { + runtest($test); + } + } + else + { + runtest($test_name); + } } else { @@ -57,6 +71,8 @@ else # report results print "--------\n",join("\n",@results),"\n"; +exit $exit_code; + sub runtest { my ($t) = @_; @@ -67,6 +83,7 @@ sub runtest if($make_res != 0) { push @results,"$t: make failed"; + $exit_code = 2; return; } @@ -82,8 +99,14 @@ sub runtest $last = $_ if m/\w/; } close RESULTS; + chomp $last; push @results,"$t: $last"; + + if ($last ne "PASSED") + { + $exit_code = 1; + } } else { diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index d532d8a6..806ede89 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -66,22 +66,20 @@ bool files_identical(const char *file1, const char *file2) void make_file_of_zeros(const char *filename, size_t size) { - static const size_t bs = 0x10000; - size_t remSize = size; - void *b = malloc(bs); - memset(b, 0, bs); - FILE *f = fopen(filename, "wb"); - - // Using largish blocks like this is much faster, while not consuming too much RAM - while(remSize > bs) - { - fwrite(b, bs, 1, f); - remSize -= bs; - } - fwrite(b, remSize, 1, f); - - fclose(f); - free(b); + #ifdef WIN32 + HANDLE handle = openfile(filename, O_WRONLY | O_CREAT | O_EXCL, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + SetFilePointer(handle, size, NULL, FILE_BEGIN); + TEST_THAT(GetLastError() == NO_ERROR); + TEST_THAT(SetEndOfFile(handle) == true); + TEST_THAT(CloseHandle(handle) == true); + #else + int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) perror(filename); + TEST_THAT(fd >= 0); + TEST_THAT(ftruncate(fd, size) == 0); + TEST_THAT(close(fd) == 0); + #endif TEST_THAT((size_t)TestGetFileSize(filename) == size); } @@ -118,12 +116,20 @@ void check_encoded_file(const char *filename, int64_t OtherFileID, int new_block if(s > 0) { nnew++; + #ifdef WIN32 + TRACE2("%8I64d this s=%8I64d", b, s); + #else TRACE2("%8lld this s=%8lld", b, s); + #endif } else { nold++; + #ifdef WIN32 + TRACE2("%8I64d other i=%8I64d", b, 0 - s); + #else TRACE2("%8lld other i=%8lld", b, 0 - s); + #endif } // Decode the rest uint64_t iv = box_ntoh64(hdr.mEntryIVBase); @@ -207,10 +213,18 @@ void test_diff(int from, int to, int new_blocks_expected, int old_blocks_expecte } else { +#ifdef WIN32 + // Emulate the above stage! + char src[256], dst[256]; + sprintf(src, "testfiles\\f%d.diff", to); + sprintf(dst, "testfiles\\f%d.encoded", to); + TEST_THAT(CopyFile(src, dst, FALSE) != 0) +#else // Emulate the above stage! char cmd[256]; sprintf(cmd, "cp testfiles/f%d.diff testfiles/f%d.encoded", to, to); ::system(cmd); +#endif } // Decode it @@ -355,8 +369,10 @@ int test(int argc, const char *argv[]) { // Want to trace out all the details #ifndef NDEBUG + #ifndef WIN32 BackupStoreFile::TraceDetailsOfDiffProcess = true; #endif + #endif // Create all the test files create_test_files(); @@ -370,6 +386,7 @@ int test(int argc, const char *argv[]) FileStream out("testfiles/f0.encoded", O_WRONLY | O_CREAT | O_EXCL); std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/f0", 1 /* dir ID */, f0name)); encoded->CopyStreamTo(out); + out.Close(); check_encoded_file("testfiles/f0.encoded", 0, 33, 0); } @@ -430,6 +447,7 @@ int test(int argc, const char *argv[]) FileStream out("testfiles/f9.zerotest", O_WRONLY | O_CREAT | O_EXCL); std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/f9", 1 /* dir ID */, fn)); encoded->CopyStreamTo(out); + out.Close(); check_encoded_file("testfiles/f9.zerotest", 0, 0, 0); } { @@ -440,6 +458,7 @@ int test(int argc, const char *argv[]) } } +#ifndef WIN32 // Check that symlinks aren't diffed TEST_THAT(::symlink("f2", "testfiles/f2.symlink") == 0) // And go and diff it against the previous encoded file @@ -467,8 +486,10 @@ int test(int argc, const char *argv[]) TEST_THAT(completelyDifferent == true); check_encoded_file("testfiles/f2.symlink.diff", 0, 0, 0); } +#endif - // Check that diffing against a file which isn't "complete" and referes another isn't allowed + // Check that diffing against a file which isn't "complete" and + // references another isn't allowed { FileStream blockindex("testfiles/f1.diff"); BackupStoreFile::MoveStreamPositionToBlockIndex(blockindex); @@ -480,10 +501,19 @@ int test(int argc, const char *argv[]) 0, 0), BackupStoreException, CannotDiffAnIncompleteStoreFile); } - // Found a nasty case where files of lots of the same thing sock up lots of processor - // time -- because of lots of matches found. Check this out! + // Found a nasty case where files of lots of the same thing + // suck up lots of processor time -- because of lots of matches + // found. Check this out! + + #ifdef WIN32 + ::fprintf(stdout, "Testing diffing two large streams, " + "may take a while!\n"); + ::fflush(stdout); + #endif + make_file_of_zeros("testfiles/zero.0", 20*1024*1024); make_file_of_zeros("testfiles/zero.1", 200*1024*1024); + // Generate a first encoded file { BackupStoreFilenameClear f0name("zero.0"); @@ -503,7 +533,14 @@ int test(int argc, const char *argv[]) 2000 /* object ID of the file diffing from */, blockindex, IOStream::TimeOutInfinite, 0, 0)); encoded->CopyStreamTo(out); + + printf("Time taken: %d seconds\n", (int)(time(0) - beginTime)); + + #ifdef WIN32 + TEST_THAT(time(0) < (beginTime + 300)); + #else TEST_THAT(time(0) < (beginTime + 40)); + #endif } // Remove zero-files to save disk space remove("testfiles/zero.0"); diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index f89d2ff7..f3637902 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -425,7 +425,8 @@ void test_test_file(int t, IOStream &rStream) } free(data); - unlink("testfiles/test_download"); + in.Close(); + TEST_THAT(unlink("testfiles/test_download") == 0); } void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID) @@ -930,6 +931,7 @@ int test_server(const char *hostname) // Check marker is 0 TEST_THAT(loginConf->GetClientStoreMarker() == 0); +#ifndef WIN32 // Check that we can't open a new connection which requests write permissions { SocketStreamTLS conn; @@ -941,10 +943,12 @@ int test_server(const char *hostname) ConnectionException, Conn_Protocol_UnexpectedReply); protocol.QueryFinished(); } +#endif // Set the client store marker protocol.QuerySetClientStoreMarker(0x8732523ab23aLL); +#ifndef WIN32 // Open a new connection which is read only SocketStreamTLS connReadOnly; connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED); @@ -963,10 +967,11 @@ int test_server(const char *hostname) // Check client store marker TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL); } +#else // WIN32 + BackupProtocolClient& protocolReadOnly(protocol); +#endif test_server_1(protocol, protocolReadOnly); - - // Create and upload some test files int64_t maxID = 0; for(int t = 0; t < UPLOAD_NUM; ++t) @@ -1438,11 +1443,15 @@ int test_server(const char *hostname) } // Finish the connections +#ifndef WIN32 protocolReadOnly.QueryFinished(); +#endif protocol.QueryFinished(); // Close logs +#ifndef WIN32 ::fclose(protocolReadOnlyLog); +#endif ::fclose(protocolLog); } @@ -1520,35 +1529,48 @@ int test3(int argc, const char *argv[]) // The test block to a file { - FileStream f("testfiles/testenc1", O_WRONLY | O_CREAT | O_EXCL); + FileStream f("testfiles" DIRECTORY_SEPARATOR + "testenc1", O_WRONLY | O_CREAT | O_EXCL); f.Write(encfile, sizeof(encfile)); } // Encode it { - FileStream out("testfiles/testenc1_enc", O_WRONLY | O_CREAT | O_EXCL); - BackupStoreFilenameClear name("testfiles/testenc1"); + FileStream out("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc", O_WRONLY | O_CREAT | O_EXCL); + BackupStoreFilenameClear name("testfiles" + DIRECTORY_SEPARATOR "testenc1"); - std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/testenc1", 32, name)); + std::auto_ptr encoded( + BackupStoreFile::EncodeFile( + "testfiles" DIRECTORY_SEPARATOR + "testenc1", 32, name)); encoded->CopyStreamTo(out); } // Verify it { - FileStream enc("testfiles/testenc1_enc"); + FileStream enc("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc"); TEST_THAT(BackupStoreFile::VerifyEncodedFileFormat(enc) == true); } // Decode it { - FileStream enc("testfiles/testenc1_enc"); - BackupStoreFile::DecodeFile(enc, "testfiles/testenc1_orig", IOStream::TimeOutInfinite); + FileStream enc("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc"); + BackupStoreFile::DecodeFile(enc, "testfiles" + DIRECTORY_SEPARATOR "testenc1_orig", + IOStream::TimeOutInfinite); } // Read in rebuilt original, and compare contents { - TEST_THAT(TestGetFileSize("testfiles/testenc1_orig") == sizeof(encfile)); - FileStream in("testfiles/testenc1_orig"); + TEST_THAT(TestGetFileSize("testfiles" + DIRECTORY_SEPARATOR "testenc1_orig") + == sizeof(encfile)); + FileStream in("testfiles" DIRECTORY_SEPARATOR + "testenc1_orig"); int encfile_i[ENCFILE_SIZE]; in.Read(encfile_i, sizeof(encfile_i)); TEST_THAT(memcmp(encfile, encfile_i, sizeof(encfile)) == 0); @@ -1556,7 +1578,8 @@ int test3(int argc, const char *argv[]) // Check how many blocks it had, and test the stream based interface { - FileStream enc("testfiles/testenc1_enc"); + FileStream enc("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc"); std::auto_ptr decoded(BackupStoreFile::DecodeFileStream(enc, IOStream::TimeOutInfinite)); CollectInBufferStream d; decoded->CopyStreamTo(d, IOStream::TimeOutInfinite, 971 /* buffer block size */); @@ -1570,10 +1593,15 @@ int test3(int argc, const char *argv[]) // Test that the last block in a file, if less than 256 bytes, gets put into the last block { #define FILE_SIZE_JUST_OVER ((4096*2)+58) - FileStream f("testfiles/testenc2", O_WRONLY | O_CREAT | O_EXCL); + FileStream f("testfiles" DIRECTORY_SEPARATOR + "testenc2", O_WRONLY | O_CREAT | O_EXCL); f.Write(encfile + 2, FILE_SIZE_JUST_OVER); + f.Close(); BackupStoreFilenameClear name("testenc2"); - std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/testenc2", 32, name)); + std::auto_ptr encoded( + BackupStoreFile::EncodeFile( + "testfiles" DIRECTORY_SEPARATOR + "testenc2", 32, name)); CollectInBufferStream e; encoded->CopyStreamTo(e); e.SetForReading(); @@ -1589,7 +1617,8 @@ int test3(int argc, const char *argv[]) // Test that reordered streams work too { - FileStream enc("testfiles/testenc1_enc"); + FileStream enc("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc"); std::auto_ptr reordered(BackupStoreFile::ReorderFileToStreamOrder(&enc, false)); std::auto_ptr decoded(BackupStoreFile::DecodeFileStream(*reordered, IOStream::TimeOutInfinite)); CollectInBufferStream d; @@ -1601,6 +1630,7 @@ int test3(int argc, const char *argv[]) TEST_THAT(decoded->GetNumBlocks() == 3); } +#ifndef WIN32 // Try out doing this on a symlink { TEST_THAT(::symlink("does/not/exist", "testfiles/testsymlink") == 0); @@ -1614,14 +1644,20 @@ int test3(int argc, const char *argv[]) // Decode it BackupStoreFile::DecodeFile(b, "testfiles/testsymlink_2", IOStream::TimeOutInfinite); } +#endif } // Store info { RaidFileWrite::CreateDirectory(0, "test-info"); - BackupStoreInfo::CreateNew(76, "test-info/", 0, 3461231233455433LL, 2934852487LL); - TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, "test-info/", 0, 0, 0), RaidFileException, CannotOverwriteExistingFile); - std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, true)); + BackupStoreInfo::CreateNew(76, "test-info" DIRECTORY_SEPARATOR, + 0, 3461231233455433LL, 2934852487LL); + TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, + "test-info" DIRECTORY_SEPARATOR, 0, 0, 0), + RaidFileException, CannotOverwriteExistingFile); + std::auto_ptr info( + BackupStoreInfo::Load(76, + "test-info" DIRECTORY_SEPARATOR, 0, true)); TEST_CHECK_THROWS(info->Save(), BackupStoreException, StoreInfoIsReadOnly); TEST_CHECK_THROWS(info->ChangeBlocksUsed(1), BackupStoreException, StoreInfoIsReadOnly); TEST_CHECK_THROWS(info->ChangeBlocksInOldFiles(1), BackupStoreException, StoreInfoIsReadOnly); @@ -1630,7 +1666,8 @@ int test3(int argc, const char *argv[]) TEST_CHECK_THROWS(info->AddDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly); } { - std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, false)); + std::auto_ptr info(BackupStoreInfo::Load(76, + "test-info" DIRECTORY_SEPARATOR, 0, false)); info->ChangeBlocksUsed(8); info->ChangeBlocksInOldFiles(9); info->ChangeBlocksInDeletedFiles(10); @@ -1648,7 +1685,8 @@ int test3(int argc, const char *argv[]) info->Save(); } { - std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, true)); + std::auto_ptr info(BackupStoreInfo::Load(76, + "test-info" DIRECTORY_SEPARATOR, 0, true)); TEST_THAT(info->GetBlocksUsed() == 7); TEST_THAT(info->GetBlocksInOldFiles() == 5); TEST_THAT(info->GetBlocksInDeletedFiles() == 1); @@ -1666,12 +1704,18 @@ int test3(int argc, const char *argv[]) // Context TLSContext context; context.Initialise(false /* client */, - "testfiles/clientCerts.pem", - "testfiles/clientPrivKey.pem", - "testfiles/clientTrustedCAs.pem"); + "testfiles" DIRECTORY_SEPARATOR "clientCerts.pem", + "testfiles" DIRECTORY_SEPARATOR "clientPrivKey.pem", + "testfiles" DIRECTORY_SEPARATOR "clientTrustedCAs.pem"); // First, try logging in without an account having been created... just make sure login fails. + +#ifdef WIN32 + int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); +#else int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); +#endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -1700,8 +1744,13 @@ int test3(int argc, const char *argv[]) } // Create an account for the test client +#ifdef WIN32 + TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); +#else TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); +#endif + TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567")); @@ -1725,15 +1774,27 @@ int test3(int argc, const char *argv[]) TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); +#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); +#endif // Set a new limit on the account -- leave the hard limit high to make sure the target for // freeing space is the soft limit. + +#ifdef WIN32 + TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); +#else TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); +#endif // Start things up +#ifdef WIN32 + pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); +#else pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); +#endif + ::sleep(1); TEST_THAT(ServerIsAlive(pid)); @@ -1758,8 +1819,12 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(after.old == 0); // Set a really small hard limit +#ifdef WIN32 + TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); +#else TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); +#endif // Try to upload a file and create a directory, and check an error is generated { @@ -1808,7 +1873,10 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); + +#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); +#endif } return 0; @@ -1820,10 +1888,19 @@ int multi_server() // Create an account for the test client TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); + +#ifndef WIN32 TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); +#endif // First, try logging in without an account having been created... just make sure login fails. + +#ifdef WIN32 + int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid"); +#else int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid"); +#endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -1840,15 +1917,63 @@ int multi_server() TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); +#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); +#endif } return 0; } +#ifdef WIN32 +WCHAR* ConvertUtf8ToWideString(const char* pString); +std::string ConvertPathToAbsoluteUnicode(const char *pFileName); +#endif + int test(int argc, const char *argv[]) { +#ifdef WIN32 + // Under win32 we must initialise the Winsock library + // before using sockets + + WSADATA info; + TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) + + // this had better work, or bbstored will die when combining diffs + char* file = "foo"; + std::string abs = ConvertPathToAbsoluteUnicode(file); + WCHAR* wfile = ConvertUtf8ToWideString(abs.c_str()); + + DWORD accessRights = FILE_READ_ATTRIBUTES | + FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | + FILE_WRITE_DATA | FILE_WRITE_EA /*| FILE_ALL_ACCESS*/; + DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + + HANDLE h1 = CreateFileW(wfile, accessRights, shareMode, + NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL); + assert(h1 != INVALID_HANDLE_VALUE); + TEST_THAT(h1 != INVALID_HANDLE_VALUE); + + accessRights = FILE_READ_ATTRIBUTES | + FILE_LIST_DIRECTORY | FILE_READ_EA; + + HANDLE h2 = CreateFileW(wfile, accessRights, shareMode, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + assert(h2 != INVALID_HANDLE_VALUE); + TEST_THAT(h2 != INVALID_HANDLE_VALUE); + + CloseHandle(h2); + CloseHandle(h1); + + h1 = openfile("foo", O_CREAT | O_RDWR, 0); + TEST_THAT(h1 != INVALID_HANDLE_VALUE); + h2 = openfile("foo", O_RDWR, 0); + TEST_THAT(h2 != INVALID_HANDLE_VALUE); + CloseHandle(h2); + CloseHandle(h1); +#endif + // SSL library SSLLib::Initialise(); @@ -1865,7 +1990,11 @@ int test(int argc, const char *argv[]) // Use the setup crypto command to set up all these keys, so that the bbackupquery command can be used // for seeing what's going on. +#ifdef WIN32 + BackupClientCryptoKeys_Setup("testfiles\\bbackupd.keys"); +#else BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys"); +#endif // encode in some filenames -- can't do static initialisation because the key won't be set up when these are initialised for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l) diff --git a/test/backupstorefix/testfiles/testbackupstorefix.pl.in b/test/backupstorefix/testfiles/testbackupstorefix.pl.in index b57f10ac..e64474f0 100755 --- a/test/backupstorefix/testfiles/testbackupstorefix.pl.in +++ b/test/backupstorefix/testfiles/testbackupstorefix.pl.in @@ -54,7 +54,7 @@ elsif($ARGV[0] eq 'check') open INITIAL,'testfiles/initial-listing.txt' or die "Can't open original listing"; while() { - chomp; + chomp; s/\r//; $expected{$_} = 1; m/\A(.+?) .+? (.+)\Z/; $filenames{$2} = $_; @@ -99,7 +99,7 @@ elsif($ARGV[0] eq 'check') while() { print LISTING_COPY; - chomp; + chomp; s/\r//; s/\[FILENAME NOT ENCRYPTED\]//; if(exists $expected{$_}) { diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index 5d77c3fd..61ad0e18 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -283,6 +283,14 @@ void test_depends_in_dirs() int test(int argc, const char *argv[]) { +#ifdef WIN32 + // Under win32 we must initialise the Winsock library + // before using sockets + + WSADATA info; + TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) +#endif + // Allocate a buffer buffer = ::malloc(BUFFER_SIZE); TEST_THAT(buffer != 0); @@ -309,8 +317,12 @@ int test(int argc, const char *argv[]) "testfiles/clientTrustedCAs.pem"); // Create an account +#ifdef WIN32 + TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); +#else TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); +#endif // Create test files create_test_files(); @@ -319,7 +331,12 @@ int test(int argc, const char *argv[]) test_depends_in_dirs(); // First, try logging in without an account having been created... just make sure login fails. +#ifdef WIN32 + int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); +#else int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); +#endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -397,7 +414,13 @@ int test(int argc, const char *argv[]) // Store details test_files[f].IDOnServer = stored->GetObjectID(); test_files[f].IsCompletelyDifferent = isCompletelyDifferent; - printf("ID %lld, completely different: %s\n", test_files[f].IDOnServer, + +#ifdef WIN32 + printf("ID %I64d, completely different: %s\n", +#else + printf("ID %lld, completely different: %s\n", +#endif + test_files[f].IDOnServer, test_files[f].IsCompletelyDifferent?"yes":"no"); } else @@ -565,9 +588,14 @@ int test(int argc, const char *argv[]) writedir.Commit(true); } - // Send the server a restart signal, so it does housekeeping immedaitely, and wait for it to happen +#ifdef WIN32 + wait_for_operation(12); +#else + // Send the server a restart signal, so it does housekeeping immediately, and wait for it to happen ::sleep(1); // wait for old connections to terminate ::kill(pid, SIGHUP); +#endif + // Get the revision number of the info file int64_t first_revision = 0; RaidFileRead::FileExists(0, "backup/01234567/o01", &first_revision); @@ -611,7 +639,10 @@ int test(int argc, const char *argv[]) // Kill store server TEST_THAT(KillServer(pid)); TEST_THAT(!ServerIsAlive(pid)); + + #ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); + #endif } ::free(buffer); diff --git a/test/basicserver/TestCommands.cpp b/test/basicserver/TestCommands.cpp index b18a3326..657e79ea 100644 --- a/test/basicserver/TestCommands.cpp +++ b/test/basicserver/TestCommands.cpp @@ -1,7 +1,9 @@ #include "Box.h" +#ifdef HAVE_SYSLOG_H #include +#endif #include "autogen_TestProtocolServer.h" #include "CollectInBufferStream.h" diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index f5185b96..1403df42 100644 --- a/test/basicserver/testbasicserver.cpp +++ b/test/basicserver/testbasicserver.cpp @@ -31,7 +31,6 @@ #include "MemLeakFindOn.h" - #define SERVER_LISTEN_PORT 2003 // in ms @@ -62,10 +61,14 @@ void basicdaemon::Run() void testservers_pause_before_reply() { - struct timespec t; - t.tv_sec = 0; - t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000; // convert to ns - ::nanosleep(&t, NULL); +#ifdef WIN32 + Sleep(COMMS_SERVER_WAIT_BEFORE_REPLYING); +#else + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000; // convert to ns + ::nanosleep(&t, NULL); +#endif } #define LARGE_DATA_BLOCK_SIZE 19870 @@ -427,84 +430,138 @@ int test(int argc, const char *argv[]) } } +#ifdef WIN32 + // Under win32 we must initialise the Winsock library + // before using sockets + + WSADATA info; + TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) +#endif + //printf("SKIPPING TESTS------------------------\n"); //goto protocolserver; // Launch a basic server { - int pid = LaunchServer("./test srv1 testfiles/srv1.conf", "testfiles/srv1.pid"); +#ifdef WIN32 + int pid = LaunchServer("test srv1 testfiles\\srv1.conf", + "testfiles\\srv1.pid"); +#else + int pid = LaunchServer("./test srv1 testfiles/srv1.conf", + "testfiles/srv1.pid"); +#endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Check that it's written the expected file - TEST_THAT(TestFileExists("testfiles/srv1.test1")); + TEST_THAT(TestFileExists("testfiles" + DIRECTORY_SEPARATOR "srv1.test1")); TEST_THAT(ServerIsAlive(pid)); // Move the config file over - TEST_THAT(::rename("testfiles/srv1b.conf", "testfiles/srv1.conf") != -1); +#ifdef WIN32 + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR + "srv1.conf") != -1); +#endif + TEST_THAT(::rename( + "testfiles" DIRECTORY_SEPARATOR "srv1b.conf", + "testfiles" DIRECTORY_SEPARATOR "srv1.conf") + != -1); +#ifndef WIN32 // Get it to reread the config file TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); // Check that new file exists - TEST_THAT(TestFileExists("testfiles/srv1.test2")); + TEST_THAT(TestFileExists("testfiles" + DIRECTORY_SEPARATOR "srv1.test2")); +#endif // !WIN32 // Kill it off TEST_THAT(KillServer(pid)); +#ifndef WIN32 TestRemoteProcessMemLeaks("generic-daemon.memleaks"); +#endif // !WIN32 } } // Launch a test forking server { - int pid = LaunchServer("./test srv2 testfiles/srv2.conf", "testfiles/srv2.pid"); +#ifdef WIN32 + int pid = LaunchServer("test srv2 testfiles\\srv2.conf", + "testfiles\\srv2.pid"); +#else + int pid = LaunchServer("./test srv2 testfiles/srv2.conf", + "testfiles/srv2.pid"); +#endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Will it restart? TEST_THAT(ServerIsAlive(pid)); +#ifndef WIN32 TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); +#endif // !WIN32 // Make some connections { SocketStream conn1; conn1.Open(Socket::TypeINET, "localhost", 2003); +#ifndef WIN32 SocketStream conn2; conn2.Open(Socket::TypeUNIX, "testfiles/srv2.sock"); SocketStream conn3; conn3.Open(Socket::TypeINET, "localhost", 2003); +#endif // !WIN32 // Quick check that reconnections fail TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX, "testfiles/srv2.sock");, ServerException, SocketAlreadyOpen); // Stuff some data around std::vector conns; conns.push_back(&conn1); +#ifndef WIN32 conns.push_back(&conn2); conns.push_back(&conn3); +#endif // !WIN32 Srv2TestConversations(conns); // Implicit close } +#ifndef WIN32 // HUP again TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); +#endif // !WIN32 // Kill it TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); +#ifndef WIN32 TestRemoteProcessMemLeaks("test-srv2.memleaks"); +#endif // !WIN32 } } // Launch a test SSL server { +#ifdef WIN32 + int pid = LaunchServer("test srv3 testfiles\\srv3.conf", + "testfiles\\srv3.pid"); +#else int pid = LaunchServer("./test srv3 testfiles/srv3.conf", "testfiles/srv3.pid"); +#endif TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Will it restart? TEST_THAT(ServerIsAlive(pid)); + +#ifndef WIN32 TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); +#endif + // Make some connections { // SSL library @@ -519,36 +576,50 @@ int test(int argc, const char *argv[]) SocketStreamTLS conn1; conn1.Open(context, Socket::TypeINET, "localhost", 2003); +#ifndef WIN32 SocketStreamTLS conn2; conn2.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock"); SocketStreamTLS conn3; conn3.Open(context, Socket::TypeINET, "localhost", 2003); +#endif // Quick check that reconnections fail TEST_CHECK_THROWS(conn1.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock");, ServerException, SocketAlreadyOpen); // Stuff some data around std::vector conns; conns.push_back(&conn1); +#ifndef WIN32 conns.push_back(&conn2); conns.push_back(&conn3); +#endif Srv2TestConversations(conns); // Implicit close } +#ifndef WIN32 // HUP again TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); +#endif // Kill it TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); +#ifndef WIN32 TestRemoteProcessMemLeaks("test-srv3.memleaks"); +#endif } } //protocolserver: // Launch a test protocol handling server { - int pid = LaunchServer("./test srv4 testfiles/srv4.conf", "testfiles/srv4.pid"); +#ifdef WIN32 + int pid = LaunchServer("test srv4 testfiles\\srv4.conf", + "testfiles\\srv4.pid"); +#else + int pid = LaunchServer("./test srv4 testfiles/srv4.conf", + "testfiles/srv4.pid"); +#endif TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -557,7 +628,11 @@ int test(int argc, const char *argv[]) // Open a connection to it SocketStream conn; +#ifdef WIN32 + conn.Open(Socket::TypeINET, "localhost", 2003); +#else conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock"); +#endif // Create a protocol TestProtocolClient protocol(conn); @@ -620,7 +695,9 @@ int test(int argc, const char *argv[]) TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); +#ifndef WIN32 TestRemoteProcessMemLeaks("test-srv4.memleaks"); +#endif } } diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 51047177..7207680a 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -718,7 +718,7 @@ int test_bbackupd() // Wait and test... wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 2*256); // should find differences + TEST_THAT(compareReturnValue == 3*256); // should find differences TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Check that it was reported correctly TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1")); diff --git a/test/bbackupd/testfiles/bbackupd.conf b/test/bbackupd/testfiles/bbackupd.conf deleted file mode 100644 index 6d381d5b..00000000 --- a/test/bbackupd/testfiles/bbackupd.conf +++ /dev/null @@ -1,50 +0,0 @@ - -CertificateFile = testfiles/clientCerts.pem -PrivateKeyFile = testfiles/clientPrivKey.pem -TrustedCAsFile = testfiles/clientTrustedCAs.pem - -KeysFile = testfiles/bbackupd.keys - -DataDirectory = testfiles/bbackupd-data - -StoreHostname = localhost -AccountNumber = 0x01234567 - -UpdateStoreInterval = 3 -MinimumFileAge = 4 -MaxUploadWait = 24 - -FileTrackingSizeThreshold = 1024 -DiffingUploadSizeThreshold = 1024 - -MaximumDiffingTime = 8 - -ExtendedLogging = yes - -CommandSocket = testfiles/bbackupd.sock - -NotifyScript = @PERL@ testfiles/notifyscript.pl - -Server -{ - PidFile = testfiles/bbackupd.pid -} - -BackupLocations -{ - Test1 - { - Path = testfiles/TestDir1 - - ExcludeFile = testfiles/TestDir1/excluded_1 - ExcludeFile = testfiles/TestDir1/excluded_2 - ExcludeFilesRegex = \.excludethis$ - ExcludeFilesRegex = EXCLUDE - AlwaysIncludeFile = testfiles/TestDir1/dont.excludethis - ExcludeDir = testfiles/TestDir1/exclude_dir - ExcludeDir = testfiles/TestDir1/exclude_dir_2 - ExcludeDirsRegex = not_this_dir - AlwaysIncludeDirsRegex = ALWAYSINCLUDE - } -} - diff --git a/test/bbackupd/testfiles/bbackupd.conf.in b/test/bbackupd/testfiles/bbackupd.conf.in new file mode 100644 index 00000000..6d381d5b --- /dev/null +++ b/test/bbackupd/testfiles/bbackupd.conf.in @@ -0,0 +1,50 @@ + +CertificateFile = testfiles/clientCerts.pem +PrivateKeyFile = testfiles/clientPrivKey.pem +TrustedCAsFile = testfiles/clientTrustedCAs.pem + +KeysFile = testfiles/bbackupd.keys + +DataDirectory = testfiles/bbackupd-data + +StoreHostname = localhost +AccountNumber = 0x01234567 + +UpdateStoreInterval = 3 +MinimumFileAge = 4 +MaxUploadWait = 24 + +FileTrackingSizeThreshold = 1024 +DiffingUploadSizeThreshold = 1024 + +MaximumDiffingTime = 8 + +ExtendedLogging = yes + +CommandSocket = testfiles/bbackupd.sock + +NotifyScript = @PERL@ testfiles/notifyscript.pl + +Server +{ + PidFile = testfiles/bbackupd.pid +} + +BackupLocations +{ + Test1 + { + Path = testfiles/TestDir1 + + ExcludeFile = testfiles/TestDir1/excluded_1 + ExcludeFile = testfiles/TestDir1/excluded_2 + ExcludeFilesRegex = \.excludethis$ + ExcludeFilesRegex = EXCLUDE + AlwaysIncludeFile = testfiles/TestDir1/dont.excludethis + ExcludeDir = testfiles/TestDir1/exclude_dir + ExcludeDir = testfiles/TestDir1/exclude_dir_2 + ExcludeDirsRegex = not_this_dir + AlwaysIncludeDirsRegex = ALWAYSINCLUDE + } +} + diff --git a/test/bbackupd/testfiles/extcheck1.pl.in b/test/bbackupd/testfiles/extcheck1.pl.in index edbacd0a..955515b9 100755 --- a/test/bbackupd/testfiles/extcheck1.pl.in +++ b/test/bbackupd/testfiles/extcheck1.pl.in @@ -1,7 +1,9 @@ #!@PERL@ use strict; -unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit|") +my $flags = $ARGV[0] or ""; + +unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit|") { print "Couldn't open compare utility\n"; exit 2; @@ -15,14 +17,23 @@ while() next unless m/\S/; if(m/continousupdate/) { - $ret = 2 unless m/exists/; + unless (/exists/) + { + print "FAIL: continousupdate line does not match\n"; + $ret = 2; + } $seen = 1; } else { - $ret = 2 unless m/\AWARNING/ || m/\ADifferences/ || /might be reason/ || /probably due to file mod/; + unless (/\AWARNING/ or /\ADifferences/ or /might be reason/ + or /probably due to file mod/) + { + print "FAIL: Summary line does not match\n"; + $ret = 2; + } } - print; + print "READ: $_"; } close IN; diff --git a/test/bbackupd/testfiles/extcheck2.pl.in b/test/bbackupd/testfiles/extcheck2.pl.in index 68baa045..bfa6f253 100755 --- a/test/bbackupd/testfiles/extcheck2.pl.in +++ b/test/bbackupd/testfiles/extcheck2.pl.in @@ -1,7 +1,9 @@ #!@PERL@ use strict; -unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit|") +my $flags = $ARGV[0] or ""; + +unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit|") { print "Couldn't open compare utility\n"; exit 2; @@ -14,13 +16,23 @@ while() next unless m/\S/; if(m/continousupdate/) { - $ret = 2 unless m/contents/ || m/attributes/; + unless (m/contents/ or m/attributes/) + { + print "FAIL: continuousupdate line does not match\n"; + $ret = 2; + } } else { - $ret = 2 unless m/\AWARNING/ || m/\ADifferences/ || /might be reason/ || /probably due to file mod/; + unless (/\AWARNING/ or /\ADifferences/ or /might be reason/ + or /probably due to file mod/) + { + print "FAIL: summary line does not match\n"; + $ret = 2; + } } - print; + + print "READ: $_"; } close IN; diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 910b6814..5565b406 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -24,6 +24,8 @@ #include "CommonException.h" #include "Conversion.h" #include "autogen_ConversionException.h" +#include "CollectInBufferStream.h" +#include "Archive.h" #include "MemLeakFindOn.h" @@ -565,5 +567,63 @@ int test(int argc, const char *argv[]) test_conversions(); + // test that we can use Archive and CollectInBufferStream + // to read and write arbitrary types to a memory buffer + + { + CollectInBufferStream buffer; + ASSERT(buffer.GetPosition() == 0); + + { + Archive archive(buffer, 0); + ASSERT(buffer.GetPosition() == 0); + + archive.Write((bool) true); + archive.Write((bool) false); + archive.Write((int) 0x12345678); + archive.Write((int) 0x87654321); + archive.Write((int64_t) 0x0badfeedcafebabeLL); + archive.Write((uint64_t) 0xfeedfacedeadf00dLL); + archive.Write((uint8_t) 0x01); + archive.Write((uint8_t) 0xfe); + archive.Write(std::string("hello world!")); + archive.Write(std::string("goodbye cruel world!")); + } + + CollectInBufferStream buf2; + buf2.Write(buffer.GetBuffer(), buffer.GetSize()); + TEST_THAT(buf2.GetPosition() == buffer.GetSize()); + + buf2.SetForReading(); + TEST_THAT(buf2.GetPosition() == 0); + + { + Archive archive(buf2, 0); + TEST_THAT(buf2.GetPosition() == 0); + + bool b; + archive.Read(b); TEST_THAT(b == true); + archive.Read(b); TEST_THAT(b == false); + + int i; + archive.Read(i); TEST_THAT(i == 0x12345678); + archive.Read(i); TEST_THAT((unsigned int)i == 0x87654321); + + uint64_t i64; + archive.Read(i64); TEST_THAT(i64 == 0x0badfeedcafebabeLL); + archive.Read(i64); TEST_THAT(i64 == 0xfeedfacedeadf00dLL); + + uint8_t i8; + archive.Read(i8); TEST_THAT(i8 == 0x01); + archive.Read(i8); TEST_THAT(i8 == 0xfe); + + std::string s; + archive.Read(s); TEST_THAT(s == "hello world!"); + archive.Read(s); TEST_THAT(s == "goodbye cruel world!"); + + TEST_THAT(!buf2.StreamDataLeft()); + } + } + return 0; } diff --git a/test/raidfile/intercept.cpp b/test/raidfile/intercept.cpp index 6df344e1..0a5b4ab9 100644 --- a/test/raidfile/intercept.cpp +++ b/test/raidfile/intercept.cpp @@ -14,7 +14,11 @@ #endif #include #include + +#ifdef HAVE_SYS_UIO_H #include +#endif + #include #ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE diff --git a/test/raidfile/testraidfile.cpp b/test/raidfile/testraidfile.cpp index 1e510486..40703de5 100644 --- a/test/raidfile/testraidfile.cpp +++ b/test/raidfile/testraidfile.cpp @@ -12,7 +12,10 @@ #include #include #include + +#ifdef HAVE_SYSCALL #include +#endif #include @@ -207,16 +210,24 @@ void testReadingFileContents(int set, const char *filename, void *data, int data bytesread += r; } TEST_THAT(!readstream4.StreamDataLeft()); // check IOStream interface is correct + pread.reset(); // Be nasty, and create some errors for the RAID stuff to recover from... if(TestRAIDProperties) { char stripe1fn[256], stripe1fnRename[256]; - sprintf(stripe1fn, "testfiles/%d_%d/%s.rf", set, startDisc, filename); - sprintf(stripe1fnRename, "testfiles/%d_%d/%s.rf-REMOVED", set, startDisc, filename); + sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename); + sprintf(stripe1fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, startDisc, + filename); char stripe2fn[256], stripe2fnRename[256]; - sprintf(stripe2fn, "testfiles/%d_%d/%s.rf", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename); - sprintf(stripe2fnRename, "testfiles/%d_%d/%s.rf-REMOVED", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename); + sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, + (startDisc + 1) % RAID_NUMBER_DISCS, filename); + sprintf(stripe2fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, + (startDisc + 1) % RAID_NUMBER_DISCS, filename); // Read with stripe1 + parity TEST_THAT(::rename(stripe2fn, stripe2fnRename) == 0); @@ -252,9 +263,15 @@ void testReadingFileContents(int set, const char *filename, void *data, int data } mungefilename[m++] = '\0'; char stripe1munge[256]; - sprintf(stripe1munge, "testfiles/%d_%d/.raidfile-unreadable/%s", set, startDisc, mungefilename); + sprintf(stripe1munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR ".raidfile-unreadable" + DIRECTORY_SEPARATOR "%s", set, startDisc, + mungefilename); char stripe2munge[256]; - sprintf(stripe2munge, "testfiles/%d_%d/.raidfile-unreadable/%s", set, (startDisc + 1) % RAID_NUMBER_DISCS, mungefilename); + sprintf(stripe2munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR ".raidfile-unreadable" + DIRECTORY_SEPARATOR "%s", set, + (startDisc + 1) % RAID_NUMBER_DISCS, mungefilename); #ifdef TRF_CAN_INTERCEPT @@ -359,10 +376,12 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize write4.Write(data, datasize); // This time, don't discard and transform it to a RAID File char writefnPre[256]; - sprintf(writefnPre, "testfiles/%d_%d/%s.rfwX", set, startDisc, filename); + sprintf(writefnPre, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rfwX", set, startDisc, filename); TEST_THAT(TestFileExists(writefnPre)); char writefn[256]; - sprintf(writefn, "testfiles/%d_%d/%s.rfw", set, startDisc, filename); + sprintf(writefn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rfw", set, startDisc, filename); int usageInBlocks = write4.GetDiscUsageInBlocks(); write4.Commit(DoTransform); // Check that files are nicely done... @@ -390,14 +409,19 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize fs1 = ((fullblocks / 2)+1) * RAID_BLOCK_SIZE; } char stripe1fn[256]; - sprintf(stripe1fn, "testfiles/%d_%d/%s.rf", set, startDisc, filename); + sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename); TEST_THAT(TestGetFileSize(stripe1fn) == fs1); char stripe2fn[256]; - sprintf(stripe2fn, "testfiles/%d_%d/%s.rf", set, (startDisc + 1) % RAID_NUMBER_DISCS, filename); + sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, + (startDisc + 1) % RAID_NUMBER_DISCS, filename); TEST_THAT(TestGetFileSize(stripe2fn) == (int)(datasize - fs1)); // Parity file size char parityfn[256]; - sprintf(parityfn, "testfiles/%d_%d/%s.rf", set, (startDisc + 2) % RAID_NUMBER_DISCS, filename); + sprintf(parityfn, "testfiles" DIRECTORY_SEPARATOR "%d_%d" + DIRECTORY_SEPARATOR "%s.rf", set, + (startDisc + 2) % RAID_NUMBER_DISCS, filename); // Mildly complex calculation unsigned int blocks = datasize / RAID_BLOCK_SIZE; unsigned int bytesOver = datasize % RAID_BLOCK_SIZE; @@ -436,14 +460,16 @@ void testReadWriteFileDo(int set, const char *filename, void *data, int datasize if(datasize > (3*1024)) { int f; - TEST_THAT((f = ::open(stripe1fn, O_RDONLY, 0)) != -1); + TEST_THAT((f = ::open(stripe1fn, O_RDONLY | O_BINARY, + 0)) != -1); TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock))); for(unsigned int q = 0; q < sizeof(testblock); ++q) { TEST_THAT(testblock[q] == ((char*)data)[q]); } ::close(f); - TEST_THAT((f = ::open(stripe2fn, O_RDONLY, 0)) != -1); + TEST_THAT((f = ::open(stripe2fn, O_RDONLY | O_BINARY, + 0)) != -1); TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock))); for(unsigned int q = 0; q < sizeof(testblock); ++q) { @@ -536,7 +562,9 @@ void test_overwrites() // Generate a random pre-existing write file (and ensure that it doesn't exist already) int f; - TEST_THAT((f = ::open("testfiles/0_2/overwrite_B.rfwX", O_WRONLY | O_CREAT | O_EXCL, 0755)) != -1); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "overwrite_B.rfwX", + O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0755)) != -1); TEST_THAT(::write(f, "TESTTEST", 8) == 8); ::close(f); @@ -557,7 +585,7 @@ int test(int argc, const char *argv[]) // Initialise the controller RaidFileController &rcontroller = RaidFileController::GetController(); - rcontroller.Initialise("testfiles/raidfile.conf"); + rcontroller.Initialise("testfiles" DIRECTORY_SEPARATOR "raidfile.conf"); // some data char data[TEST_DATA_SIZE]; @@ -574,9 +602,12 @@ int test(int argc, const char *argv[]) // Try creating a directory RaidFileWrite::CreateDirectory(0, "test-dir"); - TEST_THAT(TestDirExists("testfiles/0_0/test-dir")); - TEST_THAT(TestDirExists("testfiles/0_1/test-dir")); - TEST_THAT(TestDirExists("testfiles/0_2/test-dir")); + TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_0" + DIRECTORY_SEPARATOR "test-dir")); + TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_1" + DIRECTORY_SEPARATOR "test-dir")); + TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test-dir")); TEST_THAT(RaidFileRead::DirectoryExists(0, "test-dir")); TEST_THAT(!RaidFileRead::DirectoryExists(0, "test-dir-not")); @@ -608,9 +639,12 @@ int test(int argc, const char *argv[]) // Before it's deleted, check to see the contents are as expected int f; - TEST_THAT((f = ::open("testfiles/0_2/test1.rfwX", O_RDONLY, 0)) >= 0); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test1.rfwX", O_RDONLY | O_BINARY, 0)) + >= 0); char buffer[sizeof(data)]; - TEST_THAT(::read(f, buffer, sizeof(buffer)) == sizeof(buffer)); + int bytes_read = ::read(f, buffer, sizeof(buffer)); + TEST_THAT(bytes_read == sizeof(buffer)); for(unsigned int l = 0; l < 1024; ++l) { TEST_THAT(buffer[l] == data[l]); @@ -624,7 +658,8 @@ int test(int argc, const char *argv[]) TEST_THAT(buffer[l+2048+sizeof(data2)] == data2[l]); } TEST_THAT(::lseek(f, sizeof(data), SEEK_SET) == sizeof(buffer)); - TEST_THAT(::read(f, buffer, sizeof(buffer)) == sizeof(buffer)); + bytes_read = ::read(f, buffer, sizeof(buffer)); + TEST_THAT(bytes_read == sizeof(buffer)); for(unsigned int l = 0; l < 1024; ++l) { TEST_THAT(buffer[l] == data[l]); @@ -635,7 +670,9 @@ int test(int argc, const char *argv[]) // Commit the data write1.Commit(); - TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) >= 0); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) + >= 0); ::close(f); // Now try and read it @@ -687,7 +724,9 @@ int test(int argc, const char *argv[]) write2.Write(data, sizeof(data)); // This time, discard it write2.Discard(); - TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) == -1); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) + == -1); // And leaving it there... RaidFileWrite writeLeave(0, "test1"); @@ -695,7 +734,9 @@ int test(int argc, const char *argv[]) writeLeave.Write(data, sizeof(data)); // This time, commit it writeLeave.Commit(); - TEST_THAT((f = ::open("testfiles/0_2/test1.rfw", O_RDONLY, 0)) != -1); + TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" + DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) + != -1); ::close(f); // Then check that the thing will refuse to open it again. @@ -712,7 +753,8 @@ int test(int argc, const char *argv[]) write3b.Write(data + 3, sizeof(data) - 3); write3b.Commit(); // Test it - testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false /*TestRAIDProperties*/); + testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false + /* TestRAIDProperties */); // And once again, but this time making it a raid file RaidFileWrite write3c(0, "test1"); @@ -721,7 +763,8 @@ int test(int argc, const char *argv[]) write3c.Write(data + 7, sizeof(data) - 7); write3c.Commit(true); // make RAID // Test it - testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false /*TestRAIDProperties*/); + testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false + /*TestRAIDProperties*/); // Test opening a file which doesn't exist TEST_CHECK_THROWS( @@ -736,20 +779,23 @@ int test(int argc, const char *argv[]) w.Commit(true); // Try removing the parity file - TEST_THAT(::rename("testfiles/0_0/damage.rf", "testfiles/0_0/damage.rf-NT") == 0); + TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0" + DIRECTORY_SEPARATOR "damage.rf", + "testfiles" DIRECTORY_SEPARATOR "0_0" + DIRECTORY_SEPARATOR "damage.rf-NT") == 0); { std::auto_ptr pr0 = RaidFileRead::Open(0, "damage"); pr0->Read(buffer, sizeof(data)); } - TEST_THAT(::rename("testfiles/0_0/damage.rf-NT", "testfiles/0_0/damage.rf") == 0); - + TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf-NT", "testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0); + // Delete one of the files - TEST_THAT(::unlink("testfiles/0_1/damage.rf") == 0); // stripe 1 + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "damage.rf") == 0); // stripe 1 #ifdef TRF_CAN_INTERCEPT // Open it and read... { - intercept_setup_error("testfiles/0_2/damage.rf", 0, EIO, SYS_read); // stripe 2 + intercept_setup_error("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "damage.rf", 0, EIO, SYS_read); // stripe 2 std::auto_ptr pr1 = RaidFileRead::Open(0, "damage"); TEST_CHECK_THROWS( pr1->Read(buffer, sizeof(data)), @@ -761,7 +807,7 @@ int test(int argc, const char *argv[]) #endif //TRF_CAN_INTERCEPT // Delete another - TEST_THAT(::unlink("testfiles/0_0/damage.rf") == 0); // parity + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0); // parity TEST_CHECK_THROWS( std::auto_ptr pread2 = RaidFileRead::Open(0, "damage"), @@ -772,22 +818,22 @@ int test(int argc, const char *argv[]) { RaidFileWrite::CreateDirectory(0, "dirread"); // Make some contents - RaidFileWrite::CreateDirectory(0, "dirread/dfsdf1"); - RaidFileWrite::CreateDirectory(0, "dirread/ponwq2"); + RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "dfsdf1"); + RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "ponwq2"); { - RaidFileWrite w(0, "dirread/sdf9873241"); + RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "sdf9873241"); w.Open(); w.Write(data, sizeof(data)); w.Commit(true); } { - RaidFileWrite w(0, "dirread/fsdcxjni3242"); + RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "fsdcxjni3242"); w.Open(); w.Write(data, sizeof(data)); w.Commit(true); } { - RaidFileWrite w(0, "dirread/cskjnds3"); + RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "cskjnds3"); w.Open(); w.Write(data, sizeof(data)); w.Commit(false); @@ -803,15 +849,15 @@ int test(int argc, const char *argv[]) TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_DirsOnly, names)); TEST_THAT(list_matches(names, dir_list1)); // Delete things - TEST_THAT(::unlink("testfiles/0_0/dirread/sdf9873241.rf") == 0); + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0); TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names)); TEST_THAT(list_matches(names, file_list1)); // Delete something else so that it's not recoverable - TEST_THAT(::unlink("testfiles/0_1/dirread/sdf9873241.rf") == 0); + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0); TEST_THAT(false == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names)); TEST_THAT(list_matches(names, file_list1)); // And finally... - TEST_THAT(::unlink("testfiles/0_2/dirread/sdf9873241.rf") == 0); + TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0); TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names)); TEST_THAT(list_matches(names, file_list2)); } diff --git a/test/win32/testlibwin32.cpp b/test/win32/testlibwin32.cpp index ca2989d8..fb735c56 100644 --- a/test/win32/testlibwin32.cpp +++ b/test/win32/testlibwin32.cpp @@ -6,12 +6,214 @@ #ifdef WIN32 +#include +#include +#include + #include "../../bin/bbackupd/BackupDaemon.h" #include "BoxPortsAndFiles.h" #include "emu.h" int main(int argc, char* argv[]) { + // ACL tests + char* exename = getenv("WINDIR"); + + PSID psidOwner; + PSID psidGroup; + PACL pDacl; + PSECURITY_DESCRIPTOR pSecurityDesc; + + DWORD result = GetNamedSecurityInfo( + exename, // pObjectName + SE_FILE_OBJECT, // ObjectType + DACL_SECURITY_INFORMATION | // SecurityInfo + GROUP_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION, + &psidOwner, // ppsidOwner, + &psidGroup, // ppsidGroup, + &pDacl, // ppDacl, + NULL, // ppSacl, + &pSecurityDesc // ppSecurityDescriptor + ); + if (result != ERROR_SUCCESS) + { + printf("Error getting security info for '%s': error %d", + exename, result); + } + assert(result == ERROR_SUCCESS); + + char namebuf[1024]; + char domainbuf[1024]; + SID_NAME_USE nametype; + DWORD namelen = sizeof(namebuf); + DWORD domainlen = sizeof(domainbuf); + + assert(LookupAccountSid(NULL, psidOwner, namebuf, &namelen, + domainbuf, &domainlen, &nametype)); + + printf("Owner:\n"); + printf("User name: %s\n", namebuf); + printf("Domain name: %s\n", domainbuf); + printf("Name type: %d\n", nametype); + printf("\n"); + + namelen = sizeof(namebuf); + domainlen = sizeof(domainbuf); + + assert(LookupAccountSid(NULL, psidGroup, namebuf, &namelen, + domainbuf, &domainlen, &nametype)); + + printf("Group:\n"); + printf("User name: %s\n", namebuf); + printf("Domain name: %s\n", domainbuf); + printf("Name type: %d\n", nametype); + printf("\n"); + + ULONG numEntries; + PEXPLICIT_ACCESS pEntries; + result = GetExplicitEntriesFromAcl + ( + pDacl, // pAcl + &numEntries, // pcCountOfExplicitEntries, + &pEntries // pListOfExplicitEntries + ); + assert(result == ERROR_SUCCESS); + + printf("Found %lu explicit DACL entries for '%s'\n\n", + (unsigned long)numEntries, exename); + + for (ULONG i = 0; i < numEntries; i++) + { + EXPLICIT_ACCESS* pEntry = &(pEntries[i]); + printf("DACL entry %lu:\n", (unsigned long)i); + + DWORD perms = pEntry->grfAccessPermissions; + printf(" Access permissions: ", perms); + + #define PRINT_PERM(name) \ + if (perms & name) \ + { \ + printf(#name " "); \ + perms &= ~name; \ + } + + PRINT_PERM(FILE_ADD_FILE); + PRINT_PERM(FILE_ADD_SUBDIRECTORY); + PRINT_PERM(FILE_ALL_ACCESS); + PRINT_PERM(FILE_APPEND_DATA); + PRINT_PERM(FILE_CREATE_PIPE_INSTANCE); + PRINT_PERM(FILE_DELETE_CHILD); + PRINT_PERM(FILE_EXECUTE); + PRINT_PERM(FILE_LIST_DIRECTORY); + PRINT_PERM(FILE_READ_ATTRIBUTES); + PRINT_PERM(FILE_READ_DATA); + PRINT_PERM(FILE_READ_EA); + PRINT_PERM(FILE_TRAVERSE); + PRINT_PERM(FILE_WRITE_ATTRIBUTES); + PRINT_PERM(FILE_WRITE_DATA); + PRINT_PERM(FILE_WRITE_EA); + PRINT_PERM(STANDARD_RIGHTS_READ); + PRINT_PERM(STANDARD_RIGHTS_WRITE); + PRINT_PERM(SYNCHRONIZE); + PRINT_PERM(DELETE); + PRINT_PERM(READ_CONTROL); + PRINT_PERM(WRITE_DAC); + PRINT_PERM(WRITE_OWNER); + PRINT_PERM(MAXIMUM_ALLOWED); + PRINT_PERM(GENERIC_ALL); + PRINT_PERM(GENERIC_EXECUTE); + PRINT_PERM(GENERIC_WRITE); + PRINT_PERM(GENERIC_READ); + printf("\n"); + + if (perms) + { + printf(" Bits left over: %08x\n", perms); + } + assert(!perms); + + printf(" Access mode: "); + switch(pEntry->grfAccessMode) + { + case NOT_USED_ACCESS: + printf("NOT_USED_ACCESS\n"); break; + case GRANT_ACCESS: + printf("GRANT_ACCESS\n"); break; + case DENY_ACCESS: + printf("DENY_ACCESS\n"); break; + case REVOKE_ACCESS: + printf("REVOKE_ACCESS\n"); break; + case SET_AUDIT_SUCCESS: + printf("SET_AUDIT_SUCCESS\n"); break; + case SET_AUDIT_FAILURE: + printf("SET_AUDIT_FAILURE\n"); break; + default: + printf("Unknown (%08x)\n", pEntry->grfAccessMode); + } + + printf(" Trustee: "); + assert(pEntry->Trustee.pMultipleTrustee == NULL); + assert(pEntry->Trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE); + switch(pEntry->Trustee.TrusteeForm) + { + case TRUSTEE_IS_SID: + { + PSID trusteeSid = (PSID)(pEntry->Trustee.ptstrName); + + namelen = sizeof(namebuf); + domainlen = sizeof(domainbuf); + + assert(LookupAccountSid(NULL, trusteeSid, namebuf, &namelen, + domainbuf, &domainlen, &nametype)); + + printf("SID of %s\\%s (%d)\n", domainbuf, namebuf, nametype); + } + break; + case TRUSTEE_IS_NAME: + printf("Name\n"); break; + case TRUSTEE_BAD_FORM: + printf("Bad form\n"); assert(0); + case TRUSTEE_IS_OBJECTS_AND_SID: + printf("Objects and SID\n"); break; + case TRUSTEE_IS_OBJECTS_AND_NAME: + printf("Objects and name\n"); break; + default: + printf("Unknown form\n"); assert(0); + } + + printf(" Trustee type: "); + switch(pEntry->Trustee.TrusteeType) + { + case TRUSTEE_IS_UNKNOWN: + printf("Unknown type.\n"); break; + case TRUSTEE_IS_USER: + printf("User\n"); break; + case TRUSTEE_IS_GROUP: + printf("Group\n"); break; + case TRUSTEE_IS_DOMAIN: + printf("Domain\n"); break; + case TRUSTEE_IS_ALIAS: + printf("Alias\n"); break; + case TRUSTEE_IS_WELL_KNOWN_GROUP: + printf("Well-known group\n"); break; + case TRUSTEE_IS_DELETED: + printf("Deleted account\n"); break; + case TRUSTEE_IS_INVALID: + printf("Invalid trustee type\n"); break; + case TRUSTEE_IS_COMPUTER: + printf("Computer\n"); break; + default: + printf("Unknown type %d\n", pEntry->Trustee.TrusteeType); + assert(0); + } + + printf("\n"); + } + + assert(LocalFree((HLOCAL)pEntries) == 0); + assert(LocalFree((HLOCAL)pSecurityDesc) == 0); + chdir("c:\\tmp"); openfile("test", O_CREAT, 0); struct stat ourfs; @@ -25,12 +227,11 @@ int main(int argc, char* argv[]) do { info = readdir(ourDir); - if ( info ) printf("File/Dir name is : %s\r\n", info->d_name); - - }while ( info != NULL ); + if (info) printf("File/Dir name is : %s\r\n", info->d_name); + } + while (info != NULL); closedir(ourDir); - } std::string diry("C:\\Projects\\boxbuild\\testfiles\\"); @@ -41,12 +242,12 @@ int main(int argc, char* argv[]) do { info = readdir(ourDir); - if ( info == NULL ) break; + if (info == NULL) break; std::string file(diry + info->d_name); stat(file.c_str(), &ourfs); - if ( info ) printf("File/Dir name is : %s\r\n", info->d_name); - - }while ( info != NULL ); + if (info) printf("File/Dir name is : %s\r\n", info->d_name); + } + while ( info != NULL ); closedir(ourDir); @@ -54,47 +255,70 @@ int main(int argc, char* argv[]) stat("c:\\windows", &ourfs); stat("c:\\autoexec.bat", &ourfs); - printf("Finished dir read"); -#if 0 - //remove - sleepycat include a version of getopt - mine never REALLY worked ! - //test our getopt function - std::string commline("-q -c fgfgfg -f -l hello"); + printf("Finished dir read\n"); - int c; - while((c = getopt(commline.size(), (char * const *)commline.c_str(), "qwc:l:")) != -1) + //test our getopt function + char * test_argv[] = { - printf("switch = %c, param is %s\r\n", c, optarg); - } -#endif + "foobar.exe", + "-qwc", + "-", + "-c", + "fgfgfg", + "-f", + "-l", + "hello", + "-", + "force-sync", + NULL + }; + int test_argc; + for (test_argc = 0; test_argv[test_argc]; test_argc++) { } + const char* opts = "qwc:l:"; + + assert(getopt(test_argc, test_argv, opts) == 'q'); + assert(getopt(test_argc, test_argv, opts) == 'w'); + assert(getopt(test_argc, test_argv, opts) == 'c'); + assert(strcmp(optarg, "-") == 0); + assert(getopt(test_argc, test_argv, opts) == 'c'); + assert(strcmp(optarg, "fgfgfg") == 0); + assert(getopt(test_argc, test_argv, opts) == '?'); + assert(optopt == 'f'); + assert(getopt(test_argc, test_argv, opts) == 'l'); + assert(strcmp(optarg, "hello") == 0); + assert(getopt(test_argc, test_argv, opts) == -1); + // assert(optopt == 0); // no more options + assert(strcmp(test_argv[optind], "-") == 0); + assert(strcmp(test_argv[optind+1], "force-sync") == 0); //end of getopt test //now test our statfs funct stat("c:\\cert.cer", &ourfs); - - char *timee; timee = ctime(&ourfs.st_mtime); - if ( S_ISREG(ourfs.st_mode)) + if (S_ISREG(ourfs.st_mode)) { - printf("is a normal file"); + printf("is a normal file\n"); } else { - printf("is a directory?"); + printf("is a directory?\n"); + exit(1); } - lstat("c:\\windows", &ourfs); + lstat(getenv("WINDIR"), &ourfs); if ( S_ISDIR(ourfs.st_mode)) { - printf("is a directory"); + printf("is a directory\n"); } else { - printf("is a file?"); + printf("is a file?\n"); + exit(1); } //test the syslog functions @@ -105,6 +329,7 @@ int main(int argc, char* argv[]) closelog(); + /* //first off get the path name for the default char buf[MAX_PATH]; @@ -112,7 +337,7 @@ int main(int argc, char* argv[]) std::string buffer(buf); std::string conf("-c " + buffer.substr(0,(buffer.find("win32test.exe"))) + "bbackupd.conf"); //std::string conf( "-c " + buffer.substr(0,(buffer.find("bbackupd.exe"))) + "bbackupd.conf"); - + */ return 0; } diff --git a/win32.bat b/win32.bat index 56829dde..e4a39359 100644 --- a/win32.bat +++ b/win32.bat @@ -3,6 +3,8 @@ echo quick and dirty to get up and running by generating the required files echo using Cygwin and Perl +copy .\infrastructure\BoxPlatform.pm.in .\infrastructure\BoxPlatform.pm + cd .\bin\bbackupquery\ & perl ./../../bin/bbackupquery/makedocumentation.pl cd ..\..\ @@ -25,4 +27,4 @@ echo server parts - which appears as though some of the clients rely on cd .\lib\server & perl ./../../lib/common/makeexception.pl ServerException.txt & perl ./../../lib/common/makeexception.pl ConnectionException.txt cd ..\..\ -copy lib\win32\config.h.win32 lib\common\BoxConfig.h +perl -i.orig -pe 's/@PERL@/perl/' ./test/bbackupd/testfiles/bbackupd.conf -- cgit v1.2.3 From 7de93826a58d901b8b136470d7b8be19342dbbc5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 7 Aug 2006 20:56:23 +0000 Subject: * BoxPlatform.pm.in - Removed $build_cpu and `uname -p` entirely, as they are not used anywhere --- infrastructure/BoxPlatform.pm.in | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in index 8297b93b..81629414 100644 --- a/infrastructure/BoxPlatform.pm.in +++ b/infrastructure/BoxPlatform.pm.in @@ -1,7 +1,7 @@ package BoxPlatform; use Exporter; @ISA = qw/Exporter/; -@EXPORT = qw/$build_os $build_cpu $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows update_if_changed/; +@EXPORT = qw/$build_os $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows update_if_changed/; BEGIN { @@ -15,14 +15,11 @@ BEGIN if ($^O eq "MSWin32" and not -x "/usr/bin/uname") { $build_os = "winnt"; - $build_cpu = "ix86"; } else { $build_os = `uname`; chomp $build_os; - $build_cpu = `uname -m`; - chomp $build_cpu; } # Cygwin Builds usually something like CYGWIN_NT-5.0, CYGWIN_NT-5.1 -- cgit v1.2.3 From 5336613257f0d84ab54a5d4712821d2351c4b407 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 7 Aug 2006 22:43:43 +0000 Subject: * bbackupctl.cpp - Revert all changes back to trunk state --- bin/bbackupctl/bbackupctl.cpp | 104 ++++++------------------------------------ 1 file changed, 14 insertions(+), 90 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index 37d5c377..dfadc37d 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -32,14 +32,12 @@ void PrintUsageAndExit() { printf("Usage: bbackupctl [-q] [-c config_file] \n" "Commands are:\n" - " sync -- start a synchronisation (backup) run now\n" - " force-sync -- force the start of a synchronisation run, " + " sync -- start a syncronisation run now\n" + " force-sync -- force the start of a syncronisation run, " "even if SyncAllowScript says no\n" " reload -- reload daemon configuration\n" " terminate -- terminate daemon now\n" " wait-for-sync -- wait until the next sync starts, then exit\n" - " wait-for-end -- wait until the next sync finishes, then exit\n" - " sync-and-wait -- start sync, wait until it finishes, then exit\n" ); exit(1); } @@ -109,10 +107,7 @@ int main(int argc, const char *argv[]) // Check there's a socket defined in the config file if(!conf.KeyExists("CommandSocket")) { - printf("Daemon isn't using a control socket, " - "could not execute command.\n" - "Add a CommandSocket declaration to the " - "bbackupd.conf file.\n"); + printf("Daemon isn't using a control socket, could not execute command.\nAdd a CommandSocket declaration to the bbackupd.conf file.\n"); return 1; } @@ -193,74 +188,27 @@ int main(int argc, const char *argv[]) // Print summary? if(!quiet) { - printf("Daemon configuration summary:\n" - " AutomaticBackup = %s\n" - " UpdateStoreInterval = %d seconds\n" - " MinimumFileAge = %d seconds\n" - " MaxUploadWait = %d seconds\n", - autoBackup?"true":"false", updateStoreInterval, - minimumFileAge, maxUploadWait); - } - - std::string stateLine; - if(!getLine.GetLine(stateLine) || getLine.IsEOF()) - { -#if defined WIN32 && ! defined NDEBUG - syslog(LOG_ERR, "Failed to receive state line from daemon"); -#else - printf("Failed to receive state line from daemon\n"); -#endif - return 1; - } - - // Decode it - int currentState; - if(::sscanf(stateLine.c_str(), "state %d", ¤tState) != 1) - { - printf("State line didn't decode\n"); - return 1; + printf("Daemon configuration summary:\n" \ + " AutomaticBackup = %s\n" \ + " UpdateStoreInterval = %d seconds\n" \ + " MinimumFileAge = %d seconds\n" \ + " MaxUploadWait = %d seconds\n", + autoBackup?"true":"false", updateStoreInterval, minimumFileAge, maxUploadWait); } // Is the command the "wait for sync to start" command? bool areWaitingForSync = false; - bool areWaitingForSyncEnd = false; - - if(::strcmp(argv[0], "wait-for-sync") == 0 || - ::strcmp(argv[0], "wait-for-end") == 0) + if(::strcmp(argv[0], "wait-for-sync") == 0) { - // Check that it's not in non-automatic mode, - // because then it'll never start + // Check that it's not in non-automatic mode, because then it'll never start if(!autoBackup) { - printf("ERROR: Daemon is not in automatic mode -- " - "sync will never start!\n"); + printf("ERROR: Daemon is not in automatic mode -- sync will never start!\n"); return 1; } - // Yes... set the flag so we know that - // we're waiting for a sync to start/end - if(::strcmp(argv[0], "wait-for-sync") == 0) - { - areWaitingForSync = true; - } - else if (::strcmp(argv[0], "wait-for-end") == 0) - { - areWaitingForSyncEnd = true; - } - } - else if (::strcmp(argv[0], "sync-and-wait") == 0) - { - // send a sync command - std::string cmd("force-sync\n"); - connection.Write(cmd.c_str(), cmd.size()); - connection.WriteAllBuffered(); - areWaitingForSyncEnd = true; - - if (currentState != 0) - { - printf("Waiting for current sync/error state " - "to finish...\n"); - } + // Yes... set the flag so we know what we're waiting for a sync to start + areWaitingForSync = true; } else { @@ -272,8 +220,6 @@ int main(int argc, const char *argv[]) // Read the response std::string line; - bool syncIsRunning = false; - while(!getLine.IsEOF() && getLine.GetLine(line)) { if(areWaitingForSync) @@ -288,28 +234,6 @@ int main(int argc, const char *argv[]) break; } } - else if(areWaitingForSyncEnd) - { - if(line == "start-sync") - { - if (!quiet) printf("Sync started...\n"); - syncIsRunning = true; - } - else if(line == "finish-sync" && syncIsRunning) - { - if (!quiet) printf("Sync finished.\n"); - // Send a quit command to finish nicely - connection.Write("quit\n", 5); - - // And we're done - break; - } - else if(line == "finish-sync") - { - if (!quiet) printf("Previous sync finished.\n"); - } - // daemon must still be busy - } else { // Is this an OK or error line? -- cgit v1.2.3 From 66795cd28013030795ea355415e0d6e620e2adfd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 7 Aug 2006 22:46:35 +0000 Subject: * bin/bbackupctl/bbackupctl.cpp - Changed code structure to be more readable and robust, following Martin's advice. --- bin/bbackupctl/bbackupctl.cpp | 202 ++++++++++++++++++++++++++++++++---------- 1 file changed, 154 insertions(+), 48 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index dfadc37d..6f7c55f7 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -28,16 +28,26 @@ #include "MemLeakFindOn.h" +enum Command +{ + Default, + WaitForSyncStart, + WaitForSyncEnd, + SyncAndWaitForEnd, +}; + void PrintUsageAndExit() { printf("Usage: bbackupctl [-q] [-c config_file] \n" "Commands are:\n" - " sync -- start a syncronisation run now\n" - " force-sync -- force the start of a syncronisation run, " + " sync -- start a synchronisation (backup) run now\n" + " force-sync -- force the start of a synchronisation run, " "even if SyncAllowScript says no\n" " reload -- reload daemon configuration\n" " terminate -- terminate daemon now\n" " wait-for-sync -- wait until the next sync starts, then exit\n" + " wait-for-end -- wait until the next sync finishes, then exit\n" + " sync-and-wait -- start sync, wait until it finishes, then exit\n" ); exit(1); } @@ -107,7 +117,10 @@ int main(int argc, const char *argv[]) // Check there's a socket defined in the config file if(!conf.KeyExists("CommandSocket")) { - printf("Daemon isn't using a control socket, could not execute command.\nAdd a CommandSocket declaration to the bbackupd.conf file.\n"); + printf("Daemon isn't using a control socket, " + "could not execute command.\n" + "Add a CommandSocket declaration to the " + "bbackupd.conf file.\n"); return 1; } @@ -188,68 +201,161 @@ int main(int argc, const char *argv[]) // Print summary? if(!quiet) { - printf("Daemon configuration summary:\n" \ - " AutomaticBackup = %s\n" \ - " UpdateStoreInterval = %d seconds\n" \ - " MinimumFileAge = %d seconds\n" \ - " MaxUploadWait = %d seconds\n", - autoBackup?"true":"false", updateStoreInterval, minimumFileAge, maxUploadWait); + printf("Daemon configuration summary:\n" + " AutomaticBackup = %s\n" + " UpdateStoreInterval = %d seconds\n" + " MinimumFileAge = %d seconds\n" + " MaxUploadWait = %d seconds\n", + autoBackup?"true":"false", updateStoreInterval, + minimumFileAge, maxUploadWait); } - // Is the command the "wait for sync to start" command? - bool areWaitingForSync = false; - if(::strcmp(argv[0], "wait-for-sync") == 0) + std::string stateLine; + if(!getLine.GetLine(stateLine) || getLine.IsEOF()) { - // Check that it's not in non-automatic mode, because then it'll never start - if(!autoBackup) - { - printf("ERROR: Daemon is not in automatic mode -- sync will never start!\n"); - return 1; - } - - // Yes... set the flag so we know what we're waiting for a sync to start - areWaitingForSync = true; +#if defined WIN32 && ! defined NDEBUG + syslog(LOG_ERR, "Failed to receive state line from daemon"); +#else + printf("Failed to receive state line from daemon\n"); +#endif + return 1; + } + + // Decode it + int currentState; + if(::sscanf(stateLine.c_str(), "state %d", ¤tState) != 1) + { + printf("State line didn't decode\n"); + return 1; } - else + + Command command = Default; + std::string commandName(argv[0]); + + if (commandName == "wait-for-sync") + { + command = WaitForSyncStart; + } + else if (commandName == "wait-for-end") { - // No? Just send the command given plus a quit command. - std::string cmd(argv[0]); - cmd += "\nquit\n"; - connection.Write(cmd.c_str(), cmd.size()); + command = WaitForSyncEnd; + } + else if (commandName == "sync-and-wait") + { + command = SyncAndWaitForEnd; + } + + switch (command) + { + case WaitForSyncStart: + case WaitForSyncEnd: + { + // Check that it's not in non-automatic mode, + // because then it'll never start + + if(!autoBackup) + { + printf("ERROR: Daemon is not in automatic mode -- " + "sync will never start!\n"); + return 1; + } + + } + break; + + case SyncAndWaitForEnd: + { + // send a sync command + std::string cmd("force-sync\n"); + connection.Write(cmd.c_str(), cmd.size()); + connection.WriteAllBuffered(); + + if (currentState != 0) + { + printf("Waiting for current sync/error state " + "to finish...\n"); + } + } + break; + + default: + { + // Normal case, just send the command given + // plus a quit command. + std::string cmd = commandName; + cmd += "\nquit\n"; + connection.Write(cmd.c_str(), cmd.size()); + } } // Read the response std::string line; - while(!getLine.IsEOF() && getLine.GetLine(line)) + bool syncIsRunning = false; + bool finished = false; + + while(!finished && !getLine.IsEOF() && getLine.GetLine(line)) { - if(areWaitingForSync) + switch (command) { - // Need to wait for the state change... - if(line == "start-sync") + case WaitForSyncStart: { - // Send a quit command to finish nicely - connection.Write("quit\n", 5); - - // And we're done - break; - } - } - else - { - // Is this an OK or error line? - if(line == "ok") + // Need to wait for the state change... + if(line == "start-sync") + { + // Send a quit command to finish nicely + connection.Write("quit\n", 5); + + // And we're done + finished = true; + } + } + break; + + case WaitForSyncEnd: + case SyncAndWaitForEnd: { - if(!quiet) + if(line == "start-sync") + { + if (!quiet) printf("Sync started...\n"); + syncIsRunning = true; + } + else if(line == "finish-sync") { - printf("Succeeded.\n"); + if (syncIsRunning) + { + if (!quiet) printf("Sync finished.\n"); + // Send a quit command to finish nicely + connection.Write("quit\n", 5); + + // And we're done + finished = true; + } + else + { + if (!quiet) printf("Previous sync finished.\n"); + } + // daemon must still be busy } - break; } - else if(line == "error") + break; + + default: { - printf("ERROR. (Check command spelling)\n"); - returnCode = 1; - break; + // Is this an OK or error line? + if(line == "ok") + { + if(!quiet) + { + printf("Succeeded.\n"); + } + finished = true; + } + else if(line == "error") + { + printf("ERROR. (Check command spelling)\n"); + returnCode = 1; + finished = true; + } } } } -- cgit v1.2.3 From dfcff7c33462820519c47ddc9773f68fffb07ec9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Aug 2006 23:54:33 +0000 Subject: * bbackupctl.cpp - Grammar fix in comments (cosmetic) --- bin/bbackupctl/bbackupctl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index 6f7c55f7..4a5ee5a9 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -250,8 +250,8 @@ int main(int argc, const char *argv[]) case WaitForSyncStart: case WaitForSyncEnd: { - // Check that it's not in non-automatic mode, - // because then it'll never start + // Check that it's in automatic mode, + // because otherwise it'll never start if(!autoBackup) { -- cgit v1.2.3 From 9217c2609e49a0b771b88fe0e879fcbee53506e2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 08:44:56 +0000 Subject: * Win32ServiceFunctions.cpp - Revert to trunk --- bin/bbackupd/Win32ServiceFunctions.cpp | 184 ++++++++++----------------------- 1 file changed, 52 insertions(+), 132 deletions(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index 1b50a7fa..b74c7e09 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -93,30 +93,28 @@ void WINAPI ServiceControlHandler( DWORD controlCode ) // It also returns on any error because the // service cannot start if there is an eror. -static char* spConfigFileName; - VOID ServiceMain(DWORD argc, LPTSTR *argv) { - // initialise service status - gServiceStatus.dwServiceType = SERVICE_WIN32; - gServiceStatus.dwCurrentState = SERVICE_STOPPED; - gServiceStatus.dwControlsAccepted = 0; - gServiceStatus.dwWin32ExitCode = NO_ERROR; - gServiceStatus.dwServiceSpecificExitCode = NO_ERROR; - gServiceStatus.dwCheckPoint = 0; - gServiceStatus.dwWaitHint = 0; - - gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName, - ServiceControlHandler); - - if (gServiceStatusHandle) - { - // service is starting - gServiceStatus.dwCurrentState = SERVICE_START_PENDING; - SetServiceStatus(gServiceStatusHandle, &gServiceStatus); - - // do initialisation here - gStopServiceEvent = CreateEvent(0, TRUE, FALSE, 0); + // initialise service status + gServiceStatus.dwServiceType = SERVICE_WIN32; + gServiceStatus.dwCurrentState = SERVICE_STOPPED; + gServiceStatus.dwControlsAccepted = 0; + gServiceStatus.dwWin32ExitCode = NO_ERROR; + gServiceStatus.dwServiceSpecificExitCode = NO_ERROR; + gServiceStatus.dwCheckPoint = 0; + gServiceStatus.dwWaitHint = 0; + + gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName, + ServiceControlHandler); + + if (gServiceStatusHandle) + { + // service is starting + gServiceStatus.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(gServiceStatusHandle, &gServiceStatus); + + // do initialisation here + gStopServiceEvent = CreateEvent( 0, TRUE, FALSE, 0 ); if (!gStopServiceEvent) { gServiceStatus.dwControlsAccepted &= @@ -131,7 +129,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) NULL, 0, RunService, - spConfigFileName, + 0, CREATE_SUSPENDED, NULL); @@ -140,7 +138,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) // we are now running so tell the SCM gServiceStatus.dwControlsAccepted |= - (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); gServiceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(gServiceStatusHandle, &gServiceStatus); @@ -158,13 +156,11 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); gServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(gServiceStatusHandle, &gServiceStatus); - } + } } -void OurService(char* pConfigFileName) +void OurService(void) { - spConfigFileName = pConfigFileName; - SERVICE_TABLE_ENTRY serviceTable[] = { { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain }, @@ -183,52 +179,28 @@ void OurService(char* pConfigFileName) } } -int InstallService(const char* pConfigFileName) +void InstallService(void) { - if (pConfigFileName != NULL) - { - struct stat st; + SC_HANDLE newService, scm; - if (emu_stat(pConfigFileName, &st) != 0) - { - syslog(LOG_ERR, "Failed to open configuration file: " - "%s: %s", pConfigFileName, strerror(errno)); - return 1; - } - - if (! st.st_mode & S_IFREG) - { - - syslog(LOG_ERR, "Failed to open configuration file: " - "%s: not a file", pConfigFileName); - return 1; - } - } - - SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); if (!scm) { syslog(LOG_ERR, "Failed to open service control manager: " "error %d", GetLastError()); - return 1; + return; } char cmd[MAX_PATH]; GetModuleFileName(NULL, cmd, sizeof(cmd)-1); cmd[sizeof(cmd)-1] = 0; - std::string cmdWithArgs(cmd); - cmdWithArgs += " --service"; + char cmd_args[MAX_PATH]; + _snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd); + cmd_args[sizeof(cmd_args)-1] = 0; - if (pConfigFileName != NULL) - { - cmdWithArgs += " \""; - cmdWithArgs += pConfigFileName; - cmdWithArgs += "\""; - } - - SC_HANDLE newService = CreateService( + newService = CreateService( scm, SERVICE_NAME, "Box Backup", @@ -236,36 +208,14 @@ int InstallService(const char* pConfigFileName) SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - cmdWithArgs.c_str(), + cmd_args, 0,0,0,0,0); - DWORD err = GetLastError(); - CloseServiceHandle(scm); - if (!newService) { - if (err == ERROR_SERVICE_EXISTS) - { - ::syslog(LOG_ERR, "Failed to create Box Backup " - "service: it already exists"); - } - else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) - { - ::syslog(LOG_ERR, "Failed to create Box Backup " - "service: it is waiting to be deleted"); - } - else if (err == ERROR_DUPLICATE_SERVICE_NAME) - { - ::syslog(LOG_ERR, "Failed to create Box Backup " - "service: a service with this name " - "already exists"); - } - else - { - ::syslog(LOG_ERR, "Failed to create Box Backup " - "service: error %d", err); - } - return 1; + ::syslog(LOG_ERR, "Failed to create Box Backup service: " + "error %d", GetLastError()); + return; } ::syslog(LOG_INFO, "Created Box Backup service"); @@ -281,75 +231,45 @@ int InstallService(const char* pConfigFileName) } CloseServiceHandle(newService); - - return 0; + CloseServiceHandle(scm); } -int RemoveService(void) +void RemoveService(void) { - SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + SC_HANDLE service, scm; + SERVICE_STATUS status; + + scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); if (!scm) { syslog(LOG_ERR, "Failed to open service control manager: " "error %d", GetLastError()); - return 1; + return; } - SC_HANDLE service = OpenService(scm, SERVICE_NAME, - SERVICE_ALL_ACCESS|DELETE); - DWORD err = GetLastError(); - CloseServiceHandle(scm); + service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE); + ControlService(service, SERVICE_CONTROL_STOP, &status); if (!service) { - if (err == ERROR_SERVICE_DOES_NOT_EXIST || - err == ERROR_IO_PENDING) - // hello microsoft? anyone home? - { - syslog(LOG_ERR, "Failed to open Box Backup service: " - "not installed or not found"); - } - else - { - syslog(LOG_ERR, "Failed to open Box Backup service: " - "error %d", err); - } - return 1; - } - - SERVICE_STATUS status; - if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) - { - err = GetLastError(); - if (err != ERROR_SERVICE_NOT_ACTIVE) - { - syslog(LOG_WARNING, "Failed to stop Box Backup " - "service: error %d", err); - } + syslog(LOG_ERR, "Failed to open Box Backup service: " + "error %d", GetLastError()); + return; } - BOOL deleted = DeleteService(service); - err = GetLastError(); - CloseServiceHandle(service); - - if (deleted) + if (DeleteService(service)) { syslog(LOG_INFO, "Box Backup service deleted"); - return 0; - } - else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) - { - syslog(LOG_ERR, "Failed to remove Box Backup service: " - "it is already being deleted"); } else { syslog(LOG_ERR, "Failed to remove Box Backup service: " - "error %d", err); + "error %d", GetLastError()); } - return 1; + CloseServiceHandle(service); + CloseServiceHandle(scm); } #endif // WIN32 -- cgit v1.2.3 From 366e8c7acc2952aebfc909cbc9ed532df6769a06 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 08:49:54 +0000 Subject: * Win32ServiceFunctions.cpp - Reindent ServiceMain function to match coding standards and rest of file --- bin/bbackupd/Win32ServiceFunctions.cpp | 43 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index b74c7e09..c8f87813 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -95,26 +95,27 @@ void WINAPI ServiceControlHandler( DWORD controlCode ) VOID ServiceMain(DWORD argc, LPTSTR *argv) { - // initialise service status - gServiceStatus.dwServiceType = SERVICE_WIN32; - gServiceStatus.dwCurrentState = SERVICE_STOPPED; - gServiceStatus.dwControlsAccepted = 0; - gServiceStatus.dwWin32ExitCode = NO_ERROR; - gServiceStatus.dwServiceSpecificExitCode = NO_ERROR; - gServiceStatus.dwCheckPoint = 0; - gServiceStatus.dwWaitHint = 0; - - gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName, - ServiceControlHandler); - - if (gServiceStatusHandle) - { - // service is starting - gServiceStatus.dwCurrentState = SERVICE_START_PENDING; - SetServiceStatus(gServiceStatusHandle, &gServiceStatus); - - // do initialisation here - gStopServiceEvent = CreateEvent( 0, TRUE, FALSE, 0 ); + // initialise service status + gServiceStatus.dwServiceType = SERVICE_WIN32; + gServiceStatus.dwCurrentState = SERVICE_STOPPED; + gServiceStatus.dwControlsAccepted = 0; + gServiceStatus.dwWin32ExitCode = NO_ERROR; + gServiceStatus.dwServiceSpecificExitCode = NO_ERROR; + gServiceStatus.dwCheckPoint = 0; + gServiceStatus.dwWaitHint = 0; + + gServiceStatusHandle = RegisterServiceCtrlHandler(gServiceName, + ServiceControlHandler); + + if (gServiceStatusHandle) + { + // service is starting + gServiceStatus.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(gServiceStatusHandle, &gServiceStatus); + + // do initialisation here + gStopServiceEvent = CreateEvent( 0, TRUE, FALSE, 0 ); + if (!gStopServiceEvent) { gServiceStatus.dwControlsAccepted &= @@ -156,7 +157,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); gServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(gServiceStatusHandle, &gServiceStatus); - } + } } void OurService(void) -- cgit v1.2.3 From 0a73aa9dfbd49d86036672c3953663313cf1790a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 12:32:16 +0000 Subject: * bin/bbackupd/Win32ServiceFunctions.cpp - More cosmetic spacing fixes --- bin/bbackupd/Win32ServiceFunctions.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index c8f87813..2897f822 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -114,8 +114,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) SetServiceStatus(gServiceStatusHandle, &gServiceStatus); // do initialisation here - gStopServiceEvent = CreateEvent( 0, TRUE, FALSE, 0 ); - + gStopServiceEvent = CreateEvent(0, TRUE, FALSE, 0); if (!gStopServiceEvent) { gServiceStatus.dwControlsAccepted &= @@ -139,7 +138,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) // we are now running so tell the SCM gServiceStatus.dwControlsAccepted |= - (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); gServiceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(gServiceStatusHandle, &gServiceStatus); -- cgit v1.2.3 From a79c301c0f1f42cdb32c3ccc2cc46c0877b29853 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 12:38:20 +0000 Subject: * bin/bbackupd/Win32ServiceFunctions.cpp - Keep a static char pointer to hold onto the config file name to pass it to ServiceMain (over whose parameters we have no control). - ServiceMain passes the config file name as the parameter of the thread it creates. --- bin/bbackupd/Win32ServiceFunctions.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index 2897f822..f0449226 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -93,6 +93,8 @@ void WINAPI ServiceControlHandler( DWORD controlCode ) // It also returns on any error because the // service cannot start if there is an eror. +static char* spConfigFileName; + VOID ServiceMain(DWORD argc, LPTSTR *argv) { // initialise service status @@ -129,7 +131,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) NULL, 0, RunService, - 0, + spConfigFileName, CREATE_SUSPENDED, NULL); -- cgit v1.2.3 From e1c40b699a0ccd9710de27aedad36d706b2ac88a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 12:43:59 +0000 Subject: * Win32ServiceFunctions.cpp - RemoveService() returns a status code, 0 for success, 1 for error - RemoveService() outputs better diagnostic messages on failure --- bin/bbackupd/Win32ServiceFunctions.cpp | 59 +++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index f0449226..ca8bc1ca 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -236,42 +236,71 @@ void InstallService(void) CloseServiceHandle(scm); } -void RemoveService(void) +int RemoveService(void) { - SC_HANDLE service, scm; - SERVICE_STATUS status; - - scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); if (!scm) { syslog(LOG_ERR, "Failed to open service control manager: " "error %d", GetLastError()); - return; + return 1; } - service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE); - ControlService(service, SERVICE_CONTROL_STOP, &status); + SC_HANDLE service = OpenService(scm, SERVICE_NAME, + SERVICE_ALL_ACCESS|DELETE); + DWORD err = GetLastError(); + CloseServiceHandle(scm); if (!service) { - syslog(LOG_ERR, "Failed to open Box Backup service: " - "error %d", GetLastError()); - return; + if (err == ERROR_SERVICE_DOES_NOT_EXIST || + err == ERROR_IO_PENDING) + // hello microsoft? anyone home? + { + syslog(LOG_ERR, "Failed to open Box Backup service: " + "not installed or not found"); + } + else + { + syslog(LOG_ERR, "Failed to open Box Backup service: " + "error %d", err); + } + return 1; } - if (DeleteService(service)) + SERVICE_STATUS status; + if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) + { + err = GetLastError(); + if (err != ERROR_SERVICE_NOT_ACTIVE) + { + syslog(LOG_WARNING, "Failed to stop Box Backup " + "service: error %d", err); + } + } + + BOOL deleted = DeleteService(service); + err = GetLastError(); + CloseServiceHandle(service); + + if (deleted) { syslog(LOG_INFO, "Box Backup service deleted"); + return 0; + } + else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) + { + syslog(LOG_ERR, "Failed to remove Box Backup service: " + "it is already being deleted"); } else { syslog(LOG_ERR, "Failed to remove Box Backup service: " - "error %d", GetLastError()); + "error %d", err); } - CloseServiceHandle(service); - CloseServiceHandle(scm); + return 1; } #endif // WIN32 -- cgit v1.2.3 From 89bfa52d830f1a623214eb63242a1be99fe710ab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 12:51:32 +0000 Subject: * bbackupd.cpp * Win32ServiceFunctions.h - Revert to trunk --- bin/bbackupd/Win32ServiceFunctions.h | 6 ++-- bin/bbackupd/bbackupd.cpp | 56 ++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.h b/bin/bbackupd/Win32ServiceFunctions.h index 3fe77187..72f65479 100644 --- a/bin/bbackupd/Win32ServiceFunctions.h +++ b/bin/bbackupd/Win32ServiceFunctions.h @@ -12,8 +12,8 @@ #ifndef WIN32SERVICEFUNCTIONS_H #define WIN32SERVICEFUNCTIONS_H -int RemoveService(void); -int InstallService(const char* pConfigFilePath); -void OurService(char* pConfigFileName); +void RemoveService(void); +void InstallService(void); +void OurService(void); #endif diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index e00d3628..089b2d09 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -19,7 +19,7 @@ #include "Win32ServiceFunctions.h" #include "Win32BackupService.h" - extern Win32BackupService* gpDaemonService; + extern Win32BackupService gDaemonService; #endif int main(int argc, const char *argv[]) @@ -28,7 +28,7 @@ int main(int argc, const char *argv[]) #ifdef WIN32 - ::openlog("Box Backup (bbackupd)", LOG_PID, LOG_LOCAL6); + ::openlog("Box Backup (bbackupd)", 0, 0); if(argc == 2 && (::strcmp(argv[1], "--help") == 0 || @@ -40,25 +40,32 @@ int main(int argc, const char *argv[]) } if(argc == 2 && ::strcmp(argv[1], "-r") == 0) { - return RemoveService(); + RemoveService(); + return 0; } - if((argc == 2 || argc == 3) && ::strcmp(argv[1], "-i") == 0) + if(argc == 2 && ::strcmp(argv[1], "-i") == 0) { - const char* config = NULL; - if (argc == 3) - { - config = argv[2]; - } - return InstallService(config); + InstallService(); + return 0; } bool runAsWin32Service = false; - if (argc >= 2 && ::strcmp(argv[1], "--service") == 0) + if (argc == 2 && ::strcmp(argv[1], "--service") == 0) { runAsWin32Service = true; } + + // Under win32 we must initialise the Winsock library + // before using sockets + + WSADATA info; - gpDaemonService = new Win32BackupService(); + if (WSAStartup(0x0101, &info) == SOCKET_ERROR) + { + // box backup will not run without sockets + ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); + THROW_EXCEPTION(BackupStoreException, Internal) + } EnableBackupRights(); @@ -66,32 +73,19 @@ int main(int argc, const char *argv[]) if (runAsWin32Service) { - syslog(LOG_INFO, "Box Backup service starting"); - - char* config = NULL; - if (argc >= 3) - { - config = strdup(argv[2]); - } - - OurService(config); - - if (config) - { - free(config); - } - - syslog(LOG_INFO, "Box Backup service shut down"); + syslog(LOG_INFO,"Starting Box Backup Service"); + OurService(); } else { - ExitCode = gpDaemonService->Main( + ExitCode = gDaemonService.Main( BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); } - ::closelog(); + // Clean up our sockets + WSACleanup(); - delete gpDaemonService; + ::closelog(); return ExitCode; -- cgit v1.2.3 From 52dfab19cd69b6423af80c7276caa5b65fdd6545 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 12:54:05 +0000 Subject: * Win32ServiceFunctions.h - Header update --- bin/bbackupd/Win32ServiceFunctions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.h b/bin/bbackupd/Win32ServiceFunctions.h index 72f65479..39f3a4e3 100644 --- a/bin/bbackupd/Win32ServiceFunctions.h +++ b/bin/bbackupd/Win32ServiceFunctions.h @@ -12,7 +12,7 @@ #ifndef WIN32SERVICEFUNCTIONS_H #define WIN32SERVICEFUNCTIONS_H -void RemoveService(void); +int RemoveService(void); void InstallService(void); void OurService(void); -- cgit v1.2.3 From bec6ea866b973c9661b4b2d4a7d342fa0a075185 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 17:27:46 +0000 Subject: * bin/bbackupd/Win32ServiceFunctions.h * bin/bbackupd/Win32ServiceFunctions.cpp - InstallService() and OurService() take the config file name as a parameter - InstallService() returns an integer status code like RemoveService() - OurService() sets the global static config file name to pass into the main thread later * bin/bbackupd/bbackupd.cpp - Call InstallService() and OurService() with the config file name as a parameter --- bin/bbackupd/Win32ServiceFunctions.cpp | 12 ++++++++---- bin/bbackupd/Win32ServiceFunctions.h | 6 +++--- bin/bbackupd/bbackupd.cpp | 29 ++++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index ca8bc1ca..4a54fd1c 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -161,8 +161,10 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) } } -void OurService(void) +void OurService(char* pConfigFileName) { + spConfigFileName = pConfigFileName; + SERVICE_TABLE_ENTRY serviceTable[] = { { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain }, @@ -181,7 +183,7 @@ void OurService(void) } } -void InstallService(void) +int InstallService(const char* pConfigFileName) { SC_HANDLE newService, scm; @@ -191,7 +193,7 @@ void InstallService(void) { syslog(LOG_ERR, "Failed to open service control manager: " "error %d", GetLastError()); - return; + return 1; } char cmd[MAX_PATH]; @@ -217,7 +219,7 @@ void InstallService(void) { ::syslog(LOG_ERR, "Failed to create Box Backup service: " "error %d", GetLastError()); - return; + return 1; } ::syslog(LOG_INFO, "Created Box Backup service"); @@ -234,6 +236,8 @@ void InstallService(void) CloseServiceHandle(newService); CloseServiceHandle(scm); + + return 0; } int RemoveService(void) diff --git a/bin/bbackupd/Win32ServiceFunctions.h b/bin/bbackupd/Win32ServiceFunctions.h index 39f3a4e3..70e1f085 100644 --- a/bin/bbackupd/Win32ServiceFunctions.h +++ b/bin/bbackupd/Win32ServiceFunctions.h @@ -12,8 +12,8 @@ #ifndef WIN32SERVICEFUNCTIONS_H #define WIN32SERVICEFUNCTIONS_H -int RemoveService(void); -void InstallService(void); -void OurService(void); +int RemoveService (void); +int InstallService (const char* pConfigFilePath); +void OurService (char* pConfigFileName); #endif diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index 089b2d09..d2279074 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -43,14 +43,19 @@ int main(int argc, const char *argv[]) RemoveService(); return 0; } - if(argc == 2 && ::strcmp(argv[1], "-i") == 0) + if((argc == 2 || argc == 3) && ::strcmp(argv[1], "-i") == 0) { - InstallService(); + const char* config = NULL; + if (argc == 3) + { + config = argv[2]; + } + InstallService(config); return 0; } bool runAsWin32Service = false; - if (argc == 2 && ::strcmp(argv[1], "--service") == 0) + if (argc >= 2 && ::strcmp(argv[1], "--service") == 0) { runAsWin32Service = true; } @@ -73,8 +78,22 @@ int main(int argc, const char *argv[]) if (runAsWin32Service) { - syslog(LOG_INFO,"Starting Box Backup Service"); - OurService(); + syslog(LOG_INFO, "Box Backup service starting"); + + char* config = NULL; + if (argc >= 3) + { + config = strdup(argv[2]); + } + + OurService(config); + + if (config) + { + free(config); + } + + syslog(LOG_INFO, "Box Backup service shut down"); } else { -- cgit v1.2.3 From b59a411d69caa7ff32119bd2a1fceb58565a581a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 17:29:59 +0000 Subject: * bbackupd.cpp - Return the status code from InstallService() and RemoveService() as exit code (0 on success, 1 on failure) --- bin/bbackupd/bbackupd.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index d2279074..3c283596 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -40,8 +40,7 @@ int main(int argc, const char *argv[]) } if(argc == 2 && ::strcmp(argv[1], "-r") == 0) { - RemoveService(); - return 0; + return RemoveService(); } if((argc == 2 || argc == 3) && ::strcmp(argv[1], "-i") == 0) { @@ -50,8 +49,7 @@ int main(int argc, const char *argv[]) { config = argv[2]; } - InstallService(config); - return 0; + return InstallService(config); } bool runAsWin32Service = false; -- cgit v1.2.3 From 56a8d711ecbcb5f0c034c26eb0bf9a00cfa27ea5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 17:39:28 +0000 Subject: * bin/bbackupd/Win32ServiceFunctions.cpp - Improved diagnostic output if InstallService() fails - Ensure that InstallService() cleans up all resources - Check that the requested configuration file is accessible - Include the configuration file in the service parameters --- bin/bbackupd/Win32ServiceFunctions.cpp | 75 +++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index 4a54fd1c..2f842fb6 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -185,9 +185,27 @@ void OurService(char* pConfigFileName) int InstallService(const char* pConfigFileName) { - SC_HANDLE newService, scm; + if (pConfigFileName != NULL) + { + struct stat st; + + if (emu_stat(pConfigFileName, &st) != 0) + { + syslog(LOG_ERR, "Failed to open configuration file: " + "%s: %s", pConfigFileName, strerror(errno)); + return 1; + } + + if (! st.st_mode & S_IFREG) + { + + syslog(LOG_ERR, "Failed to open configuration file: " + "%s: not a file", pConfigFileName); + return 1; + } + } - scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); if (!scm) { @@ -200,11 +218,17 @@ int InstallService(const char* pConfigFileName) GetModuleFileName(NULL, cmd, sizeof(cmd)-1); cmd[sizeof(cmd)-1] = 0; - char cmd_args[MAX_PATH]; - _snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd); - cmd_args[sizeof(cmd_args)-1] = 0; + std::string cmdWithArgs(cmd); + cmdWithArgs += " --service"; - newService = CreateService( + if (pConfigFileName != NULL) + { + cmdWithArgs += " \""; + cmdWithArgs += pConfigFileName; + cmdWithArgs += "\""; + } + + SC_HANDLE newService = CreateService( scm, SERVICE_NAME, "Box Backup", @@ -212,13 +236,45 @@ int InstallService(const char* pConfigFileName) SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - cmd_args, + cmdWithArgs.c_str(), 0,0,0,0,0); + DWORD err = GetLastError(); + CloseServiceHandle(scm); + if (!newService) { - ::syslog(LOG_ERR, "Failed to create Box Backup service: " - "error %d", GetLastError()); + switch (err) + { + case ERROR_SERVICE_EXISTS: + { + ::syslog(LOG_ERR, "Failed to create Box Backup " + "service: it already exists"); + } + break; + + case ERROR_SERVICE_MARKED_FOR_DELETE: + { + ::syslog(LOG_ERR, "Failed to create Box Backup " + "service: it is waiting to be deleted"); + } + break; + + case ERROR_DUPLICATE_SERVICE_NAME: + { + ::syslog(LOG_ERR, "Failed to create Box Backup " + "service: a service with this name " + "already exists"); + } + break; + + default: + { + ::syslog(LOG_ERR, "Failed to create Box Backup " + "service: error %d", err); + } + } + return 1; } @@ -235,7 +291,6 @@ int InstallService(const char* pConfigFileName) } CloseServiceHandle(newService); - CloseServiceHandle(scm); return 0; } -- cgit v1.2.3 From 432985db4c66b30874af49af456eba5189aa25db Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 17:45:36 +0000 Subject: * bbackupd/Win32BackupService.cpp - Revert to trunk --- bin/bbackupd/Win32BackupService.cpp | 47 ++++++++++++++----------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/bin/bbackupd/Win32BackupService.cpp b/bin/bbackupd/Win32BackupService.cpp index 7cbf4828..aa3bf55c 100644 --- a/bin/bbackupd/Win32BackupService.cpp +++ b/bin/bbackupd/Win32BackupService.cpp @@ -12,51 +12,40 @@ #include "Win32BackupService.h" -Win32BackupService* gpDaemonService = NULL; +Win32BackupService gDaemonService; extern HANDLE gStopServiceEvent; unsigned int WINAPI RunService(LPVOID lpParameter) { - DWORD retVal = gpDaemonService->WinService((const char*) lpParameter); - SetEvent(gStopServiceEvent); + DWORD retVal = gDaemonService.WinService(); + SetEvent( gStopServiceEvent ); return retVal; } void TerminateService(void) { - gpDaemonService->SetTerminateWanted(); + gDaemonService.SetTerminateWanted(); } -DWORD Win32BackupService::WinService(const char* pConfigFileName) +DWORD Win32BackupService::WinService(void) { - char exepath[MAX_PATH]; - GetModuleFileName(NULL, exepath, sizeof(exepath)); - - std::string configfile; + int argc = 2; + //first off get the path name for the default + char buf[MAX_PATH]; - if (pConfigFileName != NULL) - { - configfile = pConfigFileName; - } - else - { - // make the default config file name, - // based on the program path - configfile = exepath; - configfile = configfile.substr(0, - configfile.rfind(DIRECTORY_SEPARATOR_ASCHAR)); - configfile += DIRECTORY_SEPARATOR "bbackupd.conf"; - } - - const char *argv[] = {exepath, "-c", configfile.c_str()}; - int argc = sizeof(argv) / sizeof(*argv); - DWORD ret; + GetModuleFileName(NULL, buf, sizeof(buf)); + std::string buffer(buf); + std::string conf( "-c"); + std::string cfile(buffer.substr(0,(buffer.find("bbackupd.exe"))) + + "bbackupd.conf"); + + const char *argv[] = {conf.c_str(), cfile.c_str()}; MAINHELPER_START - ret = this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); - MAINHELPER_END - return ret; + return this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); + + MAINHELPER_END } #endif // WIN32 -- cgit v1.2.3 From 753960ecd7f89708431fee9565d2d6fd3235e710 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 17:51:00 +0000 Subject: * bin/bbackupd/Win32BackupService.cpp - Made RunService() pass the configuration file name to Win32BackupService::WinService() - Made WinService() calculate the default configuration file name more sanely and safely - Made WinService() not return before MAINHELPER_END --- bin/bbackupd/Win32BackupService.cpp | 43 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/bin/bbackupd/Win32BackupService.cpp b/bin/bbackupd/Win32BackupService.cpp index aa3bf55c..2f9c1583 100644 --- a/bin/bbackupd/Win32BackupService.cpp +++ b/bin/bbackupd/Win32BackupService.cpp @@ -17,8 +17,8 @@ extern HANDLE gStopServiceEvent; unsigned int WINAPI RunService(LPVOID lpParameter) { - DWORD retVal = gDaemonService.WinService(); - SetEvent( gStopServiceEvent ); + DWORD retVal = gDaemonService.WinService((const char*) lpParameter); + SetEvent(gStopServiceEvent); return retVal; } @@ -27,25 +27,36 @@ void TerminateService(void) gDaemonService.SetTerminateWanted(); } -DWORD Win32BackupService::WinService(void) +DWORD Win32BackupService::WinService(const char* pConfigFileName) { - int argc = 2; - //first off get the path name for the default - char buf[MAX_PATH]; - - GetModuleFileName(NULL, buf, sizeof(buf)); - std::string buffer(buf); - std::string conf( "-c"); - std::string cfile(buffer.substr(0,(buffer.find("bbackupd.exe"))) - + "bbackupd.conf"); + char exepath[MAX_PATH]; + GetModuleFileName(NULL, exepath, sizeof(exepath)); - const char *argv[] = {conf.c_str(), cfile.c_str()}; + std::string configfile; + + if (pConfigFileName != NULL) + { + configfile = pConfigFileName; + } + else + { + // make the default config file name, + // based on the program path + configfile = exepath; + configfile = configfile.substr(0, + configfile.rfind(DIRECTORY_SEPARATOR_ASCHAR)); + configfile += DIRECTORY_SEPARATOR "bbackupd.conf"; + } + + const char *argv[] = {exepath, "-c", configfile.c_str()}; + int argc = sizeof(argv) / sizeof(*argv); + DWORD ret; MAINHELPER_START - - return this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); - + ret = this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); MAINHELPER_END + + return ret; } #endif // WIN32 -- cgit v1.2.3 From e7103096b1b6c9f0e90dd0c884d81957c9d7bec3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 17:53:34 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Reverted to trunk --- bin/bbackupd/BackupDaemon.cpp | 282 ++++++++++++------------------------------ 1 file changed, 79 insertions(+), 203 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index e2d7c5e7..ebf5a1ea 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -125,29 +125,6 @@ BackupDaemon::BackupDaemon() } #ifdef WIN32 - // Create the event object to signal from main thread to worker - // when new messages are queued to be sent to the command socket. - mhMessageToSendEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (mhMessageToSendEvent == INVALID_HANDLE_VALUE) - { - syslog(LOG_ERR, "Failed to create event object: error %d", - GetLastError); - exit(1); - } - - // Create the event object to signal from worker to main thread - // when a command has been received on the command socket. - mhCommandReceivedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (mhCommandReceivedEvent == INVALID_HANDLE_VALUE) - { - syslog(LOG_ERR, "Failed to create event object: error %d", - GetLastError); - exit(1); - } - - // Create the critical section to protect the message queue - InitializeCriticalSection(&mMessageQueueLock); - // Create a thread to handle the named pipe HANDLE hThread; unsigned int dwThreadId; @@ -286,34 +263,15 @@ void BackupDaemon::DeleteAllLocations() void BackupDaemon::RunHelperThread(void) { mpCommandSocketInfo = new CommandSocketInfo; - WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); + this->mReceivedCommandConn = false; // loop until the parent process exits - while (!IsTerminateWanted()) + while (TRUE) { try { - rSocket.Accept(BOX_NAMED_PIPE_NAME); - } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to open command socket: %s", - e.what()); - SetTerminateWanted(); - break; // this is fatal - } - catch (...) - { - ::syslog(LOG_ERR, "Failed to open command socket: " - "unknown error"); - SetTerminateWanted(); - break; // this is fatal - } - - try - { - // Errors here do not kill the thread, - // only the current connection. + mpCommandSocketInfo->mListeningSocket.Accept( + BOX_NAMED_PIPE_NAME); // This next section comes from Ben's original function // Log @@ -331,72 +289,17 @@ void BackupDaemon::RunHelperThread(void) conf.GetKeyValueInt("MaxUploadWait"), mState); - rSocket.Write(summary, summarySize); - rSocket.Write("ping\n", 5); - - // old queued messages are not useful - EnterCriticalSection(&mMessageQueueLock); - mMessageList.clear(); - ResetEvent(mhMessageToSendEvent); - LeaveCriticalSection(&mMessageQueueLock); + mpCommandSocketInfo->mListeningSocket.Write(summary, summarySize); + mpCommandSocketInfo->mListeningSocket.Write("ping\n", 5); - IOStreamGetLine readLine(rSocket); + IOStreamGetLine readLine(mpCommandSocketInfo->mListeningSocket); std::string command; - while (rSocket.IsConnected() && !IsTerminateWanted()) + while (mpCommandSocketInfo->mListeningSocket.IsConnected() && + readLine.GetLine(command) ) { - HANDLE handles[2]; - handles[0] = mhMessageToSendEvent; - handles[1] = rSocket.GetReadableEvent(); - - DWORD result = WaitForMultipleObjects( - sizeof(handles)/sizeof(*handles), - handles, FALSE, 1000); - - if (result == 0) - { - ResetEvent(mhMessageToSendEvent); - - EnterCriticalSection(&mMessageQueueLock); - try - { - while (mMessageList.size() > 0) - { - std::string message = *(mMessageList.begin()); - mMessageList.erase(mMessageList.begin()); - printf("Sending '%s' to waiting client... ", message.c_str()); - message += "\n"; - rSocket.Write(message.c_str(), - message.length()); - - printf("done.\n"); - } - } - catch (...) - { - LeaveCriticalSection(&mMessageQueueLock); - throw; - } - LeaveCriticalSection(&mMessageQueueLock); - continue; - } - else if (result == WAIT_TIMEOUT) - { - continue; - } - else if (result != 1) - { - ::syslog(LOG_ERR, "WaitForMultipleObjects returned invalid result %d", result); - continue; - } - - if (!readLine.GetLine(command)) - { - ::syslog(LOG_ERR, "Failed to read line"); - continue; - } - - printf("Received command '%s' from client\n", command.c_str()); + TRACE1("Receiving command '%s' over " + "command socket\n", command.c_str()); bool sendOK = false; bool sendResponse = true; @@ -435,18 +338,12 @@ void BackupDaemon::RunHelperThread(void) SetTerminateWanted(); sendOK = true; } - else - { - ::syslog(LOG_ERR, "Received unknown command '%s' from client", command.c_str()); - sendResponse = true; - sendOK = false; - } // Send a response back? if (sendResponse) { const char* response = sendOK ? "ok\n" : "error\n"; - rSocket.Write( + mpCommandSocketInfo->mListeningSocket.Write( response, strlen(response)); } @@ -455,10 +352,10 @@ void BackupDaemon::RunHelperThread(void) break; } - // this->mReceivedCommandConn = true; + this->mReceivedCommandConn = true; } - rSocket.Close(); + mpCommandSocketInfo->mListeningSocket.Close(); } catch (BoxException &e) { @@ -607,8 +504,8 @@ void BackupDaemon::Run2() BackupClientContext::ClientStoreMarker_NotKnown; // haven't contacted the store yet - bool deleteStoreObjectInfoFile = DeserializeStoreObjectInfo( - clientStoreMarker, lastSyncTime, nextSyncTime); + bool deserialised = DeserializeStoreObjectInfo(clientStoreMarker, + lastSyncTime, nextSyncTime); // -------------------------------------------------------------------------------------------- @@ -714,8 +611,7 @@ void BackupDaemon::Run2() // Delete the serialised store object file, // so that we don't try to reload it after a // partially completed backup - if(deleteStoreObjectInfoFile && - !DeleteStoreObjectInfo()) + if(deserialised && !DeleteStoreObjectInfo()) { ::syslog(LOG_ERR, "Failed to delete the " "StoreObjectInfoFile, backup cannot " @@ -725,11 +621,6 @@ void BackupDaemon::Run2() ::sleep(60); continue; } - - // In case the backup throws an exception, - // we should not try to delete the store info - // object file again. - deleteStoreObjectInfoFile = false; // Do sync bool errorOccurred = false; @@ -838,14 +729,8 @@ void BackupDaemon::Run2() // -------------------------------------------------------------------------------------------- - // We had a successful backup, save the store - // info. If we save successfully, we must - // delete the file next time we start a backup - - deleteStoreObjectInfoFile = - SerializeStoreObjectInfo( - clientStoreMarker, - lastSyncTime, nextSyncTime); + // We had a successful backup, save the store info + SerializeStoreObjectInfo(clientStoreMarker, lastSyncTime, nextSyncTime); // -------------------------------------------------------------------------------------------- } @@ -1017,27 +902,25 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut) { #ifdef WIN32 - DWORD requiredDelayMs = BoxTimeToMilliSeconds(RequiredDelay); - - DWORD result = WaitForSingleObject(mhCommandReceivedEvent, - (DWORD)requiredDelayMs); + // Really could use some interprocess protection, mutex etc + // any side effect should be too bad???? :) + DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay); - if (result == WAIT_OBJECT_0) - { - DoSyncFlagOut = this->mDoSyncFlagOut; - SyncIsForcedOut = this->mSyncIsForcedOut; - ResetEvent(mhCommandReceivedEvent); - } - else if (result == WAIT_TIMEOUT) + while ( this->mReceivedCommandConn == false ) { - DoSyncFlagOut = false; - SyncIsForcedOut = false; - } - else - { - ::syslog(LOG_ERR, "Unexpected result from " - "WaitForSingleObject: error %d", GetLastError()); + Sleep(1); + + if ( timeout == 0 ) + { + DoSyncFlagOut = false; + SyncIsForcedOut = false; + return; + } + timeout--; } + this->mReceivedCommandConn = false; + DoSyncFlagOut = this->mDoSyncFlagOut; + SyncIsForcedOut = this->mSyncIsForcedOut; return; #else // ! WIN32 @@ -1070,7 +953,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla { #ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET bool uidOK = true; - ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credentials of peers connecting to the command socket. (bbackupctl)"); + ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)"); #else // Security check -- does the process connecting to this socket have // the same UID as this process? @@ -1140,13 +1023,8 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla while(mpCommandSocketInfo->mpGetLine != 0 && !mpCommandSocketInfo->mpGetLine->IsEOF() && mpCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout)) { - TRACE1("Receiving command '%s' over command socket\n", - command.c_str()); - - #ifdef WIN32 - SetEvent(mhCommandReceivedEvent); - #endif - + TRACE1("Receiving command '%s' over command socket\n", command.c_str()); + bool sendOK = false; bool sendResponse = true; @@ -1259,8 +1137,12 @@ void BackupDaemon::CloseCommandConnection() // -------------------------------------------------------------------------- void BackupDaemon::SendSyncStartOrFinish(bool SendStart) { - // The bbackupctl program can't rely on a state change, because it - // may never change if the server doesn't need to be contacted. + // The bbackupctl program can't rely on a state change, because it may never + // change if the server doesn't need to be contacted. + +#ifdef __MINGW32__ +#warning race condition: what happens if socket is closed? +#endif if (mpCommandSocketInfo != NULL && #ifdef WIN32 @@ -1270,18 +1152,15 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) #endif ) { - std::string message = SendStart ? "start-sync" : "finish-sync"; + const char* message = SendStart ? "start-sync\n" : "finish-sync\n"; try { #ifdef WIN32 - EnterCriticalSection(&mMessageQueueLock); - mMessageList.push_back(message); - SetEvent(mhMessageToSendEvent); - LeaveCriticalSection(&mMessageQueueLock); + mpCommandSocketInfo->mListeningSocket.Write(message, + (int)strlen(message)); #else - message += "\n"; - mpCommandSocketInfo->mpConnectedSocket->Write( - message.c_str(), message.size()); + mpCommandSocketInfo->mpConnectedSocket->Write(message, + strlen(message)); #endif } catch(...) @@ -1877,36 +1756,39 @@ void BackupDaemon::SetState(int State) // command socket if there's an error char newState[64]; - sprintf(newState, "state %d", State); - std::string message = newState; + char newStateSize = sprintf(newState, "state %d\n", State); #ifdef WIN32 - EnterCriticalSection(&mMessageQueueLock); - mMessageList.push_back(newState); - SetEvent(mhMessageToSendEvent); - LeaveCriticalSection(&mMessageQueueLock); -#else - message += "\n"; - - if(mpCommandSocketInfo == 0) - { - return; - } + #ifndef _MSC_VER + #warning FIX ME: race condition + #endif - if (mpCommandSocketInfo->mpConnectedSocket.get() == 0) + // what happens if the socket is closed by the other thread before + // we can write to it? Null pointer deref at best. + if (mpCommandSocketInfo && + mpCommandSocketInfo->mListeningSocket.IsConnected()) { - return; - } - - // Something connected to the command socket, tell it about the new state - try - { - mpCommandSocketInfo->mpConnectedSocket->Write(message.c_str(), - message.length()); + try + { + mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize); + } + catch(...) + { + CloseCommandConnection(); + } } - catch(...) +#else + if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0) { - CloseCommandConnection(); + // Something connected to the command socket, tell it about the new state + try + { + mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize); + } + catch(...) + { + CloseCommandConnection(); + } } #endif } @@ -2291,11 +2173,11 @@ static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F; static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE"; static const int STOREOBJECTINFO_VERSION = 1; -bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const +void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const { if(!GetConfiguration().KeyExists("StoreObjectInfoFile")) { - return false; + return; } std::string StoreObjectInfoFile = @@ -2303,17 +2185,13 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time if (StoreObjectInfoFile.size() <= 0) { - return false; + return; } - bool created = false; - try { FileStream aFile(StoreObjectInfoFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC); - created = true; - Archive anArchive(aFile, 0); anArchive.Write(STOREOBJECTINFO_MAGIC_ID_VALUE); @@ -2358,8 +2236,6 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time "not accessible or could not be created", StoreObjectInfoFile.c_str()); } - - return created; } // -------------------------------------------------------------------------- -- cgit v1.2.3 From 290a15db219034d057f3428e2dcefb724a4b8b8c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 17:55:23 +0000 Subject: * bin/bbackupd/BackupDaemon.h - Revert to trunk --- bin/bbackupd/BackupDaemon.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 94a142f5..3bd15fad 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -46,12 +46,9 @@ public: ~BackupDaemon(); private: - // methods below do partial (specialized) serialization of - // client state only - bool SerializeStoreObjectInfo(int64_t aClientStoreMarker, - box_time_t theLastSyncTime, box_time_t theNextSyncTime) const; - bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, - box_time_t & theLastSyncTime, box_time_t & theNextSyncTime); + // methods below do partial (specialized) serialization of client state only + void SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const; + bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime); bool DeleteStoreObjectInfo() const; BackupDaemon(const BackupDaemon &); public: @@ -185,10 +182,7 @@ private: void RunHelperThread(void); private: - bool mDoSyncFlagOut, mSyncIsForcedOut; - HANDLE mhMessageToSendEvent, mhCommandReceivedEvent; - CRITICAL_SECTION mMessageQueueLock; - std::vector mMessageList; + bool mDoSyncFlagOut, mSyncIsForcedOut, mReceivedCommandConn; #endif }; -- cgit v1.2.3 From d2c12caedda424456bf8f47ce385822d744eeede Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 17:59:53 +0000 Subject: * bbackupd/BackupDaemon.h * bbackupd/BackupDaemon.cpp - Made SerializeStoreObjectInfo() return a boolean, true if it successfully saved the store object info file, false otherwise. --- bin/bbackupd/BackupDaemon.cpp | 12 +++++++++--- bin/bbackupd/BackupDaemon.h | 9 ++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index ebf5a1ea..8d6f9ee3 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -2173,11 +2173,11 @@ static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F; static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE"; static const int STOREOBJECTINFO_VERSION = 1; -void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const +bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const { if(!GetConfiguration().KeyExists("StoreObjectInfoFile")) { - return; + return false; } std::string StoreObjectInfoFile = @@ -2185,13 +2185,17 @@ void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time if (StoreObjectInfoFile.size() <= 0) { - return; + return false; } + bool created = false; + try { FileStream aFile(StoreObjectInfoFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC); + created = true; + Archive anArchive(aFile, 0); anArchive.Write(STOREOBJECTINFO_MAGIC_ID_VALUE); @@ -2236,6 +2240,8 @@ void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time "not accessible or could not be created", StoreObjectInfoFile.c_str()); } + + return created; } // -------------------------------------------------------------------------- diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 3bd15fad..347c205b 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -46,9 +46,12 @@ public: ~BackupDaemon(); private: - // methods below do partial (specialized) serialization of client state only - void SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const; - bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime); + // methods below do partial (specialized) serialization of + // client state only + bool SerializeStoreObjectInfo(int64_t aClientStoreMarker, + box_time_t theLastSyncTime, box_time_t theNextSyncTime) const; + bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, + box_time_t & theLastSyncTime, box_time_t & theNextSyncTime); bool DeleteStoreObjectInfo() const; BackupDaemon(const BackupDaemon &); public: -- cgit v1.2.3 From 275ac0cf61a56b87cabe4441d9a54445e542a041 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 18:16:21 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Use the result of SerializeStoreObjectInfo, if we failed to serialise (when no file existed) then no need to delete the file on the next run. --- bin/bbackupd/BackupDaemon.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 8d6f9ee3..7ba683b0 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -504,8 +504,8 @@ void BackupDaemon::Run2() BackupClientContext::ClientStoreMarker_NotKnown; // haven't contacted the store yet - bool deserialised = DeserializeStoreObjectInfo(clientStoreMarker, - lastSyncTime, nextSyncTime); + bool deleteStoreObjectInfoFile = DeserializeStoreObjectInfo( + clientStoreMarker, lastSyncTime, nextSyncTime); // -------------------------------------------------------------------------------------------- @@ -611,7 +611,8 @@ void BackupDaemon::Run2() // Delete the serialised store object file, // so that we don't try to reload it after a // partially completed backup - if(deserialised && !DeleteStoreObjectInfo()) + if(deleteStoreObjectInfoFile && + !DeleteStoreObjectInfo()) { ::syslog(LOG_ERR, "Failed to delete the " "StoreObjectInfoFile, backup cannot " @@ -621,6 +622,11 @@ void BackupDaemon::Run2() ::sleep(60); continue; } + + // In case the backup throws an exception, + // we should not try to delete the store info + // object file again. + deleteStoreObjectInfoFile = false; // Do sync bool errorOccurred = false; @@ -729,8 +735,14 @@ void BackupDaemon::Run2() // -------------------------------------------------------------------------------------------- - // We had a successful backup, save the store info - SerializeStoreObjectInfo(clientStoreMarker, lastSyncTime, nextSyncTime); + // We had a successful backup, save the store + // info. If we save successfully, we must + // delete the file next time we start a backup + + deleteStoreObjectInfoFile = + SerializeStoreObjectInfo( + clientStoreMarker, + lastSyncTime, nextSyncTime); // -------------------------------------------------------------------------------------------- } -- cgit v1.2.3 From 1c113f8281baadb593f818f4f12b33c50156d735 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 18:17:36 +0000 Subject: * bbackupd/BackupDaemon.cpp - Cosmetic spelling and formatting fixes --- bin/bbackupd/BackupDaemon.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 7ba683b0..35e5b7b4 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -965,7 +965,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla { #ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET bool uidOK = true; - ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)"); + ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credentials of peers connecting to the command socket. (bbackupctl)"); #else // Security check -- does the process connecting to this socket have // the same UID as this process? @@ -1149,8 +1149,8 @@ void BackupDaemon::CloseCommandConnection() // -------------------------------------------------------------------------- void BackupDaemon::SendSyncStartOrFinish(bool SendStart) { - // The bbackupctl program can't rely on a state change, because it may never - // change if the server doesn't need to be contacted. + // The bbackupctl program can't rely on a state change, because it + // may never change if the server doesn't need to be contacted. #ifdef __MINGW32__ #warning race condition: what happens if socket is closed? -- cgit v1.2.3 From e64b25d653697eb05ef506d27dc233332e7e36f8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 18:28:35 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Made the code more readable by defining a reference rSocket to mpCommandSocketInfo->mListeningSocket which is used several times. - Terminate the listening thread if it fails to bind a command socket. - Log any unrecognised commands received over the command socket. --- bin/bbackupd/BackupDaemon.cpp | 53 ++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 35e5b7b4..db19a6ff 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -263,15 +263,35 @@ void BackupDaemon::DeleteAllLocations() void BackupDaemon::RunHelperThread(void) { mpCommandSocketInfo = new CommandSocketInfo; - this->mReceivedCommandConn = false; + WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); - // loop until the parent process exits - while (TRUE) + // loop until the parent process exits, or we decide + // to kill the thread ourselves + while (!IsTerminateWanted()) { try { - mpCommandSocketInfo->mListeningSocket.Accept( - BOX_NAMED_PIPE_NAME); + rSocket.Accept(BOX_NAMED_PIPE_NAME); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to open command socket: %s", + e.what()); + SetTerminateWanted(); + break; // this is fatal to listening thread + } + catch (...) + { + ::syslog(LOG_ERR, "Failed to open command socket: " + "unknown error"); + SetTerminateWanted(); + break; // this is fatal to listening thread + } + + try + { + // Errors here do not kill the thread, + // only the current connection. // This next section comes from Ben's original function // Log @@ -289,16 +309,17 @@ void BackupDaemon::RunHelperThread(void) conf.GetKeyValueInt("MaxUploadWait"), mState); - mpCommandSocketInfo->mListeningSocket.Write(summary, summarySize); - mpCommandSocketInfo->mListeningSocket.Write("ping\n", 5); + rSocket.Write(summary, summarySize); + rSocket.Write("ping\n", 5); - IOStreamGetLine readLine(mpCommandSocketInfo->mListeningSocket); + IOStreamGetLine readLine(rSocket); std::string command; - while (mpCommandSocketInfo->mListeningSocket.IsConnected() && - readLine.GetLine(command) ) + while (rSocket.IsConnected() && + readLine.GetLine(command) && + !IsTerminateWanted()) { - TRACE1("Receiving command '%s' over " + TRACE1("Received command '%s' over " "command socket\n", command.c_str()); bool sendOK = false; @@ -338,12 +359,18 @@ void BackupDaemon::RunHelperThread(void) SetTerminateWanted(); sendOK = true; } + else + { + ::syslog(LOG_ERR, "Received unknown command '%s' from client", command.c_str()); + sendResponse = true; + sendOK = false; + } // Send a response back? if (sendResponse) { const char* response = sendOK ? "ok\n" : "error\n"; - mpCommandSocketInfo->mListeningSocket.Write( + rSocket.Write( response, strlen(response)); } @@ -355,7 +382,7 @@ void BackupDaemon::RunHelperThread(void) this->mReceivedCommandConn = true; } - mpCommandSocketInfo->mListeningSocket.Close(); + rSocket.Close(); } catch (BoxException &e) { -- cgit v1.2.3 From d36cf5c650533abc3d940dde160ee1a0c529876d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 18:36:54 +0000 Subject: * lib/win32/WinNamedPipeStream.h * lib/win32/WinNamedPipeStream.cpp * lib/server/WinNamedPipeStream.h * lib/server/WinNamedPipeStream.cpp - Moved WinNamedPipeStream class from lib/win32 to lib/server, to resolve circular dependency between lib/common and lib/win32. --- lib/server/WinNamedPipeStream.cpp | 312 ++++++++++++++++++++++++++++++++++++++ lib/server/WinNamedPipeStream.h | 60 ++++++++ lib/win32/WinNamedPipeStream.cpp | 312 -------------------------------------- lib/win32/WinNamedPipeStream.h | 60 -------- 4 files changed, 372 insertions(+), 372 deletions(-) create mode 100644 lib/server/WinNamedPipeStream.cpp create mode 100644 lib/server/WinNamedPipeStream.h delete mode 100644 lib/win32/WinNamedPipeStream.cpp delete mode 100644 lib/win32/WinNamedPipeStream.h diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp new file mode 100644 index 00000000..c5b7eaa5 --- /dev/null +++ b/lib/server/WinNamedPipeStream.cpp @@ -0,0 +1,312 @@ +// -------------------------------------------------------------------------- +// +// 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 +#endif + +#include +#include +#include + +#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/server/WinNamedPipeStream.h b/lib/server/WinNamedPipeStream.h new file mode 100644 index 00000000..5a800371 --- /dev/null +++ b/lib/server/WinNamedPipeStream.h @@ -0,0 +1,60 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: WinNamedPipeStream.h +// Purpose: I/O stream interface for Win32 named pipes +// Created: 2005/12/07 +// +// -------------------------------------------------------------------------- + +#if ! defined WINNAMEDPIPESTREAM__H && defined WIN32 +#define WINNAMEDPIPESTREAM__H + +#include "IOStream.h" + +// -------------------------------------------------------------------------- +// +// Class +// Name: WinNamedPipeStream +// Purpose: I/O stream interface for Win32 named pipes +// Created: 2003/07/31 +// +// -------------------------------------------------------------------------- +class WinNamedPipeStream : public IOStream +{ +public: + WinNamedPipeStream(); + ~WinNamedPipeStream(); + + // server side - create the named pipe and listen for connections + void Accept(const wchar_t* Name); + + // client side - connect to a waiting server + void Connect(const wchar_t* Name); + + // both sides + virtual int Read(void *pBuffer, int NBytes, + int Timeout = IOStream::TimeOutInfinite); + virtual void Write(const void *pBuffer, int NBytes); + virtual void Close(); + virtual bool StreamDataLeft(); + virtual bool StreamClosed(); + bool IsConnected() { return mIsConnected; } + +protected: + HANDLE GetSocketHandle(); + void MarkAsReadClosed() {mReadClosed = true;} + void MarkAsWriteClosed() {mWriteClosed = true;} + +private: + WinNamedPipeStream(const WinNamedPipeStream &rToCopy) + { /* do not call */ } + + HANDLE mSocketHandle; + bool mReadClosed; + bool mWriteClosed; + bool mIsServer; + bool mIsConnected; +}; + +#endif // WINNAMEDPIPESTREAM__H diff --git a/lib/win32/WinNamedPipeStream.cpp b/lib/win32/WinNamedPipeStream.cpp deleted file mode 100644 index c5b7eaa5..00000000 --- a/lib/win32/WinNamedPipeStream.cpp +++ /dev/null @@ -1,312 +0,0 @@ -// -------------------------------------------------------------------------- -// -// 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 -#endif - -#include -#include -#include - -#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/WinNamedPipeStream.h b/lib/win32/WinNamedPipeStream.h deleted file mode 100644 index 5a800371..00000000 --- a/lib/win32/WinNamedPipeStream.h +++ /dev/null @@ -1,60 +0,0 @@ -// -------------------------------------------------------------------------- -// -// File -// Name: WinNamedPipeStream.h -// Purpose: I/O stream interface for Win32 named pipes -// Created: 2005/12/07 -// -// -------------------------------------------------------------------------- - -#if ! defined WINNAMEDPIPESTREAM__H && defined WIN32 -#define WINNAMEDPIPESTREAM__H - -#include "IOStream.h" - -// -------------------------------------------------------------------------- -// -// Class -// Name: WinNamedPipeStream -// Purpose: I/O stream interface for Win32 named pipes -// Created: 2003/07/31 -// -// -------------------------------------------------------------------------- -class WinNamedPipeStream : public IOStream -{ -public: - WinNamedPipeStream(); - ~WinNamedPipeStream(); - - // server side - create the named pipe and listen for connections - void Accept(const wchar_t* Name); - - // client side - connect to a waiting server - void Connect(const wchar_t* Name); - - // both sides - virtual int Read(void *pBuffer, int NBytes, - int Timeout = IOStream::TimeOutInfinite); - virtual void Write(const void *pBuffer, int NBytes); - virtual void Close(); - virtual bool StreamDataLeft(); - virtual bool StreamClosed(); - bool IsConnected() { return mIsConnected; } - -protected: - HANDLE GetSocketHandle(); - void MarkAsReadClosed() {mReadClosed = true;} - void MarkAsWriteClosed() {mWriteClosed = true;} - -private: - WinNamedPipeStream(const WinNamedPipeStream &rToCopy) - { /* do not call */ } - - HANDLE mSocketHandle; - bool mReadClosed; - bool mWriteClosed; - bool mIsServer; - bool mIsConnected; -}; - -#endif // WINNAMEDPIPESTREAM__H -- cgit v1.2.3 From 298e354911fad55469a99c254cf8fc47be77d580 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 18:50:19 +0000 Subject: * bin/bbackupquery/BackupQueries.cpp - Revert to trunk --- bin/bbackupquery/BackupQueries.cpp | 168 ++++++++----------------------------- 1 file changed, 37 insertions(+), 131 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 05e34b7e..1e792bdc 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -70,11 +70,7 @@ BackupQueries::BackupQueries(BackupProtocolClient &rConnection, const Configurat mWarnedAboutOwnerAttributes(false), mReturnCode(0) // default return code { - #ifdef WIN32 - mRunningAsRoot = TRUE; - #else mRunningAsRoot = (::geteuid() == 0); - #endif } // -------------------------------------------------------------------------- @@ -89,12 +85,6 @@ BackupQueries::~BackupQueries() { } -typedef struct cmd_info -{ - const char* name; - const char* opts; -} cmd_info_t; - // -------------------------------------------------------------------------- // // Function @@ -172,24 +162,8 @@ void BackupQueries::DoCommand(const char *Command) } // Data about commands - static cmd_info_t commands[] = - { - { "quit", "" }, - { "exit", "" }, - { "list", "rodIFtTsh", }, - { "pwd", "" }, - { "cd", "od" }, - { "lcd", "" }, - { "sh", "" }, - { "getobject", "" }, - { "get", "i" }, - { "compare", "alcqAE" }, - { "restore", "dri" }, - { "help", "" }, - { "usage", "" }, - { "undelete", "" }, - { NULL, NULL } - }; + static const char *commandNames[] = {"quit", "exit", "list", "pwd", "cd", "lcd", "sh", "getobject", "get", "compare", "restore", "help", "usage", "undelete", 0}; + static const char *validOptions[] = {"", "", "rodIFtsh", "", "od", "", "", "", "i", "alcqE", "dri", "", "", "", 0}; #define COMMAND_Quit 0 #define COMMAND_Exit 1 #define COMMAND_List 2 @@ -209,11 +183,11 @@ void BackupQueries::DoCommand(const char *Command) // Work out which command it is... int cmd = 0; - while(commands[cmd].name != 0 && ::strcmp(cmdElements[0].c_str(), commands[cmd].name) != 0) + while(commandNames[cmd] != 0 && ::strcmp(cmdElements[0].c_str(), commandNames[cmd]) != 0) { cmd++; } - if(commands[cmd].name == 0) + if(commandNames[cmd] == 0) { // Check for aliases int a; @@ -248,10 +222,9 @@ void BackupQueries::DoCommand(const char *Command) while(*c != 0) { // Valid option? - if(::strchr(commands[cmd].opts, *c) == NULL) + if(::strchr(validOptions[cmd], *c) == NULL) { - printf("Invalid option '%c' for command %s\n", - *c, commands[cmd].name); + printf("Invalid option '%c' for command %s\n", *c, commandNames[cmd]); return; } opts[(int)*c] = true; @@ -346,9 +319,8 @@ void BackupQueries::CommandList(const std::vector &args, const bool #define LIST_OPTION_ALLOWOLD 'o' #define LIST_OPTION_ALLOWDELETED 'd' #define LIST_OPTION_NOOBJECTID 'I' - #define LIST_OPTION_NOFLAGS 'F' - #define LIST_OPTION_TIMES_LOCAL 't' - #define LIST_OPTION_TIMES_UTC 'T' + #define LIST_OPTION_NOFLAGS 'F' + #define LIST_OPTION_TIMES 't' #define LIST_OPTION_SIZEINBLOCKS 's' #define LIST_OPTION_DISPLAY_HASH 'h' @@ -390,7 +362,7 @@ void BackupQueries::CommandList(const std::vector &args, const bool // -------------------------------------------------------------------------- // // Function -// Name: BackupQueries::List(int64_t, const std::string &, const bool *, bool) +// Name: BackupQueries::List(int64_t, const std::string &, const bool *) // Purpose: Do the actual listing of directories and files // Created: 2003/10/10 // @@ -465,9 +437,9 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool } } - if(opts[LIST_OPTION_TIMES_LOCAL]) + if(opts[LIST_OPTION_TIMES]) { - // Show local times... + // Show times... std::string time = BoxTimeToISO8601String( en->GetModificationTime()); printf("%s ", time.c_str()); @@ -872,44 +844,13 @@ void BackupQueries::CommandGet(const std::vector &args, const bool } // Find object ID somehow - int64_t fileId; - int64_t dirId = GetCurrentDirectoryID(); + int64_t id; std::string localName; - // BLOCK { -#ifdef WIN32 - std::string fileName; - if(!ConvertConsoleToUtf8(args[0].c_str(), fileName)) - return; -#else - std::string fileName(args[0]); -#endif - - if(!opts['i']) - { - // does this remote filename include a path? - std::string::size_type index = fileName.rfind('/'); - if(index != std::string::npos) - { - std::string dirName(fileName.substr(0, index)); - fileName = fileName.substr(index + 1); - - dirId = FindDirectoryObjectID(dirName); - if(dirId == 0) - { - printf("Directory '%s' not found\n", - dirName.c_str()); - return; - } - } - } - - BackupStoreFilenameClear fn(fileName); - // Need to look it up in the current directory mrConnection.QueryListDirectory( - dirId, + GetCurrentDirectoryID(), BackupProtocolClientListDirectory::Flags_File, // just files (opts['i'])?(BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING):(BackupProtocolClientListDirectory::Flags_OldVersion | BackupProtocolClientListDirectory::Flags_Deleted), // only current versions false /* don't want attributes */); @@ -922,23 +863,17 @@ void BackupQueries::CommandGet(const std::vector &args, const bool if(opts['i']) { // Specified as ID. - fileId = ::strtoll(args[0].c_str(), 0, 16); - if(fileId == std::numeric_limits::min() || - fileId == std::numeric_limits::max() || - fileId == 0) + id = ::strtoll(args[0].c_str(), 0, 16); + if(id == std::numeric_limits::min() || id == std::numeric_limits::max() || id == 0) { printf("Not a valid object ID (specified in hex)\n"); return; } // Check that the item is actually in the directory - if(dir.FindEntryByID(fileId) == 0) + if(dir.FindEntryByID(id) == 0) { - printf("ID '%08llx' not found in current " - "directory on store.\n" - "(You can only download objects by ID " - "from the current directory.)\n", - fileId); + printf("ID '%08llx' not found in current directory on store.\n(You can only download objects by ID from the current directory.)\n", id); return; } @@ -949,22 +884,26 @@ void BackupQueries::CommandGet(const std::vector &args, const bool { // Specified by name, find the object in the directory to get the ID BackupStoreDirectory::Iterator i(dir); +#ifdef WIN32 + std::string fileName; + if(!ConvertConsoleToUtf8(args[0].c_str(), fileName)) + return; + BackupStoreFilenameClear fn(fileName); +#else + BackupStoreFilenameClear fn(args[0]); +#endif BackupStoreDirectory::Entry *en = i.FindMatchingClearName(fn); if(en == 0) { - printf("Filename '%s' not found in current " - "directory on store.\n" - "(Subdirectories in path not " - "searched.)\n", args[0].c_str()); + printf("Filename '%s' not found in current directory on store.\n(Subdirectories in path not searched.)\n", args[0].c_str()); return; } - fileId = en->GetObjectID(); + id = en->GetObjectID(); - // Local name is the last argument, which is either - // the looked up filename, or a filename specified - // by the user. + // Local name is the last argument, which is either the looked up filename, or + // a filename specified by the user. localName = args[args.size() - 1]; } } @@ -981,7 +920,7 @@ void BackupQueries::CommandGet(const std::vector &args, const bool try { // Request object - mrConnection.QueryGetFile(dirId, fileId); + mrConnection.QueryGetFile(GetCurrentDirectoryID(), id); // Stream containing encoded file std::auto_ptr objectStream(mrConnection.ReceiveStream()); @@ -990,7 +929,7 @@ void BackupQueries::CommandGet(const std::vector &args, const bool BackupStoreFile::DecodeFile(*objectStream, localName.c_str(), mrConnection.GetTimeout()); // Done. - printf("Object ID %08llx fetched sucessfully.\n", fileId); + printf("Object ID %08llx fetched sucessfully.\n", id); } catch(...) { @@ -1011,10 +950,8 @@ void BackupQueries::CommandGet(const std::vector &args, const bool BackupQueries::CompareParams::CompareParams() : mQuickCompare(false), mIgnoreExcludes(false), - mIgnoreAttributes(false), mDifferences(0), mDifferencesExplainedByModTime(0), - mUncheckedFiles(0), mExcludedDirs(0), mExcludedFiles(0), mpExcludeFiles(0), @@ -1075,7 +1012,6 @@ void BackupQueries::CommandCompare(const std::vector &args, const b BackupQueries::CompareParams params; params.mQuickCompare = opts['q']; params.mIgnoreExcludes = opts['E']; - params.mIgnoreAttributes = opts['A']; // Try and work out the time before which all files should be on the server { @@ -1138,29 +1074,13 @@ void BackupQueries::CommandCompare(const std::vector &args, const b return; } - printf("\n[ %d (of %d) differences probably due to file " - "modifications after the last upload ]\n" - "Differences: %d (%d dirs excluded, %d files excluded, " - "%d files not checked)\n", - params.mDifferencesExplainedByModTime, params.mDifferences, - params.mDifferences, params.mExcludedDirs, - params.mExcludedFiles, params.mUncheckedFiles); + printf("\n[ %d (of %d) differences probably due to file modifications after the last upload ]\nDifferences: %d (%d dirs excluded, %d files excluded)\n", + params.mDifferencesExplainedByModTime, params.mDifferences, params.mDifferences, params.mExcludedDirs, params.mExcludedFiles); // Set return code? if(opts['c']) { - if (params.mUncheckedFiles != 0) - { - SetReturnCode(COMPARE_RETURN_ERROR); - } - else if (params.mDifferences != 0) - { - SetReturnCode(COMPARE_RETURN_DIFFERENT); - } - else - { - SetReturnCode(COMPARE_RETURN_SAME); - } + SetReturnCode((params.mDifferences == 0)?COMPARE_RETURN_SAME:COMPARE_RETURN_DIFFERENT); } } @@ -1294,13 +1214,11 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s "(compared to server directory '%s')\n", localDirDisplay.c_str(), storeDirDisplay.c_str()); - rParams.mDifferences ++; } else { printf("ERROR: stat on local dir '%s'\n", localDirDisplay.c_str()); - rParams.mUncheckedFiles ++; } return; } @@ -1350,7 +1268,6 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s { printf("ERROR: opendir on local dir '%s'\n", localDirDisplay.c_str()); - rParams.mUncheckedFiles ++; return; } try @@ -1538,12 +1455,11 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s } // Compare attributes - box_time_t fileModTime = 0; BackupClientFileAttributes localAttr; + box_time_t fileModTime = 0; localAttr.ReadAttributes(localPath.c_str(), false /* don't zero mod times */, &fileModTime); modifiedAfterLastSync = (fileModTime > rParams.mLatestFileUploadTime); - if(!rParams.mIgnoreAttributes && - !localAttr.Compare(fileOnServerStream->GetAttributes(), + if(!localAttr.Compare(fileOnServerStream->GetAttributes(), true /* ignore attr mod time */, fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */)) { @@ -1638,12 +1554,10 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s e.GetType(), e.GetSubType(), storePathDisplay.c_str()); - rParams.mUncheckedFiles ++; } catch(...) - { + { printf("ERROR: (unknown) during file fetch and comparison for '%s'\n", storePathDisplay.c_str()); - rParams.mUncheckedFiles ++; } // Remove from set so that we know it's been compared @@ -1879,14 +1793,6 @@ void BackupQueries::CommandRestore(const std::vector &args, const b printf("The target directory exists. You cannot restore over an existing directory.\n"); break; - #ifdef WIN32 - case Restore_TargetPathNotFound: - printf("The target directory path does not exist.\n" - "To restore to a directory whose parent " - "does not exist, create the parent first.\n"); - break; - #endif - default: printf("ERROR: Unknown restore result.\n"); break; -- cgit v1.2.3 From 0837b4f6709789032d0704526edd1c62935f46f8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 18:50:58 +0000 Subject: * bbackupquery/BackupQueries.cpp - Don't call geteuid() on Windows, since it lies to us anyway --- bin/bbackupquery/BackupQueries.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 1e792bdc..9e868457 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -70,7 +70,11 @@ BackupQueries::BackupQueries(BackupProtocolClient &rConnection, const Configurat mWarnedAboutOwnerAttributes(false), mReturnCode(0) // default return code { + #ifdef WIN32 + mRunningAsRoot = TRUE; + #else mRunningAsRoot = (::geteuid() == 0); + #endif } // -------------------------------------------------------------------------- -- cgit v1.2.3 From 4be4f2e1dbcf548253cdab502636bc16b7b4c0b0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Aug 2006 18:53:34 +0000 Subject: * bin/bbackupquery/BackupQueries.cpp - Use a nicer data structure for commands and their options. --- bin/bbackupquery/BackupQueries.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 9e868457..4ca8afa0 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -89,6 +89,12 @@ BackupQueries::~BackupQueries() { } +typedef struct cmd_info +{ + const char* name; + const char* opts; +} cmd_info_t; + // -------------------------------------------------------------------------- // // Function @@ -166,8 +172,24 @@ void BackupQueries::DoCommand(const char *Command) } // Data about commands - static const char *commandNames[] = {"quit", "exit", "list", "pwd", "cd", "lcd", "sh", "getobject", "get", "compare", "restore", "help", "usage", "undelete", 0}; - static const char *validOptions[] = {"", "", "rodIFtsh", "", "od", "", "", "", "i", "alcqE", "dri", "", "", "", 0}; + static cmd_info_t commands[] = + { + { "quit", "" }, + { "exit", "" }, + { "list", "rodIFtTsh", }, + { "pwd", "" }, + { "cd", "od" }, + { "lcd", "" }, + { "sh", "" }, + { "getobject", "" }, + { "get", "i" }, + { "compare", "alcqAE" }, + { "restore", "dri" }, + { "help", "" }, + { "usage", "" }, + { "undelete", "" }, + { NULL, NULL } + }; #define COMMAND_Quit 0 #define COMMAND_Exit 1 #define COMMAND_List 2 @@ -187,11 +209,11 @@ void BackupQueries::DoCommand(const char *Command) // Work out which command it is... int cmd = 0; - while(commandNames[cmd] != 0 && ::strcmp(cmdElements[0].c_str(), commandNames[cmd]) != 0) + while(commands[cmd].name != 0 && ::strcmp(cmdElements[0].c_str(), commands[cmd].name) != 0) { cmd++; } - if(commandNames[cmd] == 0) + if(commands[cmd].name == 0) { // Check for aliases int a; @@ -226,9 +248,10 @@ void BackupQueries::DoCommand(const char *Command) while(*c != 0) { // Valid option? - if(::strchr(validOptions[cmd], *c) == NULL) + if(::strchr(commands[cmd].opts, *c) == NULL) { - printf("Invalid option '%c' for command %s\n", *c, commandNames[cmd]); + printf("Invalid option '%c' for command %s\n", + *c, commands[cmd].name); return; } opts[(int)*c] = true; -- cgit v1.2.3 From 506bd0c34fb1e35e019b799bfd5bcf788f9e9571 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 20 Aug 2006 00:29:23 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Restored initialisation of this->mReceivedCommandConn to false in handler thread. - Changed handling of all catch(...) blocks, which don't have an obvious outer exception handler, to catch std::exception first and report it with e.what(), as suggested by Martin. - Fixed some catch blocks to match coding standards. --- bin/bbackupd/BackupDaemon.cpp | 108 +++++++++++++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 18 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index db19a6ff..90c72a20 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -262,6 +262,7 @@ void BackupDaemon::DeleteAllLocations() #ifdef WIN32 void BackupDaemon::RunHelperThread(void) { + this->mReceivedCommandConn = false; mpCommandSocketInfo = new CommandSocketInfo; WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); @@ -273,14 +274,21 @@ void BackupDaemon::RunHelperThread(void) { rSocket.Accept(BOX_NAMED_PIPE_NAME); } - catch (BoxException &e) + catch(BoxException &e) { ::syslog(LOG_ERR, "Failed to open command socket: %s", e.what()); SetTerminateWanted(); break; // this is fatal to listening thread } - catch (...) + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to open command socket: " + "%s", e.what()); + SetTerminateWanted(); + break; // this is fatal to listening thread + } + catch(...) { ::syslog(LOG_ERR, "Failed to open command socket: " "unknown error"); @@ -384,12 +392,17 @@ void BackupDaemon::RunHelperThread(void) rSocket.Close(); } - catch (BoxException &e) + catch(BoxException &e) { ::syslog(LOG_ERR, "Communication error with " "control client: %s", e.what()); } - catch (...) + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error in command socket " + "thread: %s", e.what()); + } + catch(...) { ::syslog(LOG_ERR, "Communication error with control client"); } @@ -450,6 +463,12 @@ void BackupDaemon::Run() { delete mpCommandSocketInfo; } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error while " + "closing command socket after " + "another exception: %s", e.what()); + } catch(...) { ::syslog(LOG_WARNING, @@ -780,6 +799,12 @@ void BackupDaemon::Run2() errorCode = e.GetType(); errorSubCode = e.GetSubType(); } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error during " + "backup run: %s", e.what()); + errorOccurred = true; + } catch(...) { // TODO: better handling of exceptions here... need to be very careful @@ -911,6 +936,17 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() int status = 0; ::waitpid(pid, &status, 0); } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error running SyncAllowScript: " + "%s", e.what()); + // Clean up + if(pid != 0) + { + int status = 0; + ::waitpid(pid, &status, 0); + } + } catch(...) { // Ignore any exceptions @@ -1117,13 +1153,19 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla CloseCommandConnection(); } } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error in command socket thread: " + "%s", e.what()); + throw; // thread will die + } catch(...) { // If an error occurs, and there is a connection active, just close that // connection and continue. Otherwise, let the error propagate. if(mpCommandSocketInfo->mpConnectedSocket.get() == 0) { - throw; + throw; // thread will die } else { @@ -1157,6 +1199,11 @@ void BackupDaemon::CloseCommandConnection() } mpCommandSocketInfo->mpConnectedSocket.reset(); } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error while closing command " + "socket: %s", e.what()); + } catch(...) { // Ignore any errors @@ -1202,6 +1249,12 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) strlen(message)); #endif } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error while sending to " + "command socket client: %s", e.what()); + CloseCommandConnection(); + } catch(...) { CloseCommandConnection(); @@ -1311,7 +1364,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con } catch(...) { - ::endmntent(mountPointsFile); + ::endmntent(mountPointsFile); throw; } #else // ! HAVE_STRUCT_MNTENT_MNT_DIR @@ -1811,6 +1864,12 @@ void BackupDaemon::SetState(int State) { mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize); } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error while writing state " + "to command socket: %s", e.what()); + CloseCommandConnection(); + } catch(...) { CloseCommandConnection(); @@ -1824,6 +1883,12 @@ void BackupDaemon::SetState(int State) { mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize); } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error while writing state " + "to command socket: %s", e.what()); + CloseCommandConnection(); + } catch(...) { CloseCommandConnection(); @@ -2273,7 +2338,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time ::syslog(LOG_INFO, "Saved store object info file '%s'", StoreObjectInfoFile.c_str()); } - catch (...) + catch(...) { ::syslog(LOG_WARNING, "Requested store object info file '%s' " "not accessible or could not be created", @@ -2428,21 +2493,28 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ iVersion); return true; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error reading store object " + "info file: %s", e.what()); } - catch (...) + catch(...) { - DeleteAllLocations(); + ::syslog(LOG_ERR, "Internal error reading store object " + "info file: unknown error"); + } - aClientStoreMarker = - BackupClientContext::ClientStoreMarker_NotKnown; - theLastSyncTime = 0; - theNextSyncTime = 0; + DeleteAllLocations(); - ::syslog(LOG_WARNING, "Requested store object info file '%s' " - "does not exist, not accessible, or inconsistent. " - "Will re-cache from store.", - StoreObjectInfoFile.c_str()); - } + aClientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown; + theLastSyncTime = 0; + theNextSyncTime = 0; + + ::syslog(LOG_WARNING, "Requested store object info file '%s' " + "does not exist, not accessible, or inconsistent. " + "Will re-cache from store.", + StoreObjectInfoFile.c_str()); return false; } -- cgit v1.2.3 From ad0df772855c927638f0d8f900968aabfcf0275e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 20 Aug 2006 00:36:13 +0000 Subject: * bin/bbackupquery/BackupQueries.cpp - Removed options without code to handle them --- bin/bbackupquery/BackupQueries.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 4ca8afa0..c8135085 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -176,14 +176,14 @@ void BackupQueries::DoCommand(const char *Command) { { "quit", "" }, { "exit", "" }, - { "list", "rodIFtTsh", }, + { "list", "rodIFtsh", }, { "pwd", "" }, { "cd", "od" }, { "lcd", "" }, { "sh", "" }, { "getobject", "" }, { "get", "i" }, - { "compare", "alcqAE" }, + { "compare", "alcqE" }, { "restore", "dri" }, { "help", "" }, { "usage", "" }, -- cgit v1.2.3 From 0464bcfd6b131443774b4000224e523452e39de0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 20 Aug 2006 09:56:28 +0000 Subject: * bin/bbackupquery/BackupQueries.cpp - Renamed cmd_info_t to QueryCommandSpecification as requested by Ben --- bin/bbackupquery/BackupQueries.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index c8135085..a82b7f21 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -89,11 +89,11 @@ BackupQueries::~BackupQueries() { } -typedef struct cmd_info +typedef struct { const char* name; const char* opts; -} cmd_info_t; +} QueryCommandSpecification; // -------------------------------------------------------------------------- // @@ -172,7 +172,7 @@ void BackupQueries::DoCommand(const char *Command) } // Data about commands - static cmd_info_t commands[] = + static QueryCommandSpecification commands[] = { { "quit", "" }, { "exit", "" }, -- cgit v1.2.3 From 1055cfd5777dbfa86fb72e8215a264cb5f0fe636 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 20 Aug 2006 10:06:55 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Cleaned up SyncAllowScript cleanup code - Fixed catching std::exception while handling command socket to do the same as catching (...) --- bin/bbackupd/BackupDaemon.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 90c72a20..7c279f73 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -932,32 +932,24 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } } - // Wait and then cleanup child process - int status = 0; - ::waitpid(pid, &status, 0); } catch(std::exception &e) { ::syslog(LOG_ERR, "Internal error running SyncAllowScript: " "%s", e.what()); - // Clean up - if(pid != 0) - { - int status = 0; - ::waitpid(pid, &status, 0); - } } catch(...) { // Ignore any exceptions // Log that something bad happened ::syslog(LOG_ERR, "Error running SyncAllowScript '%s'", conf.GetKeyValue("SyncAllowScript").c_str()); - // Clean up though - if(pid != 0) - { - int status = 0; - ::waitpid(pid, &status, 0); - } + } + + // Wait and then cleanup child process, if any + if (pid != 0) + { + int status = 0; + ::waitpid(pid, &status, 0); } return waitInSeconds; @@ -1157,7 +1149,17 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla { ::syslog(LOG_ERR, "Internal error in command socket thread: " "%s", e.what()); - throw; // thread will die + // If an error occurs, and there is a connection active, just close that + // connection and continue. Otherwise, let the error propagate. + if(mpCommandSocketInfo->mpConnectedSocket.get() == 0) + { + throw; // thread will die + } + else + { + // Close socket and ignore error + CloseCommandConnection(); + } } catch(...) { -- cgit v1.2.3 From 512d2ccc4a5c512a70ee3464f8f7d894c5435051 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 20 Aug 2006 23:23:31 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Removed redundant exception handler (BoxException extends std::exception) - Changed error to warning if an exception is caught while trying to clean up from another exception on the command socket --- bin/bbackupd/BackupDaemon.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 7c279f73..9a3035ee 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -274,13 +274,6 @@ void BackupDaemon::RunHelperThread(void) { rSocket.Accept(BOX_NAMED_PIPE_NAME); } - catch(BoxException &e) - { - ::syslog(LOG_ERR, "Failed to open command socket: %s", - e.what()); - SetTerminateWanted(); - break; // this is fatal to listening thread - } catch(std::exception &e) { ::syslog(LOG_ERR, "Failed to open command socket: " @@ -465,7 +458,7 @@ void BackupDaemon::Run() } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error while " + ::syslog(LOG_WARNING, "Internal error while " "closing command socket after " "another exception: %s", e.what()); } -- cgit v1.2.3 From b557bd2fa0256ba4cca41d205e7b0b69602f9f18 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 20 Aug 2006 23:41:07 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Improved exception messages for reading and writing the StoreObjectInfoFile, and made them consistent. --- bin/bbackupd/BackupDaemon.cpp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 9a3035ee..2e80cd2d 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -2333,13 +2333,33 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time ::syslog(LOG_INFO, "Saved store object info file '%s'", StoreObjectInfoFile.c_str()); } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error writing store object " + "info file (%s): %s", + StoreObjectInfoFile.c_str(), e.what()); + } catch(...) { - ::syslog(LOG_WARNING, "Requested store object info file '%s' " - "not accessible or could not be created", + ::syslog(LOG_ERR, "Internal error writing store object " + "info file (%s): unknown error", StoreObjectInfoFile.c_str()); } + DeleteAllLocations(); + catch(std::exception &e) + { + ::syslog(LOG_WARNING, "Requested store object info file '%s' " + "not accessible or could not be created: %s", + StoreObjectInfoFile.c_str(), e.what()); + } + catch(...) + { + ::syslog(LOG_WARNING, "Requested store object info file '%s' " + "not accessible or could not be created: " + "unknown error", StoreObjectInfoFile.c_str()); + } + return created; } @@ -2492,12 +2512,14 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ catch(std::exception &e) { ::syslog(LOG_ERR, "Internal error reading store object " - "info file: %s", e.what()); + "info file (%s): %s", + StoreObjectInfoFile.c_str(), e.what()); } catch(...) { ::syslog(LOG_ERR, "Internal error reading store object " - "info file: unknown error"); + "info file (%s): unknown error", + StoreObjectInfoFile.c_str()); } DeleteAllLocations(); -- cgit v1.2.3 From 6c3dabe68da278f71b7c2c2b1da1858033504fce Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 21 Aug 2006 08:45:54 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Remove duplicated exception handlers --- bin/bbackupd/BackupDaemon.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 2e80cd2d..13568249 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -2346,20 +2346,6 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time StoreObjectInfoFile.c_str()); } - DeleteAllLocations(); - catch(std::exception &e) - { - ::syslog(LOG_WARNING, "Requested store object info file '%s' " - "not accessible or could not be created: %s", - StoreObjectInfoFile.c_str(), e.what()); - } - catch(...) - { - ::syslog(LOG_WARNING, "Requested store object info file '%s' " - "not accessible or could not be created: " - "unknown error", StoreObjectInfoFile.c_str()); - } - return created; } -- cgit v1.2.3 From 535ab4aec14fd9ac2753762beb28d01114753a82 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 08:53:55 +0000 Subject: * infrastructure/BoxPlatform.pm.in * win32.bat * bin/bbackupd/BackupClientDirectoryRecord.cpp - Merged back changes from trunk --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 45 +++++++++++++++++++++++----- infrastructure/BoxPlatform.pm.in | 32 +------------------- win32.bat | 17 ++++++----- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 37bd3fea..946f2bb8 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -94,6 +94,33 @@ void BackupClientDirectoryRecord::DeleteSubDirectories() mSubDirectories.clear(); } +// -------------------------------------------------------------------------- +// +// Function +// Name: MakeFullPath(const std::string& rDir, const std::string& rFile) +// Purpose: Combine directory and file name +// Created: 2006/08/10 +// +// -------------------------------------------------------------------------- +static std::string MakeFullPath(const std::string& rDir, + const std::string& rFile) +{ + std::string result; + + if (rDir.size() > 0 && + rDir[rDir.size()-1] == DIRECTORY_SEPARATOR_ASCHAR) + { + result = rDir + rFile; + } + else + { + result = rDir + DIRECTORY_SEPARATOR + rFile; + } + + return result; +} + + // -------------------------------------------------------------------------- // // Function @@ -207,8 +234,7 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn } // Stat file to get info - filename = rLocalPath + DIRECTORY_SEPARATOR + - en->d_name; + filename = MakeFullPath(rLocalPath, en->d_name); if(::lstat(filename.c_str(), &st) != 0) { @@ -512,7 +538,7 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP f != rFiles.end(); ++f) { // Filename of this file - std::string filename(rLocalPath + DIRECTORY_SEPARATOR + *f); + std::string filename(MakeFullPath(rLocalPath, *f)); // Get relevant info about file box_time_t modTime = 0; @@ -859,7 +885,7 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP d != rDirs.end(); ++d) { // Get the local filename - std::string dirname(rLocalPath + DIRECTORY_SEPARATOR + *d); + std::string dirname(MakeFullPath(rLocalPath, *d)); // See if it's in the listing (if we have one) BackupStoreFilenameClear storeFilename(*d); @@ -1063,10 +1089,13 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP BackupClientDirectoryRecord *rec = e->second; mSubDirectories.erase(e); delete rec; - TRACE2("Deleted directory record for " - "%s" DIRECTORY_SEPARATOR "%s\n", - rLocalPath.c_str(), - dirname.GetClearFilename().c_str()); + + std::string name = MakeFullPath( + rLocalPath, + dirname.GetClearFilename()); + + TRACE1("Deleted directory record for " + "%s\n", name.c_str()); } } } diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in index 81629414..828516e2 100644 --- a/infrastructure/BoxPlatform.pm.in +++ b/infrastructure/BoxPlatform.pm.in @@ -1,7 +1,7 @@ package BoxPlatform; use Exporter; @ISA = qw/Exporter/; -@EXPORT = qw/$build_os $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows update_if_changed/; +@EXPORT = qw/$build_os $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows/; BEGIN { @@ -24,7 +24,6 @@ BEGIN # Cygwin Builds usually something like CYGWIN_NT-5.0, CYGWIN_NT-5.1 # Box Backup tried on Win2000,XP only :) - $build_os = 'CYGWIN' if $build_os =~ m/CYGWIN/; $make_command = ($build_os eq 'Darwin') ? 'bsdmake' : ($build_os eq 'SunOS') ? 'gmake' : 'make'; @@ -107,34 +106,5 @@ sub make_flag return $_[0].'=1'; } -sub update_if_changed ($) -{ - my ($file) = @_; - die "$file.new: not found" unless -r "$file.new"; - - if (-r $file) - { - die "$file.new: not found" unless -r "$file.new"; - if (system("diff --brief $file $file.new") == 0) - { - unlink "$file.new"; - return; - } - } - - if (system("cp $file.new $file") != 0) - { - die "failed to copy $file.new to $file"; - } - - if (system("diff --brief $file $file.new") != 0) - { - die "$file and $file.new are still different"; - } - - unlink "$file.new"; - return; -} - 1; diff --git a/win32.bat b/win32.bat index e4a39359..81a97944 100644 --- a/win32.bat +++ b/win32.bat @@ -5,26 +5,27 @@ echo using Cygwin and Perl copy .\infrastructure\BoxPlatform.pm.in .\infrastructure\BoxPlatform.pm -cd .\bin\bbackupquery\ & perl ./../../bin/bbackupquery/makedocumentation.pl +cd .\bin\bbackupquery\ & perl ./../../bin/bbackupquery/makedocumentation.pl.in cd ..\..\ -cd .\lib\backupclient & perl ./../../lib/common/makeexception.pl BackupStoreException.txt -perl ./../../lib/server/makeprotocol.pl Client ./../../bin/bbstored/backupprotocol.txt +cd .\lib\backupclient & perl ./../../lib/common/makeexception.pl.in BackupStoreException.txt & perl ./../../lib/server/makeprotocol.pl.in Client ./../../bin/bbstored/backupprotocol.txt cd ..\..\ -cd .\lib\compress & perl ./../../lib/common/makeexception.pl CompressException.txt +cd .\lib\compress & perl ./../../lib/common/makeexception.pl.in CompressException.txt cd ..\..\ -cd .\lib\common & perl ./../../lib/common/makeexception.pl CommonException.txt & perl ./../../lib/common/makeexception.pl ConversionException.txt +cd .\lib\common & perl ./../../lib/common/makeexception.pl.in CommonException.txt & perl ./../../lib/common/makeexception.pl.in ConversionException.txt cd ..\..\ -cd .\lib\crypto & perl ./../../lib/common/makeexception.pl CipherException.txt +cd .\lib\crypto & perl ./../../lib/common/makeexception.pl.in CipherException.txt cd ..\..\ echo server parts - which appears as though some of the clients rely on -cd .\lib\server & perl ./../../lib/common/makeexception.pl ServerException.txt & perl ./../../lib/common/makeexception.pl ConnectionException.txt +cd .\lib\server & perl ./../../lib/common/makeexception.pl.in ServerException.txt & perl ./../../lib/common/makeexception.pl.in ConnectionException.txt cd ..\..\ -perl -i.orig -pe 's/@PERL@/perl/' ./test/bbackupd/testfiles/bbackupd.conf +copy lib\win32\config.h.win32 lib\common\BoxConfig.h + +perl -pe 's/@PERL@/perl/' ./test/bbackupd/testfiles/bbackupd.conf.in > .\test\bbackupd\testfiles\bbackupd.conf -- cgit v1.2.3 From 03fb61742165f24752e6392122d8d9a97366df27 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 13:46:28 +0000 Subject: * bin/bbackupd/BackupClientDirectoryRecord.cpp --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 91 ++++++++-------------------- 1 file changed, 25 insertions(+), 66 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 946f2bb8..5dc89a32 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -674,72 +674,31 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP // modification time within sync period // if it's been seen before but not uploaded, is the time from this first sight longer than the MaxUploadWait // and if we know about it from a directory listing, that it hasn't got the same upload time as on the store - - bool doUpload = false; - - // Only upload a file if the mod time locally is - // different to that on the server. - - if (en == 0 || en->GetModificationTime() != modTime) - { - // Check the file modified within the acceptable time period we're checking - // If the file isn't on the server, the acceptable time starts at zero. - // Check pDirOnStore and en, because if we didn't download a directory listing, - // pDirOnStore will be zero, but we know it's on the server. - if (modTime < rParams.mSyncPeriodEnd) - { - if (pDirOnStore != 0 && en == 0) - { - doUpload = true; - } - else if (modTime >= rParams.mSyncPeriodStart) - { - doUpload = true; - } - } - - // However, just in case things are continually - // modified, we check the first seen time. - // The two compares of syncPeriodEnd and - // pendingFirstSeenTime are because the values - // are unsigned. - - if (!doUpload && - pendingFirstSeenTime != 0 && - rParams.mSyncPeriodEnd > pendingFirstSeenTime && - (rParams.mSyncPeriodEnd - pendingFirstSeenTime) - > rParams.mMaxUploadWait) - { - doUpload = true; - } - - // Then make sure that if files are added with a - // time less than the sync period start - // (which can easily happen on file server), it - // gets uploaded. The directory contents checksum - // will pick up the fact it has been added, so the - // store listing will be available when this happens. - - if (!doUpload && - modTime <= rParams.mSyncPeriodStart && - en != 0 && - en->GetModificationTime() != modTime) - { - doUpload = true; - } - - // And just to catch really badly off clocks in - // the future for file server clients, - // just upload the file if it's madly in the future. - - if (!doUpload && modTime > - rParams.mUploadAfterThisTimeInTheFuture) - { - doUpload = true; - } - } - - if (doUpload) + if( + ( + // Check the file modified within the acceptable time period we're checking + // If the file isn't on the server, the acceptable time starts at zero. + // Check pDirOnStore and en, because if we didn't download a directory listing, + // pDirOnStore will be zero, but we know it's on the server. + ( ((pDirOnStore != 0 && en == 0) || (modTime >= rParams.mSyncPeriodStart)) && modTime < rParams.mSyncPeriodEnd) + + // However, just in case things are continually modified, we check the first seen time. + // The two compares of syncPeriodEnd and pendingFirstSeenTime are because the values are unsigned. + || (pendingFirstSeenTime != 0 && + (rParams.mSyncPeriodEnd > pendingFirstSeenTime) + && ((rParams.mSyncPeriodEnd - pendingFirstSeenTime) > rParams.mMaxUploadWait)) + + // Then make sure that if files are added with a time less than the sync period start + // (which can easily happen on file server), it gets uploaded. The directory contents checksum + // will pick up the fact it has been added, so the store listing will be available when this happens. + || ((modTime <= rParams.mSyncPeriodStart) && (en != 0) && (en->GetModificationTime() != modTime)) + + // And just to catch really badly off clocks in the future for file server clients, + // just upload the file if it's madly in the future. + || (modTime > rParams.mUploadAfterThisTimeInTheFuture) + ) + // But even then, only upload it if the mod time locally is different to that on the server. + && (en == 0 || en->GetModificationTime() != modTime)) { // Make sure we're connected -- must connect here so we know whether // the storage limit has been exceeded, and hence whether or not -- cgit v1.2.3 From 38c55c8f335756d710a06dc0f604a5f6d600f07e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 13:47:35 +0000 Subject: * bin/bbackupd/BackupClientDirectoryRecord.cpp - Restructured the backup decision logic to make it easier to understand and debug --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 91 ++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 25 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 5dc89a32..946f2bb8 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -674,31 +674,72 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP // modification time within sync period // if it's been seen before but not uploaded, is the time from this first sight longer than the MaxUploadWait // and if we know about it from a directory listing, that it hasn't got the same upload time as on the store - if( - ( - // Check the file modified within the acceptable time period we're checking - // If the file isn't on the server, the acceptable time starts at zero. - // Check pDirOnStore and en, because if we didn't download a directory listing, - // pDirOnStore will be zero, but we know it's on the server. - ( ((pDirOnStore != 0 && en == 0) || (modTime >= rParams.mSyncPeriodStart)) && modTime < rParams.mSyncPeriodEnd) - - // However, just in case things are continually modified, we check the first seen time. - // The two compares of syncPeriodEnd and pendingFirstSeenTime are because the values are unsigned. - || (pendingFirstSeenTime != 0 && - (rParams.mSyncPeriodEnd > pendingFirstSeenTime) - && ((rParams.mSyncPeriodEnd - pendingFirstSeenTime) > rParams.mMaxUploadWait)) - - // Then make sure that if files are added with a time less than the sync period start - // (which can easily happen on file server), it gets uploaded. The directory contents checksum - // will pick up the fact it has been added, so the store listing will be available when this happens. - || ((modTime <= rParams.mSyncPeriodStart) && (en != 0) && (en->GetModificationTime() != modTime)) - - // And just to catch really badly off clocks in the future for file server clients, - // just upload the file if it's madly in the future. - || (modTime > rParams.mUploadAfterThisTimeInTheFuture) - ) - // But even then, only upload it if the mod time locally is different to that on the server. - && (en == 0 || en->GetModificationTime() != modTime)) + + bool doUpload = false; + + // Only upload a file if the mod time locally is + // different to that on the server. + + if (en == 0 || en->GetModificationTime() != modTime) + { + // Check the file modified within the acceptable time period we're checking + // If the file isn't on the server, the acceptable time starts at zero. + // Check pDirOnStore and en, because if we didn't download a directory listing, + // pDirOnStore will be zero, but we know it's on the server. + if (modTime < rParams.mSyncPeriodEnd) + { + if (pDirOnStore != 0 && en == 0) + { + doUpload = true; + } + else if (modTime >= rParams.mSyncPeriodStart) + { + doUpload = true; + } + } + + // However, just in case things are continually + // modified, we check the first seen time. + // The two compares of syncPeriodEnd and + // pendingFirstSeenTime are because the values + // are unsigned. + + if (!doUpload && + pendingFirstSeenTime != 0 && + rParams.mSyncPeriodEnd > pendingFirstSeenTime && + (rParams.mSyncPeriodEnd - pendingFirstSeenTime) + > rParams.mMaxUploadWait) + { + doUpload = true; + } + + // Then make sure that if files are added with a + // time less than the sync period start + // (which can easily happen on file server), it + // gets uploaded. The directory contents checksum + // will pick up the fact it has been added, so the + // store listing will be available when this happens. + + if (!doUpload && + modTime <= rParams.mSyncPeriodStart && + en != 0 && + en->GetModificationTime() != modTime) + { + doUpload = true; + } + + // And just to catch really badly off clocks in + // the future for file server clients, + // just upload the file if it's madly in the future. + + if (!doUpload && modTime > + rParams.mUploadAfterThisTimeInTheFuture) + { + doUpload = true; + } + } + + if (doUpload) { // Make sure we're connected -- must connect here so we know whether // the storage limit has been exceeded, and hence whether or not -- cgit v1.2.3 From 6932579c38836aaec62ede8cd77bf66bb2e82d11 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 14:02:30 +0000 Subject: * bin/bbstored/BackupCommands.cpp - Revert to trunk --- bin/bbstored/BackupCommands.cpp | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index 845903b2..35bc095d 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -9,12 +9,7 @@ #include "Box.h" -#ifdef HAVE_SYSLOG_H #include -#endif - -#include -#include #include "autogen_BackupProtocolServer.h" #include "BackupConstants.h" @@ -332,15 +327,8 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto std::auto_ptr diff2(rContext.OpenObject(patchID)); // Choose a temporary filename for the result of the combination -#ifdef WIN32 - std::ostringstream fs(rContext.GetStoreRoot()); - fs << ".recombinetemp."; - fs << p; - std::string tempFn(fs.str()); - tempFn = RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), tempFn, p + 16); -#else - std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", p + 16 /* rotate which disc it's on */)); -#endif + std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", + p + 16 /* rotate which disc it's on */)); // Open the temporary file std::auto_ptr combined; @@ -348,23 +336,14 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto { { // Write nastily to allow this to work with gcc 2.x -#ifdef WIN32 - combined.reset(new FileStream( - tempFn.c_str(), - O_RDWR | O_CREAT | O_EXCL | - O_BINARY | O_TRUNC)); -#else std::auto_ptr t(new FileStream(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL)); combined = t; -#endif } -#ifndef WIN32 // Unlink immediately as it's a temporary file if(::unlink(tempFn.c_str()) != 0) { THROW_EXCEPTION(CommonException, OSFileError); } -#endif } catch(...) { @@ -380,9 +359,6 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto combined->Seek(0, IOStream::SeekType_Absolute); // Then shuffle round for the next go -#ifdef WIN32 - if (from.get()) from->Close(); -#endif from = combined; } @@ -420,9 +396,8 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto stream = t; } - // Object will be deleted when the stream is deleted, - // so can release the object auto_ptr here to avoid - // premature deletion + // Object will be deleted when the stream is deleted, so can release the object auto_ptr here to + // avoid premature deletiong object.release(); } -- cgit v1.2.3 From 824756aadab385140ae5c1ccdf382c387f646ca6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 14:18:40 +0000 Subject: * bin/bbstored/BackupCommands.cpp - Can't unlink open files on Win32. This is not the correct fix, but it does work around the problem. - Only include syslog.h if we have it --- bin/bbstored/BackupCommands.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index 35bc095d..845903b2 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -9,7 +9,12 @@ #include "Box.h" +#ifdef HAVE_SYSLOG_H #include +#endif + +#include +#include #include "autogen_BackupProtocolServer.h" #include "BackupConstants.h" @@ -327,8 +332,15 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto std::auto_ptr diff2(rContext.OpenObject(patchID)); // Choose a temporary filename for the result of the combination - std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", - p + 16 /* rotate which disc it's on */)); +#ifdef WIN32 + std::ostringstream fs(rContext.GetStoreRoot()); + fs << ".recombinetemp."; + fs << p; + std::string tempFn(fs.str()); + tempFn = RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), tempFn, p + 16); +#else + std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", p + 16 /* rotate which disc it's on */)); +#endif // Open the temporary file std::auto_ptr combined; @@ -336,14 +348,23 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto { { // Write nastily to allow this to work with gcc 2.x +#ifdef WIN32 + combined.reset(new FileStream( + tempFn.c_str(), + O_RDWR | O_CREAT | O_EXCL | + O_BINARY | O_TRUNC)); +#else std::auto_ptr t(new FileStream(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL)); combined = t; +#endif } +#ifndef WIN32 // Unlink immediately as it's a temporary file if(::unlink(tempFn.c_str()) != 0) { THROW_EXCEPTION(CommonException, OSFileError); } +#endif } catch(...) { @@ -359,6 +380,9 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto combined->Seek(0, IOStream::SeekType_Absolute); // Then shuffle round for the next go +#ifdef WIN32 + if (from.get()) from->Close(); +#endif from = combined; } @@ -396,8 +420,9 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto stream = t; } - // Object will be deleted when the stream is deleted, so can release the object auto_ptr here to - // avoid premature deletiong + // Object will be deleted when the stream is deleted, + // so can release the object auto_ptr here to avoid + // premature deletion object.release(); } -- cgit v1.2.3 From 6eab81fb160cb8849308f40fa22dc46aeaf0727b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:05:55 +0000 Subject: * bin/bbackupd/Win32BackupService.h - Revert to trunk --- bin/bbackupd/Win32BackupService.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupd/Win32BackupService.h b/bin/bbackupd/Win32BackupService.h index e7f077f2..38cebacc 100644 --- a/bin/bbackupd/Win32BackupService.h +++ b/bin/bbackupd/Win32BackupService.h @@ -12,7 +12,7 @@ class BackupDaemon; class Win32BackupService : public BackupDaemon { public: - DWORD WinService(const char* pConfigFileName); + DWORD WinService(void); }; #endif // WIN32 -- cgit v1.2.3 From 47abe80c1ec91cb91ac6148e3a216d64d7bea7d6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:06:30 +0000 Subject: * bin/bbackupd/Win32BackupService.h - Prototype update to match changes to Win32BackupService.cpp --- bin/bbackupd/Win32BackupService.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupd/Win32BackupService.h b/bin/bbackupd/Win32BackupService.h index 38cebacc..e7f077f2 100644 --- a/bin/bbackupd/Win32BackupService.h +++ b/bin/bbackupd/Win32BackupService.h @@ -12,7 +12,7 @@ class BackupDaemon; class Win32BackupService : public BackupDaemon { public: - DWORD WinService(void); + DWORD WinService(const char* pConfigFileName); }; #endif // WIN32 -- cgit v1.2.3 From fc8d3bddf9630767b949879c4a4c5605aa033d71 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:14:35 +0000 Subject: * bin/bbackupquery/BackupQueries.h - Revert to trunk --- bin/bbackupquery/BackupQueries.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.h b/bin/bbackupquery/BackupQueries.h index 42fd54fe..e84de6ab 100644 --- a/bin/bbackupquery/BackupQueries.h +++ b/bin/bbackupquery/BackupQueries.h @@ -68,10 +68,8 @@ private: void DeleteExcludeLists(); bool mQuickCompare; bool mIgnoreExcludes; - bool mIgnoreAttributes; int mDifferences; int mDifferencesExplainedByModTime; - int mUncheckedFiles; int mExcludedDirs; int mExcludedFiles; const ExcludeList *mpExcludeFiles; -- cgit v1.2.3 From 403eb599a83bc6913d4cbaff391197e6c931465b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:17:08 +0000 Subject: * bin/bbackupquery/documentation.txt - Revert to trunk --- bin/bbackupquery/documentation.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/bbackupquery/documentation.txt b/bin/bbackupquery/documentation.txt index 0fb0bacb..429caabe 100644 --- a/bin/bbackupquery/documentation.txt +++ b/bin/bbackupquery/documentation.txt @@ -104,7 +104,6 @@ compare -c -- set return code -q -- quick compare. Only checks file contents against checksums, doesn't do a full download - -A -- ignore attribute differences -E -- ignore exclusion settings Comparing with the root directory is an error, use -a option instead. -- cgit v1.2.3 From 88a078d6c0a97dc5c8212dc75f6c1109b8007b64 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:20:08 +0000 Subject: * bin/bbstored/BackupContext.cpp - Revert to trunk --- bin/bbstored/BackupContext.cpp | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp index cd17812c..c796c13a 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupContext.cpp @@ -132,7 +132,6 @@ bool BackupContext::AttemptToGetWriteLock() // Request the lock bool gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */); -#ifndef WIN32 if(!gotLock) { // The housekeeping process might have the thing open -- ask it to stop @@ -151,7 +150,6 @@ bool BackupContext::AttemptToGetWriteLock() } while(!gotLock && tries > 0); } -#endif if(gotLock) { @@ -455,21 +453,13 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod try { // Open it twice -#ifdef WIN32 - FileStream diff(tempFn.c_str(), - O_RDWR | O_CREAT | O_BINARY); - FileStream diff2(tempFn.c_str(), - O_RDWR | O_BINARY); -#else FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL); FileStream diff2(tempFn.c_str(), O_RDONLY); - - // Unlink it immediately, so it definitely goes away + // Unlink it immediately, so it definately goes away if(::unlink(tempFn.c_str()) != 0) { THROW_EXCEPTION(CommonException, OSFileError); } -#endif // Stream the incoming diff to this temporary file if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT)) @@ -518,14 +508,6 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod ::unlink(tempFn.c_str()); throw; } - -#ifdef WIN32 - // we can't delete the file while it's open, above - if(::unlink(tempFn.c_str()) != 0) - { - THROW_EXCEPTION(CommonException, OSFileError); - } -#endif } // Get the blocks used -- cgit v1.2.3 From d66c1cf54727d91ed8a1ef937c07ff32abb879d4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:24:04 +0000 Subject: * bin/bbstored/BackupContext.cpp - Removed locking on Win32, there is no housekeeping process to lock against - Open files with O_BINARY on Win32 - Fixed a cosmetic spelling mistake in a comment - Unlink file later on Windows, since we can't do it while it's open --- bin/bbstored/BackupContext.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp index c796c13a..a3f614a5 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupContext.cpp @@ -125,6 +125,7 @@ void BackupContext::ReceivedFinishCommand() // -------------------------------------------------------------------------- bool BackupContext::AttemptToGetWriteLock() { +#ifndef WIN32 // Make the filename of the write lock file std::string writeLockFile; StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, writeLockFile); @@ -150,7 +151,7 @@ bool BackupContext::AttemptToGetWriteLock() } while(!gotLock && tries > 0); } - + if(gotLock) { // Got the lock, mark as not read only @@ -158,6 +159,10 @@ bool BackupContext::AttemptToGetWriteLock() } return gotLock; +#else // WIN32 + // no housekeeping process, we do have the lock + return true; +#endif // !WIN32 } @@ -453,13 +458,21 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod try { // Open it twice +#ifdef WIN32 + FileStream diff(tempFn.c_str(), + O_RDWR | O_CREAT | O_BINARY); + FileStream diff2(tempFn.c_str(), + O_RDWR | O_BINARY); +#else FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL); FileStream diff2(tempFn.c_str(), O_RDONLY); - // Unlink it immediately, so it definately goes away + + // Unlink it immediately, so it definitely goes away if(::unlink(tempFn.c_str()) != 0) { THROW_EXCEPTION(CommonException, OSFileError); } +#endif // Stream the incoming diff to this temporary file if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT)) @@ -508,6 +521,14 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod ::unlink(tempFn.c_str()); throw; } + +#ifdef WIN32 + // we can't delete the file while it's open, above + if(::unlink(tempFn.c_str()) != 0) + { + THROW_EXCEPTION(CommonException, OSFileError); + } +#endif } // Get the blocks used -- cgit v1.2.3 From 0d0ad416458a2bf4e04dfa35f549063b381c4e50 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:26:11 +0000 Subject: * bin/bbstored/BackupStoreDaemon.cpp - Revert to trunk --- bin/bbstored/BackupStoreDaemon.cpp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 24a81ceb..2752893a 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -11,11 +11,8 @@ #include #include -#include - -#ifdef HAVE_SYSLOG_H #include -#endif +#include #include "BackupContext.h" #include "BackupStoreDaemon.h" @@ -42,11 +39,7 @@ BackupStoreDaemon::BackupStoreDaemon() mExtendedLogging(false), mHaveForkedHousekeeping(false), mIsHousekeepingProcess(false), -#ifdef WIN32 - mHousekeepingInited(false) -#else mInterProcessComms(mInterProcessCommsSocket) -#endif { } @@ -163,7 +156,6 @@ void BackupStoreDaemon::Run() const Configuration &config(GetConfiguration()); mExtendedLogging = config.GetKeyValueBool("ExtendedLogging"); -#ifndef WIN32 // Fork off housekeeping daemon -- must only do this the first time Run() is called if(!mHaveForkedHousekeeping) { @@ -227,11 +219,9 @@ void BackupStoreDaemon::Run() } else { -#endif // !WIN32 // In server process -- use the base class to do the magic ServerTLS::Run(); -#ifndef WIN32 // Why did it stop? Tell the housekeeping process to do the same if(IsReloadConfigWanted()) { @@ -242,7 +232,6 @@ void BackupStoreDaemon::Run() mInterProcessCommsSocket.Write("t\n", 2); } } -#endif } @@ -308,8 +297,6 @@ void BackupStoreDaemon::LogConnectionStats(const char *commonName, // Log the amount of data transferred ::syslog(LOG_INFO, "Connection statistics for %s: " "IN=%lld OUT=%lld TOTAL=%lld\n", commonName, - (long long)s.GetBytesRead(), - (long long)s.GetBytesWritten(), - (long long)s.GetBytesRead() + - (long long)s.GetBytesWritten()); + s.GetBytesRead(), s.GetBytesWritten(), + s.GetBytesRead() + s.GetBytesWritten()); } -- cgit v1.2.3 From f9fbe34b3d409749264bc69497d7e51bf744fbf3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:26:45 +0000 Subject: * bin/bbstored/BackupStoreDaemon.cpp - Only include if we have it --- bin/bbstored/BackupStoreDaemon.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 2752893a..fc09b624 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -11,9 +11,12 @@ #include #include -#include #include +#ifdef HAVE_SYSLOG_H + #include +#endif + #include "BackupContext.h" #include "BackupStoreDaemon.h" #include "BackupStoreConfigVerify.h" -- cgit v1.2.3 From 55c923c1ce31cb02aec672b6f78098cfdecafa40 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:28:29 +0000 Subject: * bin/bbstored/BackupStoreDaemon.h - Revert to trunk --- bin/bbstored/BackupStoreDaemon.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index 857a9356..2fbe486d 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -38,13 +38,11 @@ private: BackupStoreDaemon(const BackupStoreDaemon &rToCopy); public: -#ifndef WIN32 // For BackupContext to comminicate with housekeeping process void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) { mInterProcessCommsSocket.Write(Msg, MsgLen); } -#endif protected: @@ -59,11 +57,9 @@ protected: const ConfigurationVerify *GetConfigVerify() const; -#ifndef WIN32 // Housekeeping functions void HousekeepingProcess(); bool CheckForInterProcessMsg(int AccountNum = 0, int MaximumWaitTime = 0); -#endif void LogConnectionStats(const char *commonName, const SocketStreamTLS &s); @@ -74,17 +70,8 @@ private: bool mHaveForkedHousekeeping; bool mIsHousekeepingProcess; -#ifdef WIN32 - virtual void OnIdle(); - bool mHousekeepingInited; -#else SocketStream mInterProcessCommsSocket; IOStreamGetLine mInterProcessComms; -#endif - - void HousekeepingInit(); - void RunHousekeepingIfNeeded(); - int64_t mLastHousekeepingRun; }; -- cgit v1.2.3 From 27bb0b1740173c7c6b7b313678abf3760f94402b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:31:54 +0000 Subject: * bin/bbstored/BackupStoreDaemon.cpp - Cast off_t to long long, in case they differ in size (e.g. Win32) --- bin/bbstored/BackupStoreDaemon.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index fc09b624..ce7263da 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -300,6 +300,8 @@ void BackupStoreDaemon::LogConnectionStats(const char *commonName, // Log the amount of data transferred ::syslog(LOG_INFO, "Connection statistics for %s: " "IN=%lld OUT=%lld TOTAL=%lld\n", commonName, - s.GetBytesRead(), s.GetBytesWritten(), - s.GetBytesRead() + s.GetBytesWritten()); + (long long)s.GetBytesRead(), + (long long)s.GetBytesWritten(), + (long long)s.GetBytesRead() + + (long long)s.GetBytesWritten()); } -- cgit v1.2.3 From 7286b52c4b2f703d8862088b1197bb848bba36da Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:37:38 +0000 Subject: * bin/bbstored/BBStoreDHousekeeping.cpp - Revert to trunk --- bin/bbstored/BBStoreDHousekeeping.cpp | 174 +++++++++++++--------------------- 1 file changed, 68 insertions(+), 106 deletions(-) diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp index 86b2468b..d3656630 100644 --- a/bin/bbstored/BBStoreDHousekeeping.cpp +++ b/bin/bbstored/BBStoreDHousekeeping.cpp @@ -10,10 +10,7 @@ #include "Box.h" #include - -#ifdef HAVE_SYSLOG_H #include -#endif #include "BackupStoreDaemon.h" #include "BackupStoreAccountDatabase.h" @@ -32,128 +29,95 @@ // Created: 11/12/03 // // -------------------------------------------------------------------------- -void BackupStoreDaemon::HousekeepingInit() -{ - - mLastHousekeepingRun = 0; -} - -#ifndef WIN32 void BackupStoreDaemon::HousekeepingProcess() { - HousekeepingInit(); - // Get the time between housekeeping runs const Configuration &rconfig(GetConfiguration()); int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping")); + + int64_t lastHousekeepingRun = 0; while(!StopRun()) { - RunHousekeepingIfNeeded(); - - // Calculate how long should wait before doing the next housekeeping run + // Time now int64_t timeNow = GetCurrentBoxTime(); - time_t secondsToGo = BoxTimeToSeconds((mLastHousekeepingRun + housekeepingInterval) - timeNow); - if(secondsToGo < 1) secondsToGo = 1; - if(secondsToGo > 60) secondsToGo = 60; - int32_t millisecondsToGo = ((int)secondsToGo) * 1000; - - // Check to see if there's any message pending - CheckForInterProcessMsg(0 /* no account */, millisecondsToGo); - } -} -#endif - -void BackupStoreDaemon::RunHousekeepingIfNeeded() -{ - // Get the time between housekeeping runs - const Configuration &rconfig(GetConfiguration()); - int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping")); - - // Time now - int64_t timeNow = GetCurrentBoxTime(); - // Do housekeeping if the time interval has elapsed since the last check - if((timeNow - mLastHousekeepingRun) < housekeepingInterval) - { - return; - } - - // Store the time - mLastHousekeepingRun = timeNow; - ::syslog(LOG_INFO, "Starting housekeeping"); + // Do housekeeping if the time interval has elapsed since the last check + if((timeNow - lastHousekeepingRun) >= housekeepingInterval) + { + // Store the time + lastHousekeepingRun = timeNow; + ::syslog(LOG_INFO, "Starting housekeeping"); - // Get the list of accounts - std::vector accounts; - if(mpAccountDatabase) - { - mpAccountDatabase->GetAllAccountIDs(accounts); - } + // Get the list of accounts + std::vector accounts; + if(mpAccountDatabase) + { + mpAccountDatabase->GetAllAccountIDs(accounts); + } - SetProcessTitle("housekeeping, active"); + SetProcessTitle("housekeeping, active"); - // Check them all - for(std::vector::const_iterator i = accounts.begin(); i != accounts.end(); ++i) - { - try - { - if(mpAccounts) + // Check them all + for(std::vector::const_iterator i = accounts.begin(); i != accounts.end(); ++i) { - // Get the account root - std::string rootDir; - int discSet = 0; - mpAccounts->GetAccountRoot(*i, rootDir, discSet); + try + { + if(mpAccounts) + { + // Get the account root + std::string rootDir; + int discSet = 0; + mpAccounts->GetAccountRoot(*i, rootDir, discSet); + + // Do housekeeping on this account + HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); + housekeeping.DoHousekeeping(); + } + } + catch(BoxException &e) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account", + *i, e.what(), e.GetType(), e.GetSubType()); + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account", + *i, e.what()); + } + catch(...) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account", + *i); + } - // Do housekeeping on this account - HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); - housekeeping.DoHousekeeping(); + // Check to see if there's any message pending + CheckForInterProcessMsg(0 /* no account */); + + // Stop early? + if(StopRun()) + { + break; + } } + + ::syslog(LOG_INFO, "Finished housekeeping"); } - catch(BoxException &e) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account", - *i, e.what(), e.GetType(), e.GetSubType()); - } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account", - *i, e.what()); - } - catch(...) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account", - *i); - } + + // Placed here for accuracy, if StopRun() is true, for example. + SetProcessTitle("housekeeping, idle"); + + // Calculate how long should wait before doing the next housekeeping run + timeNow = GetCurrentBoxTime(); + time_t secondsToGo = BoxTimeToSeconds((lastHousekeepingRun + housekeepingInterval) - timeNow); + if(secondsToGo < 1) secondsToGo = 1; + if(secondsToGo > 60) secondsToGo = 60; + int32_t millisecondsToGo = ((int)secondsToGo) * 1000; -#ifndef WIN32 // Check to see if there's any message pending - CheckForInterProcessMsg(0 /* no account */); -#endif - - // Stop early? - if(StopRun()) - { - break; - } + CheckForInterProcessMsg(0 /* no account */, millisecondsToGo); } - - ::syslog(LOG_INFO, "Finished housekeeping"); - - // Placed here for accuracy, if StopRun() is true, for example. - SetProcessTitle("housekeeping, idle"); } -#ifdef WIN32 -void BackupStoreDaemon::OnIdle() -{ - if (!mHousekeepingInited) - { - HousekeepingInit(); - mHousekeepingInited = true; - } - - RunHousekeepingIfNeeded(); -} -#endif // -------------------------------------------------------------------------- // @@ -164,7 +128,6 @@ void BackupStoreDaemon::OnIdle() // Created: 11/12/03 // // -------------------------------------------------------------------------- -#ifndef WIN32 bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitTime) { // First, check to see if it's EOF -- this means something has gone wrong, and the housekeeping should terminate. @@ -208,6 +171,5 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT return false; } -#endif -- cgit v1.2.3 From 5989931d7c88696a1e4858c9ea4a93a8312efc53 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:52:01 +0000 Subject: * bin/bbstored/BackupStoreDaemon.h - Removed SendMessageToHousekeepingProcess() on Win32, no longer needed --- bin/bbstored/BackupStoreDaemon.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index 2fbe486d..3123b21f 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -38,11 +38,13 @@ private: BackupStoreDaemon(const BackupStoreDaemon &rToCopy); public: - // For BackupContext to comminicate with housekeeping process +#ifndef WIN32 + // For BackupContext to communicate with housekeeping process void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) { mInterProcessCommsSocket.Write(Msg, MsgLen); } +#endif protected: -- cgit v1.2.3 From 82c4503253a2fb311c1fda5c6b5f545200e89ad7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 18:54:31 +0000 Subject: * bin/bbstored/BBStoreDHousekeeping.cpp - Only include syslog.h if we have one --- bin/bbstored/BBStoreDHousekeeping.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp index d3656630..be6d71f5 100644 --- a/bin/bbstored/BBStoreDHousekeeping.cpp +++ b/bin/bbstored/BBStoreDHousekeeping.cpp @@ -10,7 +10,10 @@ #include "Box.h" #include -#include + +#ifdef HAVE_SYSLOG_H + #include +#endif #include "BackupStoreDaemon.h" #include "BackupStoreAccountDatabase.h" -- cgit v1.2.3 From f2fedcebe908b2fb77a2743575098230ca67236a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 19:01:05 +0000 Subject: * bin/bbstored/BackupStoreDaemon.h * bin/bbstored/BBStoreDHousekeeping.cpp - Split housekeeping process into separate initialisation, process loop and run methods (we don't want the process loop on Win32) --- bin/bbstored/BBStoreDHousekeeping.cpp | 158 ++++++++++++++++++++-------------- bin/bbstored/BackupStoreDaemon.h | 4 + 2 files changed, 96 insertions(+), 66 deletions(-) diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp index be6d71f5..8c725b0f 100644 --- a/bin/bbstored/BBStoreDHousekeeping.cpp +++ b/bin/bbstored/BBStoreDHousekeeping.cpp @@ -32,95 +32,121 @@ // Created: 11/12/03 // // -------------------------------------------------------------------------- +void BackupStoreDaemon::HousekeepingInit() +{ + + mLastHousekeepingRun = 0; +} + void BackupStoreDaemon::HousekeepingProcess() { + HousekeepingInit(); + // Get the time between housekeeping runs const Configuration &rconfig(GetConfiguration()); int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping")); - - int64_t lastHousekeepingRun = 0; while(!StopRun()) { - // Time now + RunHousekeepingIfNeeded(); + + // Calculate how long should wait before doing the next housekeeping run int64_t timeNow = GetCurrentBoxTime(); - // Do housekeeping if the time interval has elapsed since the last check - if((timeNow - lastHousekeepingRun) >= housekeepingInterval) - { - // Store the time - lastHousekeepingRun = timeNow; - ::syslog(LOG_INFO, "Starting housekeeping"); + time_t secondsToGo = BoxTimeToSeconds( + (mLastHousekeepingRun + housekeepingInterval) - + timeNow); + if(secondsToGo < 1) secondsToGo = 1; + if(secondsToGo > 60) secondsToGo = 60; + int32_t millisecondsToGo = ((int)secondsToGo) * 1000; + + // Check to see if there's any message pending + CheckForInterProcessMsg(0 /* no account */, millisecondsToGo); + } +} - // Get the list of accounts - std::vector accounts; - if(mpAccountDatabase) - { - mpAccountDatabase->GetAllAccountIDs(accounts); - } +void BackupStoreDaemon::RunHousekeepingIfNeeded() +{ + // Get the time between housekeeping runs + const Configuration &rconfig(GetConfiguration()); + int64_t housekeepingInterval = SecondsToBoxTime(rconfig.GetKeyValueInt("TimeBetweenHousekeeping")); + + // Time now + int64_t timeNow = GetCurrentBoxTime(); + // Do housekeeping if the time interval has elapsed since the last check + if((timeNow - mLastHousekeepingRun) < housekeepingInterval) + { + return; + } + + // Store the time + mLastHousekeepingRun = timeNow; + ::syslog(LOG_INFO, "Starting housekeeping"); + + // Get the list of accounts + std::vector accounts; + if(mpAccountDatabase) + { + mpAccountDatabase->GetAllAccountIDs(accounts); + } - SetProcessTitle("housekeeping, active"); + SetProcessTitle("housekeeping, active"); - // Check them all - for(std::vector::const_iterator i = accounts.begin(); i != accounts.end(); ++i) + // Check them all + for(std::vector::const_iterator i = accounts.begin(); i != accounts.end(); ++i) + { + try + { + if(mpAccounts) { - try - { - if(mpAccounts) - { - // Get the account root - std::string rootDir; - int discSet = 0; - mpAccounts->GetAccountRoot(*i, rootDir, discSet); - - // Do housekeeping on this account - HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); - housekeeping.DoHousekeeping(); - } - } - catch(BoxException &e) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account", - *i, e.what(), e.GetType(), e.GetSubType()); - } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account", - *i, e.what()); - } - catch(...) - { - ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account", - *i); - } + // Get the account root + std::string rootDir; + int discSet = 0; + mpAccounts->GetAccountRoot(*i, rootDir, discSet); - // Check to see if there's any message pending - CheckForInterProcessMsg(0 /* no account */); - - // Stop early? - if(StopRun()) - { - break; - } + // Do housekeeping on this account + HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); + housekeeping.DoHousekeeping(); } - - ::syslog(LOG_INFO, "Finished housekeeping"); } - - // Placed here for accuracy, if StopRun() is true, for example. - SetProcessTitle("housekeeping, idle"); - - // Calculate how long should wait before doing the next housekeeping run - timeNow = GetCurrentBoxTime(); - time_t secondsToGo = BoxTimeToSeconds((lastHousekeepingRun + housekeepingInterval) - timeNow); + catch(BoxException &e) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account", + *i, e.what(), e.GetType(), e.GetSubType()); + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account", + *i, e.what()); + } + catch(...) + { + ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account", + *i); + } + + int64_t timeNow = GetCurrentBoxTime(); + time_t secondsToGo = BoxTimeToSeconds( + (mLastHousekeepingRun + housekeepingInterval) - + timeNow); if(secondsToGo < 1) secondsToGo = 1; if(secondsToGo > 60) secondsToGo = 60; int32_t millisecondsToGo = ((int)secondsToGo) * 1000; - + // Check to see if there's any message pending CheckForInterProcessMsg(0 /* no account */, millisecondsToGo); + + // Stop early? + if(StopRun()) + { + break; + } } -} + + ::syslog(LOG_INFO, "Finished housekeeping"); + // Placed here for accuracy, if StopRun() is true, for example. + SetProcessTitle("housekeeping, idle"); +} // -------------------------------------------------------------------------- // diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index 3123b21f..47f29327 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -74,6 +74,10 @@ private: SocketStream mInterProcessCommsSocket; IOStreamGetLine mInterProcessComms; + + void HousekeepingInit(); + void RunHousekeepingIfNeeded(); + int64_t mLastHousekeepingRun; }; -- cgit v1.2.3 From 2c64f7e2f6c0dbf7106b63af2c1cd39caa2078f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 19:20:35 +0000 Subject: * bin/bbstored/HousekeepStoreAccount.cpp - Revert to trunk --- bin/bbstored/HousekeepStoreAccount.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp index 91945306..4aa1999e 100644 --- a/bin/bbstored/HousekeepStoreAccount.cpp +++ b/bin/bbstored/HousekeepStoreAccount.cpp @@ -225,7 +225,6 @@ void HousekeepStoreAccount::MakeObjectFilename(int64_t ObjectID, std::string &rF // -------------------------------------------------------------------------- bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) { -#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -236,7 +235,6 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) return false; } } -#endif // Get the filename std::string objectFilename; @@ -253,7 +251,6 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) // Read the directory in BackupStoreDirectory dir; dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite); - dirStream->Close(); // Is it empty? if(dir.GetNumberOfEntries() == 0) @@ -488,7 +485,6 @@ bool HousekeepStoreAccount::DeleteFiles() // (there is likely to be more in the set than should be actually deleted). for(std::set::iterator i(mPotentialDeletions.begin()); i != mPotentialDeletions.end(); ++i) { -#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -499,7 +495,6 @@ bool HousekeepStoreAccount::DeleteFiles() return true; } } -#endif // Load up the directory it's in // Get the filename @@ -734,7 +729,6 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() // Go through list for(std::vector::const_iterator i(mEmptyDirectories.begin()); i != mEmptyDirectories.end(); ++i) { -#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -745,7 +739,6 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() return true; } } -#endif // Do not delete the root directory if(*i == BACKUPSTORE_ROOT_DIRECTORY_ID) -- cgit v1.2.3 From c283b5715077a8e9c273e53816b3ad473888610a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Aug 2006 19:29:23 +0000 Subject: * bin/bbstored/HousekeepStoreAccount.cpp - Disable checks for inter-process messages on Win32 (there is only one process) - Close directory immediately after we finish reading it --- bin/bbstored/HousekeepStoreAccount.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp index 4aa1999e..91945306 100644 --- a/bin/bbstored/HousekeepStoreAccount.cpp +++ b/bin/bbstored/HousekeepStoreAccount.cpp @@ -225,6 +225,7 @@ void HousekeepStoreAccount::MakeObjectFilename(int64_t ObjectID, std::string &rF // -------------------------------------------------------------------------- bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -235,6 +236,7 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) return false; } } +#endif // Get the filename std::string objectFilename; @@ -251,6 +253,7 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) // Read the directory in BackupStoreDirectory dir; dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite); + dirStream->Close(); // Is it empty? if(dir.GetNumberOfEntries() == 0) @@ -485,6 +488,7 @@ bool HousekeepStoreAccount::DeleteFiles() // (there is likely to be more in the set than should be actually deleted). for(std::set::iterator i(mPotentialDeletions.begin()); i != mPotentialDeletions.end(); ++i) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -495,6 +499,7 @@ bool HousekeepStoreAccount::DeleteFiles() return true; } } +#endif // Load up the directory it's in // Get the filename @@ -729,6 +734,7 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() // Go through list for(std::vector::const_iterator i(mEmptyDirectories.begin()); i != mEmptyDirectories.end(); ++i) { +#ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; @@ -739,6 +745,7 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() return true; } } +#endif // Do not delete the root directory if(*i == BACKUPSTORE_ROOT_DIRECTORY_ID) -- cgit v1.2.3 From 63738c47e89fb0117e0d217644584d330c48c565 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 08:01:43 +0000 Subject: * bin/bbackupd/BackupClientDirectoryRecord.cpp - Sync subdirectories even when store is full, allows user to exclude files to free up space to complete their backups --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 49 ++++++++++++++++++---------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 946f2bb8..d9b11ee4 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -922,11 +922,15 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP // In the list, just use this pointer psubDirRecord = e->second; } - else if(!rParams.mrContext.StorageLimitExceeded()) // know we've got a connection if we get this far, as dir will have been modified. + else { - // Note: only think about adding directory records if there's space left on the server. - // If there isn't, this step will be repeated when there is some available. - + // Note: if we have exceeded our storage limit, then + // we should not upload any more data, nor create any + // DirectoryRecord representing data that would have + // been uploaded. This step will be repeated when + // there is some space available. + bool doCreateDirectoryRecord = true; + // Need to create the record. But do we need to create the directory on the server? int64_t subDirObjectID = 0; if(en != 0) @@ -934,6 +938,12 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP // No. Exists on the server, and we know about it from the listing. subDirObjectID = en->GetObjectID(); } + else if(rParams.mrContext.StorageLimitExceeded()) + // know we've got a connection if we get this far, + // as dir will have been modified. + { + doCreateDirectoryRecord = false; + } else { // Yes, creation required! @@ -1016,20 +1026,23 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP haveJustCreatedDirOnServer = true; } } - - // New an object for this - psubDirRecord = new BackupClientDirectoryRecord(subDirObjectID, *d); - - // Store in list - try - { - mSubDirectories[*d] = psubDirRecord; - } - catch(...) - { - delete psubDirRecord; - psubDirRecord = 0; - throw; + + if (doCreateDirectoryRecord) + { + // New an object for this + psubDirRecord = new BackupClientDirectoryRecord(subDirObjectID, *d); + + // Store in list + try + { + mSubDirectories[*d] = psubDirRecord; + } + catch(...) + { + delete psubDirRecord; + psubDirRecord = 0; + throw; + } } } -- cgit v1.2.3 From a774a6288de6b346c5642edbeca4343a1c88512f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 08:49:52 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Revert to trunk --- bin/bbackupd/BackupDaemon.cpp | 68 +++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 13568249..2b5a1b23 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -262,7 +262,6 @@ void BackupDaemon::DeleteAllLocations() #ifdef WIN32 void BackupDaemon::RunHelperThread(void) { - this->mReceivedCommandConn = false; mpCommandSocketInfo = new CommandSocketInfo; WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); @@ -274,6 +273,21 @@ void BackupDaemon::RunHelperThread(void) { rSocket.Accept(BOX_NAMED_PIPE_NAME); } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to open command socket: %s", + e.what()); + SetTerminateWanted(); + break; // this is fatal to listening thread + } + catch (...) + { + ::syslog(LOG_ERR, "Failed to open command socket: " + "unknown error"); + SetTerminateWanted(); + break; // this is fatal to listening thread + } + } catch(std::exception &e) { ::syslog(LOG_ERR, "Failed to open command socket: " @@ -458,7 +472,7 @@ void BackupDaemon::Run() } catch(std::exception &e) { - ::syslog(LOG_WARNING, "Internal error while " + ::syslog(LOG_ERR, "Internal error while " "closing command socket after " "another exception: %s", e.what()); } @@ -925,24 +939,32 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } } + // Wait and then cleanup child process + int status = 0; + ::waitpid(pid, &status, 0); } catch(std::exception &e) { ::syslog(LOG_ERR, "Internal error running SyncAllowScript: " "%s", e.what()); + // Clean up + if(pid != 0) + { + int status = 0; + ::waitpid(pid, &status, 0); + } } catch(...) { // Ignore any exceptions // Log that something bad happened ::syslog(LOG_ERR, "Error running SyncAllowScript '%s'", conf.GetKeyValue("SyncAllowScript").c_str()); - } - - // Wait and then cleanup child process, if any - if (pid != 0) - { - int status = 0; - ::waitpid(pid, &status, 0); + // Clean up though + if(pid != 0) + { + int status = 0; + ::waitpid(pid, &status, 0); + } } return waitInSeconds; @@ -1142,17 +1164,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla { ::syslog(LOG_ERR, "Internal error in command socket thread: " "%s", e.what()); - // If an error occurs, and there is a connection active, just close that - // connection and continue. Otherwise, let the error propagate. - if(mpCommandSocketInfo->mpConnectedSocket.get() == 0) - { - throw; // thread will die - } - else - { - // Close socket and ignore error - CloseCommandConnection(); - } + throw; // thread will die } catch(...) { @@ -2333,16 +2345,10 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time ::syslog(LOG_INFO, "Saved store object info file '%s'", StoreObjectInfoFile.c_str()); } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "Internal error writing store object " - "info file (%s): %s", - StoreObjectInfoFile.c_str(), e.what()); - } catch(...) { - ::syslog(LOG_ERR, "Internal error writing store object " - "info file (%s): unknown error", + ::syslog(LOG_WARNING, "Requested store object info file '%s' " + "not accessible or could not be created", StoreObjectInfoFile.c_str()); } @@ -2498,14 +2504,12 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ catch(std::exception &e) { ::syslog(LOG_ERR, "Internal error reading store object " - "info file (%s): %s", - StoreObjectInfoFile.c_str(), e.what()); + "info file: %s", e.what()); } catch(...) { ::syslog(LOG_ERR, "Internal error reading store object " - "info file (%s): unknown error", - StoreObjectInfoFile.c_str()); + "info file: unknown error"); } DeleteAllLocations(); -- cgit v1.2.3 From 4db6a80d27444cf90ae41c6876c141f9c6db8284 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 08:51:44 +0000 Subject: * bin/bbackupd/BackupDaemon.cpp - Reinstate missing mReceivedCommandConn - Clean up exception handling --- bin/bbackupd/BackupDaemon.cpp | 53 ++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 2b5a1b23..99abb01f 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -262,6 +262,7 @@ void BackupDaemon::DeleteAllLocations() #ifdef WIN32 void BackupDaemon::RunHelperThread(void) { + this->mReceivedCommandConn = false; mpCommandSocketInfo = new CommandSocketInfo; WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); @@ -472,7 +473,7 @@ void BackupDaemon::Run() } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error while " + ::syslog(LOG_WARNING, "Internal error while " "closing command socket after " "another exception: %s", e.what()); } @@ -939,32 +940,24 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } } - // Wait and then cleanup child process - int status = 0; - ::waitpid(pid, &status, 0); } catch(std::exception &e) { ::syslog(LOG_ERR, "Internal error running SyncAllowScript: " "%s", e.what()); - // Clean up - if(pid != 0) - { - int status = 0; - ::waitpid(pid, &status, 0); - } } catch(...) { // Ignore any exceptions // Log that something bad happened ::syslog(LOG_ERR, "Error running SyncAllowScript '%s'", conf.GetKeyValue("SyncAllowScript").c_str()); - // Clean up though - if(pid != 0) - { - int status = 0; - ::waitpid(pid, &status, 0); - } + } + + // Wait and then cleanup child process, if any + if (pid != 0) + { + int status = 0; + ::waitpid(pid, &status, 0); } return waitInSeconds; @@ -1164,7 +1157,17 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla { ::syslog(LOG_ERR, "Internal error in command socket thread: " "%s", e.what()); - throw; // thread will die + // If an error occurs, and there is a connection active, just close that + // connection and continue. Otherwise, let the error propagate. + if(mpCommandSocketInfo->mpConnectedSocket.get() == 0) + { + throw; // thread will die + } + else + { + // Close socket and ignore error + CloseCommandConnection(); + } } catch(...) { @@ -2345,10 +2348,16 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time ::syslog(LOG_INFO, "Saved store object info file '%s'", StoreObjectInfoFile.c_str()); } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error writing store object " + "info file (%s): %s", + StoreObjectInfoFile.c_str(), e.what()); + } catch(...) { - ::syslog(LOG_WARNING, "Requested store object info file '%s' " - "not accessible or could not be created", + ::syslog(LOG_ERR, "Internal error writing store object " + "info file (%s): unknown error", StoreObjectInfoFile.c_str()); } @@ -2504,12 +2513,14 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ catch(std::exception &e) { ::syslog(LOG_ERR, "Internal error reading store object " - "info file: %s", e.what()); + "info file (%s): %s", + StoreObjectInfoFile.c_str(), e.what()); } catch(...) { ::syslog(LOG_ERR, "Internal error reading store object " - "info file: unknown error"); + "info file (%s): unknown error", + StoreObjectInfoFile.c_str()); } DeleteAllLocations(); -- cgit v1.2.3 From 94212acf332d56413ae0dc2a6c9c9fccb02f6bee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 19:59:02 +0000 Subject: * bin/bbstored/BackupCommands.cpp - Use the same code for file names and file closing on other platforms that's needed on Win32 --- bin/bbstored/BackupCommands.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index 845903b2..60a660d1 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -332,15 +332,11 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto std::auto_ptr diff2(rContext.OpenObject(patchID)); // Choose a temporary filename for the result of the combination -#ifdef WIN32 std::ostringstream fs(rContext.GetStoreRoot()); fs << ".recombinetemp."; fs << p; std::string tempFn(fs.str()); tempFn = RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), tempFn, p + 16); -#else - std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(rContext.GetStoreDiscSet(), rContext.GetStoreRoot() + ".recombinetemp", p + 16 /* rotate which disc it's on */)); -#endif // Open the temporary file std::auto_ptr combined; @@ -380,9 +376,7 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto combined->Seek(0, IOStream::SeekType_Absolute); // Then shuffle round for the next go -#ifdef WIN32 if (from.get()) from->Close(); -#endif from = combined; } -- cgit v1.2.3 From b97df587f4ebf1cd445d72d9f129a24bb8d29b67 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 20:08:11 +0000 Subject: * bin/bbstored/BackupContext.cpp - Delete the temporary file on Win32 just like on other platforms (note that this reduces the guarantees that the file will be deleted, especially if an exception is thrown, refs #819) --- bin/bbstored/BackupContext.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp index a3f614a5..d78ed9b1 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupContext.cpp @@ -125,7 +125,6 @@ void BackupContext::ReceivedFinishCommand() // -------------------------------------------------------------------------- bool BackupContext::AttemptToGetWriteLock() { -#ifndef WIN32 // Make the filename of the write lock file std::string writeLockFile; StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, writeLockFile); @@ -159,10 +158,6 @@ bool BackupContext::AttemptToGetWriteLock() } return gotLock; -#else // WIN32 - // no housekeeping process, we do have the lock - return true; -#endif // !WIN32 } @@ -466,12 +461,6 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod #else FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL); FileStream diff2(tempFn.c_str(), O_RDONLY); - - // Unlink it immediately, so it definitely goes away - if(::unlink(tempFn.c_str()) != 0) - { - THROW_EXCEPTION(CommonException, OSFileError); - } #endif // Stream the incoming diff to this temporary file @@ -514,6 +503,14 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod spaceAdjustFromDiff = from->GetDiscUsageInBlocks() - oldVersionNewBlocksUsed; // Everything cleans up here... + diff.Close(); + diff2.Close(); + + // Unlink the temporary file + if(::unlink(tempFn.c_str()) != 0) + { + THROW_EXCEPTION(CommonException, OSFileError); + } } catch(...) { -- cgit v1.2.3 From b4f24408e408ca7f9f8c64955477f5c2aa47a459 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 20:11:19 +0000 Subject: * bin/bbstored/BackupStoreDaemon.h - Reinstate SendMessageToHousekeepingProcess() on Win32, but make it do nothing (refs #3) --- bin/bbstored/BackupStoreDaemon.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index 47f29327..0ce6f21f 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -38,13 +38,13 @@ private: BackupStoreDaemon(const BackupStoreDaemon &rToCopy); public: -#ifndef WIN32 // For BackupContext to communicate with housekeeping process void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) { +#ifndef WIN32 mInterProcessCommsSocket.Write(Msg, MsgLen); - } #endif + } protected: -- cgit v1.2.3 From c587d1b5f7b40ac675e6785362406928f2e974a2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 21:48:24 +0000 Subject: * configure.ac Revert to trunk (refs #3) --- configure.ac | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index f3fe26b1..922ad500 100644 --- a/configure.ac +++ b/configure.ac @@ -44,7 +44,7 @@ AC_CHECK_LIB([z], [zlibVersion],, [AC_MSG_ERROR([[cannot find zlib]])]) VL_LIB_READLINE([have_libreadline=yes], [have_libreadline=no]) ## Check for Berkely DB. Restrict to certain versions -AX_PATH_BDB([1.x or 4.1], [ +AX_PATH_BDB(, [ LIBS="$BDB_LIBS $LIBS" LDFLAGS="$BDB_LDFLAGS $LDFLAGS" CPPFLAGS="$CPPFLAGS $BDB_CPPFLAGS" @@ -89,7 +89,7 @@ AC_CHECK_HEADERS([execinfo.h process.h pwd.h regex.h signal.h]) AC_CHECK_HEADERS([syslog.h time.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h]) -AC_CHECK_HEADERS([sys/uio.h sys/xattr.h]) +AC_CHECK_HEADERS([sys/xattr.h]) if test "$ac_cv_header_regex_h" = "yes"; then AC_SEARCH_LIBS([regcomp], [pcreposix]) @@ -116,7 +116,6 @@ AC_CHECK_MEMBERS([struct sockaddr_in.sin_len],,, [[ ]]) AC_CHECK_DECLS([INFTIM],,, [[#include ]]) AC_CHECK_DECLS([SO_PEERCRED],,, [[#include ]]) -AC_CHECK_DECLS([O_BINARY],,,) AC_HEADER_TIME AC_STRUCT_TM AX_CHECK_DIRENT_D_TYPE @@ -125,14 +124,14 @@ AX_CHECK_DEFINE_PRAGMA if test "x$ac_cv_c_bigendian" != "xyes"; then AX_BSWAP64 fi - if test "$target_os" != "mingw32"; then AX_RANDOM_DEVICE - AX_CHECK_MOUNT_POINT(,[ +fi +AX_CHECK_MOUNT_POINT(,[ + if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then AC_MSG_ERROR([[cannot work out how to discover mount points on your platform]]) + fi ]) -fi - AX_CHECK_MALLOC_WORKAROUND @@ -239,7 +238,6 @@ A summary of the build configuration is below. Box Backup will function without these features, but will work better where they are present. Refer to the documentation for more information on each feature. -Regular expressions: $ac_cv_header_regex_h Large files: $have_large_file_support Berkeley DB: $ax_path_bdb_ok Readline: $have_libreadline -- cgit v1.2.3 From cb1158a6d4610b542756ca120b1ce7b30852409e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 21:51:03 +0000 Subject: * configure.ac Show the required versions of Berkeley DB when configure fails to find them Check for sys/uio.h Check for O_BINARY Clean up code for AX_CHECK_MOUNT_POINT Display whether regular expressions are enabled at the end --- configure.ac | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 922ad500..f3fe26b1 100644 --- a/configure.ac +++ b/configure.ac @@ -44,7 +44,7 @@ AC_CHECK_LIB([z], [zlibVersion],, [AC_MSG_ERROR([[cannot find zlib]])]) VL_LIB_READLINE([have_libreadline=yes], [have_libreadline=no]) ## Check for Berkely DB. Restrict to certain versions -AX_PATH_BDB(, [ +AX_PATH_BDB([1.x or 4.1], [ LIBS="$BDB_LIBS $LIBS" LDFLAGS="$BDB_LDFLAGS $LDFLAGS" CPPFLAGS="$CPPFLAGS $BDB_CPPFLAGS" @@ -89,7 +89,7 @@ AC_CHECK_HEADERS([execinfo.h process.h pwd.h regex.h signal.h]) AC_CHECK_HEADERS([syslog.h time.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h]) -AC_CHECK_HEADERS([sys/xattr.h]) +AC_CHECK_HEADERS([sys/uio.h sys/xattr.h]) if test "$ac_cv_header_regex_h" = "yes"; then AC_SEARCH_LIBS([regcomp], [pcreposix]) @@ -116,6 +116,7 @@ AC_CHECK_MEMBERS([struct sockaddr_in.sin_len],,, [[ ]]) AC_CHECK_DECLS([INFTIM],,, [[#include ]]) AC_CHECK_DECLS([SO_PEERCRED],,, [[#include ]]) +AC_CHECK_DECLS([O_BINARY],,,) AC_HEADER_TIME AC_STRUCT_TM AX_CHECK_DIRENT_D_TYPE @@ -124,14 +125,14 @@ AX_CHECK_DEFINE_PRAGMA if test "x$ac_cv_c_bigendian" != "xyes"; then AX_BSWAP64 fi + if test "$target_os" != "mingw32"; then AX_RANDOM_DEVICE -fi -AX_CHECK_MOUNT_POINT(,[ - if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then + AX_CHECK_MOUNT_POINT(,[ AC_MSG_ERROR([[cannot work out how to discover mount points on your platform]]) - fi ]) +fi + AX_CHECK_MALLOC_WORKAROUND @@ -238,6 +239,7 @@ A summary of the build configuration is below. Box Backup will function without these features, but will work better where they are present. Refer to the documentation for more information on each feature. +Regular expressions: $ac_cv_header_regex_h Large files: $have_large_file_support Berkeley DB: $ax_path_bdb_ok Readline: $have_libreadline -- cgit v1.2.3 From aad966c81fd2c9b2df5cb301928e0aed6ffbbfe6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 21:52:27 +0000 Subject: * docs/backup/win32_build_on_linux_using_mingw.txt - Revert to trunk - --- docs/backup/win32_build_on_linux_using_mingw.txt | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/docs/backup/win32_build_on_linux_using_mingw.txt b/docs/backup/win32_build_on_linux_using_mingw.txt index 12261d51..a3243a50 100644 --- a/docs/backup/win32_build_on_linux_using_mingw.txt +++ b/docs/backup/win32_build_on_linux_using_mingw.txt @@ -7,11 +7,6 @@ Install the MinGW cross-compiler for Windows: - Fedora and SuSE users can download RPM packages from [http://mirzam.it.vu.nl/mingw/] -You will need to know the prefix used by the cross-compiler executables. -It will usually be something like "ix86-mingw32*-". All the binaries in the -cross-compiler package will start with this prefix. The documentation below -assumes that it is "i386-mingw32-". Adjust to taste. - Download Zlib from [http://www.zlib.net/], unpack and enter source directory: export CC=i386-mingw32-gcc @@ -21,18 +16,7 @@ Download Zlib from [http://www.zlib.net/], unpack and enter source directory: make make install prefix=/usr/local/i386-mingw32 -Download OpenSSL 0.9.8b from -[http://www.openssl.org/source/openssl-0.9.8b.tar.gz] - -Unpack and configure: - - tar xzvf openssl-0.9.8b.tar.gz - cd openssl-0.9.8b - ./Configure mingw - make makefile.one - wget http://bbdev.fluffy.co.uk/svn/box/chris/win32/support/openssl-0.9.8b-mingw-cross.patch - patch -p1 < openssl-0.9.8b-mingw-cross.patch - make -f makefile.one +Download OpenSSL 0.9.7 from Configure Box with: @@ -43,6 +27,5 @@ Configure Box with: export CXXFLAGS="-mthreads" export LDFLAGS="-mthreads" export LIBS="-lcrypto -lws2_32 -lgdi32" - (if you don't have a "configure" file, run "./bootstrap") ./configure --target=i386-mingw32 - make CXX="$CXX" AR="$AR" RANLIB="$RANLIB" WINDRES="i386-mingw32-windres" + make CXX="$CXX" AR="$AR" RANLIB="$RANLIB" -- cgit v1.2.3 From b661881dc58e85a484f7d036a33858b71e808722 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 21:53:19 +0000 Subject: * docs/backup/win32_build_on_linux_using_mingw.txt (refs #3) Updated documentation for building Win32 native builds on Linux --- docs/backup/win32_build_on_linux_using_mingw.txt | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/docs/backup/win32_build_on_linux_using_mingw.txt b/docs/backup/win32_build_on_linux_using_mingw.txt index a3243a50..12261d51 100644 --- a/docs/backup/win32_build_on_linux_using_mingw.txt +++ b/docs/backup/win32_build_on_linux_using_mingw.txt @@ -7,6 +7,11 @@ Install the MinGW cross-compiler for Windows: - Fedora and SuSE users can download RPM packages from [http://mirzam.it.vu.nl/mingw/] +You will need to know the prefix used by the cross-compiler executables. +It will usually be something like "ix86-mingw32*-". All the binaries in the +cross-compiler package will start with this prefix. The documentation below +assumes that it is "i386-mingw32-". Adjust to taste. + Download Zlib from [http://www.zlib.net/], unpack and enter source directory: export CC=i386-mingw32-gcc @@ -16,7 +21,18 @@ Download Zlib from [http://www.zlib.net/], unpack and enter source directory: make make install prefix=/usr/local/i386-mingw32 -Download OpenSSL 0.9.7 from +Download OpenSSL 0.9.8b from +[http://www.openssl.org/source/openssl-0.9.8b.tar.gz] + +Unpack and configure: + + tar xzvf openssl-0.9.8b.tar.gz + cd openssl-0.9.8b + ./Configure mingw + make makefile.one + wget http://bbdev.fluffy.co.uk/svn/box/chris/win32/support/openssl-0.9.8b-mingw-cross.patch + patch -p1 < openssl-0.9.8b-mingw-cross.patch + make -f makefile.one Configure Box with: @@ -27,5 +43,6 @@ Configure Box with: export CXXFLAGS="-mthreads" export LDFLAGS="-mthreads" export LIBS="-lcrypto -lws2_32 -lgdi32" + (if you don't have a "configure" file, run "./bootstrap") ./configure --target=i386-mingw32 - make CXX="$CXX" AR="$AR" RANLIB="$RANLIB" + make CXX="$CXX" AR="$AR" RANLIB="$RANLIB" WINDRES="i386-mingw32-windres" -- cgit v1.2.3 From de770199ef641369de102f1d9be740e19a0e191b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 21:55:11 +0000 Subject: * infrastructure/BoxPlatform.pm.in - Revert to trunk --- infrastructure/BoxPlatform.pm.in | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in index 828516e2..afcbee6e 100644 --- a/infrastructure/BoxPlatform.pm.in +++ b/infrastructure/BoxPlatform.pm.in @@ -1,26 +1,14 @@ package BoxPlatform; use Exporter; @ISA = qw/Exporter/; -@EXPORT = qw/$build_os $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows/; +@EXPORT = qw/$build_os $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext/; BEGIN { # which OS are we building under? - $target_os = '@target_os@'; - $target_windows = 0; - $target_windows = 1 if $target_os =~ m'^mingw32' - or $target_os eq "winnt"; - - if ($^O eq "MSWin32" and not -x "/usr/bin/uname") - { - $build_os = "winnt"; - } - else - { - $build_os = `uname`; - chomp $build_os; - } + $build_os = `uname`; + chomp $build_os; # Cygwin Builds usually something like CYGWIN_NT-5.0, CYGWIN_NT-5.1 # Box Backup tried on Win2000,XP only :) @@ -34,18 +22,11 @@ BEGIN $platform_compile_line_extra =~ s/ -O2//; $platform_link_line_extra = '@LDFLAGS@'; $platform_lib_files = '@LIBS@'; + $target_os = '@target_os@'; $platform_exe_ext = '@EXEEXT@'; # get version - if (! -r "VERSION.txt" and -r "../../VERSION.txt") - { - open VERSION,"../../VERSION.txt" or die "../../VERSION.txt: $!"; - } - else - { - open VERSION,"VERSION.txt" or die "VERSION.txt: $!"; - } - + open VERSION,"VERSION.txt" or die "VERSION.txt: $!"; $product_version = ; chomp $product_version; $product_name = ; -- cgit v1.2.3 From 8f9b028e742dd186757714f23e25d551bfa30556 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 21:57:48 +0000 Subject: * infrastructure/BoxPlatform.pm.in Determine whether we are building for Windows or not, and export that information Search for VERSION.txt in a few more places, for example when running Perl scripts like getversion.pl (refs #3) --- infrastructure/BoxPlatform.pm.in | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in index afcbee6e..828516e2 100644 --- a/infrastructure/BoxPlatform.pm.in +++ b/infrastructure/BoxPlatform.pm.in @@ -1,14 +1,26 @@ package BoxPlatform; use Exporter; @ISA = qw/Exporter/; -@EXPORT = qw/$build_os $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext/; +@EXPORT = qw/$build_os $target_os $make_command $bsd_make $platform_define $platform_cpu $gcc_v3 $product_version $product_name $install_into_dir $sub_make_options $platform_compile_line_extra $platform_link_line_extra $platform_lib_files $platform_exe_ext $target_windows/; BEGIN { # which OS are we building under? - $build_os = `uname`; - chomp $build_os; + $target_os = '@target_os@'; + $target_windows = 0; + $target_windows = 1 if $target_os =~ m'^mingw32' + or $target_os eq "winnt"; + + if ($^O eq "MSWin32" and not -x "/usr/bin/uname") + { + $build_os = "winnt"; + } + else + { + $build_os = `uname`; + chomp $build_os; + } # Cygwin Builds usually something like CYGWIN_NT-5.0, CYGWIN_NT-5.1 # Box Backup tried on Win2000,XP only :) @@ -22,11 +34,18 @@ BEGIN $platform_compile_line_extra =~ s/ -O2//; $platform_link_line_extra = '@LDFLAGS@'; $platform_lib_files = '@LIBS@'; - $target_os = '@target_os@'; $platform_exe_ext = '@EXEEXT@'; # get version - open VERSION,"VERSION.txt" or die "VERSION.txt: $!"; + if (! -r "VERSION.txt" and -r "../../VERSION.txt") + { + open VERSION,"../../VERSION.txt" or die "../../VERSION.txt: $!"; + } + else + { + open VERSION,"VERSION.txt" or die "VERSION.txt: $!"; + } + $product_version = ; chomp $product_version; $product_name = ; -- cgit v1.2.3 From 7f0afeb139fa0a490e6cf2302ca3048a8ce3971e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 21:58:47 +0000 Subject: * buildenv-testmain-template.cpp - Revert to trunk --- infrastructure/buildenv-testmain-template.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index c64c1fa5..f95f01e6 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -41,8 +41,6 @@ int test(int argc, const char *argv[]); #endif int failures = 0; -int first_fail_line; -std::string first_fail_file; int filedes_open_at_beginning = -1; @@ -130,10 +128,7 @@ int main(int argc, const char *argv[]) } if(failures > 0) { - printf("FAILED: %d tests failed (first at " - "%s:%d)\n", failures, - first_fail_file.c_str(), - first_fail_line); + printf("FAILED: %d tests failed\n", failures); } else { -- cgit v1.2.3 From 4f8f01cee6b1cd29186d9c8dbfe9e98fa7595433 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:00:04 +0000 Subject: * infrastructure/buildenv-testmain-template.cpp Record the file and line of first test failure, and print them at the end of the test, useful for debugging when the first failure has scrolled off screen (refs #3) --- infrastructure/buildenv-testmain-template.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index f95f01e6..c64c1fa5 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -41,6 +41,8 @@ int test(int argc, const char *argv[]); #endif int failures = 0; +int first_fail_line; +std::string first_fail_file; int filedes_open_at_beginning = -1; @@ -128,7 +130,10 @@ int main(int argc, const char *argv[]) } if(failures > 0) { - printf("FAILED: %d tests failed\n", failures); + printf("FAILED: %d tests failed (first at " + "%s:%d)\n", failures, + first_fail_file.c_str(), + first_fail_line); } else { -- cgit v1.2.3 From bd4bb103b1d776aafca77fdb7ea1cd6f56e0150a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:01:53 +0000 Subject: * infrastructure/makebuildenv.pl.in - Revert to trunk --- infrastructure/makebuildenv.pl.in | 144 +++++++++++--------------------------- 1 file changed, 40 insertions(+), 104 deletions(-) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index 9306a8c1..f70321a7 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -14,7 +14,8 @@ $|=1; print "Box build environment setup.\n\n"; -my @implicit_deps = ('lib/common'); + +my $implicit_dep = 'lib/common'; # work out platform variables use lib 'infrastructure'; @@ -37,15 +38,11 @@ unless(-d 'local') # flags about the environment my %env_flags; -my $windows_include_path = ""; -if ($target_windows) -{ - $module_dependency{"lib/common"} = ["lib/win32"]; - push @implicit_deps, "lib/win32"; -} -else +my $windows_include_path = "-I../../lib/win32 "; +if ($target_os ne "mingw32" && $target_os ne "winnt") { - # $env_flags{'IGNORE_lib/win32'} = 1; + $windows_include_path = ""; + $env_flags{'IGNORE_lib/win32'} = 1; } # print "Flag: $_\n" for(keys %env_flags); @@ -114,7 +111,7 @@ close FINDAUTOGEN; print "done\n\n"; -# open test main program template file +# open test mail program template file my $test_template_file = 'infrastructure/buildenv-testmain-template.cpp'; open FL,$test_template_file or die "Can't open test template file\n"; my $test_template; @@ -274,7 +271,7 @@ for(@modules_files) push @md,$_ unless ignore_module($_) } } - $module_dependency{$mod} = [@implicit_deps,@md]; + $module_dependency{$mod} = [$implicit_dep,@md]; $module_library_link_opts{$mod} = [@lo]; # make directories, but not if we're using an external library and this a library module @@ -289,21 +286,17 @@ for(@modules_files) } # make dirs for implicit dep -foreach my $dep (@implicit_deps) -{ - mkdir "release/$dep",0755; - mkdir "debug/$dep",0755; -} +mkdir "release/$implicit_dep",0755; +mkdir "debug/$implicit_dep",0755; # write a list of all the modules we've configured to use -open CONFIGURED_MODS,'>local/modules.h.new' or die - "Can't write configured modules list"; +open CONFIGURED_MODS,'>local/modules.h' or die "Can't write configured modules list"; print CONFIGURED_MODS <<__E; // automatically generated file, do not edit #ifndef _CONFIGURED_MODULES__H #define _CONFIGURED_MODULES__H __E -for(@implicit_deps,@modules) +for($implicit_dep,@modules) { my $m = $_; $m =~ s~/~_~; @@ -313,11 +306,11 @@ print CONFIGURED_MODS <<__E; #endif // _CONFIGURED_MODULES__H __E close CONFIGURED_MODS; -update_if_changed("local/modules.h"); + # now make a list of all the .h files we can find, recording which module they're in my %hfiles; -for my $mod (@modules, @implicit_deps) +for my $mod (@modules, $implicit_dep) { opendir DIR,$mod; my @items = readdir DIR; @@ -354,7 +347,7 @@ for my $mod (@modules, @implicit_deps) } } -for my $mod (@modules, @implicit_deps) +for my $mod (@modules, $implicit_dep) { opendir DIR,$mod; for my $h (grep /\.h\Z/i, readdir DIR) @@ -380,10 +373,9 @@ for my $mod (@modules, @implicit_deps) print "done\n\nGenerating Makefiles...\n"; -my %module_resources_win32; # Then write a makefile for each module -for my $mod (@implicit_deps, @modules) +for my $mod (@modules, $implicit_dep) { print $mod,"\n"; @@ -394,19 +386,15 @@ for my $mod (@implicit_deps, @modules) { my $testmain = $test_template; $testmain =~ s/TEST_NAME/$name/g; - open TESTMAIN,">$mod/_main.cpp.new" or die - "Can't open test main file for $mod for writing\n"; + open TESTMAIN,">$mod/_main.cpp" or die "Can't open test main file for $mod for writing\n"; print TESTMAIN $testmain; close TESTMAIN; - update_if_changed("$mod/_main.cpp"); # test file... sub writetestfile { my ($filename,$runcmd,$module) = @_; - open TESTFILE,">$filename.new" or die - "Can't open test script file for $module " . - "for writing\n"; + open TESTFILE,">$filename" or die "Can't open test script file for $module for writing\n"; print TESTFILE "#!/bin/sh\necho TEST: $module\n"; if(-d "$module/testfiles") { @@ -425,13 +413,12 @@ __E } print TESTFILE "$runcmd\n"; close TESTFILE; - update_if_changed($filename); } writetestfile("$mod/_t", - './test' . $platform_exe_ext . ' $1 $2 $3 $4 $5', $mod); + './test' . $platform_exe_ext . '$1 $2 $3 $4 $5', $mod); writetestfile("$mod/_t-gdb", - 'gdb ./test' . $platform_exe_ext, $mod); + 'gdb ./test ' . $platform_exe_ext, $mod); } @@ -454,14 +441,14 @@ __E add_mod_deps(\@deps_raw, $mod); # and then dedup and reorder them my %d_done; - foreach my $dep (reverse @deps_raw) + for(my $a = $#deps_raw; $a >= 0; $a--) { - if(!exists $d_done{$dep}) + if(!exists $d_done{$deps_raw[$a]}) { # insert - push @all_deps_for_module, $dep; + push @all_deps_for_module, $deps_raw[$a]; # mark as done - $d_done{$dep} = 1; + $d_done{$deps_raw[$a]} = 1; } } } @@ -493,12 +480,11 @@ __E # start the makefile my $mk_name_extra = ($bsd_make)?'':'X'; - open MAKE,">$mod/Makefile".$mk_name_extra.".new" or die - "Can't open Makefile for $mod\n"; + open MAKE,">$mod/Makefile".$mk_name_extra or die "Can't open Makefile for $mod\n"; my $debug_link_extra = ($target_is_library)?'':'../../debug/lib/debug/debug.a'; my $release_flags = "-O2"; - if ($target_windows) + if ($target_os eq "mingw32") { $release_flags = "-O0 -g"; } @@ -513,7 +499,6 @@ CXX = g++ AR = ar RANLIB = ranlib PERL = "@PERL@" -WINDRES = windres .ifdef RELEASE CXXFLAGS = -DNDEBUG $release_flags -Wall $include_paths $extra_platform_defines -DBOX_VERSION="\\"$product_version\\"" OUTBASE = ../../release @@ -561,7 +546,7 @@ __E @items = (@items, @autogen_items); } - # first, obtain a list of dependencies within the .h files + # first, obtain a list of depenencies within the .h files my %headers; for my $h (grep /\.h\Z/i, @items) { @@ -581,30 +566,19 @@ __E # then... do the cpp files... my @obj_base; - for my $file (@items) + for my $cpp (@items) { - my $is_cpp = $file =~ m/\A(.+)\.cpp\Z/i; - my $is_rc = $file =~ m/\A(.+)\.rc\Z/i; - my $base = $1; - - if ($target_windows) - { - next if not $is_cpp and not $is_rc; - } - else - { - next if not $is_cpp; - } - - next if $file =~ /\A\._/; # Temp Mac OS Resource hack + next unless $cpp =~ m/\A(.+)\.cpp\Z/i; + next if $cpp =~ /\A\._/; # Temp Mac OS Resource hack # store for later + my $base = $1; push @obj_base,$base; # get the file... - open FL,"$mod/$file"; + open FL,"$mod/$cpp"; my $f; - read FL,$f,-s "$mod/$file"; + read FL,$f,-s "$mod/$cpp"; close FL; my %dep; @@ -618,29 +592,10 @@ __E my $out_name = '$(OUTDIR)/'.$base.'.o'; # write the line for this cpp file - my @dep_paths = map - { - ($hfiles{$_} eq $mod) - ? $_ - : '../../'.$hfiles{$_}."/$_" - } - keys %dep; + $make .= $out_name.': '.join(' ',$cpp,map + { ($hfiles{$_} eq $mod)?$_:'../../'.$hfiles{$_}."/$_" } keys %dep)."\n"; + $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra -c $cpp -o $out_name\n\n"; - $make .= $out_name.': '.join(' ',$file,@dep_paths)."\n"; - - if ($is_cpp) - { - $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra ". - "-c $file -o $out_name\n\n"; - } - elsif ($is_rc) - { - $make .= "\t\$(WINDRES) $file $out_name\n\n"; - my $res_list = $module_resources_win32{$mod}; - $res_list ||= []; - push @$res_list, $base.'.o'; - $module_resources_win32{$mod} = $res_list; - } } my $has_deps = ($#{$module_dependency{$mod}} >= 0); @@ -692,28 +647,11 @@ __E additional_objects_from_make_fragment("$mod/Makefile.extra.$build_os", \@objs, \@makefile_includes); my $o_file_list = join(' ',map {'$(OUTDIR)/'.$_.'.o'} @objs); - - if ($has_deps and not $bsd_make) - { - print MAKE ".PHONY: all\n" . - "all: dep_modules $end_target\n\n"; - } - print MAKE $end_target,': ',$o_file_list; + print MAKE ' dep_modules' if $has_deps and not $bsd_make; print MAKE " ",$lib_files unless $target_is_library; print MAKE "\n"; - if ($target_windows) - { - foreach my $dep (@all_deps_for_module) - { - my $res_list = $module_resources_win32{$dep}; - next unless $res_list; - $o_file_list .= ' '.join(' ', - map {'$(OUTBASE)/'.$dep."/$_"} @$res_list); - } - } - # stuff to make the final target... if($target_is_library) { @@ -792,8 +730,8 @@ __E if(!$bsd_make) { # need to post process this into a GNU makefile - open MAKE,">$mod/Makefile.new" or die $!; - open MAKEB,"$mod/MakefileX.new" or die $!; + open MAKE,">$mod/Makefile"; + open MAKEB,"$mod/MakefileX"; while() { @@ -805,10 +743,8 @@ __E close MAKEB; close MAKE; - unlink "$mod/MakefileX.new"; + unlink "$mod/MakefileX"; } - - update_if_changed("$mod/Makefile"); } print "\nType 'cd ; $make_command' to build a module\n\n"; -- cgit v1.2.3 From 1cba2ee82939ad6c04176cbc31b61b1971ef8a45 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:09:46 +0000 Subject: * infrastructure/makebuildenv.pl.in Support multiple implicit dependencies Add lib/win32 as an implicit dependency on Win32 Make lib/common depend on lib/win32 on Win32 Fix space between test file name platform executable extension, and between executable name and arguments, in test shell scripts Add support for compiling resource files (.rc) on Win32 Fix dependencies to avoid unnecessary rebuilds when not using BSD make Code cleanups Fix typos (refs #3) --- infrastructure/makebuildenv.pl.in | 117 ++++++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 31 deletions(-) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index f70321a7..41623bc2 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -14,8 +14,7 @@ $|=1; print "Box build environment setup.\n\n"; - -my $implicit_dep = 'lib/common'; +my @implicit_deps = ('lib/common'); # work out platform variables use lib 'infrastructure'; @@ -38,11 +37,15 @@ unless(-d 'local') # flags about the environment my %env_flags; -my $windows_include_path = "-I../../lib/win32 "; -if ($target_os ne "mingw32" && $target_os ne "winnt") +my $windows_include_path = ""; +if ($target_windows) +{ + $module_dependency{"lib/common"} = ["lib/win32"]; + push @implicit_deps, "lib/win32"; +} +else { - $windows_include_path = ""; - $env_flags{'IGNORE_lib/win32'} = 1; + # $env_flags{'IGNORE_lib/win32'} = 1; } # print "Flag: $_\n" for(keys %env_flags); @@ -271,7 +274,7 @@ for(@modules_files) push @md,$_ unless ignore_module($_) } } - $module_dependency{$mod} = [$implicit_dep,@md]; + $module_dependency{$mod} = [@implicit_deps,@md]; $module_library_link_opts{$mod} = [@lo]; # make directories, but not if we're using an external library and this a library module @@ -286,8 +289,11 @@ for(@modules_files) } # make dirs for implicit dep -mkdir "release/$implicit_dep",0755; -mkdir "debug/$implicit_dep",0755; +foreach my $dep (@implicit_deps) +{ + mkdir "release/$dep",0755; + mkdir "debug/$dep",0755; +} # write a list of all the modules we've configured to use open CONFIGURED_MODS,'>local/modules.h' or die "Can't write configured modules list"; @@ -296,7 +302,7 @@ print CONFIGURED_MODS <<__E; #ifndef _CONFIGURED_MODULES__H #define _CONFIGURED_MODULES__H __E -for($implicit_dep,@modules) +for(@implicit_deps,@modules) { my $m = $_; $m =~ s~/~_~; @@ -310,7 +316,7 @@ close CONFIGURED_MODS; # now make a list of all the .h files we can find, recording which module they're in my %hfiles; -for my $mod (@modules, $implicit_dep) +for my $mod (@modules, @implicit_deps) { opendir DIR,$mod; my @items = readdir DIR; @@ -347,7 +353,7 @@ for my $mod (@modules, $implicit_dep) } } -for my $mod (@modules, $implicit_dep) +for my $mod (@modules, @implicit_deps) { opendir DIR,$mod; for my $h (grep /\.h\Z/i, readdir DIR) @@ -373,9 +379,10 @@ for my $mod (@modules, $implicit_dep) print "done\n\nGenerating Makefiles...\n"; +my %module_resources_win32; # Then write a makefile for each module -for my $mod (@modules, $implicit_dep) +for my $mod (@implicit_deps, @modules) { print $mod,"\n"; @@ -416,9 +423,9 @@ __E } writetestfile("$mod/_t", - './test' . $platform_exe_ext . '$1 $2 $3 $4 $5', $mod); + './test' . $platform_exe_ext . ' $1 $2 $3 $4 $5', $mod); writetestfile("$mod/_t-gdb", - 'gdb ./test ' . $platform_exe_ext, $mod); + 'gdb ./test' . $platform_exe_ext, $mod); } @@ -441,14 +448,14 @@ __E add_mod_deps(\@deps_raw, $mod); # and then dedup and reorder them my %d_done; - for(my $a = $#deps_raw; $a >= 0; $a--) + foreach my $dep (reverse @deps_raw) { - if(!exists $d_done{$deps_raw[$a]}) + if(!exists $d_done{$dep}) { # insert - push @all_deps_for_module, $deps_raw[$a]; + push @all_deps_for_module, $dep; # mark as done - $d_done{$deps_raw[$a]} = 1; + $d_done{$dep} = 1; } } } @@ -484,7 +491,7 @@ __E my $debug_link_extra = ($target_is_library)?'':'../../debug/lib/debug/debug.a'; my $release_flags = "-O2"; - if ($target_os eq "mingw32") + if ($target_windows) { $release_flags = "-O0 -g"; } @@ -499,6 +506,7 @@ CXX = g++ AR = ar RANLIB = ranlib PERL = "@PERL@" +WINDRES = windres .ifdef RELEASE CXXFLAGS = -DNDEBUG $release_flags -Wall $include_paths $extra_platform_defines -DBOX_VERSION="\\"$product_version\\"" OUTBASE = ../../release @@ -546,7 +554,7 @@ __E @items = (@items, @autogen_items); } - # first, obtain a list of depenencies within the .h files + # first, obtain a list of dependencies within the .h files my %headers; for my $h (grep /\.h\Z/i, @items) { @@ -566,19 +574,30 @@ __E # then... do the cpp files... my @obj_base; - for my $cpp (@items) + for my $file (@items) { - next unless $cpp =~ m/\A(.+)\.cpp\Z/i; - next if $cpp =~ /\A\._/; # Temp Mac OS Resource hack + my $is_cpp = $file =~ m/\A(.+)\.cpp\Z/i; + my $is_rc = $file =~ m/\A(.+)\.rc\Z/i; + my $base = $1; + + if ($target_windows) + { + next if not $is_cpp and not $is_rc; + } + else + { + next if not $is_cpp; + } + + next if $file =~ /\A\._/; # Temp Mac OS Resource hack # store for later - my $base = $1; push @obj_base,$base; # get the file... - open FL,"$mod/$cpp"; + open FL,"$mod/$file"; my $f; - read FL,$f,-s "$mod/$cpp"; + read FL,$f,-s "$mod/$file"; close FL; my %dep; @@ -592,10 +611,29 @@ __E my $out_name = '$(OUTDIR)/'.$base.'.o'; # write the line for this cpp file - $make .= $out_name.': '.join(' ',$cpp,map - { ($hfiles{$_} eq $mod)?$_:'../../'.$hfiles{$_}."/$_" } keys %dep)."\n"; - $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra -c $cpp -o $out_name\n\n"; + my @dep_paths = map + { + ($hfiles{$_} eq $mod) + ? $_ + : '../../'.$hfiles{$_}."/$_" + } + keys %dep; + $make .= $out_name.': '.join(' ',$file,@dep_paths)."\n"; + + if ($is_cpp) + { + $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra ". + "-c $file -o $out_name\n\n"; + } + elsif ($is_rc) + { + $make .= "\t\$(WINDRES) $file $out_name\n\n"; + my $res_list = $module_resources_win32{$mod}; + $res_list ||= []; + push @$res_list, $base.'.o'; + $module_resources_win32{$mod} = $res_list; + } } my $has_deps = ($#{$module_dependency{$mod}} >= 0); @@ -647,11 +685,28 @@ __E additional_objects_from_make_fragment("$mod/Makefile.extra.$build_os", \@objs, \@makefile_includes); my $o_file_list = join(' ',map {'$(OUTDIR)/'.$_.'.o'} @objs); + + if ($has_deps and not $bsd_make) + { + print MAKE ".PHONY: all\n" . + "all: dep_modules $end_target\n\n"; + } + print MAKE $end_target,': ',$o_file_list; - print MAKE ' dep_modules' if $has_deps and not $bsd_make; print MAKE " ",$lib_files unless $target_is_library; print MAKE "\n"; + if ($target_windows) + { + foreach my $dep (@all_deps_for_module) + { + my $res_list = $module_resources_win32{$dep}; + next unless $res_list; + $o_file_list .= ' '.join(' ', + map {'$(OUTBASE)/'.$dep."/$_"} @$res_list); + } + } + # stuff to make the final target... if($target_is_library) { -- cgit v1.2.3 From 04302de443ce25e6cda606bd15c173270ddcf783 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:11:50 +0000 Subject: * lib/backupclient/BackupClientFileAttributes.cpp - Revert to trunk --- lib/backupclient/BackupClientFileAttributes.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp index ace72cf8..974db3c9 100644 --- a/lib/backupclient/BackupClientFileAttributes.cpp +++ b/lib/backupclient/BackupClientFileAttributes.cpp @@ -642,7 +642,6 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const } // If working as root, set user IDs - #ifndef WIN32 if(::geteuid() == 0) { #ifndef HAVE_LCHOWN @@ -662,7 +661,6 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const } #endif } - #endif if(static_cast(xattrOffset+sizeof(u_int32_t))<=mpClearAttributes->GetSize()) { -- cgit v1.2.3 From 0ed31fe9c03c894be162974e3c7139f5c0f7f040 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:14:22 +0000 Subject: * lib/backupclient/BackupClientFileAttributes.cpp Don't call geteuid() on Win32, since it's emulated, always returns 0, and I want to remove it entirely (refs #3) --- lib/backupclient/BackupClientFileAttributes.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp index 974db3c9..49bae665 100644 --- a/lib/backupclient/BackupClientFileAttributes.cpp +++ b/lib/backupclient/BackupClientFileAttributes.cpp @@ -642,7 +642,11 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const } // If working as root, set user IDs + #ifdef WIN32 + if(0) + #else if(::geteuid() == 0) + #endif { #ifndef HAVE_LCHOWN // only if not a link, can't set their owner on this platform -- cgit v1.2.3 From 6737cc23c9b9cd71060b06f41283dca9549898ef Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:15:09 +0000 Subject: * lib/backupclient/BackupStoreFile.cpp - Revert to trunk --- lib/backupclient/BackupStoreFile.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp index 278bf50a..f5a55207 100644 --- a/lib/backupclient/BackupStoreFile.cpp +++ b/lib/backupclient/BackupStoreFile.cpp @@ -289,8 +289,6 @@ void BackupStoreFile::DecodeFile(IOStream &rEncodedFile, const char *DecodedFile // Copy it out to the file stream->CopyStreamTo(out); } - - out.Close(); // Write the attributes stream->GetAttributes().WriteAttributes(DecodedFilename); -- cgit v1.2.3 From 3a30b42c228ae481bd95a4363c853f477573b20d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:16:17 +0000 Subject: * lib/backupclient/BackupStoreFile.cpp Close file before trying to apply attributes to it. Otherwise, when we close it the timestamp will be updated on Win32 (refs #3) --- lib/backupclient/BackupStoreFile.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp index f5a55207..278bf50a 100644 --- a/lib/backupclient/BackupStoreFile.cpp +++ b/lib/backupclient/BackupStoreFile.cpp @@ -289,6 +289,8 @@ void BackupStoreFile::DecodeFile(IOStream &rEncodedFile, const char *DecodedFile // Copy it out to the file stream->CopyStreamTo(out); } + + out.Close(); // Write the attributes stream->GetAttributes().WriteAttributes(DecodedFilename); -- cgit v1.2.3 From c3e3f974e26957a674729f761e27534c0db2b9d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:17:12 +0000 Subject: * lib/backupclient/BackupStoreObjectDump.cpp - Revert to trunk --- lib/backupclient/BackupStoreObjectDump.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/backupclient/BackupStoreObjectDump.cpp b/lib/backupclient/BackupStoreObjectDump.cpp index d3d9cc17..b4ccc731 100644 --- a/lib/backupclient/BackupStoreObjectDump.cpp +++ b/lib/backupclient/BackupStoreObjectDump.cpp @@ -113,13 +113,7 @@ void BackupStoreDirectory::Dump(void *clibFileHandle, bool ToTrace) // Output item int16_t f = (*i)->GetFlags(); -#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 + OutputLine(file, ToTrace, "%06llx %4lld %016llx %4d %3d %4d%s%s%s%s%s%s\n", (*i)->GetObjectID(), (*i)->GetSizeInBlocks(), (*i)->GetAttributesHash(), -- cgit v1.2.3 From 76f120d7ec171c3e0b88bc1fe317a4b0dacf19a5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:18:02 +0000 Subject: * lib/backupclient/BackupStoreObjectDump.cpp Fix format strings on Win32 (refs #3) --- lib/backupclient/BackupStoreObjectDump.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/backupclient/BackupStoreObjectDump.cpp b/lib/backupclient/BackupStoreObjectDump.cpp index b4ccc731..d3d9cc17 100644 --- a/lib/backupclient/BackupStoreObjectDump.cpp +++ b/lib/backupclient/BackupStoreObjectDump.cpp @@ -113,7 +113,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(), -- cgit v1.2.3 From 5cfed38449e0265dcfcc0bd684b2bf958390552f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:19:09 +0000 Subject: * lib/backupstore/BackupStoreAccounts.cpp - Revert to trunk --- lib/backupstore/BackupStoreAccounts.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index eb10b385..36d9cad3 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -141,9 +141,8 @@ 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" DIRECTORY_SEPARATOR, ID); - return std::string(std::string(BOX_RAIDFILE_ROOT_BBSTORED - DIRECTORY_SEPARATOR) + accid); + ::sprintf(accid, "%08x/", ID); + return std::string(std::string(BOX_RAIDFILE_ROOT_BBSTORED DIRECTORY_SEPARATOR) + accid); } -- cgit v1.2.3 From 98cae61cf5d5ffc29ccdca2c75a415702dd13936 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:20:45 +0000 Subject: Use DIRECTORY_SEPARATOR instead of assuming that it's a forward slash --- lib/backupstore/BackupStoreAccounts.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 36d9cad3..eb10b385 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -141,8 +141,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); } -- cgit v1.2.3 From 8c087ccbf91e7e5c475c447519bd45a5ec69911e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:22:35 +0000 Subject: Revert to trunk --- lib/backupstore/BackupStoreCheck.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/backupstore/BackupStoreCheck.cpp b/lib/backupstore/BackupStoreCheck.cpp index 16d397a2..eca1df2f 100644 --- a/lib/backupstore/BackupStoreCheck.cpp +++ b/lib/backupstore/BackupStoreCheck.cpp @@ -328,8 +328,7 @@ 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] == DIRECTORY_SEPARATOR_ASCHAR); + ASSERT(dirName.size() > 4 && dirName[dirName.size() - 4] == '/'); // Remove the filename from it dirName.resize(dirName.size() - 4); // four chars for "/o00" @@ -378,9 +377,7 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID) if(!fileOK) { // Unexpected or bad file, delete it - ::printf("Spurious file %s" DIRECTORY_SEPARATOR "%s " - "found%s\n", dirName.c_str(), (*i).c_str(), - mFixErrors?", deleting":""); + ::printf("Spurious file %s/%s found%s\n", dirName.c_str(), (*i).c_str(), mFixErrors?", deleting":""); ++mNumberErrorsFound; if(mFixErrors) { @@ -469,11 +466,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(...) -- cgit v1.2.3 From ee5edcd9303a50a8381dc5493171609e8f3c3d51 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:24:00 +0000 Subject: Use DIRECTORY_SEPARATOR instead of assuming that it's a forward slash (refs #3) --- lib/backupstore/BackupStoreCheck.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/backupstore/BackupStoreCheck.cpp b/lib/backupstore/BackupStoreCheck.cpp index eca1df2f..16eeecf9 100644 --- a/lib/backupstore/BackupStoreCheck.cpp +++ b/lib/backupstore/BackupStoreCheck.cpp @@ -328,7 +328,8 @@ 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" @@ -377,7 +378,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":""); + ::printf("Spurious file %s" DIRECTORY_SEPARATOR "%s " + "found%s\n", dirName.c_str(), (*i).c_str(), + mFixErrors?", deleting":""); ++mNumberErrorsFound; if(mFixErrors) { -- cgit v1.2.3 From 228ae771b9643d557ea7623e2de7ef077336d99c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:25:27 +0000 Subject: Revert to trunk --- lib/common/BoxPlatform.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h index cb83f7a9..b766706a 100644 --- a/lib/common/BoxPlatform.h +++ b/lib/common/BoxPlatform.h @@ -40,8 +40,8 @@ #endif #endif -// Slight hack; disable interception in raidfile test on Darwin and Windows -#if defined __APPLE__ || defined WIN32 +// Slight hack; disable interception on Darwin within raidfile test +#ifdef __APPLE__ // TODO: Replace with autoconf test #define PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE #endif @@ -138,11 +138,6 @@ #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 -- cgit v1.2.3 From ea96cab5ecd516360b684703de3f38981ce82b9e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:26:54 +0000 Subject: Disable intercept tests on Win32 as well Define O_BINARY to 0 (zero) if our platform doesn't have it (all except Win32?) which enables us to reduce #ifdefs (refs #3) --- lib/common/BoxPlatform.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h index b766706a..cb83f7a9 100644 --- a/lib/common/BoxPlatform.h +++ b/lib/common/BoxPlatform.h @@ -40,8 +40,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 @@ -138,6 +138,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 -- cgit v1.2.3 From 926350684c452b7d8c73cd2c11bed49be6139f17 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:28:35 +0000 Subject: Revert to trunk --- lib/common/FdGetLine.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/common/FdGetLine.h b/lib/common/FdGetLine.h index a18007a3..fecb0371 100644 --- a/lib/common/FdGetLine.h +++ b/lib/common/FdGetLine.h @@ -14,10 +14,6 @@ #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 -- cgit v1.2.3 From 0de8b64db1faec206adcffbd5e9c8d72f4930288 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:29:31 +0000 Subject: Make FDGETLINE_BUFFER_SIZE big enough for one unicode character on Win32, otherwise reading from console can fail due to insufficient buffer size. (refs #3) --- lib/common/FdGetLine.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/common/FdGetLine.h b/lib/common/FdGetLine.h index fecb0371..a18007a3 100644 --- a/lib/common/FdGetLine.h +++ b/lib/common/FdGetLine.h @@ -14,6 +14,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 -- cgit v1.2.3 From 472d823f46324a84ece80c97b5fd41744b937d0d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:30:27 +0000 Subject: Revert to trunk --- lib/common/Guards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/Guards.h b/lib/common/Guards.h index b1bca0fa..17d73b3f 100644 --- a/lib/common/Guards.h +++ b/lib/common/Guards.h @@ -24,7 +24,7 @@ #include "MemLeakFindOn.h" -template +template class FileHandleGuard { public: -- cgit v1.2.3 From d917c007a871e3570cf94bba6577e04272a20625 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:31:10 +0000 Subject: Add O_BINARY to default flags, since most files opened this way should be opened in binary mode on Win32 (refs #3) --- lib/common/Guards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/Guards.h b/lib/common/Guards.h index 17d73b3f..b1bca0fa 100644 --- a/lib/common/Guards.h +++ b/lib/common/Guards.h @@ -24,7 +24,7 @@ #include "MemLeakFindOn.h" -template +template class FileHandleGuard { public: -- cgit v1.2.3 From e0e456e245ff5b39a8675d70e19882599df135b7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:32:17 +0000 Subject: Revert to trunk --- lib/common/makeexception.pl.in | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/common/makeexception.pl.in b/lib/common/makeexception.pl.in index c03b8277..1564b75b 100755 --- a/lib/common/makeexception.pl.in +++ b/lib/common/makeexception.pl.in @@ -1,11 +1,9 @@ #!@PERL@ -use lib "../../infrastructure"; -use BoxPlatform; - # global exception list file my $global_list = '../../ExceptionCodes.txt'; + my @exception; my @exception_desc; my $class; @@ -48,8 +46,8 @@ close EXCEPTION_DESC; # write the code print "Generating $class exception...\n"; -open CPP,">autogen_${class}Exception.cpp.new" or die "Can't open cpp file for writing"; -open H,">autogen_${class}Exception.h.new" or die "Can't open h file for writing"; +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'; @@ -202,9 +200,6 @@ __E close H; close CPP; -update_if_changed("autogen_${class}Exception.cpp"); -update_if_changed("autogen_${class}Exception.h"); - # update the global exception list my $list_before; my $list_after; -- cgit v1.2.3 From 85d5ccab78c156a8113cfef02748facb91aa6393 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:33:05 +0000 Subject: Revert to trunk --- lib/common/UnixUser.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/common/UnixUser.cpp b/lib/common/UnixUser.cpp index d0fd337b..df2d0ddd 100644 --- a/lib/common/UnixUser.cpp +++ b/lib/common/UnixUser.cpp @@ -75,7 +75,6 @@ UnixUser::UnixUser(uid_t UID, gid_t GID) // -------------------------------------------------------------------------- UnixUser::~UnixUser() { -#ifndef WIN32 if(mRevertOnDestruction) { // Revert to "real" user and group id of the process @@ -85,7 +84,6 @@ UnixUser::~UnixUser() THROW_EXCEPTION(CommonException, CouldNotRestoreProcessUser) } } -#endif } @@ -100,7 +98,6 @@ UnixUser::~UnixUser() // -------------------------------------------------------------------------- void UnixUser::ChangeProcessUser(bool Temporary) { -#ifndef WIN32 if(Temporary) { // Change temporarily (change effective only) @@ -122,7 +119,6 @@ void UnixUser::ChangeProcessUser(bool Temporary) THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser) } } -#endif } -- cgit v1.2.3 From 186fbcc5fa57fa5899262d877f10be5cb4f87654 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:35:51 +0000 Subject: Disable all calls to set*id() on Win32 (doesn't work) (refs #3) --- lib/common/UnixUser.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/common/UnixUser.cpp b/lib/common/UnixUser.cpp index df2d0ddd..1ec9608d 100644 --- a/lib/common/UnixUser.cpp +++ b/lib/common/UnixUser.cpp @@ -78,8 +78,12 @@ UnixUser::~UnixUser() if(mRevertOnDestruction) { // Revert to "real" user and group id of the process + #ifdef WIN32 + if(0) + #else if(::setegid(::getgid()) != 0 || ::seteuid(::getuid()) != 0) + #endif { THROW_EXCEPTION(CommonException, CouldNotRestoreProcessUser) } @@ -101,8 +105,12 @@ void UnixUser::ChangeProcessUser(bool Temporary) if(Temporary) { // Change temporarily (change effective only) + #ifdef WIN32 + if(0) + #else if(::setegid(mGID) != 0 || ::seteuid(mUID) != 0) + #endif { THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser) } @@ -112,9 +120,13 @@ void UnixUser::ChangeProcessUser(bool Temporary) } else { - // Change perminantely (change all UIDs and GIDs) + // Change permanently (change all UIDs and GIDs) + #ifdef WIN32 + if(0) + #else if(::setgid(mGID) != 0 || ::setuid(mUID) != 0) + #endif { THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser) } -- cgit v1.2.3 From 7dc378feba507f8f3e03402496aeb99723651a8e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:37:03 +0000 Subject: Revert to trunk --- lib/raidfile/RaidFileRead.cpp | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp index bc728113..d60936fc 100644 --- a/lib/raidfile/RaidFileRead.cpp +++ b/lib/raidfile/RaidFileRead.cpp @@ -14,20 +14,10 @@ #include #include #include - -#ifdef HAVE_SYS_UIO_H #include -#endif - -#ifdef HAVE_SYSLOG_H #include -#endif - #include - -#ifdef HAVE_DIRENT_H #include -#endif #include #include @@ -593,8 +583,7 @@ 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 | O_BINARY, 0555); + mParityHandle = ::open(parityFilename.c_str(), O_RDONLY, 0555); if(mParityHandle == -1) { THROW_EXCEPTION(RaidFileException, OSError) @@ -1028,8 +1017,7 @@ std::auto_ptr 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 | O_BINARY, 0); + int osFileHandle = ::open(writeFilename.c_str(), O_RDONLY, 0); if(osFileHandle == -1) { THROW_EXCEPTION(RaidFileException, ErrorOpeningFileForRead) @@ -1067,15 +1055,13 @@ std::auto_ptr RaidFileRead::Open(int SetNumber, const std::string try { // Open stripe1 - stripe1 = ::open(stripe1Filename.c_str(), - O_RDONLY | O_BINARY, 0555); + stripe1 = ::open(stripe1Filename.c_str(), O_RDONLY, 0555); if(stripe1 == -1) { stripe1errno = errno; } // Open stripe2 - stripe2 = ::open(stripe2Filename.c_str(), - O_RDONLY | O_BINARY, 0555); + stripe2 = ::open(stripe2Filename.c_str(), O_RDONLY, 0555); if(stripe2 == -1) { stripe2errno = errno; @@ -1183,8 +1169,7 @@ std::auto_ptr RaidFileRead::Open(int SetNumber, const std::string // Open stripe1? if(existingFiles & RaidFileUtil::Stripe1Exists) { - stripe1 = ::open(stripe1Filename.c_str(), - O_RDONLY | O_BINARY, 0555); + stripe1 = ::open(stripe1Filename.c_str(), O_RDONLY, 0555); if(stripe1 == -1) { THROW_EXCEPTION(RaidFileException, OSError) @@ -1193,16 +1178,14 @@ std::auto_ptr RaidFileRead::Open(int SetNumber, const std::string // Open stripe2? if(existingFiles & RaidFileUtil::Stripe2Exists) { - stripe2 = ::open(stripe2Filename.c_str(), - O_RDONLY | O_BINARY, 0555); + stripe2 = ::open(stripe2Filename.c_str(), O_RDONLY, 0555); if(stripe2 == -1) { THROW_EXCEPTION(RaidFileException, OSError) } } // Open parity - parity = ::open(parityFilename.c_str(), - O_RDONLY | O_BINARY, 0555); + parity = ::open(parityFilename.c_str(), O_RDONLY, 0555); if(parity == -1) { THROW_EXCEPTION(RaidFileException, OSError) -- cgit v1.2.3 From e8cb13f44ca67a088c132545a4f2483b9588c98b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:39:45 +0000 Subject: (refs #3) Don't include headers that we don't have Open RAID files in binary mode --- lib/raidfile/RaidFileRead.cpp | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp index d60936fc..ad040c22 100644 --- a/lib/raidfile/RaidFileRead.cpp +++ b/lib/raidfile/RaidFileRead.cpp @@ -14,10 +14,19 @@ #include #include #include -#include -#include #include -#include + +#ifdef HAVE_SYS_UIO_H + #include +#endif + +#ifdef HAVE_SYSLOG_H + #include +#endif + +#ifdef HAVE_DIRENT_H + #include +#endif #include #include @@ -583,7 +592,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) @@ -1017,7 +1027,8 @@ std::auto_ptr 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) @@ -1055,13 +1066,15 @@ std::auto_ptr 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; @@ -1169,7 +1182,8 @@ std::auto_ptr 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) @@ -1178,14 +1192,16 @@ std::auto_ptr 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) -- cgit v1.2.3 From 6852b32189e57e928b1941687ad07b3b486f9460 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:44:18 +0000 Subject: Revert to trunk --- lib/raidfile/RaidFileWrite.cpp | 69 ++++++------------------------------------ 1 file changed, 10 insertions(+), 59 deletions(-) diff --git a/lib/raidfile/RaidFileWrite.cpp b/lib/raidfile/RaidFileWrite.cpp index b3c98701..e30162fa 100644 --- a/lib/raidfile/RaidFileWrite.cpp +++ b/lib/raidfile/RaidFileWrite.cpp @@ -104,8 +104,7 @@ void RaidFileWrite::Open(bool AllowOverwrite) writeFilename += 'X'; // Attempt to open - mOSFileHandle = ::open(writeFilename.c_str(), - O_WRONLY | O_CREAT | O_BINARY, + mOSFileHandle = ::open(writeFilename.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if(mOSFileHandle == -1) { @@ -116,7 +115,7 @@ void RaidFileWrite::Open(bool AllowOverwrite) #ifdef HAVE_FLOCK int errnoBlock = EWOULDBLOCK; if(::flock(mOSFileHandle, LOCK_EX | LOCK_NB) != 0) -#elif HAVE_DECL_F_SETLK +#else int errnoBlock = EAGAIN; struct flock desc; desc.l_type = F_WRLCK; @@ -124,9 +123,6 @@ 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. @@ -246,46 +242,23 @@ 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) @@ -319,15 +292,8 @@ void RaidFileWrite::Discard() writeFilename += 'X'; // Unlink and close it - -#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 + if((::unlink(writeFilename.c_str()) != 0) + || (::close(mOSFileHandle) != 0)) { THROW_EXCEPTION(RaidFileException, OSError) } @@ -422,13 +388,13 @@ void RaidFileWrite::TransformToRaidStorage() try { #if HAVE_DECL_O_EXLOCK - 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()); + 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()); #else - 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()); + 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()); #endif // Then... read in data... @@ -564,21 +530,6 @@ 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 -- cgit v1.2.3 From f48dacd80f38fe1caa9f6374047f15b16e90a713 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:50:02 +0000 Subject: (refs #3) Open files in binary mode (Win32) Disable the lock failure block when we don't have any locking mechanism Close and delete files before renaming over them on Win32. This breaks Ben's desired recovery semantics, so it's not done on other platforms, but Win32 requires it. --- lib/raidfile/RaidFileWrite.cpp | 70 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/lib/raidfile/RaidFileWrite.cpp b/lib/raidfile/RaidFileWrite.cpp index e30162fa..2de9dde5 100644 --- a/lib/raidfile/RaidFileWrite.cpp +++ b/lib/raidfile/RaidFileWrite.cpp @@ -104,7 +104,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) { @@ -115,7 +116,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; @@ -123,6 +124,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. @@ -242,23 +246,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) @@ -292,8 +319,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) } @@ -388,13 +422,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... @@ -530,6 +564,22 @@ void RaidFileWrite::TransformToRaidStorage() parity.Close(); stripe2.Close(); stripe1.Close(); + +#ifdef WIN32 + // Must delete before renaming + if (::unlink(stripe1Filename.c_str()) != 0 && errno != ENOENT) + { + THROW_EXCEPTION(RaidFileException, OSError); + } + if (::unlink(stripe2Filename.c_str()) != 0 && errno != ENOENT) + { + THROW_EXCEPTION(RaidFileException, OSError); + } + if (::unlink(parityFilename.c_str()) != 0 && errno != ENOENT) + { + THROW_EXCEPTION(RaidFileException, OSError); + } +#endif // Rename them into place if(::rename(stripe1FilenameW.c_str(), stripe1Filename.c_str()) != 0 -- cgit v1.2.3 From 53ef33b388fdfebf13c98d4a264715fff390c948 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:51:29 +0000 Subject: Revert to trunk --- lib/server/Daemon.cpp | 50 +++++++++----------------------------------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 2131bdcb..2f902473 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -23,10 +23,6 @@ #include #endif -#ifdef WIN32 - #include -#endif - #include "Daemon.h" #include "Configuration.h" #include "ServerException.h" @@ -146,7 +142,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) { fprintf(stderr, "%s: failed to start: " "failed to open configuration file: " - "%s\n", DaemonName(), + "%s", DaemonName(), mConfigFileName.c_str()); #ifdef WIN32 ::syslog(LOG_ERR, "%s: failed to start: " @@ -193,7 +189,6 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) { THROW_EXCEPTION(ServerException, DaemoniseFailed) } -#endif // !WIN32 // Server configuration const Configuration &serverConfig( @@ -202,8 +197,7 @@ 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")) { @@ -273,25 +267,20 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // open the log ::openlog(DaemonName(), LOG_PID, LOG_LOCAL6); - // Log the start message ::syslog(LOG_INFO, "Starting daemon (config: %s) (version " BOX_VERSION ")", mConfigFileName.c_str()); +#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"); THROW_EXCEPTION(ServerException, DaemoniseFailed) } +#endif // Set up memory leak reporting #ifdef BOX_MEMORY_LEAK_TESTING @@ -363,22 +352,6 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) #endif 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 - ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); - THROW_EXCEPTION(CommonException, Internal) - } -#endif - - int retcode = 0; // Main Daemon running try @@ -408,8 +381,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) mConfigFileName.c_str(), errors.c_str()); // And give up - retcode = 1; - break; + return 1; } // delete old configuration @@ -437,26 +409,22 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) ::syslog(LOG_ERR, "%s: terminating due to exception %s " "(%d/%d)", DaemonName(), e.what(), e.GetType(), e.GetSubType()); - retcode = 1; + return 1; } catch(std::exception &e) { ::syslog(LOG_ERR, "%s: terminating due to exception %s", DaemonName(), e.what()); - retcode = 1; + return 1; } catch(...) { ::syslog(LOG_ERR, "%s: terminating due to unknown exception", DaemonName()); - retcode = 1; + return 1; } - -#ifdef WIN32 - WSACleanup(); -#endif - return retcode; + return 0; } // -------------------------------------------------------------------------- -- cgit v1.2.3 From e941015d11b611e421de1cb7de26a9440eb5f445 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:55:35 +0000 Subject: (refs #3) Initialise Windows sockets automatically for all daemons on Win32 Write PID files on Win32 --- lib/server/Daemon.cpp | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 2f902473..2131bdcb 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -23,6 +23,10 @@ #include #endif +#ifdef WIN32 + #include +#endif + #include "Daemon.h" #include "Configuration.h" #include "ServerException.h" @@ -142,7 +146,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) { fprintf(stderr, "%s: failed to start: " "failed to open configuration file: " - "%s", DaemonName(), + "%s\n", DaemonName(), mConfigFileName.c_str()); #ifdef WIN32 ::syslog(LOG_ERR, "%s: failed to start: " @@ -189,6 +193,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) { THROW_EXCEPTION(ServerException, DaemoniseFailed) } +#endif // !WIN32 // Server configuration const Configuration &serverConfig( @@ -197,7 +202,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")) { @@ -267,20 +273,25 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // open the log ::openlog(DaemonName(), LOG_PID, LOG_LOCAL6); + // Log the start message ::syslog(LOG_INFO, "Starting daemon (config: %s) (version " BOX_VERSION ")", mConfigFileName.c_str()); -#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"); THROW_EXCEPTION(ServerException, DaemoniseFailed) } -#endif // Set up memory leak reporting #ifdef BOX_MEMORY_LEAK_TESTING @@ -352,6 +363,22 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) #endif 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 + ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); + THROW_EXCEPTION(CommonException, Internal) + } +#endif + + int retcode = 0; // Main Daemon running try @@ -381,7 +408,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) mConfigFileName.c_str(), errors.c_str()); // And give up - return 1; + retcode = 1; + break; } // delete old configuration @@ -409,22 +437,26 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) ::syslog(LOG_ERR, "%s: terminating due to exception %s " "(%d/%d)", DaemonName(), e.what(), e.GetType(), e.GetSubType()); - return 1; + retcode = 1; } catch(std::exception &e) { ::syslog(LOG_ERR, "%s: terminating due to exception %s", DaemonName(), e.what()); - return 1; + retcode = 1; } catch(...) { ::syslog(LOG_ERR, "%s: terminating due to unknown exception", DaemonName()); - return 1; + retcode = 1; } + +#ifdef WIN32 + WSACleanup(); +#endif - return 0; + return retcode; } // -------------------------------------------------------------------------- -- cgit v1.2.3 From eaed0b5d59d44b6e2027d8b449b9f9bba773df79 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:56:11 +0000 Subject: Revert to trunk --- lib/server/makeprotocol.pl.in | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in index efe6519d..3dce6118 100755 --- a/lib/server/makeprotocol.pl.in +++ b/lib/server/makeprotocol.pl.in @@ -1,9 +1,6 @@ #!@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) @@ -170,8 +167,8 @@ close IN; # open files my $h_filename = 'autogen_'.$protocol_name.'Protocol'.$type.'.h'; -open CPP,'>autogen_'.$protocol_name.'Protocol'.$type.'.cpp.new'; -open H,">$h_filename.new"; +open CPP,'>autogen_'.$protocol_name.'Protocol'.$type.'.cpp'; +open H,">$h_filename"; print CPP <<__E; @@ -915,8 +912,6 @@ __E close H; close CPP; -update_if_changed('autogen_'.$protocol_name.'Protocol'.$type.'.cpp'); -update_if_changed($h_filename); sub obj_is_type { @@ -986,15 +981,8 @@ sub make_log_strings { # 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; + $arg =~ s/VAR/m$nm/g; push @arg,$arg; } else -- cgit v1.2.3 From c038702ec1cf0e0bb4225356593bacbef3647c28 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:57:36 +0000 Subject: (refs #3) 64-bit format fixes (Win32) --- lib/server/makeprotocol.pl.in | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in index 3dce6118..b5b9dd19 100755 --- a/lib/server/makeprotocol.pl.in +++ b/lib/server/makeprotocol.pl.in @@ -912,7 +912,6 @@ __E close H; close CPP; - sub obj_is_type { my ($c,$ty) = @_; @@ -981,8 +980,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 -- cgit v1.2.3 From 7fb9db539446478122a8c3563a42699942c4d55e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 22:58:30 +0000 Subject: Revert to trunk --- lib/server/ServerStream.h | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h index 745c3ccb..8dafccae 100644 --- a/lib/server/ServerStream.h +++ b/lib/server/ServerStream.h @@ -56,10 +56,6 @@ public: return "generic-stream-server"; } - #ifdef WIN32 - virtual void OnIdle() { } - #endif - virtual void Run() { // Set process title as appropraite @@ -219,7 +215,6 @@ public: if(connection.get()) { // Since this is a template parameter, the if() will be optimised out by the compiler - #ifndef WIN32 // no fork on Win32 if(ForkToHandleRequests) { pid_t pid = ::fork(); @@ -260,20 +255,14 @@ public: } else { - #endif // !WIN32 // Just handle in this connection SetProcessTitle("handling"); HandleConnection(*connection); SetProcessTitle("idle"); - #ifndef WIN32 } - #endif // !WIN32 } } - - #ifdef WIN32 - OnIdle(); - #else // !WIN32 + // Clean up child processes (if forking daemon) if(ForkToHandleRequests) { @@ -288,7 +277,6 @@ public: } } while(p > 0); } - #endif // !WIN32 } } catch(...) @@ -313,11 +301,7 @@ protected: // depends on the forking model in case someone changes it later. bool WillForkToHandleRequests() { - #ifdef WIN32 - return false; - #else return ForkToHandleRequests; - #endif // WIN32 } private: -- cgit v1.2.3 From 0087222f8fe71800b0d22b0034a5f8971359e959 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:02:20 +0000 Subject: (refs #3) Added an OnIdle method which can be overridden by subclasses for idle tasks. Used for housekeeping on Win32. Avoid forking on Win32, and trying to clean up after children. --- lib/server/ServerStream.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h index 8dafccae..67890d83 100644 --- a/lib/server/ServerStream.h +++ b/lib/server/ServerStream.h @@ -56,6 +56,8 @@ public: return "generic-stream-server"; } + virtual void OnIdle() { } + virtual void Run() { // Set process title as appropraite @@ -215,7 +217,7 @@ public: if(connection.get()) { // Since this is a template parameter, the if() will be optimised out by the compiler - if(ForkToHandleRequests) + if(WillForkToHandleRequests()) { pid_t pid = ::fork(); switch(pid) @@ -262,9 +264,11 @@ public: } } } - + + OnIdle(); + // Clean up child processes (if forking daemon) - if(ForkToHandleRequests) + if(WillForkToHandleRequests()) { int status = 0; int p = 0; @@ -301,7 +305,11 @@ protected: // depends on the forking model in case someone changes it later. bool WillForkToHandleRequests() { + #ifdef WIN32 + return false; + #else return ForkToHandleRequests; + #endif // WIN32 } private: -- cgit v1.2.3 From c9f3ad3e9e6e1671b9d9f07233f98de77bde2ac6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:12:51 +0000 Subject: Revert to trunk --- lib/server/SocketStream.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/server/SocketStream.h b/lib/server/SocketStream.h index ca07434e..7f1cb741 100644 --- a/lib/server/SocketStream.h +++ b/lib/server/SocketStream.h @@ -14,10 +14,8 @@ #ifdef WIN32 typedef SOCKET tOSSocketHandle; - #define INVALID_SOCKET_VALUE (tOSSocketHandle)(-1) #else typedef int tOSSocketHandle; - #define INVALID_SOCKET_VALUE -1 #endif // -------------------------------------------------------------------------- -- cgit v1.2.3 From aa9a69c95da99bcd630f404ff061c103afd50893 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:30:04 +0000 Subject: (refs #3) Define a suitable constant for invalid socket handles, for use in SocketStream.cpp --- lib/server/SocketStream.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/server/SocketStream.h b/lib/server/SocketStream.h index 7f1cb741..7d5e6d93 100644 --- a/lib/server/SocketStream.h +++ b/lib/server/SocketStream.h @@ -14,8 +14,10 @@ #ifdef WIN32 typedef SOCKET tOSSocketHandle; + #define INVALID_SOCKET_VALUE INVALID_SOCKET #else typedef int tOSSocketHandle; + #define INVALID_SOCKET_VALUE -1 #endif // -------------------------------------------------------------------------- -- cgit v1.2.3 From 8da19e8052c45c1dd2d1e82b50b956dcf2a33638 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:30:42 +0000 Subject: Revert to trunk --- lib/server/SocketStream.cpp | 47 +++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp index 61d3846f..aa3825bf 100644 --- a/lib/server/SocketStream.cpp +++ b/lib/server/SocketStream.cpp @@ -36,7 +36,7 @@ // // -------------------------------------------------------------------------- SocketStream::SocketStream() - : mSocketHandle(INVALID_SOCKET_VALUE), + : mSocketHandle(-1), mReadClosed(false), mWriteClosed(false), mBytesRead(0), @@ -85,7 +85,7 @@ SocketStream::SocketStream(const SocketStream &rToCopy) { THROW_EXCEPTION(ServerException, BadSocketHandle); } - if(mSocketHandle == INVALID_SOCKET_VALUE) + if(mSocketHandle == -1) { THROW_EXCEPTION(ServerException, DupError); } @@ -101,7 +101,7 @@ SocketStream::SocketStream(const SocketStream &rToCopy) // -------------------------------------------------------------------------- SocketStream::~SocketStream() { - if(mSocketHandle != INVALID_SOCKET_VALUE) + if(mSocketHandle != -1) { Close(); } @@ -117,10 +117,7 @@ SocketStream::~SocketStream() // -------------------------------------------------------------------------- void SocketStream::Attach(int socket) { - if(mSocketHandle != INVALID_SOCKET_VALUE) - { - THROW_EXCEPTION(ServerException, SocketAlreadyOpen) - } + if(mSocketHandle != -1) {THROW_EXCEPTION(ServerException, SocketAlreadyOpen)} mSocketHandle = socket; ResetCounters(); @@ -137,10 +134,7 @@ void SocketStream::Attach(int socket) // -------------------------------------------------------------------------- void SocketStream::Open(int Type, const char *Name, int Port) { - if(mSocketHandle != INVALID_SOCKET_VALUE) - { - THROW_EXCEPTION(ServerException, SocketAlreadyOpen) - } + if(mSocketHandle != -1) {THROW_EXCEPTION(ServerException, SocketAlreadyOpen)} // Setup parameters based on type, looking up names if required int sockDomain = 0; @@ -150,7 +144,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 == INVALID_SOCKET_VALUE) + if(mSocketHandle == -1) { THROW_EXCEPTION(ServerException, SocketOpenError) } @@ -164,7 +158,7 @@ void SocketStream::Open(int Type, const char *Name, int Port) #else ::close(mSocketHandle); #endif - mSocketHandle = INVALID_SOCKET_VALUE; + mSocketHandle = -1; THROW_EXCEPTION(ConnectionException, Conn_SocketConnectError) } ResetCounters(); @@ -180,10 +174,7 @@ void SocketStream::Open(int Type, const char *Name, int Port) // -------------------------------------------------------------------------- int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) { - if(mSocketHandle == INVALID_SOCKET_VALUE) - { - THROW_EXCEPTION(ServerException, BadSocketHandle) - } + if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)} if(Timeout != IOStream::TimeOutInfinite) { @@ -256,10 +247,7 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) // -------------------------------------------------------------------------- void SocketStream::Write(const void *pBuffer, int NBytes) { - if(mSocketHandle == INVALID_SOCKET_VALUE) - { - THROW_EXCEPTION(ServerException, BadSocketHandle) - } + if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)} // Buffer in byte sized type. ASSERT(sizeof(char) == 1); @@ -323,10 +311,7 @@ void SocketStream::Write(const void *pBuffer, int NBytes) // -------------------------------------------------------------------------- void SocketStream::Close() { - if(mSocketHandle == INVALID_SOCKET_VALUE) - { - THROW_EXCEPTION(ServerException, BadSocketHandle) - } + if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)} #ifdef WIN32 if(::closesocket(mSocketHandle) == -1) #else @@ -335,7 +320,7 @@ void SocketStream::Close() { THROW_EXCEPTION(ServerException, SocketCloseError) } - mSocketHandle = INVALID_SOCKET_VALUE; + mSocketHandle = -1; } // -------------------------------------------------------------------------- @@ -348,10 +333,7 @@ void SocketStream::Close() // -------------------------------------------------------------------------- void SocketStream::Shutdown(bool Read, bool Write) { - if(mSocketHandle == INVALID_SOCKET_VALUE) - { - THROW_EXCEPTION(ServerException, BadSocketHandle) - } + if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)} // Do anything? if(!Read && !Write) return; @@ -406,10 +388,7 @@ bool SocketStream::StreamClosed() // -------------------------------------------------------------------------- tOSSocketHandle SocketStream::GetSocketHandle() { - if(mSocketHandle == INVALID_SOCKET_VALUE) - { - THROW_EXCEPTION(ServerException, BadSocketHandle) - } + if(mSocketHandle == -1) {THROW_EXCEPTION(ServerException, BadSocketHandle)} return mSocketHandle; } -- cgit v1.2.3 From e694703be46f51b88c8b3dc1497b905edaedceea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:31:38 +0000 Subject: Use INVALID_SOCKET_VALUE instead of -1 --- lib/server/SocketStream.cpp | 47 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp index aa3825bf..61d3846f 100644 --- a/lib/server/SocketStream.cpp +++ b/lib/server/SocketStream.cpp @@ -36,7 +36,7 @@ // // -------------------------------------------------------------------------- SocketStream::SocketStream() - : mSocketHandle(-1), + : mSocketHandle(INVALID_SOCKET_VALUE), mReadClosed(false), mWriteClosed(false), mBytesRead(0), @@ -85,7 +85,7 @@ SocketStream::SocketStream(const SocketStream &rToCopy) { THROW_EXCEPTION(ServerException, BadSocketHandle); } - if(mSocketHandle == -1) + if(mSocketHandle == INVALID_SOCKET_VALUE) { THROW_EXCEPTION(ServerException, DupError); } @@ -101,7 +101,7 @@ SocketStream::SocketStream(const SocketStream &rToCopy) // -------------------------------------------------------------------------- SocketStream::~SocketStream() { - if(mSocketHandle != -1) + if(mSocketHandle != INVALID_SOCKET_VALUE) { Close(); } @@ -117,7 +117,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(); @@ -134,7 +137,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; @@ -144,7 +150,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) } @@ -158,7 +164,7 @@ void SocketStream::Open(int Type, const char *Name, int Port) #else ::close(mSocketHandle); #endif - mSocketHandle = -1; + mSocketHandle = INVALID_SOCKET_VALUE; THROW_EXCEPTION(ConnectionException, Conn_SocketConnectError) } ResetCounters(); @@ -174,7 +180,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) { @@ -247,7 +256,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); @@ -311,7 +323,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 @@ -320,7 +335,7 @@ void SocketStream::Close() { THROW_EXCEPTION(ServerException, SocketCloseError) } - mSocketHandle = -1; + mSocketHandle = INVALID_SOCKET_VALUE; } // -------------------------------------------------------------------------- @@ -333,7 +348,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; @@ -388,7 +406,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; } -- cgit v1.2.3 From 246dc62e9cc104d67af7bc85c75d8d343026bcf4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:39:24 +0000 Subject: Revert to trunk --- lib/server/SocketStreamTLS.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp index af4ad460..94aa3868 100644 --- a/lib/server/SocketStreamTLS.cpp +++ b/lib/server/SocketStreamTLS.cpp @@ -137,12 +137,8 @@ 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 @@ -313,7 +309,7 @@ int SocketStreamTLS::Read(void *pBuffer, int NBytes, int Timeout) case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: - // wait for the required data + // wait for the requried data // Will only get once around this loop, so don't need to calculate timeout values if(WaitWhenRetryRequired(se, Timeout) == false) { -- cgit v1.2.3 From ec4516362d759a8b4070729f5129ba24dcbe5e4a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:40:18 +0000 Subject: (refs #3) Added support for non-blocking sockets on Win32 as well --- lib/server/SocketStreamTLS.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp index 94aa3868..af4ad460 100644 --- a/lib/server/SocketStreamTLS.cpp +++ b/lib/server/SocketStreamTLS.cpp @@ -137,8 +137,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 @@ -309,7 +313,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) { -- cgit v1.2.3 From a3f5f3a3a94a59bc9337ea4af140c50c1b4941a7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:41:33 +0000 Subject: Revert to trunk --- runtest.pl.in | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/runtest.pl.in b/runtest.pl.in index db58726d..f2b70a14 100755 --- a/runtest.pl.in +++ b/runtest.pl.in @@ -1,14 +1,11 @@ #!@PERL@ -use strict; -use warnings; - use lib 'infrastructure'; use BoxPlatform; my ($test_name,$test_mode) = @ARGV; -$test_mode = 'debug' if not defined $test_mode or $test_mode eq ''; +$test_mode = 'debug' if $test_mode eq ''; if($test_name eq '' || ($test_mode ne 'debug' && $test_mode ne 'release')) { @@ -20,26 +17,15 @@ runtest.pl (test|ALL) [release|debug] Mode defaults to debug. __E - exit(2); + exit(0); } my @results; -my $exit_code = 0; if($test_name ne 'ALL') { - # run one or more specified test - if ($test_name =~ m/,/) - { - foreach my $test (split m/,/, $test_name) - { - runtest($test); - } - } - else - { - runtest($test_name); - } + # run one test + runtest($test_name); } else { @@ -71,8 +57,6 @@ else # report results print "--------\n",join("\n",@results),"\n"; -exit $exit_code; - sub runtest { my ($t) = @_; @@ -83,7 +67,6 @@ sub runtest if($make_res != 0) { push @results,"$t: make failed"; - $exit_code = 2; return; } @@ -99,14 +82,8 @@ sub runtest $last = $_ if m/\w/; } close RESULTS; - chomp $last; push @results,"$t: $last"; - - if ($last ne "PASSED") - { - $exit_code = 1; - } } else { -- cgit v1.2.3 From c08e922469af23eebdf54c174fc01611a748cdf4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 31 Aug 2006 23:43:40 +0000 Subject: (refs #3) Use strict and warnings for code safety. Exit with status 2 on invalid usage. Allow running multiple tests, comma separated. Exit with status 2 if make fails for any test. Exit with status 1 if any test fails. --- runtest.pl.in | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/runtest.pl.in b/runtest.pl.in index f2b70a14..db58726d 100755 --- a/runtest.pl.in +++ b/runtest.pl.in @@ -1,11 +1,14 @@ #!@PERL@ +use strict; +use warnings; + use lib 'infrastructure'; use BoxPlatform; my ($test_name,$test_mode) = @ARGV; -$test_mode = 'debug' if $test_mode eq ''; +$test_mode = 'debug' if not defined $test_mode or $test_mode eq ''; if($test_name eq '' || ($test_mode ne 'debug' && $test_mode ne 'release')) { @@ -17,15 +20,26 @@ runtest.pl (test|ALL) [release|debug] Mode defaults to debug. __E - exit(0); + exit(2); } my @results; +my $exit_code = 0; if($test_name ne 'ALL') { - # run one test - runtest($test_name); + # run one or more specified test + if ($test_name =~ m/,/) + { + foreach my $test (split m/,/, $test_name) + { + runtest($test); + } + } + else + { + runtest($test_name); + } } else { @@ -57,6 +71,8 @@ else # report results print "--------\n",join("\n",@results),"\n"; +exit $exit_code; + sub runtest { my ($t) = @_; @@ -67,6 +83,7 @@ sub runtest if($make_res != 0) { push @results,"$t: make failed"; + $exit_code = 2; return; } @@ -82,8 +99,14 @@ sub runtest $last = $_ if m/\w/; } close RESULTS; + chomp $last; push @results,"$t: $last"; + + if ($last ne "PASSED") + { + $exit_code = 1; + } } else { -- cgit v1.2.3 From ebd3eab50bef24078e9e6c3e4dabcc7b55b7c4b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 07:48:12 +0000 Subject: Revert to trunk --- test/backupdiff/testbackupdiff.cpp | 75 ++++++++++---------------------------- 1 file changed, 19 insertions(+), 56 deletions(-) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index 806ede89..d532d8a6 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -66,20 +66,22 @@ bool files_identical(const char *file1, const char *file2) void make_file_of_zeros(const char *filename, size_t size) { - #ifdef WIN32 - HANDLE handle = openfile(filename, O_WRONLY | O_CREAT | O_EXCL, 0); - TEST_THAT(handle != INVALID_HANDLE_VALUE); - SetFilePointer(handle, size, NULL, FILE_BEGIN); - TEST_THAT(GetLastError() == NO_ERROR); - TEST_THAT(SetEndOfFile(handle) == true); - TEST_THAT(CloseHandle(handle) == true); - #else - int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) perror(filename); - TEST_THAT(fd >= 0); - TEST_THAT(ftruncate(fd, size) == 0); - TEST_THAT(close(fd) == 0); - #endif + static const size_t bs = 0x10000; + size_t remSize = size; + void *b = malloc(bs); + memset(b, 0, bs); + FILE *f = fopen(filename, "wb"); + + // Using largish blocks like this is much faster, while not consuming too much RAM + while(remSize > bs) + { + fwrite(b, bs, 1, f); + remSize -= bs; + } + fwrite(b, remSize, 1, f); + + fclose(f); + free(b); TEST_THAT((size_t)TestGetFileSize(filename) == size); } @@ -116,20 +118,12 @@ void check_encoded_file(const char *filename, int64_t OtherFileID, int new_block if(s > 0) { nnew++; - #ifdef WIN32 - TRACE2("%8I64d this s=%8I64d", b, s); - #else TRACE2("%8lld this s=%8lld", b, s); - #endif } else { nold++; - #ifdef WIN32 - TRACE2("%8I64d other i=%8I64d", b, 0 - s); - #else TRACE2("%8lld other i=%8lld", b, 0 - s); - #endif } // Decode the rest uint64_t iv = box_ntoh64(hdr.mEntryIVBase); @@ -213,18 +207,10 @@ void test_diff(int from, int to, int new_blocks_expected, int old_blocks_expecte } else { -#ifdef WIN32 - // Emulate the above stage! - char src[256], dst[256]; - sprintf(src, "testfiles\\f%d.diff", to); - sprintf(dst, "testfiles\\f%d.encoded", to); - TEST_THAT(CopyFile(src, dst, FALSE) != 0) -#else // Emulate the above stage! char cmd[256]; sprintf(cmd, "cp testfiles/f%d.diff testfiles/f%d.encoded", to, to); ::system(cmd); -#endif } // Decode it @@ -369,10 +355,8 @@ int test(int argc, const char *argv[]) { // Want to trace out all the details #ifndef NDEBUG - #ifndef WIN32 BackupStoreFile::TraceDetailsOfDiffProcess = true; #endif - #endif // Create all the test files create_test_files(); @@ -386,7 +370,6 @@ int test(int argc, const char *argv[]) FileStream out("testfiles/f0.encoded", O_WRONLY | O_CREAT | O_EXCL); std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/f0", 1 /* dir ID */, f0name)); encoded->CopyStreamTo(out); - out.Close(); check_encoded_file("testfiles/f0.encoded", 0, 33, 0); } @@ -447,7 +430,6 @@ int test(int argc, const char *argv[]) FileStream out("testfiles/f9.zerotest", O_WRONLY | O_CREAT | O_EXCL); std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/f9", 1 /* dir ID */, fn)); encoded->CopyStreamTo(out); - out.Close(); check_encoded_file("testfiles/f9.zerotest", 0, 0, 0); } { @@ -458,7 +440,6 @@ int test(int argc, const char *argv[]) } } -#ifndef WIN32 // Check that symlinks aren't diffed TEST_THAT(::symlink("f2", "testfiles/f2.symlink") == 0) // And go and diff it against the previous encoded file @@ -486,10 +467,8 @@ int test(int argc, const char *argv[]) TEST_THAT(completelyDifferent == true); check_encoded_file("testfiles/f2.symlink.diff", 0, 0, 0); } -#endif - // Check that diffing against a file which isn't "complete" and - // references another isn't allowed + // Check that diffing against a file which isn't "complete" and referes another isn't allowed { FileStream blockindex("testfiles/f1.diff"); BackupStoreFile::MoveStreamPositionToBlockIndex(blockindex); @@ -501,19 +480,10 @@ int test(int argc, const char *argv[]) 0, 0), BackupStoreException, CannotDiffAnIncompleteStoreFile); } - // Found a nasty case where files of lots of the same thing - // suck up lots of processor time -- because of lots of matches - // found. Check this out! - - #ifdef WIN32 - ::fprintf(stdout, "Testing diffing two large streams, " - "may take a while!\n"); - ::fflush(stdout); - #endif - + // Found a nasty case where files of lots of the same thing sock up lots of processor + // time -- because of lots of matches found. Check this out! make_file_of_zeros("testfiles/zero.0", 20*1024*1024); make_file_of_zeros("testfiles/zero.1", 200*1024*1024); - // Generate a first encoded file { BackupStoreFilenameClear f0name("zero.0"); @@ -533,14 +503,7 @@ int test(int argc, const char *argv[]) 2000 /* object ID of the file diffing from */, blockindex, IOStream::TimeOutInfinite, 0, 0)); encoded->CopyStreamTo(out); - - printf("Time taken: %d seconds\n", (int)(time(0) - beginTime)); - - #ifdef WIN32 - TEST_THAT(time(0) < (beginTime + 300)); - #else TEST_THAT(time(0) < (beginTime + 40)); - #endif } // Remove zero-files to save disk space remove("testfiles/zero.0"); -- cgit v1.2.3 From 9d1c5b2aa1adceffbb21e6fc93d477d5874af9a4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 07:49:31 +0000 Subject: (refs #3) Use truncation/sparse files to quickly create files with 200MB of zeroes --- test/backupdiff/testbackupdiff.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index d532d8a6..6520907e 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -66,22 +66,20 @@ bool files_identical(const char *file1, const char *file2) void make_file_of_zeros(const char *filename, size_t size) { - static const size_t bs = 0x10000; - size_t remSize = size; - void *b = malloc(bs); - memset(b, 0, bs); - FILE *f = fopen(filename, "wb"); - - // Using largish blocks like this is much faster, while not consuming too much RAM - while(remSize > bs) - { - fwrite(b, bs, 1, f); - remSize -= bs; - } - fwrite(b, remSize, 1, f); - - fclose(f); - free(b); + #ifdef WIN32 + HANDLE handle = openfile(filename, O_WRONLY | O_CREAT | O_EXCL, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + SetFilePointer(handle, size, NULL, FILE_BEGIN); + TEST_THAT(GetLastError() == NO_ERROR); + TEST_THAT(SetEndOfFile(handle) == true); + TEST_THAT(CloseHandle(handle) == true); + #else + int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) perror(filename); + TEST_THAT(fd >= 0); + TEST_THAT(ftruncate(fd, size) == 0); + TEST_THAT(close(fd) == 0); + #endif TEST_THAT((size_t)TestGetFileSize(filename) == size); } -- cgit v1.2.3 From c72f7fdb37891d32a75c91348e8cd4f50da661f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 07:50:47 +0000 Subject: (refs #3) 64-bit format string fixes for Win32 --- test/backupdiff/testbackupdiff.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index 6520907e..b000e88d 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -116,12 +116,20 @@ void check_encoded_file(const char *filename, int64_t OtherFileID, int new_block if(s > 0) { nnew++; + #ifdef WIN32 + TRACE2("%8I64d this s=%8I64d", b, s); + #else TRACE2("%8lld this s=%8lld", b, s); + #endif } else { nold++; + #ifdef WIN32 + TRACE2("%8I64d other i=%8I64d", b, 0 - s); + #else TRACE2("%8lld other i=%8lld", b, 0 - s); + #endif } // Decode the rest uint64_t iv = box_ntoh64(hdr.mEntryIVBase); -- cgit v1.2.3 From 3eeab89ddcaa563a316092c1a20df3d67ce2d456 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 07:51:45 +0000 Subject: (refs #3) Use CopyFile to copy on Windows, instead of shelling out to cp, which doesn't understand native paths. --- test/backupdiff/testbackupdiff.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index b000e88d..9daa916e 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -213,10 +213,18 @@ void test_diff(int from, int to, int new_blocks_expected, int old_blocks_expecte } else { +#ifdef WIN32 + // Emulate the above stage! + char src[256], dst[256]; + sprintf(src, "testfiles\\f%d.diff", to); + sprintf(dst, "testfiles\\f%d.encoded", to); + TEST_THAT(CopyFile(src, dst, FALSE) != 0) +#else // Emulate the above stage! char cmd[256]; sprintf(cmd, "cp testfiles/f%d.diff testfiles/f%d.encoded", to, to); ::system(cmd); +#endif } // Decode it -- cgit v1.2.3 From 77ce6b04eccfc64b7f7a91cf2376ebb1e28fd56e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 07:52:51 +0000 Subject: (refs #3) Close open file handles on Win32 --- test/backupdiff/testbackupdiff.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index 9daa916e..7a48ec20 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -384,6 +384,7 @@ int test(int argc, const char *argv[]) FileStream out("testfiles/f0.encoded", O_WRONLY | O_CREAT | O_EXCL); std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/f0", 1 /* dir ID */, f0name)); encoded->CopyStreamTo(out); + out.Close(); check_encoded_file("testfiles/f0.encoded", 0, 33, 0); } @@ -444,6 +445,7 @@ int test(int argc, const char *argv[]) FileStream out("testfiles/f9.zerotest", O_WRONLY | O_CREAT | O_EXCL); std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/f9", 1 /* dir ID */, fn)); encoded->CopyStreamTo(out); + out.Close(); check_encoded_file("testfiles/f9.zerotest", 0, 0, 0); } { -- cgit v1.2.3 From fc470983d6d94a41fbdf9e8d1dc4a154993d8467 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 07:54:40 +0000 Subject: (refs #3) Completely disable symlink test on Win32 --- test/backupdiff/testbackupdiff.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index 7a48ec20..a1b4287e 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -456,6 +456,7 @@ int test(int argc, const char *argv[]) } } +#ifndef WIN32 // Check that symlinks aren't diffed TEST_THAT(::symlink("f2", "testfiles/f2.symlink") == 0) // And go and diff it against the previous encoded file @@ -483,6 +484,7 @@ int test(int argc, const char *argv[]) TEST_THAT(completelyDifferent == true); check_encoded_file("testfiles/f2.symlink.diff", 0, 0, 0); } +#endif // Check that diffing against a file which isn't "complete" and referes another isn't allowed { -- cgit v1.2.3 From 66e7ea3352c7025bd171a87c714cc6f7d45d271a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 07:57:05 +0000 Subject: (refs #3) Cosmetic fixes to comments --- test/backupdiff/testbackupdiff.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index a1b4287e..c5301d9b 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -486,7 +486,8 @@ int test(int argc, const char *argv[]) } #endif - // Check that diffing against a file which isn't "complete" and referes another isn't allowed + // Check that diffing against a file which isn't "complete" and + // references another isn't allowed { FileStream blockindex("testfiles/f1.diff"); BackupStoreFile::MoveStreamPositionToBlockIndex(blockindex); @@ -498,8 +499,10 @@ int test(int argc, const char *argv[]) 0, 0), BackupStoreException, CannotDiffAnIncompleteStoreFile); } - // Found a nasty case where files of lots of the same thing sock up lots of processor - // time -- because of lots of matches found. Check this out! + // Found a nasty case where files of lots of the same thing + // suck up lots of processor time -- because of lots of matches + // found. Check this out! + make_file_of_zeros("testfiles/zero.0", 20*1024*1024); make_file_of_zeros("testfiles/zero.1", 200*1024*1024); // Generate a first encoded file -- cgit v1.2.3 From 51b47019e88e86de7bc8636f134664e05296b68a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 08:00:04 +0000 Subject: (refs #3) This test takes a long time on Win32 (slow file access? VMware?), so: * Disable verbose debug logging, which makes it even slower * Print a warning before the slow test starts * Increase timeout --- test/backupdiff/testbackupdiff.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index c5301d9b..806ede89 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -369,8 +369,10 @@ int test(int argc, const char *argv[]) { // Want to trace out all the details #ifndef NDEBUG + #ifndef WIN32 BackupStoreFile::TraceDetailsOfDiffProcess = true; #endif + #endif // Create all the test files create_test_files(); @@ -503,8 +505,15 @@ int test(int argc, const char *argv[]) // suck up lots of processor time -- because of lots of matches // found. Check this out! + #ifdef WIN32 + ::fprintf(stdout, "Testing diffing two large streams, " + "may take a while!\n"); + ::fflush(stdout); + #endif + make_file_of_zeros("testfiles/zero.0", 20*1024*1024); make_file_of_zeros("testfiles/zero.1", 200*1024*1024); + // Generate a first encoded file { BackupStoreFilenameClear f0name("zero.0"); @@ -524,7 +533,14 @@ int test(int argc, const char *argv[]) 2000 /* object ID of the file diffing from */, blockindex, IOStream::TimeOutInfinite, 0, 0)); encoded->CopyStreamTo(out); + + printf("Time taken: %d seconds\n", (int)(time(0) - beginTime)); + + #ifdef WIN32 + TEST_THAT(time(0) < (beginTime + 300)); + #else TEST_THAT(time(0) < (beginTime + 40)); + #endif } // Remove zero-files to save disk space remove("testfiles/zero.0"); -- cgit v1.2.3 From 6b19bc3aac1dcb32ed4db56252bcd6110568a647 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 08:03:32 +0000 Subject: Revert to trunk --- test/backupstore/testbackupstore.cpp | 177 +++++------------------------------ 1 file changed, 24 insertions(+), 153 deletions(-) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index f3637902..f89d2ff7 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -425,8 +425,7 @@ void test_test_file(int t, IOStream &rStream) } free(data); - in.Close(); - TEST_THAT(unlink("testfiles/test_download") == 0); + unlink("testfiles/test_download"); } void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID) @@ -931,7 +930,6 @@ int test_server(const char *hostname) // Check marker is 0 TEST_THAT(loginConf->GetClientStoreMarker() == 0); -#ifndef WIN32 // Check that we can't open a new connection which requests write permissions { SocketStreamTLS conn; @@ -943,12 +941,10 @@ int test_server(const char *hostname) ConnectionException, Conn_Protocol_UnexpectedReply); protocol.QueryFinished(); } -#endif // Set the client store marker protocol.QuerySetClientStoreMarker(0x8732523ab23aLL); -#ifndef WIN32 // Open a new connection which is read only SocketStreamTLS connReadOnly; connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED); @@ -967,11 +963,10 @@ int test_server(const char *hostname) // Check client store marker TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL); } -#else // WIN32 - BackupProtocolClient& protocolReadOnly(protocol); -#endif test_server_1(protocol, protocolReadOnly); + + // Create and upload some test files int64_t maxID = 0; for(int t = 0; t < UPLOAD_NUM; ++t) @@ -1443,15 +1438,11 @@ int test_server(const char *hostname) } // Finish the connections -#ifndef WIN32 protocolReadOnly.QueryFinished(); -#endif protocol.QueryFinished(); // Close logs -#ifndef WIN32 ::fclose(protocolReadOnlyLog); -#endif ::fclose(protocolLog); } @@ -1529,48 +1520,35 @@ int test3(int argc, const char *argv[]) // The test block to a file { - FileStream f("testfiles" DIRECTORY_SEPARATOR - "testenc1", O_WRONLY | O_CREAT | O_EXCL); + FileStream f("testfiles/testenc1", O_WRONLY | O_CREAT | O_EXCL); f.Write(encfile, sizeof(encfile)); } // Encode it { - FileStream out("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc", O_WRONLY | O_CREAT | O_EXCL); - BackupStoreFilenameClear name("testfiles" - DIRECTORY_SEPARATOR "testenc1"); + FileStream out("testfiles/testenc1_enc", O_WRONLY | O_CREAT | O_EXCL); + BackupStoreFilenameClear name("testfiles/testenc1"); - std::auto_ptr encoded( - BackupStoreFile::EncodeFile( - "testfiles" DIRECTORY_SEPARATOR - "testenc1", 32, name)); + std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/testenc1", 32, name)); encoded->CopyStreamTo(out); } // Verify it { - FileStream enc("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc"); + FileStream enc("testfiles/testenc1_enc"); TEST_THAT(BackupStoreFile::VerifyEncodedFileFormat(enc) == true); } // Decode it { - FileStream enc("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc"); - BackupStoreFile::DecodeFile(enc, "testfiles" - DIRECTORY_SEPARATOR "testenc1_orig", - IOStream::TimeOutInfinite); + FileStream enc("testfiles/testenc1_enc"); + BackupStoreFile::DecodeFile(enc, "testfiles/testenc1_orig", IOStream::TimeOutInfinite); } // Read in rebuilt original, and compare contents { - TEST_THAT(TestGetFileSize("testfiles" - DIRECTORY_SEPARATOR "testenc1_orig") - == sizeof(encfile)); - FileStream in("testfiles" DIRECTORY_SEPARATOR - "testenc1_orig"); + TEST_THAT(TestGetFileSize("testfiles/testenc1_orig") == sizeof(encfile)); + FileStream in("testfiles/testenc1_orig"); int encfile_i[ENCFILE_SIZE]; in.Read(encfile_i, sizeof(encfile_i)); TEST_THAT(memcmp(encfile, encfile_i, sizeof(encfile)) == 0); @@ -1578,8 +1556,7 @@ int test3(int argc, const char *argv[]) // Check how many blocks it had, and test the stream based interface { - FileStream enc("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc"); + FileStream enc("testfiles/testenc1_enc"); std::auto_ptr decoded(BackupStoreFile::DecodeFileStream(enc, IOStream::TimeOutInfinite)); CollectInBufferStream d; decoded->CopyStreamTo(d, IOStream::TimeOutInfinite, 971 /* buffer block size */); @@ -1593,15 +1570,10 @@ int test3(int argc, const char *argv[]) // Test that the last block in a file, if less than 256 bytes, gets put into the last block { #define FILE_SIZE_JUST_OVER ((4096*2)+58) - FileStream f("testfiles" DIRECTORY_SEPARATOR - "testenc2", O_WRONLY | O_CREAT | O_EXCL); + FileStream f("testfiles/testenc2", O_WRONLY | O_CREAT | O_EXCL); f.Write(encfile + 2, FILE_SIZE_JUST_OVER); - f.Close(); BackupStoreFilenameClear name("testenc2"); - std::auto_ptr encoded( - BackupStoreFile::EncodeFile( - "testfiles" DIRECTORY_SEPARATOR - "testenc2", 32, name)); + std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/testenc2", 32, name)); CollectInBufferStream e; encoded->CopyStreamTo(e); e.SetForReading(); @@ -1617,8 +1589,7 @@ int test3(int argc, const char *argv[]) // Test that reordered streams work too { - FileStream enc("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc"); + FileStream enc("testfiles/testenc1_enc"); std::auto_ptr reordered(BackupStoreFile::ReorderFileToStreamOrder(&enc, false)); std::auto_ptr decoded(BackupStoreFile::DecodeFileStream(*reordered, IOStream::TimeOutInfinite)); CollectInBufferStream d; @@ -1630,7 +1601,6 @@ int test3(int argc, const char *argv[]) TEST_THAT(decoded->GetNumBlocks() == 3); } -#ifndef WIN32 // Try out doing this on a symlink { TEST_THAT(::symlink("does/not/exist", "testfiles/testsymlink") == 0); @@ -1644,20 +1614,14 @@ int test3(int argc, const char *argv[]) // Decode it BackupStoreFile::DecodeFile(b, "testfiles/testsymlink_2", IOStream::TimeOutInfinite); } -#endif } // Store info { RaidFileWrite::CreateDirectory(0, "test-info"); - BackupStoreInfo::CreateNew(76, "test-info" DIRECTORY_SEPARATOR, - 0, 3461231233455433LL, 2934852487LL); - TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, - "test-info" DIRECTORY_SEPARATOR, 0, 0, 0), - RaidFileException, CannotOverwriteExistingFile); - std::auto_ptr info( - BackupStoreInfo::Load(76, - "test-info" DIRECTORY_SEPARATOR, 0, true)); + BackupStoreInfo::CreateNew(76, "test-info/", 0, 3461231233455433LL, 2934852487LL); + TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, "test-info/", 0, 0, 0), RaidFileException, CannotOverwriteExistingFile); + std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, true)); TEST_CHECK_THROWS(info->Save(), BackupStoreException, StoreInfoIsReadOnly); TEST_CHECK_THROWS(info->ChangeBlocksUsed(1), BackupStoreException, StoreInfoIsReadOnly); TEST_CHECK_THROWS(info->ChangeBlocksInOldFiles(1), BackupStoreException, StoreInfoIsReadOnly); @@ -1666,8 +1630,7 @@ int test3(int argc, const char *argv[]) TEST_CHECK_THROWS(info->AddDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly); } { - std::auto_ptr info(BackupStoreInfo::Load(76, - "test-info" DIRECTORY_SEPARATOR, 0, false)); + std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, false)); info->ChangeBlocksUsed(8); info->ChangeBlocksInOldFiles(9); info->ChangeBlocksInDeletedFiles(10); @@ -1685,8 +1648,7 @@ int test3(int argc, const char *argv[]) info->Save(); } { - std::auto_ptr info(BackupStoreInfo::Load(76, - "test-info" DIRECTORY_SEPARATOR, 0, true)); + std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, true)); TEST_THAT(info->GetBlocksUsed() == 7); TEST_THAT(info->GetBlocksInOldFiles() == 5); TEST_THAT(info->GetBlocksInDeletedFiles() == 1); @@ -1704,18 +1666,12 @@ int test3(int argc, const char *argv[]) // Context TLSContext context; context.Initialise(false /* client */, - "testfiles" DIRECTORY_SEPARATOR "clientCerts.pem", - "testfiles" DIRECTORY_SEPARATOR "clientPrivKey.pem", - "testfiles" DIRECTORY_SEPARATOR "clientTrustedCAs.pem"); + "testfiles/clientCerts.pem", + "testfiles/clientPrivKey.pem", + "testfiles/clientTrustedCAs.pem"); // First, try logging in without an account having been created... just make sure login fails. - -#ifdef WIN32 - int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); -#else int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); -#endif - TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -1744,13 +1700,8 @@ int test3(int argc, const char *argv[]) } // Create an account for the test client -#ifdef WIN32 - TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); -#else TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); -#endif - TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567")); @@ -1774,27 +1725,15 @@ int test3(int argc, const char *argv[]) TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); -#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); -#endif // Set a new limit on the account -- leave the hard limit high to make sure the target for // freeing space is the soft limit. - -#ifdef WIN32 - TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); -#else TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); -#endif // Start things up -#ifdef WIN32 - pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); -#else pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); -#endif - ::sleep(1); TEST_THAT(ServerIsAlive(pid)); @@ -1819,12 +1758,8 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(after.old == 0); // Set a really small hard limit -#ifdef WIN32 - TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); -#else TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); -#endif // Try to upload a file and create a directory, and check an error is generated { @@ -1873,10 +1808,7 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); - -#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); -#endif } return 0; @@ -1888,19 +1820,10 @@ int multi_server() // Create an account for the test client TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); - -#ifndef WIN32 TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); -#endif // First, try logging in without an account having been created... just make sure login fails. - -#ifdef WIN32 - int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid"); -#else int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid"); -#endif - TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -1917,63 +1840,15 @@ int multi_server() TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); -#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); -#endif } return 0; } -#ifdef WIN32 -WCHAR* ConvertUtf8ToWideString(const char* pString); -std::string ConvertPathToAbsoluteUnicode(const char *pFileName); -#endif - int test(int argc, const char *argv[]) { -#ifdef WIN32 - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) - - // this had better work, or bbstored will die when combining diffs - char* file = "foo"; - std::string abs = ConvertPathToAbsoluteUnicode(file); - WCHAR* wfile = ConvertUtf8ToWideString(abs.c_str()); - - DWORD accessRights = FILE_READ_ATTRIBUTES | - FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | - FILE_WRITE_DATA | FILE_WRITE_EA /*| FILE_ALL_ACCESS*/; - DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; - - HANDLE h1 = CreateFileW(wfile, accessRights, shareMode, - NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL); - assert(h1 != INVALID_HANDLE_VALUE); - TEST_THAT(h1 != INVALID_HANDLE_VALUE); - - accessRights = FILE_READ_ATTRIBUTES | - FILE_LIST_DIRECTORY | FILE_READ_EA; - - HANDLE h2 = CreateFileW(wfile, accessRights, shareMode, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - assert(h2 != INVALID_HANDLE_VALUE); - TEST_THAT(h2 != INVALID_HANDLE_VALUE); - - CloseHandle(h2); - CloseHandle(h1); - - h1 = openfile("foo", O_CREAT | O_RDWR, 0); - TEST_THAT(h1 != INVALID_HANDLE_VALUE); - h2 = openfile("foo", O_RDWR, 0); - TEST_THAT(h2 != INVALID_HANDLE_VALUE); - CloseHandle(h2); - CloseHandle(h1); -#endif - // SSL library SSLLib::Initialise(); @@ -1990,11 +1865,7 @@ int test(int argc, const char *argv[]) // Use the setup crypto command to set up all these keys, so that the bbackupquery command can be used // for seeing what's going on. -#ifdef WIN32 - BackupClientCryptoKeys_Setup("testfiles\\bbackupd.keys"); -#else BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys"); -#endif // encode in some filenames -- can't do static initialisation because the key won't be set up when these are initialised for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l) -- cgit v1.2.3 From 164c29cecef282e61b60add7c39b0801514f829e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 08:05:29 +0000 Subject: (refs #3) Close before unlink Check that unlink succeeds --- test/backupstore/testbackupstore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index f89d2ff7..cf85b1ed 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -425,7 +425,8 @@ void test_test_file(int t, IOStream &rStream) } free(data); - unlink("testfiles/test_download"); + in.Close(); + TEST_THAT(unlink("testfiles/test_download") == 0); } void test_everything_deleted(BackupProtocolClient &protocol, int64_t DirID) -- cgit v1.2.3 From 44a55d86ad36e50923179eecfc460cf2659c1227 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 08:08:11 +0000 Subject: (refs #3) We cannot open multiple connections to the server on Win32, so work around. --- test/backupstore/testbackupstore.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index cf85b1ed..76cca520 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -931,6 +931,7 @@ int test_server(const char *hostname) // Check marker is 0 TEST_THAT(loginConf->GetClientStoreMarker() == 0); +#ifndef WIN32 // Check that we can't open a new connection which requests write permissions { SocketStreamTLS conn; @@ -942,10 +943,12 @@ int test_server(const char *hostname) ConnectionException, Conn_Protocol_UnexpectedReply); protocol.QueryFinished(); } +#endif // Set the client store marker protocol.QuerySetClientStoreMarker(0x8732523ab23aLL); +#ifndef WIN32 // Open a new connection which is read only SocketStreamTLS connReadOnly; connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED); @@ -964,10 +967,12 @@ int test_server(const char *hostname) // Check client store marker TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL); } +#else // WIN32 + BackupProtocolClient& protocolReadOnly(protocol); +#endif test_server_1(protocol, protocolReadOnly); - // Create and upload some test files int64_t maxID = 0; for(int t = 0; t < UPLOAD_NUM; ++t) @@ -1439,11 +1444,15 @@ int test_server(const char *hostname) } // Finish the connections +#ifndef WIN32 protocolReadOnly.QueryFinished(); +#endif protocol.QueryFinished(); // Close logs +#ifndef WIN32 ::fclose(protocolReadOnlyLog); +#endif ::fclose(protocolLog); } -- cgit v1.2.3 From d9dac474dcd98cba0d0cb523e7240896255572b8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 08:45:50 +0000 Subject: (refs #3) Use correct directory separator everywhere --- test/backupstore/testbackupstore.cpp | 72 +++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index 76cca520..b98058cf 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -948,7 +948,7 @@ int test_server(const char *hostname) // Set the client store marker protocol.QuerySetClientStoreMarker(0x8732523ab23aLL); -#ifndef WIN32 +#ifndef WIN32 // can't open more than one connection on Win32 // Open a new connection which is read only SocketStreamTLS connReadOnly; connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED); @@ -968,6 +968,7 @@ int test_server(const char *hostname) TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL); } #else // WIN32 + // we can't open a new connection, so fake it BackupProtocolClient& protocolReadOnly(protocol); #endif @@ -1530,35 +1531,48 @@ int test3(int argc, const char *argv[]) // The test block to a file { - FileStream f("testfiles/testenc1", O_WRONLY | O_CREAT | O_EXCL); + FileStream f("testfiles" DIRECTORY_SEPARATOR + "testenc1", O_WRONLY | O_CREAT | O_EXCL); f.Write(encfile, sizeof(encfile)); } // Encode it { - FileStream out("testfiles/testenc1_enc", O_WRONLY | O_CREAT | O_EXCL); - BackupStoreFilenameClear name("testfiles/testenc1"); + FileStream out("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc", O_WRONLY | O_CREAT | O_EXCL); + BackupStoreFilenameClear name("testfiles" + DIRECTORY_SEPARATOR "testenc1"); - std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/testenc1", 32, name)); + std::auto_ptr encoded( + BackupStoreFile::EncodeFile( + "testfiles" DIRECTORY_SEPARATOR + "testenc1", 32, name)); encoded->CopyStreamTo(out); } // Verify it { - FileStream enc("testfiles/testenc1_enc"); + FileStream enc("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc"); TEST_THAT(BackupStoreFile::VerifyEncodedFileFormat(enc) == true); } // Decode it { - FileStream enc("testfiles/testenc1_enc"); - BackupStoreFile::DecodeFile(enc, "testfiles/testenc1_orig", IOStream::TimeOutInfinite); + FileStream enc("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc"); + BackupStoreFile::DecodeFile(enc, "testfiles" + DIRECTORY_SEPARATOR "testenc1_orig", + IOStream::TimeOutInfinite); } // Read in rebuilt original, and compare contents { - TEST_THAT(TestGetFileSize("testfiles/testenc1_orig") == sizeof(encfile)); - FileStream in("testfiles/testenc1_orig"); + TEST_THAT(TestGetFileSize("testfiles" + DIRECTORY_SEPARATOR "testenc1_orig") + == sizeof(encfile)); + FileStream in("testfiles" DIRECTORY_SEPARATOR + "testenc1_orig"); int encfile_i[ENCFILE_SIZE]; in.Read(encfile_i, sizeof(encfile_i)); TEST_THAT(memcmp(encfile, encfile_i, sizeof(encfile)) == 0); @@ -1566,7 +1580,8 @@ int test3(int argc, const char *argv[]) // Check how many blocks it had, and test the stream based interface { - FileStream enc("testfiles/testenc1_enc"); + FileStream enc("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc"); std::auto_ptr decoded(BackupStoreFile::DecodeFileStream(enc, IOStream::TimeOutInfinite)); CollectInBufferStream d; decoded->CopyStreamTo(d, IOStream::TimeOutInfinite, 971 /* buffer block size */); @@ -1580,10 +1595,15 @@ int test3(int argc, const char *argv[]) // Test that the last block in a file, if less than 256 bytes, gets put into the last block { #define FILE_SIZE_JUST_OVER ((4096*2)+58) - FileStream f("testfiles/testenc2", O_WRONLY | O_CREAT | O_EXCL); + FileStream f("testfiles" DIRECTORY_SEPARATOR + "testenc2", O_WRONLY | O_CREAT | O_EXCL); f.Write(encfile + 2, FILE_SIZE_JUST_OVER); + f.Close(); BackupStoreFilenameClear name("testenc2"); - std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/testenc2", 32, name)); + std::auto_ptr encoded( + BackupStoreFile::EncodeFile( + "testfiles" DIRECTORY_SEPARATOR + "testenc2", 32, name)); CollectInBufferStream e; encoded->CopyStreamTo(e); e.SetForReading(); @@ -1599,7 +1619,8 @@ int test3(int argc, const char *argv[]) // Test that reordered streams work too { - FileStream enc("testfiles/testenc1_enc"); + FileStream enc("testfiles" DIRECTORY_SEPARATOR + "testenc1_enc"); std::auto_ptr reordered(BackupStoreFile::ReorderFileToStreamOrder(&enc, false)); std::auto_ptr decoded(BackupStoreFile::DecodeFileStream(*reordered, IOStream::TimeOutInfinite)); CollectInBufferStream d; @@ -1629,9 +1650,14 @@ int test3(int argc, const char *argv[]) // Store info { RaidFileWrite::CreateDirectory(0, "test-info"); - BackupStoreInfo::CreateNew(76, "test-info/", 0, 3461231233455433LL, 2934852487LL); - TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, "test-info/", 0, 0, 0), RaidFileException, CannotOverwriteExistingFile); - std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, true)); + BackupStoreInfo::CreateNew(76, "test-info" DIRECTORY_SEPARATOR, + 0, 3461231233455433LL, 2934852487LL); + TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, + "test-info" DIRECTORY_SEPARATOR, 0, 0, 0), + RaidFileException, CannotOverwriteExistingFile); + std::auto_ptr info( + BackupStoreInfo::Load(76, + "test-info" DIRECTORY_SEPARATOR, 0, true)); TEST_CHECK_THROWS(info->Save(), BackupStoreException, StoreInfoIsReadOnly); TEST_CHECK_THROWS(info->ChangeBlocksUsed(1), BackupStoreException, StoreInfoIsReadOnly); TEST_CHECK_THROWS(info->ChangeBlocksInOldFiles(1), BackupStoreException, StoreInfoIsReadOnly); @@ -1640,7 +1666,8 @@ int test3(int argc, const char *argv[]) TEST_CHECK_THROWS(info->AddDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly); } { - std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, false)); + std::auto_ptr info(BackupStoreInfo::Load(76, + "test-info" DIRECTORY_SEPARATOR, 0, false)); info->ChangeBlocksUsed(8); info->ChangeBlocksInOldFiles(9); info->ChangeBlocksInDeletedFiles(10); @@ -1658,7 +1685,8 @@ int test3(int argc, const char *argv[]) info->Save(); } { - std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, true)); + std::auto_ptr info(BackupStoreInfo::Load(76, + "test-info" DIRECTORY_SEPARATOR, 0, true)); TEST_THAT(info->GetBlocksUsed() == 7); TEST_THAT(info->GetBlocksInOldFiles() == 5); TEST_THAT(info->GetBlocksInDeletedFiles() == 1); @@ -1676,9 +1704,9 @@ int test3(int argc, const char *argv[]) // Context TLSContext context; context.Initialise(false /* client */, - "testfiles/clientCerts.pem", - "testfiles/clientPrivKey.pem", - "testfiles/clientTrustedCAs.pem"); + "testfiles" DIRECTORY_SEPARATOR "clientCerts.pem", + "testfiles" DIRECTORY_SEPARATOR "clientPrivKey.pem", + "testfiles" DIRECTORY_SEPARATOR "clientTrustedCAs.pem"); // First, try logging in without an account having been created... just make sure login fails. int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); -- cgit v1.2.3 From bb8f4cddf2aeddd8cb44d3b5ce13b66cce552198 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 1 Sep 2006 08:47:48 +0000 Subject: (refs #3) Disable symlink tests on Win32 --- test/backupstore/testbackupstore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index b98058cf..87f77947 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -1632,6 +1632,7 @@ int test3(int argc, const char *argv[]) TEST_THAT(decoded->GetNumBlocks() == 3); } +#ifndef WIN32 // no symlinks on Win32 // Try out doing this on a symlink { TEST_THAT(::symlink("does/not/exist", "testfiles/testsymlink") == 0); @@ -1645,6 +1646,7 @@ int test3(int argc, const char *argv[]) // Decode it BackupStoreFile::DecodeFile(b, "testfiles/testsymlink_2", IOStream::TimeOutInfinite); } +#endif } // Store info -- cgit v1.2.3 From 59088c2f8881552e61338d28a659f53a8c5ae8f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 10:44:29 +0000 Subject: (refs #3) Convert UNIX paths to native on Win32 (avoids #ifdefs in tests) --- lib/common/Test.h | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 8bac6036..75ed93aa 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -79,11 +79,31 @@ inline int TestGetFileSize(const char *Filename) return -1; } -inline int LaunchServer(const char *CommandLine, const char *pidFile) +inline int LaunchServer(const char *pCommandLine, const char *pidFile) { - if(::system(CommandLine) != 0) +#ifdef WIN32 + // convert UNIX paths to native + + std::string command; + for (int i = 0; pCommandLine[i] != 0; i++) + { + if (pCommandLine[i] == '/') + { + command += '\\'; + } + else + { + command += pCommandLine[i]; + } + } + +#else // !WIN32 + std::string command = pCommandLine; +#endif + + if(::system(command.c_str()) != 0) { - printf("Server: %s\n", CommandLine); + printf("Server: %s\n", command.c_str()); TEST_FAIL_WITH_MESSAGE("Couldn't start server"); return -1; } @@ -93,7 +113,7 @@ inline int LaunchServer(const char *CommandLine, const char *pidFile) // read pid file if(!TestFileExists(pidFile)) { - printf("Server: %s\n", CommandLine); + printf("Server: %s\n", command.c_str()); TEST_FAIL_WITH_MESSAGE("Server didn't save PID file"); return -1; } @@ -102,7 +122,7 @@ inline int LaunchServer(const char *CommandLine, const char *pidFile) int pid = -1; if(f == NULL || fscanf(f, "%d", &pid) != 1) { - printf("Server: %s (pidfile %s)\n", CommandLine, pidFile); + printf("Server: %s (pidfile %s)\n", command.c_str(), pidFile); TEST_FAIL_WITH_MESSAGE("Couldn't read PID file"); return -1; } -- cgit v1.2.3 From 6f5e003c4ca46f88e8f5bc26b67cb5a244d7b4b1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 10:48:10 +0000 Subject: (refs #3) Disable tests for memory leaks after killing bbstored on Win32, since it dies forcibly without a chance to write the memory leak file. Initialise Windows sockets on Win32 Add tests for multiply open files on Win32 --- test/backupstore/testbackupstore.cpp | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index 87f77947..7dfff806 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -1765,7 +1765,9 @@ int test3(int argc, const char *argv[]) TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); +#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); +#endif // Set a new limit on the account -- leave the hard limit high to make sure the target for // freeing space is the soft limit. @@ -1848,7 +1850,10 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); + +#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); +#endif } return 0; @@ -1860,7 +1865,10 @@ int multi_server() // Create an account for the test client TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); + +#ifndef WIN32 TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); +#endif // First, try logging in without an account having been created... just make sure login fails. int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid"); @@ -1880,15 +1888,63 @@ int multi_server() TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); +#ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); +#endif } return 0; } +#ifdef WIN32 +WCHAR* ConvertUtf8ToWideString(const char* pString); +std::string ConvertPathToAbsoluteUnicode(const char *pFileName); +#endif + int test(int argc, const char *argv[]) { +#ifdef WIN32 + // Under win32 we must initialise the Winsock library + // before using sockets + + WSADATA info; + TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) + + // this had better work, or bbstored will die when combining diffs + char* file = "foo"; + std::string abs = ConvertPathToAbsoluteUnicode(file); + WCHAR* wfile = ConvertUtf8ToWideString(abs.c_str()); + + DWORD accessRights = FILE_READ_ATTRIBUTES | + FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | + FILE_WRITE_DATA | FILE_WRITE_EA /*| FILE_ALL_ACCESS*/; + DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + + HANDLE h1 = CreateFileW(wfile, accessRights, shareMode, + NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL); + assert(h1 != INVALID_HANDLE_VALUE); + TEST_THAT(h1 != INVALID_HANDLE_VALUE); + + accessRights = FILE_READ_ATTRIBUTES | + FILE_LIST_DIRECTORY | FILE_READ_EA; + + HANDLE h2 = CreateFileW(wfile, accessRights, shareMode, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + assert(h2 != INVALID_HANDLE_VALUE); + TEST_THAT(h2 != INVALID_HANDLE_VALUE); + + CloseHandle(h2); + CloseHandle(h1); + + h1 = openfile("foo", O_CREAT | O_RDWR, 0); + TEST_THAT(h1 != INVALID_HANDLE_VALUE); + h2 = openfile("foo", O_RDWR, 0); + TEST_THAT(h2 != INVALID_HANDLE_VALUE); + CloseHandle(h2); + CloseHandle(h1); +#endif + // SSL library SSLLib::Initialise(); -- cgit v1.2.3 From da1adc8d421d8923792a0ab8c60f29cbbd5ca2c8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 10:51:01 +0000 Subject: Revert to trunk --- test/backupstorefix/testfiles/testbackupstorefix.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/backupstorefix/testfiles/testbackupstorefix.pl.in b/test/backupstorefix/testfiles/testbackupstorefix.pl.in index e64474f0..b57f10ac 100755 --- a/test/backupstorefix/testfiles/testbackupstorefix.pl.in +++ b/test/backupstorefix/testfiles/testbackupstorefix.pl.in @@ -54,7 +54,7 @@ elsif($ARGV[0] eq 'check') open INITIAL,'testfiles/initial-listing.txt' or die "Can't open original listing"; while() { - chomp; s/\r//; + chomp; $expected{$_} = 1; m/\A(.+?) .+? (.+)\Z/; $filenames{$2} = $_; @@ -99,7 +99,7 @@ elsif($ARGV[0] eq 'check') while() { print LISTING_COPY; - chomp; s/\r//; + chomp; s/\[FILENAME NOT ENCRYPTED\]//; if(exists $expected{$_}) { -- cgit v1.2.3 From aae9bedf46cd180f89a961d2cc77cf6c7fcc3055 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 10:51:41 +0000 Subject: (refs #3) Remove newlines from output to avoid failure to recognise it on Win32 --- test/backupstorefix/testfiles/testbackupstorefix.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/backupstorefix/testfiles/testbackupstorefix.pl.in b/test/backupstorefix/testfiles/testbackupstorefix.pl.in index b57f10ac..e64474f0 100755 --- a/test/backupstorefix/testfiles/testbackupstorefix.pl.in +++ b/test/backupstorefix/testfiles/testbackupstorefix.pl.in @@ -54,7 +54,7 @@ elsif($ARGV[0] eq 'check') open INITIAL,'testfiles/initial-listing.txt' or die "Can't open original listing"; while() { - chomp; + chomp; s/\r//; $expected{$_} = 1; m/\A(.+?) .+? (.+)\Z/; $filenames{$2} = $_; @@ -99,7 +99,7 @@ elsif($ARGV[0] eq 'check') while() { print LISTING_COPY; - chomp; + chomp; s/\r//; s/\[FILENAME NOT ENCRYPTED\]//; if(exists $expected{$_}) { -- cgit v1.2.3 From 651270b90d79ded4a407c75642fc47872f0ac8ce Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 10:56:48 +0000 Subject: (refs #3) Added a RunCommand() function which converts UNIX paths to native before calling ::system() on Win32. --- lib/common/Test.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 75ed93aa..5e42e406 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -79,7 +79,7 @@ inline int TestGetFileSize(const char *Filename) return -1; } -inline int LaunchServer(const char *pCommandLine, const char *pidFile) +inline int RunCommand(const char *pCommandLine) { #ifdef WIN32 // convert UNIX paths to native @@ -101,7 +101,12 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) std::string command = pCommandLine; #endif - if(::system(command.c_str()) != 0) + return ::system(command.c_str()); +} + +inline int LaunchServer(const char *pCommandLine, const char *pidFile) +{ + if(RunCommand(pCommandLine) != 0) { printf("Server: %s\n", command.c_str()); TEST_FAIL_WITH_MESSAGE("Couldn't start server"); -- cgit v1.2.3 From ec62f83fcc1e119e86929d4c1201e97e9f061554 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 10:57:16 +0000 Subject: (refs #3) Call RunCommand() instead of ::system to handle native paths better --- test/backupstore/testbackupstore.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index 7dfff806..01e7c57d 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -1740,7 +1740,7 @@ int test3(int argc, const char *argv[]) } // Create an account for the test client - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); + TEST_THAT_ABORTONFAIL(RunCommand("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567")); @@ -1771,7 +1771,7 @@ int test3(int argc, const char *argv[]) // Set a new limit on the account -- leave the hard limit high to make sure the target for // freeing space is the soft limit. - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); + TEST_THAT_ABORTONFAIL(RunCommand("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Start things up @@ -1800,7 +1800,7 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(after.old == 0); // Set a really small hard limit - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); + TEST_THAT_ABORTONFAIL(RunCommand("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Try to upload a file and create a directory, and check an error is generated @@ -1864,7 +1864,7 @@ int multi_server() printf("Starting server for connection from remote machines...\n"); // Create an account for the test client - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); + TEST_THAT_ABORTONFAIL(RunCommand("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); #ifndef WIN32 TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); -- cgit v1.2.3 From 07b592e5e1dc1be6603d0b67906f55e40a494b8e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:01:07 +0000 Subject: Revert to trunk --- test/backupstorepatch/testbackupstorepatch.cpp | 35 ++------------------------ 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index 61ad0e18..5d77c3fd 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -283,14 +283,6 @@ void test_depends_in_dirs() int test(int argc, const char *argv[]) { -#ifdef WIN32 - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) -#endif - // Allocate a buffer buffer = ::malloc(BUFFER_SIZE); TEST_THAT(buffer != 0); @@ -317,12 +309,8 @@ int test(int argc, const char *argv[]) "testfiles/clientTrustedCAs.pem"); // Create an account -#ifdef WIN32 - TEST_THAT_ABORTONFAIL(::system("..\\..\\bin\\bbstoreaccounts\\bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); -#else TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); -#endif // Create test files create_test_files(); @@ -331,12 +319,7 @@ int test(int argc, const char *argv[]) test_depends_in_dirs(); // First, try logging in without an account having been created... just make sure login fails. -#ifdef WIN32 - int pid = LaunchServer("..\\..\\bin\\bbstored\\bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); -#else int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); -#endif - TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -414,13 +397,7 @@ int test(int argc, const char *argv[]) // Store details test_files[f].IDOnServer = stored->GetObjectID(); test_files[f].IsCompletelyDifferent = isCompletelyDifferent; - -#ifdef WIN32 - printf("ID %I64d, completely different: %s\n", -#else - printf("ID %lld, completely different: %s\n", -#endif - test_files[f].IDOnServer, + printf("ID %lld, completely different: %s\n", test_files[f].IDOnServer, test_files[f].IsCompletelyDifferent?"yes":"no"); } else @@ -588,14 +565,9 @@ int test(int argc, const char *argv[]) writedir.Commit(true); } -#ifdef WIN32 - wait_for_operation(12); -#else - // Send the server a restart signal, so it does housekeeping immediately, and wait for it to happen + // Send the server a restart signal, so it does housekeeping immedaitely, and wait for it to happen ::sleep(1); // wait for old connections to terminate ::kill(pid, SIGHUP); -#endif - // Get the revision number of the info file int64_t first_revision = 0; RaidFileRead::FileExists(0, "backup/01234567/o01", &first_revision); @@ -639,10 +611,7 @@ int test(int argc, const char *argv[]) // Kill store server TEST_THAT(KillServer(pid)); TEST_THAT(!ServerIsAlive(pid)); - - #ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); - #endif } ::free(buffer); -- cgit v1.2.3 From b5a3da46888df6749712f8d1b04ef4393230b49a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:02:44 +0000 Subject: (refs #3) Initialise Windows sockets on Win32 --- test/backupstorepatch/testbackupstorepatch.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index 5d77c3fd..83ee2a8e 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -283,6 +283,14 @@ void test_depends_in_dirs() int test(int argc, const char *argv[]) { +#ifdef WIN32 + // Under win32 we must initialise the Winsock library + // before using sockets + + WSADATA info; + TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) +#endif + // Allocate a buffer buffer = ::malloc(BUFFER_SIZE); TEST_THAT(buffer != 0); -- cgit v1.2.3 From 18dc6c07753520a5464d6b385817b46f0839b1ef Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:03:48 +0000 Subject: (refs #3) Fix format strings on Win32 --- test/backupstorepatch/testbackupstorepatch.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index 83ee2a8e..d14badc6 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -405,7 +405,13 @@ int test(int argc, const char *argv[]) // Store details test_files[f].IDOnServer = stored->GetObjectID(); test_files[f].IsCompletelyDifferent = isCompletelyDifferent; - printf("ID %lld, completely different: %s\n", test_files[f].IDOnServer, + +#ifdef WIN32 + printf("ID %I64d, completely different: %s\n", +#else + printf("ID %lld, completely different: %s\n", +#endif + test_files[f].IDOnServer, test_files[f].IsCompletelyDifferent?"yes":"no"); } else -- cgit v1.2.3 From 217379b9ec7eaf4317cde68db939b910c58366cc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:06:13 +0000 Subject: (refs #3) Cannot signal bbstored to housekeep immediately on Win32, so just wait for it to happen. --- test/backupstorepatch/testbackupstorepatch.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index d14badc6..368d835a 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -579,9 +579,18 @@ int test(int argc, const char *argv[]) writedir.Commit(true); } - // Send the server a restart signal, so it does housekeeping immedaitely, and wait for it to happen - ::sleep(1); // wait for old connections to terminate +#ifdef WIN32 + // Cannot signal bbstored to do housekeeping now, + // so just wait until we're sure it's done + wait_for_operation(12); +#else + // Send the server a restart signal, so it does + // housekeeping immediately, and wait for it to happen + // Wait for old connections to terminate + ::sleep(1); ::kill(pid, SIGHUP); +#endif + // Get the revision number of the info file int64_t first_revision = 0; RaidFileRead::FileExists(0, "backup/01234567/o01", &first_revision); -- cgit v1.2.3 From 4161b680120c04f8f4a1fe35caef64645222bb67 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:07:17 +0000 Subject: (refs #3) Don't check for memory leaks on Win32, since the process is force killed and doesn't have a chance to write the log file. --- test/backupstorepatch/testbackupstorepatch.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index 368d835a..fd825016 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -634,7 +634,10 @@ int test(int argc, const char *argv[]) // Kill store server TEST_THAT(KillServer(pid)); TEST_THAT(!ServerIsAlive(pid)); + + #ifndef WIN32 TestRemoteProcessMemLeaks("bbstored.memleaks"); + #endif } ::free(buffer); -- cgit v1.2.3 From 42d5d18d05c46f00bd13aa5e47f113a6aa462423 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:09:08 +0000 Subject: (refs #3) Use RunCommand instead of ::system to convert UNIX paths to native --- test/backupstorepatch/testbackupstorepatch.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index fd825016..8e2fa5f6 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -317,7 +317,10 @@ int test(int argc, const char *argv[]) "testfiles/clientTrustedCAs.pem"); // Create an account - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); + TEST_THAT_ABORTONFAIL(RunCommand( + "../../bin/bbstoreaccounts/bbstoreaccounts " + "-c testfiles/bbstored.conf " + "create 01234567 0 30000B 40000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Create test files -- cgit v1.2.3 From 8894575935e9c3ead5ed27674f85eb4911cb85d8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:09:41 +0000 Subject: Revert to trunk --- test/basicserver/testbasicserver.cpp | 99 ++++-------------------------------- 1 file changed, 11 insertions(+), 88 deletions(-) diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index 1403df42..f5185b96 100644 --- a/test/basicserver/testbasicserver.cpp +++ b/test/basicserver/testbasicserver.cpp @@ -31,6 +31,7 @@ #include "MemLeakFindOn.h" + #define SERVER_LISTEN_PORT 2003 // in ms @@ -61,14 +62,10 @@ void basicdaemon::Run() void testservers_pause_before_reply() { -#ifdef WIN32 - Sleep(COMMS_SERVER_WAIT_BEFORE_REPLYING); -#else - struct timespec t; - t.tv_sec = 0; - t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000; // convert to ns - ::nanosleep(&t, NULL); -#endif + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000; // convert to ns + ::nanosleep(&t, NULL); } #define LARGE_DATA_BLOCK_SIZE 19870 @@ -430,138 +427,84 @@ int test(int argc, const char *argv[]) } } -#ifdef WIN32 - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) -#endif - //printf("SKIPPING TESTS------------------------\n"); //goto protocolserver; // Launch a basic server { -#ifdef WIN32 - int pid = LaunchServer("test srv1 testfiles\\srv1.conf", - "testfiles\\srv1.pid"); -#else - int pid = LaunchServer("./test srv1 testfiles/srv1.conf", - "testfiles/srv1.pid"); -#endif - + int pid = LaunchServer("./test srv1 testfiles/srv1.conf", "testfiles/srv1.pid"); TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Check that it's written the expected file - TEST_THAT(TestFileExists("testfiles" - DIRECTORY_SEPARATOR "srv1.test1")); + TEST_THAT(TestFileExists("testfiles/srv1.test1")); TEST_THAT(ServerIsAlive(pid)); // Move the config file over -#ifdef WIN32 - TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR - "srv1.conf") != -1); -#endif - TEST_THAT(::rename( - "testfiles" DIRECTORY_SEPARATOR "srv1b.conf", - "testfiles" DIRECTORY_SEPARATOR "srv1.conf") - != -1); -#ifndef WIN32 + TEST_THAT(::rename("testfiles/srv1b.conf", "testfiles/srv1.conf") != -1); // Get it to reread the config file TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); // Check that new file exists - TEST_THAT(TestFileExists("testfiles" - DIRECTORY_SEPARATOR "srv1.test2")); -#endif // !WIN32 + TEST_THAT(TestFileExists("testfiles/srv1.test2")); // Kill it off TEST_THAT(KillServer(pid)); -#ifndef WIN32 TestRemoteProcessMemLeaks("generic-daemon.memleaks"); -#endif // !WIN32 } } // Launch a test forking server { -#ifdef WIN32 - int pid = LaunchServer("test srv2 testfiles\\srv2.conf", - "testfiles\\srv2.pid"); -#else - int pid = LaunchServer("./test srv2 testfiles/srv2.conf", - "testfiles/srv2.pid"); -#endif - + int pid = LaunchServer("./test srv2 testfiles/srv2.conf", "testfiles/srv2.pid"); TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Will it restart? TEST_THAT(ServerIsAlive(pid)); -#ifndef WIN32 TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); -#endif // !WIN32 // Make some connections { SocketStream conn1; conn1.Open(Socket::TypeINET, "localhost", 2003); -#ifndef WIN32 SocketStream conn2; conn2.Open(Socket::TypeUNIX, "testfiles/srv2.sock"); SocketStream conn3; conn3.Open(Socket::TypeINET, "localhost", 2003); -#endif // !WIN32 // Quick check that reconnections fail TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX, "testfiles/srv2.sock");, ServerException, SocketAlreadyOpen); // Stuff some data around std::vector conns; conns.push_back(&conn1); -#ifndef WIN32 conns.push_back(&conn2); conns.push_back(&conn3); -#endif // !WIN32 Srv2TestConversations(conns); // Implicit close } -#ifndef WIN32 // HUP again TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); -#endif // !WIN32 // Kill it TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); -#ifndef WIN32 TestRemoteProcessMemLeaks("test-srv2.memleaks"); -#endif // !WIN32 } } // Launch a test SSL server { -#ifdef WIN32 - int pid = LaunchServer("test srv3 testfiles\\srv3.conf", - "testfiles\\srv3.pid"); -#else int pid = LaunchServer("./test srv3 testfiles/srv3.conf", "testfiles/srv3.pid"); -#endif TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Will it restart? TEST_THAT(ServerIsAlive(pid)); - -#ifndef WIN32 TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); -#endif - // Make some connections { // SSL library @@ -576,50 +519,36 @@ int test(int argc, const char *argv[]) SocketStreamTLS conn1; conn1.Open(context, Socket::TypeINET, "localhost", 2003); -#ifndef WIN32 SocketStreamTLS conn2; conn2.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock"); SocketStreamTLS conn3; conn3.Open(context, Socket::TypeINET, "localhost", 2003); -#endif // Quick check that reconnections fail TEST_CHECK_THROWS(conn1.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock");, ServerException, SocketAlreadyOpen); // Stuff some data around std::vector conns; conns.push_back(&conn1); -#ifndef WIN32 conns.push_back(&conn2); conns.push_back(&conn3); -#endif Srv2TestConversations(conns); // Implicit close } -#ifndef WIN32 // HUP again TEST_THAT(HUPServer(pid)); ::sleep(1); TEST_THAT(ServerIsAlive(pid)); -#endif // Kill it TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); -#ifndef WIN32 TestRemoteProcessMemLeaks("test-srv3.memleaks"); -#endif } } //protocolserver: // Launch a test protocol handling server { -#ifdef WIN32 - int pid = LaunchServer("test srv4 testfiles\\srv4.conf", - "testfiles\\srv4.pid"); -#else - int pid = LaunchServer("./test srv4 testfiles/srv4.conf", - "testfiles/srv4.pid"); -#endif + int pid = LaunchServer("./test srv4 testfiles/srv4.conf", "testfiles/srv4.pid"); TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -628,11 +557,7 @@ int test(int argc, const char *argv[]) // Open a connection to it SocketStream conn; -#ifdef WIN32 - conn.Open(Socket::TypeINET, "localhost", 2003); -#else conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock"); -#endif // Create a protocol TestProtocolClient protocol(conn); @@ -695,9 +620,7 @@ int test(int argc, const char *argv[]) TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); -#ifndef WIN32 TestRemoteProcessMemLeaks("test-srv4.memleaks"); -#endif } } -- cgit v1.2.3 From 23fead5de5ef2dc968d46e5a7a4d50f9e36b774a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:12:01 +0000 Subject: (refs #3) Sleep without nanosleep() on Win32 --- test/basicserver/testbasicserver.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index f5185b96..3360cd20 100644 --- a/test/basicserver/testbasicserver.cpp +++ b/test/basicserver/testbasicserver.cpp @@ -31,7 +31,6 @@ #include "MemLeakFindOn.h" - #define SERVER_LISTEN_PORT 2003 // in ms @@ -62,10 +61,14 @@ void basicdaemon::Run() void testservers_pause_before_reply() { - struct timespec t; - t.tv_sec = 0; - t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000; // convert to ns - ::nanosleep(&t, NULL); +#ifdef WIN32 + Sleep(COMMS_SERVER_WAIT_BEFORE_REPLYING); +#else + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = COMMS_SERVER_WAIT_BEFORE_REPLYING * 1000 * 1000; // convert to ns + ::nanosleep(&t, NULL); +#endif } #define LARGE_DATA_BLOCK_SIZE 19870 -- cgit v1.2.3 From 300d1fc0c31b6122d2e897acd5cee93a05eef61c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:16:22 +0000 Subject: (refs #3) Automatically initialise Windows sockets for all tests --- infrastructure/buildenv-testmain-template.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index c64c1fa5..7adbafa9 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -103,6 +103,14 @@ int main(int argc, const char *argv[]) // banner printf("Running test TEST_NAME in " MODE_TEXT " mode...\n"); + + #ifdef WIN32 + // Under win32 we must initialise the Winsock library + // before using sockets + + WSADATA info; + TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) + #endif } try { -- cgit v1.2.3 From 364ec72789db5a33c5ff35f0774a29348304d868 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:32:38 +0000 Subject: (refs #3) Reorganise typedefs for clarity --- lib/win32/emu.h | 68 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index ce0c884f..5d67264a 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -3,7 +3,48 @@ #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 + typedef uint32_t u_int32_t; +#else // MSVC + typedef __int64 int64_t; + typedef __int32 int32_t; + typedef __int16 int16_t; + typedef __int8 int8_t; + + typedef unsigned __int64 u_int64_t; + typedef unsigned __int32 u_int32_t; + + typedef unsigned __int64 uint64_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int8 uint8_t; +#endif + +// emulated types, present on MinGW but not MSVC or vice versa + +#ifdef _MSC_VER + typedef unsigned int mode_t; + typedef unsigned int pid_t; + + // must define _INO_T_DEFINED before including + // 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 #include @@ -19,6 +60,8 @@ #include +// emulated functions + #define gmtime_r( _clock, _result ) \ ( *(_result) = *gmtime( (_clock) ), \ (_result) ) @@ -50,8 +93,8 @@ inline int geteuid(void) 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; @@ -252,17 +295,6 @@ 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 @@ -283,10 +315,6 @@ 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) @@ -410,10 +438,6 @@ struct stat { time_t st_mtime; time_t st_ctime; }; - -#ifndef __MINGW32__ -typedef u_int64_t _ino_t; -#endif #endif int emu_stat(const char * name, struct stat * st); -- cgit v1.2.3 From 26bff57d54830e2d2c7cf1416cc66a7787d41640 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:39:39 +0000 Subject: (refs #3) Remove dependency on Box.h and hence on lib/common --- lib/win32/emu.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index b9cefba8..927eefb0 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -3,15 +3,13 @@ // 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 +#include #include -// #include +#include #ifdef HAVE_UNISTD_H #include -- cgit v1.2.3 From 29e9ec5e4f13ab0f191016cdba5182a2374449c2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:41:44 +0000 Subject: (refs #3) Add message definitions and resource files --- lib/win32/messages.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/win32/messages.mc | 22 ++++++++++++++++++++ lib/win32/messages.rc | 2 ++ 3 files changed, 81 insertions(+) create mode 100755 lib/win32/messages.h create mode 100644 lib/win32/messages.mc create mode 100755 lib/win32/messages.rc diff --git a/lib/win32/messages.h b/lib/win32/messages.h new file mode 100755 index 00000000..6959591b --- /dev/null +++ b/lib/win32/messages.h @@ -0,0 +1,57 @@ + // 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 -- cgit v1.2.3 From affb37c9860c4575f2580c49ee3d274dad9e4c8e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:44:24 +0000 Subject: (refs #3) Include message resource definitions --- lib/win32/emu.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 927eefb0..0fbbe047 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -21,6 +21,10 @@ #include #include +// 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 -- cgit v1.2.3 From 241e62376bc3c4dac114d25915e42eb2ab4159b0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:45:11 +0000 Subject: (refs #3) Add BSD-licensed getopt.h to replace our own version --- lib/win32/getopt.h | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100755 lib/win32/getopt.h diff --git a/lib/win32/getopt.h b/lib/win32/getopt.h new file mode 100755 index 00000000..7c290343 --- /dev/null +++ b/lib/win32/getopt.h @@ -0,0 +1,98 @@ +/* $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_ */ -- cgit v1.2.3 From 309f2d0428db81ea8bf9762e276de2458ce1d125 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 2 Sep 2006 11:50:26 +0000 Subject: (refs #3) Use our own ConvertUtf8ToWideString for simplicity --- lib/win32/emu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 0fbbe047..fa853f14 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -372,7 +372,7 @@ char* ConvertFromWideString(const WCHAR* pString, unsigned int codepage) // -------------------------------------------------------------------------- bool ConvertUtf8ToConsole(const char* pString, std::string& rDest) { - WCHAR* pWide = ConvertToWideString(pString, CP_UTF8); + WCHAR* pWide = ConvertUtf8ToWideString(pString); if (pWide == NULL) { return false; -- cgit v1.2.3 From 054f818ce7f7d9e274da16b5ab6956792fa1b986 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 22:54:58 +0000 Subject: (refs #3) Convert UNIX to native paths --- lib/win32/emu.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index fa853f14..37699bb1 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -436,13 +436,26 @@ 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] != ':') + if (filename.length() >= 2 && filename[1] != ':') { // Must be relative. We need to get the // current directory to make it absolute. @@ -465,7 +478,7 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName) } } - tmpStr += pFileName; + tmpStr += filename; return tmpStr; } -- cgit v1.2.3 From 4434ff992787675604d9868d555887579d07fc52 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:35:48 +0000 Subject: (refs #3) Return INVALID_HANDLE_VALUE instead of NULL from openfile() on failure --- lib/win32/emu.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 37699bb1..f13fb899 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -486,18 +486,20 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName) // // 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()); @@ -506,7 +508,7 @@ 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 @@ -553,7 +555,7 @@ HANDLE openfile(const char *pFileName, int flags, int mode) { ::syslog(LOG_WARNING, "Failed to open file %s: " "error %i", pFileName, GetLastError()); - return NULL; + return INVALID_HANDLE_VALUE; } return hdir; -- cgit v1.2.3 From eeeb123dddad8e61c5316fcbddfe24d9750b63e3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:39:08 +0000 Subject: (refs #3) Use INVALID_HANDLE_VALUE instead of NULL for invalid handles on Win32 --- lib/common/FileStream.cpp | 10 +++++++++- lib/common/FileStream.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/common/FileStream.cpp b/lib/common/FileStream.cpp index 917dc9c9..c6c53f2b 100644 --- a/lib/common/FileStream.cpp +++ b/lib/common/FileStream.cpp @@ -30,7 +30,7 @@ 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 @@ -56,7 +56,11 @@ 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); THROW_EXCEPTION(CommonException, OSFileOpenError) @@ -76,7 +80,11 @@ 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); THROW_EXCEPTION(CommonException, OSFileOpenError) diff --git a/lib/common/FileStream.h b/lib/common/FileStream.h index 7a4a29f3..721bf3dd 100644 --- a/lib/common/FileStream.h +++ b/lib/common/FileStream.h @@ -21,7 +21,7 @@ #endif #ifdef WIN32 - #define INVALID_FILE NULL + #define INVALID_FILE INVALID_HANDLE_VALUE typedef HANDLE tOSFileHandle; #else #define INVALID_FILE -1 -- cgit v1.2.3 From 7904931e8026a5e43bcfcdc75adb5688766b67eb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:41:31 +0000 Subject: (refs #3) Improved handling of UNIX flags to openfile(), allows multiple opens --- lib/win32/emu.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index f13fb899..3285f90c 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -518,19 +518,19 @@ HANDLE openfile(const char *pFileName, int flags, int mode) if (flags & O_WRONLY) { + accessRights = FILE_WRITE_DATA; shareMode = FILE_SHARE_WRITE; } - if (flags & O_RDWR) + else if (flags & (O_RDWR | O_CREAT)) { - shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + accessRights |= FILE_WRITE_ATTRIBUTES + | FILE_WRITE_DATA | FILE_WRITE_EA; + shareMode |= FILE_SHARE_WRITE; } + 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) { -- cgit v1.2.3 From 33c64c6247b677f6233d4c529ee162f34d1535fc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:46:11 +0000 Subject: (refs #3) Improved error handling in emu_fstat --- lib/win32/emu.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 3285f90c..41361409 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -580,8 +580,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()"); @@ -598,9 +596,18 @@ int emu_fstat(HANDLE hdir, struct stat * st) return -1; } + if (INVALID_FILE_ATTRIBUTES == fi.dwFileAttributes) + { + ::syslog(LOG_WARNING, "Failed to get file attributes: " + "error %d", GetLastError()); + 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; -- cgit v1.2.3 From a64a6f4c9c71dfe925bf5492c6e6aa828611fba0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:48:34 +0000 Subject: (refs #3) Always fill in st_uid, st_gid and st_nlink Return zero size for directories Improved emulation of Unix file modes (helps when restoring Windows files on Unix) --- lib/win32/emu.cpp | 66 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 41361409..c0bdd609 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -617,41 +617,55 @@ 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: " + "error %d", GetLastError()); + 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; + } - //the mode of the file - st->st_mode = 0; - //DWORD res = GetFileAttributes((LPCSTR)tmpStr.c_str()); + // at the mo + st->st_uid = 0; + st->st_gid = 0; + st->st_nlink = 1; - if (INVALID_FILE_ATTRIBUTES != fi.dwFileAttributes) + // 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 (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; } return 0; -- cgit v1.2.3 From a1ccaaebe529e4c054812c13394b597974c58123 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:51:22 +0000 Subject: (refs #3) Pass requested open flags to OpenFileByNameUtf8 --- lib/win32/emu.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index c0bdd609..0239724c 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -681,9 +681,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 +702,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, @@ -757,12 +758,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 +792,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) { -- cgit v1.2.3 From f2a0eaaedd261b287c11ca29661490c15ef57e72 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:52:19 +0000 Subject: (refs #3) Request READ_CONTROL when standard open fails, rather than no flags --- lib/win32/emu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 0239724c..809cfa0e 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -716,7 +716,7 @@ HANDLE OpenFileByNameUtf8(const char* pFileName, DWORD flags) // 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, -- cgit v1.2.3 From 3a073296c1630000907ba6385da0e93006adc891 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:53:13 +0000 Subject: (refs #3) Treat PATH_NOT_FOUND just like FILE_NOT_FOUND in Unix land (errno = ENOENT) --- lib/win32/emu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 809cfa0e..e54b2d72 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -730,7 +730,8 @@ HANDLE OpenFileByNameUtf8(const char* pFileName, DWORD flags) { DWORD err = GetLastError(); - if (err == ERROR_FILE_NOT_FOUND) + if (err == ERROR_FILE_NOT_FOUND || + err == ERROR_PATH_NOT_FOUND) { errno = ENOENT; } -- cgit v1.2.3 From 83bf070fb425f75bdb85b58dc810791736369814 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:55:55 +0000 Subject: (refs #3) Added emulated utimes, chmod, readv and writev Added useful utility functions ConvertFileTimeToTime_t and ConvertTime_tToFileTime --- lib/win32/emu.cpp | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index e54b2d72..d681335a 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -823,6 +823,115 @@ int statfs(const char * pName, struct statfs * s) return 0; } +// -------------------------------------------------------------------------- +// +// 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': error %d", + pName, GetLastError()); + 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': " + "error %d", pName, GetLastError()); + 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': " + "error %d", pName, GetLastError()); + errno = EACCES; + free(pBuffer); + return -1; + } + + free(pBuffer); + return 0; +} + + // -------------------------------------------------------------------------- // // Function @@ -1263,4 +1372,96 @@ int console_read(char* pBuffer, size_t BufferSize) 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: " + "error %d", GetLastError()); + return false; + } + + return true; +} + + #endif // WIN32 -- cgit v1.2.3 From 078175bdc74e4a571e30474189063af1ff48dacb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:57:08 +0000 Subject: (refs #3) Removed last vestiges of old getopt() --- lib/win32/emu.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index d681335a..1dbd98a7 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -561,15 +561,6 @@ HANDLE openfile(const char *pFileName, int flags, int mode) 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 -- cgit v1.2.3 From abd90648a83b3884039bbd813c92341807c090c8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Sep 2006 23:58:43 +0000 Subject: (refs #3) Improved poll() emulation to handle multiple fds --- lib/win32/emu.cpp | 58 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 1dbd98a7..ed89816e 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1079,10 +1079,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; @@ -1095,41 +1095,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]); + + if (FD_ISSET(ufd->fd, &readfd)) + { + ufd->revents |= POLLIN; + } + + if (FD_ISSET(ufd->fd, &writefd)) + { + ufd->revents |= POLLOUT; + } + } + } - return noffds; + return nready; } catch (...) { -- cgit v1.2.3 From b8f9eeceb44b72bbab18ebd0644e1b6cabe624da Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Sep 2006 00:02:12 +0000 Subject: (refs #3) Fixed looking up message source in syslog() Flush stdout after writing to it Allow syslog() to log to console even when openlog() has not been called --- lib/win32/emu.cpp | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++- lib/win32/emu.h | 29 ++-------- 2 files changed, 163 insertions(+), 28 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index ed89816e..dc17c1df 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1159,9 +1159,147 @@ 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 + + char cmd[MAX_PATH]; + if (GetModuleFileName(NULL, cmd, sizeof(cmd)-1) == 0) + { + ::syslog(LOG_ERR, "Failed to get the program file name: " + "error %d", GetLastError()); + return FALSE; + } + cmd[sizeof(cmd)-1] = 0; + std::string exepath(cmd); + + // 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: " + "error %d", GetLastError()); + return FALSE; + } + + // Set the name of the message file. + + if (RegSetValueEx(hk, // subkey handle + "EventMessageFile", // value name + 0, // must be zero + REG_EXPAND_SZ, // value type + (LPBYTE) exepath.c_str(), // pointer to value data + (DWORD) (exepath.size()))) // data size + { + ::syslog(LOG_ERR, "Failed to set the event message file: " + "error %d", GetLastError()); + 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: " + "error %d", GetLastError()); + RegCloseKey(hk); + return FALSE; + } + + // Set the category message file and number of categories. + + if (RegSetValueEx(hk, // subkey handle + "CategoryMessageFile", // value name + 0, // must be zero + REG_EXPAND_SZ, // value type + (LPBYTE) exepath.c_str(), // pointer to value data + (DWORD) (exepath.size()))) // data size + { + ::syslog(LOG_ERR, "Failed to set the category message file: " + "error %d", GetLastError()); + 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: " + "error %d", GetLastError()); + 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) + { + } + + if (!AddEventSource("Box Backup", 0)) + { + ::syslog(LOG_ERR, "Failed to add our own event source"); + return; + } + + HANDLE newSyslogH = RegisterEventSource(NULL, "Box Backup"); + if (newSyslogH == NULL) + { + ::syslog(LOG_ERR, "Failed to register our own event source: " + "error %d", GetLastError()); + return; + } + + DeregisterEventSource(gSyslogH); + gSyslogH = newSyslogH; +} + +void closelog(void) +{ + DeregisterEventSource(gSyslogH); +} + void syslog(int loglevel, const char *frmt, ...) { WORD errinfo; @@ -1201,17 +1339,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 @@ -1227,6 +1380,7 @@ 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; } } @@ -1234,6 +1388,7 @@ void syslog(int loglevel, const char *frmt, ...) { printf("Unable to send message to Event Log: " "error %i:\r\n", (int)err); + fflush(stdout); } } else @@ -1242,6 +1397,7 @@ void syslog(int loglevel, const char *frmt, ...) } printf("%s\r\n", buffer); + fflush(stdout); } int emu_chdir(const char* pDirName) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 5d67264a..2c4e1550 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -354,26 +354,12 @@ HANDLE openfile(const char *filename, int flags, int mode); #define LOG_WARNING 4 #define LOG_ERR 3 #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 @@ -493,13 +479,6 @@ bool EnableBackupRights( void ); 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) - // replacement for _cgetws which requires a relatively recent C runtime lib int console_read(char* pBuffer, size_t BufferSize); -- cgit v1.2.3 From 3f9f0196e6d437f225cfb14bce8b9b424def09ab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Sep 2006 00:03:28 +0000 Subject: (refs #3) Emulated chdir, mkdir and unlink should handle file names in UTF-8 as well --- lib/win32/emu.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index dc17c1df..423b3632 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1402,7 +1402,16 @@ void syslog(int loglevel, const char *frmt, ...) int emu_chdir(const char* pDirName) { - WCHAR* pBuffer = ConvertUtf8ToWideString(pDirName); + std::string AbsPathWithUnicode = + ConvertPathToAbsoluteUnicode(pDirName); + + if (AbsPathWithUnicode.size() == 0) + { + // error already logged by ConvertPathToAbsoluteUnicode() + return -1; + } + + WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str()); if (!pBuffer) return -1; int result = SetCurrentDirectoryW(pBuffer); delete [] pBuffer; @@ -1420,7 +1429,7 @@ char* emu_getcwd(char* pBuffer, int BufSize) return NULL; } - if (len > BufSize) + if ((int)len > BufSize) { errno = ENAMETOOLONG; return NULL; @@ -1457,7 +1466,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; @@ -1477,18 +1495,45 @@ 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': error %d", pFileName, (int)err); + errno = ENOSYS; + } return -1; } -- cgit v1.2.3 From 98009bbda2550b7e6aa28fd53f3daaa14d6cd577 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Sep 2006 00:05:08 +0000 Subject: (refs #3) Emulate readdir's d_type field --- lib/win32/emu.cpp | 10 +++++++++- lib/win32/emu.h | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 423b3632..109e54f6 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1002,7 +1002,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, @@ -1010,6 +1010,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 diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 2c4e1550..69daaa67 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -329,9 +329,14 @@ inline int strcasecmp(const char *s1, const char *s2) } #endif +#ifdef _DIRENT_H_ +#error You must not include MinGW's dirent.h! +#endif + struct dirent { char *d_name; + unsigned long d_type; }; struct DIR -- cgit v1.2.3 From cfbb24dbc08bcb0e506922d826808549fd107181 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Sep 2006 00:06:56 +0000 Subject: (refs #3) Remove more vestiges of old getopt --- lib/win32/emu.h | 54 +----------------------------------------------------- 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 69daaa67..a861d3b9 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -227,59 +227,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 -- cgit v1.2.3 From 502fa3141e5330a0e2e91ff4d7258f3f3c0fcaa6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Sep 2006 00:08:36 +0000 Subject: (refs #3) Added prototypes for new emulated functions emu_utimes, readv and writev --- lib/win32/emu.h | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index a861d3b9..2e9f8cd0 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -132,14 +132,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 @@ -159,23 +151,20 @@ inline int chown(const char * Filename, u_int32_t uid, u_int32_t gid) int emu_chdir (const char* pDirName); int emu_unlink(const char* pFileName); char* emu_getcwd(char* pBuffer, int BufSize); +int emu_utimes(const char* pName, const struct timeval[]); +int emu_chmod (const char* pName, mode_t mode); -#ifdef _MSC_VER - inline int emu_chmod(const char * Filename, int mode) - { - // indicate success - return 0; - } +#define utimes(buffer, times) emu_utimes(buffer, times) - #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) +#ifdef _MSC_VER + #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) + inline int chmod(const char * pName, mode_t mode) { - // indicate success - return 0; + return emu_chmod(pName, mode); } inline int chdir(const char* pDirName) @@ -435,4 +424,12 @@ bool ConvertConsoleToUtf8(const char* pString, std::string& rDest); // replacement for _cgetws which requires a relatively recent C runtime lib int console_read(char* pBuffer, size_t BufferSize); +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); + #endif // !EMU_INCLUDE && WIN32 -- cgit v1.2.3 From 012c1b4c977bc94d4f8859c04890223f48881463 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Sep 2006 00:09:26 +0000 Subject: (refs #3) Remove inline ConvertFileTimeToTime_t, add prototypes for new versions in emu.cpp --- lib/win32/emu.h | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 2e9f8cd0..54280769 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -372,29 +372,9 @@ 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; -} +// need this for conversions +time_t ConvertFileTimeToTime_t(FILETIME *fileTime); +bool ConvertTime_tToFileTime(const time_t from, FILETIME *pTo); #ifdef _MSC_VER #define stat(filename, struct) emu_stat (filename, struct) -- cgit v1.2.3 From 38429ae610b92e83cc0febb232eaa5149a0bd494 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Sep 2006 00:10:38 +0000 Subject: (refs #3) Changed WideSize from int to size_t Don't allow space for null terminator that will not be added --- lib/win32/emu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 109e54f6..91684f1c 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1559,7 +1559,7 @@ int console_read(char* pBuffer, size_t BufferSize) return -1; } - int WideSize = BufferSize / 5; + size_t WideSize = BufferSize / 5; WCHAR* pWideBuffer = new WCHAR [WideSize]; if (!pWideBuffer) @@ -1573,7 +1573,7 @@ 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 )) -- cgit v1.2.3 From d11634c0c1ced24120010f3115156c7bd65f9578 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 13 Oct 2006 22:57:55 +0000 Subject: (refs #3) * Created directory for mingw compile utilities, added configure script --- infrastructure/mingw/configure.sh | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 infrastructure/mingw/configure.sh diff --git a/infrastructure/mingw/configure.sh b/infrastructure/mingw/configure.sh new file mode 100755 index 00000000..1dd1b014 --- /dev/null +++ b/infrastructure/mingw/configure.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ ! -r "/usr/i686-pc-mingw32/lib/libssl.a" ]; then + echo "Error: install OpenSSL as instructed by" \ + "docs/backup/mingw_build.txt" >&2 + exit 2 +fi + +if [ ! -r "/usr/i686-pc-mingw32/lib/libpcreposix.a" \ + -o ! -r "/usr/i686-pc-mingw32/lib/libpcre.a" \ + -o ! -r "/usr/i686-pc-mingw32/include/regex.h" ]; then + echo "Error: install PCRE as instructed by" \ + "docs/backup/mingw_build.txt" >&2 + exit 2 +fi + +export CXX="g++ -mno-cygwin" +export LD="g++ -mno-cygwin" +export CFLAGS="-mno-cygwin -mthreads" +export CXXFLAGS="-mno-cygwin -mthreads" +export LDFLAGS="-mno-cygwin -mthreads" +export LIBS="-lcrypto -lws2_32 -lgdi32" + +if [ ! -x "configure" ]; then + if ! ./bootstrap; then + echo "Error: bootstrap failed, aborting." >&2 + exit 1 + fi +fi + +if ! ./configure --target=i686-pc-mingw32; then + echo "Error: configure failed, aborting." >&2 + exit 1 +fi + +exit 0 -- cgit v1.2.3 From 4d073c04ed57430c632b524e56ee7a4c14df11a1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 13 Oct 2006 22:58:37 +0000 Subject: (refs #3) * Updated detection of pcreposix installation to match static libraries --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f3fe26b1..b5b7a4cc 100644 --- a/configure.ac +++ b/configure.ac @@ -92,7 +92,7 @@ AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h]) AC_CHECK_HEADERS([sys/uio.h sys/xattr.h]) if test "$ac_cv_header_regex_h" = "yes"; then - AC_SEARCH_LIBS([regcomp], [pcreposix]) + AC_SEARCH_LIBS([regcomp], ["pcreposix -lpcre"]) fi ### Checks for typedefs, structures, and compiler characteristics. -- cgit v1.2.3 From f1ae01e66e6d2ed9072d17943fb04ccea0dbe592 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 13 Oct 2006 23:00:29 +0000 Subject: * Use INVALID_HANDLE_VALUE instead of NULL to represent invalid file handles under Win32 (refs #3) --- lib/common/FileStream.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/common/FileStream.cpp b/lib/common/FileStream.cpp index c6c53f2b..02b558bd 100644 --- a/lib/common/FileStream.cpp +++ b/lib/common/FileStream.cpp @@ -274,7 +274,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) } @@ -300,25 +300,25 @@ 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) { THROW_EXCEPTION(CommonException, OSFileCloseError) } - mOSFileHandle = -1; - mIsEOF = true; #endif + + mOSFileHandle = INVALID_FILE; + mIsEOF = true; } -- cgit v1.2.3 From 9635631135e1f0df36a0b038f047384dd9d8c8c0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 13 Oct 2006 23:03:23 +0000 Subject: * Added support for Win32 temporary files * Added InvisibleTempFileStream class and unit tests for it * Use InvisibleTempFileStream instead of FileStream for temporary files (refs #3) --- bin/bbstored/BackupCommands.cpp | 22 +++++---------- lib/common/InvisibleTempFileStream.cpp | 39 +++++++++++++++++++++++++++ lib/common/InvisibleTempFileStream.h | 35 ++++++++++++++++++++++++ lib/win32/emu.cpp | 11 ++++++-- test/common/testcommon.cpp | 49 ++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 lib/common/InvisibleTempFileStream.cpp create mode 100644 lib/common/InvisibleTempFileStream.h diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index 60a660d1..cf8025e4 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -29,6 +29,7 @@ #include "BackupStoreInfo.h" #include "RaidFileController.h" #include "FileStream.h" +#include "InvisibleTempFileStream.h" #include "MemLeakFindOn.h" @@ -344,23 +345,14 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto { { // Write nastily to allow this to work with gcc 2.x -#ifdef WIN32 - combined.reset(new FileStream( - tempFn.c_str(), - O_RDWR | O_CREAT | O_EXCL | - O_BINARY | O_TRUNC)); -#else - std::auto_ptr t(new FileStream(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL)); + std::auto_ptr t( + new InvisibleTempFileStream( + tempFn.c_str(), + O_RDWR | O_CREAT | + O_EXCL | O_BINARY | + O_TRUNC)); combined = t; -#endif - } -#ifndef WIN32 - // Unlink immediately as it's a temporary file - if(::unlink(tempFn.c_str()) != 0) - { - THROW_EXCEPTION(CommonException, OSFileError); } -#endif } catch(...) { diff --git a/lib/common/InvisibleTempFileStream.cpp b/lib/common/InvisibleTempFileStream.cpp new file mode 100644 index 00000000..a7e19ad3 --- /dev/null +++ b/lib/common/InvisibleTempFileStream.cpp @@ -0,0 +1,39 @@ +// -------------------------------------------------------------------------- +// +// 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..a77d05e2 --- /dev/null +++ b/lib/common/InvisibleTempFileStream.h @@ -0,0 +1,35 @@ +// -------------------------------------------------------------------------- +// +// 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/win32/emu.cpp b/lib/win32/emu.cpp index 91684f1c..6ce1790c 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -521,7 +521,7 @@ HANDLE openfile(const char *pFileName, int flags, int mode) accessRights = FILE_WRITE_DATA; shareMode = FILE_SHARE_WRITE; } - else if (flags & (O_RDWR | O_CREAT)) + else if (flags & O_RDWR) { accessRights |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA; @@ -541,12 +541,19 @@ HANDLE openfile(const char *pFileName, int flags, int mode) shareMode = 0; } + DWORD winFlags = FILE_FLAG_BACKUP_SEMANTICS; + if (flags & O_TEMPORARY) + { + winFlags |= FILE_FLAG_DELETE_ON_CLOSE; + shareMode |= FILE_SHARE_DELETE; + } + HANDLE hdir = CreateFileW(pBuffer, accessRights, shareMode, NULL, createDisposition, - FILE_FLAG_BACKUP_SEMANTICS, + winFlags, NULL); delete [] pBuffer; diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 5565b406..5a88b3f9 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -16,6 +16,7 @@ #include "FdGetLine.h" #include "Guards.h" #include "FileStream.h" +#include "InvisibleTempFileStream.h" #include "IOStreamGetLine.h" #include "NamedLock.h" #include "ReadGatherStream.h" @@ -134,6 +135,54 @@ ConfigurationVerify verify = int test(int argc, const char *argv[]) { + // Test self-deleting temporary file streams + std::string tempfile("testfiles/tempfile"); + TEST_CHECK_THROWS(InvisibleTempFileStream fs(tempfile.c_str()), + CommonException, OSFileOpenError); + InvisibleTempFileStream fs(tempfile.c_str(), O_CREAT); + +#ifdef WIN32 + // file is still visible under Windows + TEST_THAT(TestFileExists(tempfile.c_str())); + + // opening it again should work + InvisibleTempFileStream fs2(tempfile.c_str()); + TEST_THAT(TestFileExists(tempfile.c_str())); + + // opening it to create should work + InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT); + TEST_THAT(TestFileExists(tempfile.c_str())); + + // opening it to create exclusively should fail + TEST_CHECK_THROWS(InvisibleTempFileStream fs4(tempfile.c_str(), + O_CREAT | O_EXCL), CommonException, OSFileOpenError); + +#else + // file is not visible under Unix + TEST_THAT(!TestFileExists(tempfile.c_str())); + + // opening it again should fail + TEST_CHECK_THROWS(InvisibleTempFileStream fs2(tempfile.c_str()), + CommonException, OSFileOpenError); + + // opening it to create should work + InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT); + TEST_THAT(!TestFileExists(tempfile.c_str())); + + // opening it to create exclusively should work + InvisibleTempFileStream fs4(tempfile.c_str(), O_CREAT | O_EXCL); + TEST_THAT(!TestFileExists(tempfile.c_str())); + + fs4.Close(); +#endif + + fs.Close(); + fs2.Close(); + fs3.Close(); + + // now that it's closed, it should be invisible on all platforms + TEST_THAT(!TestFileExists(tempfile.c_str())); + // Test memory leak detection #ifdef BOX_MEMORY_LEAK_TESTING { -- cgit v1.2.3 From f6eaf494f8df247a85f773a7d94a6a77ff793ba7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 13:43:16 +0000 Subject: * Comment grammar fix (refs #3) --- bin/bbackupctl/bbackupctl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index 4a5ee5a9..6f7c55f7 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -250,8 +250,8 @@ int main(int argc, const char *argv[]) case WaitForSyncStart: case WaitForSyncEnd: { - // Check that it's in automatic mode, - // because otherwise it'll never start + // Check that it's not in non-automatic mode, + // because then it'll never start if(!autoBackup) { -- cgit v1.2.3 From 1470933433d676912c311868d0333497f5aa8436 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 13:51:29 +0000 Subject: * Oops, wrong direction. Undo last change. --- bin/bbackupctl/bbackupctl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index 6f7c55f7..4a5ee5a9 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -250,8 +250,8 @@ int main(int argc, const char *argv[]) case WaitForSyncStart: case WaitForSyncEnd: { - // Check that it's not in non-automatic mode, - // because then it'll never start + // Check that it's in automatic mode, + // because otherwise it'll never start if(!autoBackup) { -- cgit v1.2.3 From fb08c7f95b37da9e0b0a581236cd788f9abdee3f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:07:37 +0000 Subject: * Use readdir's d_type field to determine type of directory entry without statting the entry, which allows users to exclude unreadable entries to suppress warnings about them on Win32 (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index d9b11ee4..1db6cbe5 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -236,6 +236,18 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn // Stat file to get info filename = MakeFullPath(rLocalPath, en->d_name); + #ifdef WIN32 + // Don't stat the file just yet, to ensure + // that users can exclude unreadable files + // to suppress warnings that they are + // not accessible. + // + // Our emulated readdir() abuses en->d_type, + // which would normally contain DT_REG, + // DT_DIR, etc, but we only use it here and + // prefer S_IFREG, S_IFDIR... + int type = en->d_type; + #else if(::lstat(filename.c_str(), &st) != 0) { // Report the error (logs and @@ -248,6 +260,8 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn } int type = st.st_mode & S_IFMT; + #endif + if(type == S_IFREG || type == S_IFLNK) { // File or symbolic link @@ -278,11 +292,34 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn } else { + #ifdef WIN32 + ::syslog(LOG_ERR, "Unknown file type: " + "%d (%s)", type, + filename.c_str()); + #endif + SetErrorWhenReadingFilesystemObject( + rParams, filename.c_str()); continue; } // Here if the object is something to back up (file, symlink or dir, not excluded) // So make the information for adding to the checksum + + #ifdef WIN32 + // We didn't stat the file before, + // but now we need the information. + if(::lstat(filename.c_str(), &st) != 0) + { + // Report the error (logs and + // eventual email to administrator) + SetErrorWhenReadingFilesystemObject( + rParams, filename.c_str()); + + // Ignore this entry for now. + continue; + } + #endif + checksum_info.mModificationTime = FileModificationTime(st); checksum_info.mAttributeModificationTime = FileAttrModificationTime(st); checksum_info.mSize = st.st_size; -- cgit v1.2.3 From cfc9e4fa0518394b557d6a55596b55f4eb0590b8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:35:07 +0000 Subject: * Apply Box coding standards (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 300 +++++++++++++++++++++++++++--------------- 1 file changed, 195 insertions(+), 105 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 99abb01f..d6f4b7f4 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -59,6 +59,7 @@ #include "BackupStoreFilenameClear.h" #include "BackupClientInodeToIDMap.h" #include "autogen_BackupProtocolClient.h" +#include "autogen_ConversionException.h" #include "BackupClientCryptoKeys.h" #include "BannerText.h" #include "BackupStoreFile.h" @@ -125,6 +126,29 @@ BackupDaemon::BackupDaemon() } #ifdef WIN32 + // Create the event object to signal from main thread to worker + // when new messages are queued to be sent to the command socket. + mhMessageToSendEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(mhMessageToSendEvent == INVALID_HANDLE_VALUE) + { + syslog(LOG_ERR, "Failed to create event object: error %d", + GetLastError); + exit(1); + } + + // Create the event object to signal from worker to main thread + // when a command has been received on the command socket. + mhCommandReceivedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(mhCommandReceivedEvent == INVALID_HANDLE_VALUE) + { + syslog(LOG_ERR, "Failed to create event object: error %d", + GetLastError); + exit(1); + } + + // Create the critical section to protect the message queue + InitializeCriticalSection(&mMessageQueueLock); + // Create a thread to handle the named pipe HANDLE hThread; unsigned int dwThreadId; @@ -262,7 +286,6 @@ void BackupDaemon::DeleteAllLocations() #ifdef WIN32 void BackupDaemon::RunHelperThread(void) { - this->mReceivedCommandConn = false; mpCommandSocketInfo = new CommandSocketInfo; WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); @@ -328,15 +351,69 @@ void BackupDaemon::RunHelperThread(void) rSocket.Write(summary, summarySize); rSocket.Write("ping\n", 5); + // old queued messages are not useful + EnterCriticalSection(&mMessageQueueLock); + mMessageList.clear(); + ResetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); + IOStreamGetLine readLine(rSocket); std::string command; - while (rSocket.IsConnected() && - readLine.GetLine(command) && - !IsTerminateWanted()) + while (rSocket.IsConnected() && !IsTerminateWanted()) { - TRACE1("Received command '%s' over " - "command socket\n", command.c_str()); + HANDLE handles[2]; + handles[0] = mhMessageToSendEvent; + handles[1] = rSocket.GetReadableEvent(); + + DWORD result = WaitForMultipleObjects( + sizeof(handles)/sizeof(*handles), + handles, FALSE, 1000); + + if(result == 0) + { + ResetEvent(mhMessageToSendEvent); + + EnterCriticalSection(&mMessageQueueLock); + try + { + while (mMessageList.size() > 0) + { + std::string message = *(mMessageList.begin()); + mMessageList.erase(mMessageList.begin()); + printf("Sending '%s' to waiting client... ", message.c_str()); + message += "\n"; + rSocket.Write(message.c_str(), + message.length()); + + printf("done.\n"); + } + } + catch (...) + { + LeaveCriticalSection(&mMessageQueueLock); + throw; + } + LeaveCriticalSection(&mMessageQueueLock); + continue; + } + else if(result == WAIT_TIMEOUT) + { + continue; + } + else if(result != 1) + { + ::syslog(LOG_ERR, "WaitForMultipleObjects returned invalid result %d", result); + continue; + } + + if(!readLine.GetLine(command)) + { + ::syslog(LOG_ERR, "Failed to read line"); + continue; + } + + printf("Received command '%s' from client\n", command.c_str()); bool sendOK = false; bool sendResponse = true; @@ -355,6 +432,7 @@ void BackupDaemon::RunHelperThread(void) this->mDoSyncFlagOut = true; this->mSyncIsForcedOut = false; sendOK = true; + SetEvent(mhCommandReceivedEvent); } else if(command == "force-sync") { @@ -362,18 +440,21 @@ void BackupDaemon::RunHelperThread(void) this->mDoSyncFlagOut = true; this->mSyncIsForcedOut = true; sendOK = true; + SetEvent(mhCommandReceivedEvent); } else if(command == "reload") { // Reload the configuration SetReloadConfigWanted(); sendOK = true; + SetEvent(mhCommandReceivedEvent); } else if(command == "terminate") { // Terminate the daemon cleanly SetTerminateWanted(); sendOK = true; + SetEvent(mhCommandReceivedEvent); } else { @@ -383,19 +464,17 @@ void BackupDaemon::RunHelperThread(void) } // Send a response back? - if (sendResponse) + if(sendResponse) { const char* response = sendOK ? "ok\n" : "error\n"; rSocket.Write( response, strlen(response)); } - if (disconnect) + if(disconnect) { break; } - - this->mReceivedCommandConn = true; } rSocket.Close(); @@ -415,6 +494,9 @@ void BackupDaemon::RunHelperThread(void) ::syslog(LOG_ERR, "Communication error with control client"); } } + + CloseHandle(mhCommandReceivedEvent); + CloseHandle(mhMessageToSendEvent); } #endif @@ -934,8 +1016,21 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } else { - // How many seconds to wait? - waitInSeconds = BoxConvert::Convert(line); + try + { + // How many seconds to wait? + waitInSeconds = BoxConvert::Convert(line); + } + catch(ConversionException &e) + { + ::syslog(LOG_ERR, "Invalid output " + "from SyncAllowScript '%s': " + "'%s'", + conf.GetKeyValue("SyncAllowScript").c_str(), + line.c_str()); + throw; + } + ::syslog(LOG_INFO, "Delaying sync by %d seconds (SyncAllowScript '%s')", waitInSeconds, conf.GetKeyValue("SyncAllowScript").c_str()); } } @@ -954,7 +1049,7 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } // Wait and then cleanup child process, if any - if (pid != 0) + if(pid != 0) { int status = 0; ::waitpid(pid, &status, 0); @@ -977,25 +1072,27 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut) { #ifdef WIN32 - // Really could use some interprocess protection, mutex etc - // any side effect should be too bad???? :) - DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay); + DWORD requiredDelayMs = BoxTimeToMilliSeconds(RequiredDelay); - while ( this->mReceivedCommandConn == false ) - { - Sleep(1); + DWORD result = WaitForSingleObject(mhCommandReceivedEvent, + (DWORD)requiredDelayMs); - if ( timeout == 0 ) - { - DoSyncFlagOut = false; - SyncIsForcedOut = false; - return; - } - timeout--; + if(result == WAIT_OBJECT_0) + { + DoSyncFlagOut = this->mDoSyncFlagOut; + SyncIsForcedOut = this->mSyncIsForcedOut; + ResetEvent(mhCommandReceivedEvent); + } + else if(result == WAIT_TIMEOUT) + { + DoSyncFlagOut = false; + SyncIsForcedOut = false; + } + else + { + ::syslog(LOG_ERR, "Unexpected result from " + "WaitForSingleObject: error %d", GetLastError()); } - this->mReceivedCommandConn = false; - DoSyncFlagOut = this->mDoSyncFlagOut; - SyncIsForcedOut = this->mSyncIsForcedOut; return; #else // ! WIN32 @@ -1098,8 +1195,9 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla while(mpCommandSocketInfo->mpGetLine != 0 && !mpCommandSocketInfo->mpGetLine->IsEOF() && mpCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout)) { - TRACE1("Receiving command '%s' over command socket\n", command.c_str()); - + TRACE1("Receiving command '%s' over command socket\n", + command.c_str()); + bool sendOK = false; bool sendResponse = true; @@ -1236,11 +1334,7 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) // The bbackupctl program can't rely on a state change, because it // may never change if the server doesn't need to be contacted. -#ifdef __MINGW32__ -#warning race condition: what happens if socket is closed? -#endif - - if (mpCommandSocketInfo != NULL && + if(mpCommandSocketInfo != NULL && #ifdef WIN32 mpCommandSocketInfo->mListeningSocket.IsConnected() #else @@ -1248,15 +1342,18 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) #endif ) { - const char* message = SendStart ? "start-sync\n" : "finish-sync\n"; + std::string message = SendStart ? "start-sync" : "finish-sync"; try { #ifdef WIN32 - mpCommandSocketInfo->mListeningSocket.Write(message, - (int)strlen(message)); + EnterCriticalSection(&mMessageQueueLock); + mMessageList.push_back(message); + SetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); #else - mpCommandSocketInfo->mpConnectedSocket->Write(message, - strlen(message)); + message += "\n"; + mpCommandSocketInfo->mpConnectedSocket->Write( + message.c_str(), message.size()); #endif } catch(std::exception &e) @@ -1858,51 +1955,36 @@ void BackupDaemon::SetState(int State) // command socket if there's an error char newState[64]; - char newStateSize = sprintf(newState, "state %d\n", State); + sprintf(newState, "state %d", State); + std::string message = newState; #ifdef WIN32 - #ifndef _MSC_VER - #warning FIX ME: race condition - #endif + EnterCriticalSection(&mMessageQueueLock); + mMessageList.push_back(newState); + SetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); +#else + message += "\n"; - // what happens if the socket is closed by the other thread before - // we can write to it? Null pointer deref at best. - if (mpCommandSocketInfo && - mpCommandSocketInfo->mListeningSocket.IsConnected()) + if(mpCommandSocketInfo == 0) { - try - { - mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize); - } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "Internal error while writing state " - "to command socket: %s", e.what()); - CloseCommandConnection(); - } - catch(...) - { - CloseCommandConnection(); - } + return; } -#else - if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0) + + if(mpCommandSocketInfo->mpConnectedSocket.get() == 0) { - // Something connected to the command socket, tell it about the new state - try - { - mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize); - } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "Internal error while writing state " - "to command socket: %s", e.what()); - CloseCommandConnection(); - } - catch(...) - { - CloseCommandConnection(); - } + return; + } + + // Something connected to the command socket, tell it about the new state + try + { + mpCommandSocketInfo->mpConnectedSocket->Write(message.c_str(), + message.length()); + } + catch(...) + { + CloseCommandConnection(); } #endif } @@ -2085,12 +2167,12 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // // mpDirectoryRecord.reset(NULL); - if (mpExcludeFiles) + if(mpExcludeFiles) { delete mpExcludeFiles; mpExcludeFiles = NULL; } - if (mpExcludeDirs) + if(mpExcludeDirs) { delete mpExcludeDirs; mpExcludeDirs = NULL; @@ -2109,15 +2191,17 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) int64_t aMagicMarker = 0; rArchive.Read(aMagicMarker); - if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { BackupClientDirectoryRecord *pSubRecord = new BackupClientDirectoryRecord(0, ""); - if (!pSubRecord) + if(!pSubRecord) + { throw std::bad_alloc(); + } mpDirectoryRecord.reset(pSubRecord); mpDirectoryRecord->Deserialize(rArchive); @@ -2133,15 +2217,17 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // rArchive.Read(aMagicMarker); - if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { mpExcludeFiles = new ExcludeList; - if (!mpExcludeFiles) + if(!mpExcludeFiles) + { throw std::bad_alloc(); + } mpExcludeFiles->Deserialize(rArchive); } @@ -2156,15 +2242,17 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // rArchive.Read(aMagicMarker); - if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { mpExcludeDirs = new ExcludeList; - if (!mpExcludeDirs) + if(!mpExcludeDirs) + { throw std::bad_alloc(); + } mpExcludeDirs->Deserialize(rArchive); } @@ -2196,7 +2284,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if (mpDirectoryRecord.get() == NULL) + if(mpDirectoryRecord.get() == NULL) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2212,7 +2300,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if (!mpExcludeFiles) + if(!mpExcludeFiles) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2228,7 +2316,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if (!mpExcludeDirs) + if(!mpExcludeDirs) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2297,7 +2385,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time std::string StoreObjectInfoFile = GetConfiguration().GetKeyValue("StoreObjectInfoFile"); - if (StoreObjectInfoFile.size() <= 0) + if(StoreObjectInfoFile.size() <= 0) { return false; } @@ -2326,7 +2414,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time int64_t iCount = mLocations.size(); anArchive.Write(iCount); - for (int v = 0; v < iCount; v++) + for(int v = 0; v < iCount; v++) { ASSERT(mLocations[v]); mLocations[v]->Serialize(anArchive); @@ -2338,7 +2426,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time iCount = mIDMapMounts.size(); anArchive.Write(iCount); - for (int v = 0; v < iCount; v++) + for(int v = 0; v < iCount; v++) anArchive.Write(mIDMapMounts[v]); // @@ -2391,7 +2479,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ std::string StoreObjectInfoFile = GetConfiguration().GetKeyValue("StoreObjectInfoFile"); - if (StoreObjectInfoFile.size() <= 0) + if(StoreObjectInfoFile.size() <= 0) { return false; } @@ -2407,7 +2495,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int iMagicValue = 0; anArchive.Read(iMagicValue); - if (iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE) + if(iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE) { ::syslog(LOG_WARNING, "Store object info file '%s' " "is not a valid or compatible serialised " @@ -2422,7 +2510,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ std::string strMagicValue; anArchive.Read(strMagicValue); - if (strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING) + if(strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING) { ::syslog(LOG_WARNING, "Store object info file '%s' " "is not a valid or compatible serialised " @@ -2438,7 +2526,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int iVersion = 0; anArchive.Read(iVersion); - if (iVersion != STOREOBJECTINFO_VERSION) + if(iVersion != STOREOBJECTINFO_VERSION) { ::syslog(LOG_WARNING, "Store object info file '%s' " "version %d unsupported. " @@ -2455,7 +2543,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ box_time_t lastKnownConfigModTime; anArchive.Read(lastKnownConfigModTime); - if (lastKnownConfigModTime != GetLoadedConfigModifiedTime()) + if(lastKnownConfigModTime != GetLoadedConfigModifiedTime()) { ::syslog(LOG_WARNING, "Store object info file '%s' " "out of date. Will re-cache from store", @@ -2476,11 +2564,13 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int64_t iCount = 0; anArchive.Read(iCount); - for (int v = 0; v < iCount; v++) + for(int v = 0; v < iCount; v++) { Location* pLocation = new Location; - if (!pLocation) + if(!pLocation) + { throw std::bad_alloc(); + } pLocation->Deserialize(anArchive); mLocations.push_back(pLocation); @@ -2492,7 +2582,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ iCount = 0; anArchive.Read(iCount); - for (int v = 0; v < iCount; v++) + for(int v = 0; v < iCount; v++) { std::string strItem; anArchive.Read(strItem); -- cgit v1.2.3 From fe290e01bcb715e5fc55c98f072f2afe0d28e67c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:42:21 +0000 Subject: * Replace global daemon object with a pointer, to allow deletion and clean up reported memory leaks * No need to initialise Winsock here, now that lib/server/Daemon does it for us * Initialise logging properly (refs #3) --- bin/bbackupd/bbackupd.cpp | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index 3c283596..e00d3628 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -19,7 +19,7 @@ #include "Win32ServiceFunctions.h" #include "Win32BackupService.h" - extern Win32BackupService gDaemonService; + extern Win32BackupService* gpDaemonService; #endif int main(int argc, const char *argv[]) @@ -28,7 +28,7 @@ int main(int argc, const char *argv[]) #ifdef WIN32 - ::openlog("Box Backup (bbackupd)", 0, 0); + ::openlog("Box Backup (bbackupd)", LOG_PID, LOG_LOCAL6); if(argc == 2 && (::strcmp(argv[1], "--help") == 0 || @@ -57,18 +57,8 @@ int main(int argc, const char *argv[]) { runAsWin32Service = true; } - - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - if (WSAStartup(0x0101, &info) == SOCKET_ERROR) - { - // box backup will not run without sockets - ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); - THROW_EXCEPTION(BackupStoreException, Internal) - } + gpDaemonService = new Win32BackupService(); EnableBackupRights(); @@ -95,15 +85,14 @@ int main(int argc, const char *argv[]) } else { - ExitCode = gDaemonService.Main( + ExitCode = gpDaemonService->Main( BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); } - // Clean up our sockets - WSACleanup(); - ::closelog(); + delete gpDaemonService; + return ExitCode; #else // !WIN32 -- cgit v1.2.3 From 264ef04ecb8668b21df8539e3a807d3f266a1780 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:44:23 +0000 Subject: * Oops, svn merged too much, undo again --- bin/bbackupd/BackupDaemon.cpp | 300 +++++++++++++++--------------------------- 1 file changed, 105 insertions(+), 195 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index d6f4b7f4..99abb01f 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -59,7 +59,6 @@ #include "BackupStoreFilenameClear.h" #include "BackupClientInodeToIDMap.h" #include "autogen_BackupProtocolClient.h" -#include "autogen_ConversionException.h" #include "BackupClientCryptoKeys.h" #include "BannerText.h" #include "BackupStoreFile.h" @@ -126,29 +125,6 @@ BackupDaemon::BackupDaemon() } #ifdef WIN32 - // Create the event object to signal from main thread to worker - // when new messages are queued to be sent to the command socket. - mhMessageToSendEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(mhMessageToSendEvent == INVALID_HANDLE_VALUE) - { - syslog(LOG_ERR, "Failed to create event object: error %d", - GetLastError); - exit(1); - } - - // Create the event object to signal from worker to main thread - // when a command has been received on the command socket. - mhCommandReceivedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(mhCommandReceivedEvent == INVALID_HANDLE_VALUE) - { - syslog(LOG_ERR, "Failed to create event object: error %d", - GetLastError); - exit(1); - } - - // Create the critical section to protect the message queue - InitializeCriticalSection(&mMessageQueueLock); - // Create a thread to handle the named pipe HANDLE hThread; unsigned int dwThreadId; @@ -286,6 +262,7 @@ void BackupDaemon::DeleteAllLocations() #ifdef WIN32 void BackupDaemon::RunHelperThread(void) { + this->mReceivedCommandConn = false; mpCommandSocketInfo = new CommandSocketInfo; WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); @@ -351,69 +328,15 @@ void BackupDaemon::RunHelperThread(void) rSocket.Write(summary, summarySize); rSocket.Write("ping\n", 5); - // old queued messages are not useful - EnterCriticalSection(&mMessageQueueLock); - mMessageList.clear(); - ResetEvent(mhMessageToSendEvent); - LeaveCriticalSection(&mMessageQueueLock); - IOStreamGetLine readLine(rSocket); std::string command; - while (rSocket.IsConnected() && !IsTerminateWanted()) + while (rSocket.IsConnected() && + readLine.GetLine(command) && + !IsTerminateWanted()) { - HANDLE handles[2]; - handles[0] = mhMessageToSendEvent; - handles[1] = rSocket.GetReadableEvent(); - - DWORD result = WaitForMultipleObjects( - sizeof(handles)/sizeof(*handles), - handles, FALSE, 1000); - - if(result == 0) - { - ResetEvent(mhMessageToSendEvent); - - EnterCriticalSection(&mMessageQueueLock); - try - { - while (mMessageList.size() > 0) - { - std::string message = *(mMessageList.begin()); - mMessageList.erase(mMessageList.begin()); - printf("Sending '%s' to waiting client... ", message.c_str()); - message += "\n"; - rSocket.Write(message.c_str(), - message.length()); - - printf("done.\n"); - } - } - catch (...) - { - LeaveCriticalSection(&mMessageQueueLock); - throw; - } - LeaveCriticalSection(&mMessageQueueLock); - continue; - } - else if(result == WAIT_TIMEOUT) - { - continue; - } - else if(result != 1) - { - ::syslog(LOG_ERR, "WaitForMultipleObjects returned invalid result %d", result); - continue; - } - - if(!readLine.GetLine(command)) - { - ::syslog(LOG_ERR, "Failed to read line"); - continue; - } - - printf("Received command '%s' from client\n", command.c_str()); + TRACE1("Received command '%s' over " + "command socket\n", command.c_str()); bool sendOK = false; bool sendResponse = true; @@ -432,7 +355,6 @@ void BackupDaemon::RunHelperThread(void) this->mDoSyncFlagOut = true; this->mSyncIsForcedOut = false; sendOK = true; - SetEvent(mhCommandReceivedEvent); } else if(command == "force-sync") { @@ -440,21 +362,18 @@ void BackupDaemon::RunHelperThread(void) this->mDoSyncFlagOut = true; this->mSyncIsForcedOut = true; sendOK = true; - SetEvent(mhCommandReceivedEvent); } else if(command == "reload") { // Reload the configuration SetReloadConfigWanted(); sendOK = true; - SetEvent(mhCommandReceivedEvent); } else if(command == "terminate") { // Terminate the daemon cleanly SetTerminateWanted(); sendOK = true; - SetEvent(mhCommandReceivedEvent); } else { @@ -464,17 +383,19 @@ void BackupDaemon::RunHelperThread(void) } // Send a response back? - if(sendResponse) + if (sendResponse) { const char* response = sendOK ? "ok\n" : "error\n"; rSocket.Write( response, strlen(response)); } - if(disconnect) + if (disconnect) { break; } + + this->mReceivedCommandConn = true; } rSocket.Close(); @@ -494,9 +415,6 @@ void BackupDaemon::RunHelperThread(void) ::syslog(LOG_ERR, "Communication error with control client"); } } - - CloseHandle(mhCommandReceivedEvent); - CloseHandle(mhMessageToSendEvent); } #endif @@ -1016,21 +934,8 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } else { - try - { - // How many seconds to wait? - waitInSeconds = BoxConvert::Convert(line); - } - catch(ConversionException &e) - { - ::syslog(LOG_ERR, "Invalid output " - "from SyncAllowScript '%s': " - "'%s'", - conf.GetKeyValue("SyncAllowScript").c_str(), - line.c_str()); - throw; - } - + // How many seconds to wait? + waitInSeconds = BoxConvert::Convert(line); ::syslog(LOG_INFO, "Delaying sync by %d seconds (SyncAllowScript '%s')", waitInSeconds, conf.GetKeyValue("SyncAllowScript").c_str()); } } @@ -1049,7 +954,7 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } // Wait and then cleanup child process, if any - if(pid != 0) + if (pid != 0) { int status = 0; ::waitpid(pid, &status, 0); @@ -1072,27 +977,25 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut) { #ifdef WIN32 - DWORD requiredDelayMs = BoxTimeToMilliSeconds(RequiredDelay); + // Really could use some interprocess protection, mutex etc + // any side effect should be too bad???? :) + DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay); - DWORD result = WaitForSingleObject(mhCommandReceivedEvent, - (DWORD)requiredDelayMs); - - if(result == WAIT_OBJECT_0) - { - DoSyncFlagOut = this->mDoSyncFlagOut; - SyncIsForcedOut = this->mSyncIsForcedOut; - ResetEvent(mhCommandReceivedEvent); - } - else if(result == WAIT_TIMEOUT) - { - DoSyncFlagOut = false; - SyncIsForcedOut = false; - } - else + while ( this->mReceivedCommandConn == false ) { - ::syslog(LOG_ERR, "Unexpected result from " - "WaitForSingleObject: error %d", GetLastError()); + Sleep(1); + + if ( timeout == 0 ) + { + DoSyncFlagOut = false; + SyncIsForcedOut = false; + return; + } + timeout--; } + this->mReceivedCommandConn = false; + DoSyncFlagOut = this->mDoSyncFlagOut; + SyncIsForcedOut = this->mSyncIsForcedOut; return; #else // ! WIN32 @@ -1195,9 +1098,8 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla while(mpCommandSocketInfo->mpGetLine != 0 && !mpCommandSocketInfo->mpGetLine->IsEOF() && mpCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout)) { - TRACE1("Receiving command '%s' over command socket\n", - command.c_str()); - + TRACE1("Receiving command '%s' over command socket\n", command.c_str()); + bool sendOK = false; bool sendResponse = true; @@ -1334,7 +1236,11 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) // The bbackupctl program can't rely on a state change, because it // may never change if the server doesn't need to be contacted. - if(mpCommandSocketInfo != NULL && +#ifdef __MINGW32__ +#warning race condition: what happens if socket is closed? +#endif + + if (mpCommandSocketInfo != NULL && #ifdef WIN32 mpCommandSocketInfo->mListeningSocket.IsConnected() #else @@ -1342,18 +1248,15 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) #endif ) { - std::string message = SendStart ? "start-sync" : "finish-sync"; + const char* message = SendStart ? "start-sync\n" : "finish-sync\n"; try { #ifdef WIN32 - EnterCriticalSection(&mMessageQueueLock); - mMessageList.push_back(message); - SetEvent(mhMessageToSendEvent); - LeaveCriticalSection(&mMessageQueueLock); + mpCommandSocketInfo->mListeningSocket.Write(message, + (int)strlen(message)); #else - message += "\n"; - mpCommandSocketInfo->mpConnectedSocket->Write( - message.c_str(), message.size()); + mpCommandSocketInfo->mpConnectedSocket->Write(message, + strlen(message)); #endif } catch(std::exception &e) @@ -1955,36 +1858,51 @@ void BackupDaemon::SetState(int State) // command socket if there's an error char newState[64]; - sprintf(newState, "state %d", State); - std::string message = newState; + char newStateSize = sprintf(newState, "state %d\n", State); #ifdef WIN32 - EnterCriticalSection(&mMessageQueueLock); - mMessageList.push_back(newState); - SetEvent(mhMessageToSendEvent); - LeaveCriticalSection(&mMessageQueueLock); -#else - message += "\n"; - - if(mpCommandSocketInfo == 0) - { - return; - } - - if(mpCommandSocketInfo->mpConnectedSocket.get() == 0) - { - return; - } + #ifndef _MSC_VER + #warning FIX ME: race condition + #endif - // Something connected to the command socket, tell it about the new state - try + // what happens if the socket is closed by the other thread before + // we can write to it? Null pointer deref at best. + if (mpCommandSocketInfo && + mpCommandSocketInfo->mListeningSocket.IsConnected()) { - mpCommandSocketInfo->mpConnectedSocket->Write(message.c_str(), - message.length()); + try + { + mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize); + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error while writing state " + "to command socket: %s", e.what()); + CloseCommandConnection(); + } + catch(...) + { + CloseCommandConnection(); + } } - catch(...) +#else + if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0) { - CloseCommandConnection(); + // Something connected to the command socket, tell it about the new state + try + { + mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize); + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Internal error while writing state " + "to command socket: %s", e.what()); + CloseCommandConnection(); + } + catch(...) + { + CloseCommandConnection(); + } } #endif } @@ -2167,12 +2085,12 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // // mpDirectoryRecord.reset(NULL); - if(mpExcludeFiles) + if (mpExcludeFiles) { delete mpExcludeFiles; mpExcludeFiles = NULL; } - if(mpExcludeDirs) + if (mpExcludeDirs) { delete mpExcludeDirs; mpExcludeDirs = NULL; @@ -2191,17 +2109,15 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) int64_t aMagicMarker = 0; rArchive.Read(aMagicMarker); - if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { BackupClientDirectoryRecord *pSubRecord = new BackupClientDirectoryRecord(0, ""); - if(!pSubRecord) - { + if (!pSubRecord) throw std::bad_alloc(); - } mpDirectoryRecord.reset(pSubRecord); mpDirectoryRecord->Deserialize(rArchive); @@ -2217,17 +2133,15 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // rArchive.Read(aMagicMarker); - if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { mpExcludeFiles = new ExcludeList; - if(!mpExcludeFiles) - { + if (!mpExcludeFiles) throw std::bad_alloc(); - } mpExcludeFiles->Deserialize(rArchive); } @@ -2242,17 +2156,15 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // rArchive.Read(aMagicMarker); - if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { mpExcludeDirs = new ExcludeList; - if(!mpExcludeDirs) - { + if (!mpExcludeDirs) throw std::bad_alloc(); - } mpExcludeDirs->Deserialize(rArchive); } @@ -2284,7 +2196,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if(mpDirectoryRecord.get() == NULL) + if (mpDirectoryRecord.get() == NULL) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2300,7 +2212,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if(!mpExcludeFiles) + if (!mpExcludeFiles) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2316,7 +2228,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if(!mpExcludeDirs) + if (!mpExcludeDirs) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2385,7 +2297,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time std::string StoreObjectInfoFile = GetConfiguration().GetKeyValue("StoreObjectInfoFile"); - if(StoreObjectInfoFile.size() <= 0) + if (StoreObjectInfoFile.size() <= 0) { return false; } @@ -2414,7 +2326,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time int64_t iCount = mLocations.size(); anArchive.Write(iCount); - for(int v = 0; v < iCount; v++) + for (int v = 0; v < iCount; v++) { ASSERT(mLocations[v]); mLocations[v]->Serialize(anArchive); @@ -2426,7 +2338,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time iCount = mIDMapMounts.size(); anArchive.Write(iCount); - for(int v = 0; v < iCount; v++) + for (int v = 0; v < iCount; v++) anArchive.Write(mIDMapMounts[v]); // @@ -2479,7 +2391,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ std::string StoreObjectInfoFile = GetConfiguration().GetKeyValue("StoreObjectInfoFile"); - if(StoreObjectInfoFile.size() <= 0) + if (StoreObjectInfoFile.size() <= 0) { return false; } @@ -2495,7 +2407,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int iMagicValue = 0; anArchive.Read(iMagicValue); - if(iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE) + if (iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE) { ::syslog(LOG_WARNING, "Store object info file '%s' " "is not a valid or compatible serialised " @@ -2510,7 +2422,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ std::string strMagicValue; anArchive.Read(strMagicValue); - if(strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING) + if (strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING) { ::syslog(LOG_WARNING, "Store object info file '%s' " "is not a valid or compatible serialised " @@ -2526,7 +2438,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int iVersion = 0; anArchive.Read(iVersion); - if(iVersion != STOREOBJECTINFO_VERSION) + if (iVersion != STOREOBJECTINFO_VERSION) { ::syslog(LOG_WARNING, "Store object info file '%s' " "version %d unsupported. " @@ -2543,7 +2455,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ box_time_t lastKnownConfigModTime; anArchive.Read(lastKnownConfigModTime); - if(lastKnownConfigModTime != GetLoadedConfigModifiedTime()) + if (lastKnownConfigModTime != GetLoadedConfigModifiedTime()) { ::syslog(LOG_WARNING, "Store object info file '%s' " "out of date. Will re-cache from store", @@ -2564,13 +2476,11 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int64_t iCount = 0; anArchive.Read(iCount); - for(int v = 0; v < iCount; v++) + for (int v = 0; v < iCount; v++) { Location* pLocation = new Location; - if(!pLocation) - { + if (!pLocation) throw std::bad_alloc(); - } pLocation->Deserialize(anArchive); mLocations.push_back(pLocation); @@ -2582,7 +2492,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ iCount = 0; anArchive.Read(iCount); - for(int v = 0; v < iCount; v++) + for (int v = 0; v < iCount; v++) { std::string strItem; anArchive.Read(strItem); -- cgit v1.2.3 From 755674d88629065899cafad0e1fa7cdde20e7b31 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:47:06 +0000 Subject: * Apply Box coding standards (refs #3, replaces [1026]) --- bin/bbackupd/BackupDaemon.cpp | 70 ++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 99abb01f..023678ec 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -383,14 +383,14 @@ void BackupDaemon::RunHelperThread(void) } // Send a response back? - if (sendResponse) + if(sendResponse) { const char* response = sendOK ? "ok\n" : "error\n"; rSocket.Write( response, strlen(response)); } - if (disconnect) + if(disconnect) { break; } @@ -954,7 +954,7 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } // Wait and then cleanup child process, if any - if (pid != 0) + if(pid != 0) { int status = 0; ::waitpid(pid, &status, 0); @@ -985,7 +985,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla { Sleep(1); - if ( timeout == 0 ) + if( timeout == 0 ) { DoSyncFlagOut = false; SyncIsForcedOut = false; @@ -1240,7 +1240,7 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) #warning race condition: what happens if socket is closed? #endif - if (mpCommandSocketInfo != NULL && + if(mpCommandSocketInfo != NULL && #ifdef WIN32 mpCommandSocketInfo->mListeningSocket.IsConnected() #else @@ -1867,7 +1867,7 @@ void BackupDaemon::SetState(int State) // what happens if the socket is closed by the other thread before // we can write to it? Null pointer deref at best. - if (mpCommandSocketInfo && + if(mpCommandSocketInfo && mpCommandSocketInfo->mListeningSocket.IsConnected()) { try @@ -2085,12 +2085,12 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // // mpDirectoryRecord.reset(NULL); - if (mpExcludeFiles) + if(mpExcludeFiles) { delete mpExcludeFiles; mpExcludeFiles = NULL; } - if (mpExcludeDirs) + if(mpExcludeDirs) { delete mpExcludeDirs; mpExcludeDirs = NULL; @@ -2109,15 +2109,17 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) int64_t aMagicMarker = 0; rArchive.Read(aMagicMarker); - if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { BackupClientDirectoryRecord *pSubRecord = new BackupClientDirectoryRecord(0, ""); - if (!pSubRecord) + if(!pSubRecord) + { throw std::bad_alloc(); + } mpDirectoryRecord.reset(pSubRecord); mpDirectoryRecord->Deserialize(rArchive); @@ -2133,15 +2135,17 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // rArchive.Read(aMagicMarker); - if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { mpExcludeFiles = new ExcludeList; - if (!mpExcludeFiles) + if(!mpExcludeFiles) + { throw std::bad_alloc(); + } mpExcludeFiles->Deserialize(rArchive); } @@ -2156,15 +2160,17 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) // rArchive.Read(aMagicMarker); - if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + if(aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) { // NOOP } - else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + else if(aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) { mpExcludeDirs = new ExcludeList; - if (!mpExcludeDirs) + if(!mpExcludeDirs) + { throw std::bad_alloc(); + } mpExcludeDirs->Deserialize(rArchive); } @@ -2196,7 +2202,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if (mpDirectoryRecord.get() == NULL) + if(mpDirectoryRecord.get() == NULL) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2212,7 +2218,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if (!mpExcludeFiles) + if(!mpExcludeFiles) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2228,7 +2234,7 @@ void BackupDaemon::Location::Serialize(Archive & rArchive) const // // // - if (!mpExcludeDirs) + if(!mpExcludeDirs) { int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; rArchive.Write(aMagicMarker); @@ -2297,7 +2303,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time std::string StoreObjectInfoFile = GetConfiguration().GetKeyValue("StoreObjectInfoFile"); - if (StoreObjectInfoFile.size() <= 0) + if(StoreObjectInfoFile.size() <= 0) { return false; } @@ -2326,7 +2332,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time int64_t iCount = mLocations.size(); anArchive.Write(iCount); - for (int v = 0; v < iCount; v++) + for(int v = 0; v < iCount; v++) { ASSERT(mLocations[v]); mLocations[v]->Serialize(anArchive); @@ -2338,7 +2344,7 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time iCount = mIDMapMounts.size(); anArchive.Write(iCount); - for (int v = 0; v < iCount; v++) + for(int v = 0; v < iCount; v++) anArchive.Write(mIDMapMounts[v]); // @@ -2391,7 +2397,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ std::string StoreObjectInfoFile = GetConfiguration().GetKeyValue("StoreObjectInfoFile"); - if (StoreObjectInfoFile.size() <= 0) + if(StoreObjectInfoFile.size() <= 0) { return false; } @@ -2407,7 +2413,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int iMagicValue = 0; anArchive.Read(iMagicValue); - if (iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE) + if(iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE) { ::syslog(LOG_WARNING, "Store object info file '%s' " "is not a valid or compatible serialised " @@ -2422,7 +2428,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ std::string strMagicValue; anArchive.Read(strMagicValue); - if (strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING) + if(strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING) { ::syslog(LOG_WARNING, "Store object info file '%s' " "is not a valid or compatible serialised " @@ -2438,7 +2444,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int iVersion = 0; anArchive.Read(iVersion); - if (iVersion != STOREOBJECTINFO_VERSION) + if(iVersion != STOREOBJECTINFO_VERSION) { ::syslog(LOG_WARNING, "Store object info file '%s' " "version %d unsupported. " @@ -2455,7 +2461,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ box_time_t lastKnownConfigModTime; anArchive.Read(lastKnownConfigModTime); - if (lastKnownConfigModTime != GetLoadedConfigModifiedTime()) + if(lastKnownConfigModTime != GetLoadedConfigModifiedTime()) { ::syslog(LOG_WARNING, "Store object info file '%s' " "out of date. Will re-cache from store", @@ -2476,11 +2482,13 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ int64_t iCount = 0; anArchive.Read(iCount); - for (int v = 0; v < iCount; v++) + for(int v = 0; v < iCount; v++) { Location* pLocation = new Location; - if (!pLocation) + if(!pLocation) + { throw std::bad_alloc(); + } pLocation->Deserialize(anArchive); mLocations.push_back(pLocation); @@ -2492,7 +2500,7 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ iCount = 0; anArchive.Read(iCount); - for (int v = 0; v < iCount; v++) + for(int v = 0; v < iCount; v++) { std::string strItem; anArchive.Read(strItem); -- cgit v1.2.3 From 19976d47669d7e3345266b1f8bd9d4552d3519f1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:50:33 +0000 Subject: * Catch invalid output from sync allow script and tell the user what it was, to help them debug the problem (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 023678ec..8f993067 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -59,6 +59,7 @@ #include "BackupStoreFilenameClear.h" #include "BackupClientInodeToIDMap.h" #include "autogen_BackupProtocolClient.h" +#include "autogen_ConversionException.h" #include "BackupClientCryptoKeys.h" #include "BannerText.h" #include "BackupStoreFile.h" @@ -934,8 +935,21 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } else { - // How many seconds to wait? - waitInSeconds = BoxConvert::Convert(line); + try + { + // How many seconds to wait? + waitInSeconds = BoxConvert::Convert(line); + } + catch(ConversionException &e) + { + ::syslog(LOG_ERR, "Invalid output " + "from SyncAllowScript '%s': " + "'%s'", + conf.GetKeyValue("SyncAllowScript").c_str(), + line.c_str()); + throw; + } + ::syslog(LOG_INFO, "Delaying sync by %d seconds (SyncAllowScript '%s')", waitInSeconds, conf.GetKeyValue("SyncAllowScript").c_str()); } } -- cgit v1.2.3 From 541c5e1ad5e06c2be5eecc3bd6b2b10c4a0c8295 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:52:49 +0000 Subject: * Replace global daemon object with a pointer, to allow deletion and clean up reported memory leaks (refs #3, combine with [1027]) --- bin/bbackupd/Win32BackupService.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/bbackupd/Win32BackupService.cpp b/bin/bbackupd/Win32BackupService.cpp index 2f9c1583..7cbf4828 100644 --- a/bin/bbackupd/Win32BackupService.cpp +++ b/bin/bbackupd/Win32BackupService.cpp @@ -12,19 +12,19 @@ #include "Win32BackupService.h" -Win32BackupService gDaemonService; +Win32BackupService* gpDaemonService = NULL; extern HANDLE gStopServiceEvent; unsigned int WINAPI RunService(LPVOID lpParameter) { - DWORD retVal = gDaemonService.WinService((const char*) lpParameter); + DWORD retVal = gpDaemonService->WinService((const char*) lpParameter); SetEvent(gStopServiceEvent); return retVal; } void TerminateService(void) { - gDaemonService.SetTerminateWanted(); + gpDaemonService->SetTerminateWanted(); } DWORD Win32BackupService::WinService(const char* pConfigFileName) -- cgit v1.2.3 From 15f6df24180b688b8a4b7a8fd9512aee16ccba1a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:54:59 +0000 Subject: * Operator precedence fix (refs #3) --- bin/bbackupd/Win32ServiceFunctions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index 2f842fb6..3010cf3f 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -196,7 +196,7 @@ int InstallService(const char* pConfigFileName) return 1; } - if (! st.st_mode & S_IFREG) + if (!(st.st_mode & S_IFREG)) { syslog(LOG_ERR, "Failed to open configuration file: " -- cgit v1.2.3 From 668cc1eedb4b61357c4805d94f306d2a08b46a7f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 14:59:55 +0000 Subject: * Fix compile error caused by conflicting MSVC macros (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index a82b7f21..15fabd34 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -49,6 +49,10 @@ #include "MemLeakFindOn.h" +// min() and max() macros from stdlib.h break numeric_limits<>::min(), etc. +#undef min +#undef max + #define COMPARE_RETURN_SAME 1 #define COMPARE_RETURN_DIFFERENT 2 #define COMPARE_RETURN_ERROR 3 -- cgit v1.2.3 From b0b1c91e8f49470ce6232973f4adb0160a6c021e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 15:08:45 +0000 Subject: * Add option to bbackupquery list command to show times in UTC or local time (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 21 +++++++++++++++------ lib/common/BoxTimeToText.cpp | 38 ++++++++++++++++++++++++++------------ lib/common/BoxTimeToText.h | 2 +- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 15fabd34..4ab09a3a 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -180,7 +180,7 @@ void BackupQueries::DoCommand(const char *Command) { { "quit", "" }, { "exit", "" }, - { "list", "rodIFtsh", }, + { "list", "rodIFtTsh", }, { "pwd", "" }, { "cd", "od" }, { "lcd", "" }, @@ -350,8 +350,9 @@ void BackupQueries::CommandList(const std::vector &args, const bool #define LIST_OPTION_ALLOWOLD 'o' #define LIST_OPTION_ALLOWDELETED 'd' #define LIST_OPTION_NOOBJECTID 'I' - #define LIST_OPTION_NOFLAGS 'F' - #define LIST_OPTION_TIMES 't' + #define LIST_OPTION_NOFLAGS 'F' + #define LIST_OPTION_TIMES_LOCAL 't' + #define LIST_OPTION_TIMES_UTC 'T' #define LIST_OPTION_SIZEINBLOCKS 's' #define LIST_OPTION_DISPLAY_HASH 'h' @@ -468,11 +469,19 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool } } - if(opts[LIST_OPTION_TIMES]) + if(opts[LIST_OPTION_TIMES_UTC]) { - // Show times... + // Show UTC times... std::string time = BoxTimeToISO8601String( - en->GetModificationTime()); + en->GetModificationTime(), false); + printf("%s ", time.c_str()); + } + + if(opts[LIST_OPTION_TIMES_LOCAL]) + { + // Show local times... + std::string time = BoxTimeToISO8601String( + en->GetModificationTime(), true); printf("%s ", time.c_str()); } diff --git a/lib/common/BoxTimeToText.cpp b/lib/common/BoxTimeToText.cpp index ff8b2e49..dbeefe1b 100644 --- a/lib/common/BoxTimeToText.cpp +++ b/lib/common/BoxTimeToText.cpp @@ -20,23 +20,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"); @@ -46,11 +54,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 a25c70b6..21fa5d57 100644 --- a/lib/common/BoxTimeToText.h +++ b/lib/common/BoxTimeToText.h @@ -13,7 +13,7 @@ #include #include "BoxTime.h" -std::string BoxTimeToISO8601String(box_time_t Time); +std::string BoxTimeToISO8601String(box_time_t Time, bool localTime); #endif // BOXTIMETOTEXT__H -- cgit v1.2.3 From 639cf174e77fbdc0f6389d7a1a117fced4a96353 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Oct 2006 17:04:30 +0000 Subject: Use BoxPlatform to see if we are building on Windows (refs #3) --- lib/server/makeprotocol.pl.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in index b5b9dd19..88177b62 100755 --- a/lib/server/makeprotocol.pl.in +++ b/lib/server/makeprotocol.pl.in @@ -1,6 +1,9 @@ #!@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) @@ -912,6 +915,7 @@ __E close H; close CPP; + sub obj_is_type { my ($c,$ty) = @_; -- cgit v1.2.3 From a2c4bfae39d3c6da32f804d0dcc11e3981b3c2b4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 18:51:44 +0000 Subject: Allow getting an object with a path, not just from the current directory (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 65 +++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 4ab09a3a..6f075254 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -884,13 +884,44 @@ void BackupQueries::CommandGet(const std::vector &args, const bool } // Find object ID somehow - int64_t id; + int64_t fileId; + int64_t dirId = GetCurrentDirectoryID(); std::string localName; + // BLOCK { +#ifdef WIN32 + std::string fileName; + if(!ConvertConsoleToUtf8(args[0].c_str(), fileName)) + return; +#else + std::string fileName(args[0]); +#endif + + if(!opts['i']) + { + // does this remote filename include a path? + std::string::size_type index = fileName.rfind('/'); + if(index != std::string::npos) + { + std::string dirName(fileName.substr(0, index)); + fileName = fileName.substr(index + 1); + + dirId = FindDirectoryObjectID(dirName); + if(dirId == 0) + { + printf("Directory '%s' not found\n", + dirName.c_str()); + return; + } + } + } + + BackupStoreFilenameClear fn(fileName); + // Need to look it up in the current directory mrConnection.QueryListDirectory( - GetCurrentDirectoryID(), + dirId, BackupProtocolClientListDirectory::Flags_File, // just files (opts['i'])?(BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING):(BackupProtocolClientListDirectory::Flags_OldVersion | BackupProtocolClientListDirectory::Flags_Deleted), // only current versions false /* don't want attributes */); @@ -903,17 +934,23 @@ void BackupQueries::CommandGet(const std::vector &args, const bool if(opts['i']) { // Specified as ID. - id = ::strtoll(args[0].c_str(), 0, 16); - if(id == std::numeric_limits::min() || id == std::numeric_limits::max() || id == 0) + fileId = ::strtoll(args[0].c_str(), 0, 16); + if(fileId == std::numeric_limits::min() || + fileId == std::numeric_limits::max() || + fileId == 0) { printf("Not a valid object ID (specified in hex)\n"); return; } // Check that the item is actually in the directory - if(dir.FindEntryByID(id) == 0) + if(dir.FindEntryByID(fileId) == 0) { - printf("ID '%08llx' not found in current directory on store.\n(You can only download objects by ID from the current directory.)\n", id); + printf("ID '%08llx' not found in current " + "directory on store.\n" + "(You can only download objects by ID " + "from the current directory.)\n", + fileId); return; } @@ -936,14 +973,18 @@ void BackupQueries::CommandGet(const std::vector &args, const bool if(en == 0) { - printf("Filename '%s' not found in current directory on store.\n(Subdirectories in path not searched.)\n", args[0].c_str()); + printf("Filename '%s' not found in current " + "directory on store.\n" + "(Subdirectories in path not " + "searched.)\n", args[0].c_str()); return; } - id = en->GetObjectID(); + fileId = en->GetObjectID(); - // Local name is the last argument, which is either the looked up filename, or - // a filename specified by the user. + // Local name is the last argument, which is either + // the looked up filename, or a filename specified + // by the user. localName = args[args.size() - 1]; } } @@ -960,7 +1001,7 @@ void BackupQueries::CommandGet(const std::vector &args, const bool try { // Request object - mrConnection.QueryGetFile(GetCurrentDirectoryID(), id); + mrConnection.QueryGetFile(dirId, fileId); // Stream containing encoded file std::auto_ptr objectStream(mrConnection.ReceiveStream()); @@ -969,7 +1010,7 @@ void BackupQueries::CommandGet(const std::vector &args, const bool BackupStoreFile::DecodeFile(*objectStream, localName.c_str(), mrConnection.GetTimeout()); // Done. - printf("Object ID %08llx fetched sucessfully.\n", id); + printf("Object ID %08llx fetched sucessfully.\n", fileId); } catch(...) { -- cgit v1.2.3 From 03ac876c25900b9a8ee7640622454383a98730e2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 18:54:23 +0000 Subject: Convert command-line arguments from the system locale/character set to the console character set (code page), so they they can be converted from console to UTF-8 (yuck). Don't try to read from stdin or change its code page when it's not open (invalid file handle) (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 53 ++++++++++++++++++++++++++------------ bin/bbackupquery/bbackupquery.cpp | 22 +++++++++------- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 6f075254..69c38a4c 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -102,12 +102,12 @@ typedef struct // -------------------------------------------------------------------------- // // Function -// Name: BackupQueries::DoCommand(const char *) +// Name: BackupQueries::DoCommand(const char *, bool) // Purpose: Perform a command // Created: 2003/10/10 // // -------------------------------------------------------------------------- -void BackupQueries::DoCommand(const char *Command) +void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) { // is the command a shell command? if(Command[0] == 's' && Command[1] == 'h' && Command[2] == ' ' && Command[3] != '\0') @@ -168,6 +168,25 @@ void BackupQueries::DoCommand(const char *Command) if(!s.empty()) cmdElements.push_back(s); } + #ifdef WIN32 + if (isFromCommandLine) + { + for (std::vector::iterator + i = cmdElements.begin(); + i != cmdElements.end(); i++) + { + std::string converted; + if (!ConvertEncoding(*i, CP_ACP, converted, + GetConsoleCP())) + { + printf("Failed to convert encoding"); + return; + } + *i = converted; + } + } + #endif + // Check... if(cmdElements.size() < 1) { @@ -394,7 +413,7 @@ void BackupQueries::CommandList(const std::vector &args, const bool // -------------------------------------------------------------------------- // // Function -// Name: BackupQueries::List(int64_t, const std::string &, const bool *) +// Name: BackupQueries::List(int64_t, const std::string &, const bool *, bool) // Purpose: Do the actual listing of directories and files // Created: 2003/10/10 // @@ -871,7 +890,7 @@ void BackupQueries::CommandGetObject(const std::vector &args, const // Created: 2003/10/12 // // -------------------------------------------------------------------------- -void BackupQueries::CommandGet(const std::vector &args, const bool *opts) +void BackupQueries::CommandGet(std::vector args, const bool *opts) { // At least one argument? // Check args @@ -891,13 +910,21 @@ void BackupQueries::CommandGet(const std::vector &args, const bool // BLOCK { #ifdef WIN32 - std::string fileName; - if(!ConvertConsoleToUtf8(args[0].c_str(), fileName)) - return; -#else - std::string fileName(args[0]); + for (std::vector::iterator + i = args.begin(); i != args.end(); i++) + { + std::string out; + if(!ConvertConsoleToUtf8(i->c_str(), out)) + { + fprintf(stderr, "failed to convert encoding\n"); + return; + } + *i = out; + } #endif + std::string fileName(args[0]); + if(!opts['i']) { // does this remote filename include a path? @@ -961,14 +988,6 @@ void BackupQueries::CommandGet(const std::vector &args, const bool { // Specified by name, find the object in the directory to get the ID BackupStoreDirectory::Iterator i(dir); -#ifdef WIN32 - std::string fileName; - if(!ConvertConsoleToUtf8(args[0].c_str(), fileName)) - return; - BackupStoreFilenameClear fn(fileName); -#else - BackupStoreFilenameClear fn(args[0]); -#endif BackupStoreDirectory::Entry *en = i.FindMatchingClearName(fn); if(en == 0) diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index abd0177b..4b836406 100644 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -171,7 +171,8 @@ int main(int argc, const char *argv[]) } // enable input of Unicode characters - if (_setmode(_fileno(stdin), _O_TEXT) == -1) + if (_fileno(stdin) != -1 && + _setmode(_fileno(stdin), _O_TEXT) == -1) { perror("Failed to set the console input to " "binary mode"); @@ -245,7 +246,7 @@ int main(int argc, const char *argv[]) int c = 0; while(c < argc && !context.Stop()) { - context.DoCommand(argv[c++]); + context.DoCommand(argv[c++], true); } } @@ -263,7 +264,7 @@ int main(int argc, const char *argv[]) // Ctrl-D pressed -- terminate now break; } - context.DoCommand(command); + context.DoCommand(command, false); if(last_cmd != 0 && ::strcmp(last_cmd, command) == 0) { free(command); @@ -284,13 +285,16 @@ int main(int argc, const char *argv[]) #endif #else // Version for platforms which don't have readline by default - FdGetLine getLine(fileno(stdin)); - while(!context.Stop()) + if(fileno(stdin) >= 0) { - printf("query > "); - fflush(stdout); - std::string command(getLine.GetLine()); - context.DoCommand(command.c_str()); + FdGetLine getLine(fileno(stdin)); + while(!context.Stop()) + { + printf("query > "); + fflush(stdout); + std::string command(getLine.GetLine()); + context.DoCommand(command.c_str(), false); + } } #endif -- cgit v1.2.3 From 4c9c2b19077e767e648a781131a9440a6648b12f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:17:58 +0000 Subject: Convert command-line arguments from the system locale/character set to the console character set. (refs #3, combine with [1050]) --- bin/bbackupquery/BackupQueries.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.h b/bin/bbackupquery/BackupQueries.h index e84de6ab..41e34d34 100644 --- a/bin/bbackupquery/BackupQueries.h +++ b/bin/bbackupquery/BackupQueries.h @@ -36,7 +36,7 @@ private: BackupQueries(const BackupQueries &); public: - void DoCommand(const char *Command); + void DoCommand(const char *Command, bool isFromCommandLine); // Ready to stop? bool Stop() {return mQuitNow;} @@ -50,7 +50,7 @@ private: void CommandChangeDir(const std::vector &args, const bool *opts); void CommandChangeLocalDir(const std::vector &args); void CommandGetObject(const std::vector &args, const bool *opts); - void CommandGet(const std::vector &args, const bool *opts); + void CommandGet(std::vector args, const bool *opts); void CommandCompare(const std::vector &args, const bool *opts); void CommandRestore(const std::vector &args, const bool *opts); void CommandUndelete(const std::vector &args, const bool *opts); -- cgit v1.2.3 From 4df92a56a61fb8803e7e0541fab9c1c9af2cdcdd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:19:56 +0000 Subject: Add an option to ignore attribute differences on compare. (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 17 ++++++++++++++--- bin/bbackupquery/BackupQueries.h | 1 + bin/bbackupquery/documentation.txt | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 69c38a4c..1781282a 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -206,7 +206,7 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) { "sh", "" }, { "getobject", "" }, { "get", "i" }, - { "compare", "alcqE" }, + { "compare", "alcqAE" }, { "restore", "dri" }, { "help", "" }, { "usage", "" }, @@ -1050,6 +1050,7 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) BackupQueries::CompareParams::CompareParams() : mQuickCompare(false), mIgnoreExcludes(false), + mIgnoreAttributes(false), mDifferences(0), mDifferencesExplainedByModTime(0), mExcludedDirs(0), @@ -1112,6 +1113,7 @@ void BackupQueries::CommandCompare(const std::vector &args, const b BackupQueries::CompareParams params; params.mQuickCompare = opts['q']; params.mIgnoreExcludes = opts['E']; + params.mIgnoreAttributes = opts['A']; // Try and work out the time before which all files should be on the server { @@ -1559,8 +1561,17 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s box_time_t fileModTime = 0; localAttr.ReadAttributes(localPath.c_str(), false /* don't zero mod times */, &fileModTime); modifiedAfterLastSync = (fileModTime > rParams.mLatestFileUploadTime); - if(!localAttr.Compare(fileOnServerStream->GetAttributes(), - true /* ignore attr mod time */, + bool ignoreAttrModTime = true; + + #ifdef WIN32 + // attr mod time is really + // creation time, so check it + ignoreAttrModTime = false; + #endif + + if(!rParams.mIgnoreAttributes && + !localAttr.Compare(fileOnServerStream->GetAttributes(), + ignoreAttrModTime, fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */)) { printf("Local file '%s' " diff --git a/bin/bbackupquery/BackupQueries.h b/bin/bbackupquery/BackupQueries.h index 41e34d34..17043b61 100644 --- a/bin/bbackupquery/BackupQueries.h +++ b/bin/bbackupquery/BackupQueries.h @@ -68,6 +68,7 @@ private: void DeleteExcludeLists(); bool mQuickCompare; bool mIgnoreExcludes; + bool mIgnoreAttributes; int mDifferences; int mDifferencesExplainedByModTime; int mExcludedDirs; diff --git a/bin/bbackupquery/documentation.txt b/bin/bbackupquery/documentation.txt index 429caabe..0fb0bacb 100644 --- a/bin/bbackupquery/documentation.txt +++ b/bin/bbackupquery/documentation.txt @@ -104,6 +104,7 @@ compare -c -- set return code -q -- quick compare. Only checks file contents against checksums, doesn't do a full download + -A -- ignore attribute differences -E -- ignore exclusion settings Comparing with the root directory is an error, use -a option instead. -- cgit v1.2.3 From d3cec4b830d6799bf161f80e79bc0dc69dc0f9e1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:20:30 +0000 Subject: Compile fix. (refs #3) --- lib/common/Test.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 5e42e406..35e9ba58 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -108,7 +108,7 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) { if(RunCommand(pCommandLine) != 0) { - printf("Server: %s\n", command.c_str()); + printf("Server: %s\n", pCommandLine); TEST_FAIL_WITH_MESSAGE("Couldn't start server"); return -1; } @@ -118,7 +118,7 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) // read pid file if(!TestFileExists(pidFile)) { - printf("Server: %s\n", command.c_str()); + printf("Server: %s\n", pCommandLine); TEST_FAIL_WITH_MESSAGE("Server didn't save PID file"); return -1; } @@ -127,7 +127,7 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) int pid = -1; if(f == NULL || fscanf(f, "%d", &pid) != 1) { - printf("Server: %s (pidfile %s)\n", command.c_str(), pidFile); + printf("Server: %s (pidfile %s)\n", pCommandLine, pidFile); TEST_FAIL_WITH_MESSAGE("Couldn't read PID file"); return -1; } -- cgit v1.2.3 From 9a1c50ad833480750f82168a0bea138c461ec8b6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:20:49 +0000 Subject: Compile fix (refs #3) --- lib/win32/emu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 54280769..d898968a 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -267,7 +267,7 @@ inline int strcasecmp(const char *s1, const char *s2) #endif #ifdef _DIRENT_H_ -#error You must not include MinGW's dirent.h! +#error You must not include the MinGW dirent.h! #endif struct dirent -- cgit v1.2.3 From 5fc8f91af0e42aa463ff8ee1bce6e38fa8ca0d08 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:21:05 +0000 Subject: Compile fix (refs #3) --- test/common/testcommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 5a88b3f9..c4a4c784 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -157,6 +157,7 @@ int test(int argc, const char *argv[]) TEST_CHECK_THROWS(InvisibleTempFileStream fs4(tempfile.c_str(), O_CREAT | O_EXCL), CommonException, OSFileOpenError); + fs2.Close(); #else // file is not visible under Unix TEST_THAT(!TestFileExists(tempfile.c_str())); @@ -177,7 +178,6 @@ int test(int argc, const char *argv[]) #endif fs.Close(); - fs2.Close(); fs3.Close(); // now that it's closed, it should be invisible on all platforms -- cgit v1.2.3 From e09c8d4eeea1ef9fb55d5a1ec8e75f92d1799b18 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:28:21 +0000 Subject: Added tests for case-insensitive matching in exclude lists on Win32. (refs #3) --- test/common/testcommon.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index c4a4c784..4f82f587 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -597,21 +597,43 @@ int test(int argc, const char *argv[]) TEST_CHECK_THROWS(elist.AddRegexEntries(std::string("[a-d]+\\.reg$" "\x01" "EXCLUDE" "\x01" "^exclude$")), CommonException, RegexNotSupportedOnThisPlatform); TEST_THAT(elist.SizeOfRegexList() == 0); #endif + + #ifdef WIN32 + #define CASE_SENSITIVE false + #else + #define CASE_SENSITIVE true + #endif + // Try some matches! TEST_THAT(elist.IsExcluded(std::string("Definite1")) == true); TEST_THAT(elist.IsExcluded(std::string("/dir/DefNumberTwo")) == true); TEST_THAT(elist.IsExcluded(std::string("ThingDefThree")) == true); TEST_THAT(elist.IsExcluded(std::string("AnotherDef")) == true); TEST_THAT(elist.IsExcluded(std::string("dir/DefNumberTwo")) == false); + + // Try some case insensitive matches, + // that should pass on Win32 and fail elsewhere + TEST_THAT(elist.IsExcluded("DEFINITe1") + == !CASE_SENSITIVE); + TEST_THAT(elist.IsExcluded("/Dir/DefNumberTwo") + == !CASE_SENSITIVE); + TEST_THAT(elist.IsExcluded("thingdefthree") + == !CASE_SENSITIVE); + #ifdef HAVE_REGEX_H TEST_THAT(elist.IsExcluded(std::string("b.reg")) == true); + TEST_THAT(elist.IsExcluded(std::string("B.reg")) == !CASE_SENSITIVE); + TEST_THAT(elist.IsExcluded(std::string("b.Reg")) == !CASE_SENSITIVE); TEST_THAT(elist.IsExcluded(std::string("e.reg")) == false); - TEST_THAT(elist.IsExcluded(std::string("b.Reg")) == false); - TEST_THAT(elist.IsExcluded(std::string("DEfinite1")) == false); + TEST_THAT(elist.IsExcluded(std::string("e.Reg")) == false); + TEST_THAT(elist.IsExcluded(std::string("DEfinite1")) == !CASE_SENSITIVE); TEST_THAT(elist.IsExcluded(std::string("DEXCLUDEfinite1")) == true); - TEST_THAT(elist.IsExcluded(std::string("DEfinitexclude1")) == false); + TEST_THAT(elist.IsExcluded(std::string("DEfinitexclude1")) == !CASE_SENSITIVE); TEST_THAT(elist.IsExcluded(std::string("exclude")) == true); + TEST_THAT(elist.IsExcluded(std::string("ExcludE")) == !CASE_SENSITIVE); #endif + + #undef CASE_SENSITIVE } test_conversions(); -- cgit v1.2.3 From 33642449e8ba850deed990d95c0a4e542ebcee99 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:30:11 +0000 Subject: Copy our template config.h to BoxConfig.h when compiling with MSVC. (refs #3) --- win32.bat | 2 -- 1 file changed, 2 deletions(-) diff --git a/win32.bat b/win32.bat index 81a97944..86fcf943 100644 --- a/win32.bat +++ b/win32.bat @@ -26,6 +26,4 @@ echo server parts - which appears as though some of the clients rely on cd .\lib\server & perl ./../../lib/common/makeexception.pl.in ServerException.txt & perl ./../../lib/common/makeexception.pl.in ConnectionException.txt cd ..\..\ -copy lib\win32\config.h.win32 lib\common\BoxConfig.h - perl -pe 's/@PERL@/perl/' ./test/bbackupd/testfiles/bbackupd.conf.in > .\test\bbackupd\testfiles\bbackupd.conf -- cgit v1.2.3 From e3273ee1e61dc94baa733aeba533af886717142a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:49:11 +0000 Subject: Revert patch [862] (refs #3) --- bin/bbstored/BackupContext.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp index d78ed9b1..a3f614a5 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupContext.cpp @@ -125,6 +125,7 @@ void BackupContext::ReceivedFinishCommand() // -------------------------------------------------------------------------- bool BackupContext::AttemptToGetWriteLock() { +#ifndef WIN32 // Make the filename of the write lock file std::string writeLockFile; StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, writeLockFile); @@ -158,6 +159,10 @@ bool BackupContext::AttemptToGetWriteLock() } return gotLock; +#else // WIN32 + // no housekeeping process, we do have the lock + return true; +#endif // !WIN32 } @@ -461,6 +466,12 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod #else FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL); FileStream diff2(tempFn.c_str(), O_RDONLY); + + // Unlink it immediately, so it definitely goes away + if(::unlink(tempFn.c_str()) != 0) + { + THROW_EXCEPTION(CommonException, OSFileError); + } #endif // Stream the incoming diff to this temporary file @@ -503,14 +514,6 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod spaceAdjustFromDiff = from->GetDiscUsageInBlocks() - oldVersionNewBlocksUsed; // Everything cleans up here... - diff.Close(); - diff2.Close(); - - // Unlink the temporary file - if(::unlink(tempFn.c_str()) != 0) - { - THROW_EXCEPTION(CommonException, OSFileError); - } } catch(...) { -- cgit v1.2.3 From 0b4fae0d39ee4ef1df329cfbc852ef16463c26a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 19:59:30 +0000 Subject: Revert patch [825] (mostly). Re-enable locking code on Win32 (although it's never used). Use InvisibleTempFileStream to ensure that the temporary file is always deleted. (refs #3) --- bin/bbstored/BackupContext.cpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp index a3f614a5..fa1d88a6 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupContext.cpp @@ -24,6 +24,7 @@ #include "BackupStoreDaemon.h" #include "RaidFileController.h" #include "FileStream.h" +#include "InvisibleTempFileStream.h" #include "MemLeakFindOn.h" @@ -125,7 +126,6 @@ void BackupContext::ReceivedFinishCommand() // -------------------------------------------------------------------------- bool BackupContext::AttemptToGetWriteLock() { -#ifndef WIN32 // Make the filename of the write lock file std::string writeLockFile; StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, writeLockFile); @@ -151,7 +151,7 @@ bool BackupContext::AttemptToGetWriteLock() } while(!gotLock && tries > 0); } - + if(gotLock) { // Got the lock, mark as not read only @@ -159,10 +159,6 @@ bool BackupContext::AttemptToGetWriteLock() } return gotLock; -#else // WIN32 - // no housekeeping process, we do have the lock - return true; -#endif // !WIN32 } @@ -459,9 +455,9 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod { // Open it twice #ifdef WIN32 - FileStream diff(tempFn.c_str(), + InvisibleTempFileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_BINARY); - FileStream diff2(tempFn.c_str(), + InvisibleTempFileStream diff2(tempFn.c_str(), O_RDWR | O_BINARY); #else FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL); @@ -521,14 +517,6 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod ::unlink(tempFn.c_str()); throw; } - -#ifdef WIN32 - // we can't delete the file while it's open, above - if(::unlink(tempFn.c_str()) != 0) - { - THROW_EXCEPTION(CommonException, OSFileError); - } -#endif } // Get the blocks used -- cgit v1.2.3 From 7b0b44a30ce55a12c082f80b8f9c1465e8d3717a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Oct 2006 21:23:38 +0000 Subject: Change test for return code 3 back to 2, until or unless the bbackupquery compare error (unreadable files) patch is merged. (refs #3) --- test/bbackupd/testbbackupd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 7207680a..51047177 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -718,7 +718,7 @@ int test_bbackupd() // Wait and test... wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 3*256); // should find differences + TEST_THAT(compareReturnValue == 2*256); // should find differences TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Check that it was reported correctly TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1")); -- cgit v1.2.3 From 4cf0546485a28ba331edc75dd0d263a6e2259462 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 19:23:47 +0000 Subject: Don't check for nanosleep, random device, or flock/F_SETLK on any mingw32 platform (including mingw32msvc). (refs #3) --- configure.ac | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index b5b7a4cc..c6b27fea 100644 --- a/configure.ac +++ b/configure.ac @@ -36,10 +36,15 @@ fi ### Checks for libraries. -if test "$target_os" != "mingw32" -a "$target_os" != "winnt"; then +case $target_os in +mingw32*) ;; +winnt) ;; +*) AC_SEARCH_LIBS([nanosleep], [rt], [ac_have_nanosleep=yes], [AC_MSG_ERROR([[cannot find a short sleep function (nanosleep)]])]) -fi + ;; +esac + AC_CHECK_LIB([z], [zlibVersion],, [AC_MSG_ERROR([[cannot find zlib]])]) VL_LIB_READLINE([have_libreadline=yes], [have_libreadline=no]) @@ -126,12 +131,16 @@ if test "x$ac_cv_c_bigendian" != "xyes"; then AX_BSWAP64 fi -if test "$target_os" != "mingw32"; then +case $target_os in +mingw32*) ;; +winnt*) ;; +*) AX_RANDOM_DEVICE AX_CHECK_MOUNT_POINT(,[ AC_MSG_ERROR([[cannot work out how to discover mount points on your platform]]) ]) -fi +;; +esac AX_CHECK_MALLOC_WORKAROUND @@ -170,13 +179,19 @@ AC_CACHE_CHECK([if we have large file support enabled], [have_large_file_support AC_CHECK_FUNCS([flock]) AC_CHECK_DECLS([O_EXLOCK],,, [[#include ]]) AC_CHECK_DECLS([F_SETLK],,, [[#include ]]) + +case $target_os in +mingw32*) ;; +winnt*) ;; +*) if test "x$ac_cv_func_flock" != "xyes" && \ test "x$ac_cv_have_decl_O_EXLOCK" != "xyes" && \ - test "x$ac_cv_have_decl_F_SETLK" != "xyes" && \ - test "$target_os" != "mingw32" -a "$target_os" != "winnt" + test "x$ac_cv_have_decl_F_SETLK" != "xyes" then AC_MSG_ERROR([[cannot work out how to do file locking on your platform]]) fi +;; +esac ## Get tmpdir temp_directory_name="/tmp" -- cgit v1.2.3 From 6b67a185db7d655e0ce74f47b6d51458ab4dc43b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 19:25:18 +0000 Subject: Don't check for AC_HEADER_DIRENT on any mingw32 platform. (refs #3) --- configure.ac | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c6b27fea..5ce21491 100644 --- a/configure.ac +++ b/configure.ac @@ -84,9 +84,13 @@ Upgrade or read the documentation for alternatives]]) ### Checks for header files. -if test "$target_os" != "mingw32"; then +case $target_os in +mingw32*) ;; +winnt*) ;; +*) AC_HEADER_DIRENT -fi + ;; +esac AC_HEADER_STDC AC_HEADER_SYS_WAIT -- cgit v1.2.3 From bd610e6fea1585387be0127215379c0b5d92c388 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 19:26:51 +0000 Subject: Different check for have_regex_h (the old one doesn't seem to work on MinGW). (refs #3) --- configure.ac | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 5ce21491..564a9076 100644 --- a/configure.ac +++ b/configure.ac @@ -94,13 +94,16 @@ esac AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([execinfo.h process.h pwd.h regex.h signal.h]) +AC_CHECK_HEADERS([execinfo.h process.h pwd.h signal.h]) AC_CHECK_HEADERS([syslog.h time.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h]) AC_CHECK_HEADERS([sys/uio.h sys/xattr.h]) -if test "$ac_cv_header_regex_h" = "yes"; then +AC_CHECK_HEADER([regex.h], [have_regex_h=yes]) + +if test "$have_regex_h" = "yes"; then + AC_DEFINE([HAVE_REGEX_H], [1], [Define to 1 if regex.h is available]) AC_SEARCH_LIBS([regcomp], ["pcreposix -lpcre"]) fi @@ -258,7 +261,7 @@ A summary of the build configuration is below. Box Backup will function without these features, but will work better where they are present. Refer to the documentation for more information on each feature. -Regular expressions: $ac_cv_header_regex_h +Regular expressions: $have_regex_h Large files: $have_large_file_support Berkeley DB: $ax_path_bdb_ok Readline: $have_libreadline -- cgit v1.2.3 From e57ac80dde19d259e6e65be60a89c0cdd46c3b64 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 19:28:43 +0000 Subject: Add test/bbackupd/testfiles/syncallowscript.pl to the list of Perl files auto-generated with substitutions. (refs #3) --- configure.ac | 3 ++- test/bbackupd/testfiles/syncallowscript.pl.in | 33 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100755 test/bbackupd/testfiles/syncallowscript.pl.in diff --git a/configure.ac b/configure.ac index 564a9076..8b6221a2 100644 --- a/configure.ac +++ b/configure.ac @@ -246,7 +246,8 @@ AX_CONFIG_SCRIPTS([bin/bbackupd/bbackupd-config test/bbackupd/testfiles/bbackupd.conf test/bbackupd/testfiles/extcheck1.pl test/bbackupd/testfiles/extcheck2.pl - test/bbackupd/testfiles/notifyscript.pl]) + test/bbackupd/testfiles/notifyscript.pl + test/bbackupd/testfiles/syncallowscript.pl]) # TODO: Need to do contrib/cygwin/install-cygwin-service.pl but location varies AC_OUTPUT diff --git a/test/bbackupd/testfiles/syncallowscript.pl.in b/test/bbackupd/testfiles/syncallowscript.pl.in new file mode 100755 index 00000000..af425e90 --- /dev/null +++ b/test/bbackupd/testfiles/syncallowscript.pl.in @@ -0,0 +1,33 @@ +#!@PERL@ + +use strict; +use warnings; + +my $control_file = 'testfiles/syncallowscript.control'; +if (! -r $control_file) +{ + print "now\n"; + exit 0; +} + +my $control_state; +open CONTROL, "< $control_file" or die "$control_file: $!"; +$control_state = ; +defined $control_state or die "$control_file: read failed: $!"; +close CONTROL; + +my $marker_file_root = 'testfiles/syncallowscript.notifyran.'; +my $n = 1; +my $marker_file; + +while($marker_file = $marker_file_root.$n and -e $marker_file) +{ + $n ++; +} + +open FL,'>'.$marker_file or die "$marker_file: $!"; +print FL localtime(); +close FL; + +print $control_state; +exit 0; -- cgit v1.2.3 From da8282e7a87b67c1585ce9b81199d7966d8481c9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 22:50:57 +0000 Subject: Rename config.h.win32 to the new name, which will be auto-included by another change (refs #3) --- lib/common/BoxConfig-MSVC.h | 390 ++++++++++++++++++++++++++++++++++++++++++++ lib/win32/config.h.win32 | 390 -------------------------------------------- 2 files changed, 390 insertions(+), 390 deletions(-) create mode 100644 lib/common/BoxConfig-MSVC.h delete mode 100644 lib/win32/config.h.win32 diff --git a/lib/common/BoxConfig-MSVC.h b/lib/common/BoxConfig-MSVC.h new file mode 100644 index 00000000..edc44a75 --- /dev/null +++ b/lib/common/BoxConfig-MSVC.h @@ -0,0 +1,390 @@ +/* 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 */ + +/* Define to major version for BDB_VERSION */ +/* #undef BDB_VERSION_MAJOR */ + +/* Define to minor version for BDB_VERSION */ +/* #undef BDB_VERSION_MINOR */ + +/* Define to point version for BDB_VERSION */ +/* #undef BDB_VERSION_POINT */ + +/* Name of the 64 bit endian swapping function */ +/* #undef BSWAP64 */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +#define CLOSEDIR_VOID 1 + +/* 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 header file. */ +/* #undef HAVE_ASM_BYTEORDER_H */ + +/* Define to 1 if BSWAP64 is defined to the name of a valid 64 bit endian + swapping function */ +/* #undef HAVE_BSWAP64 */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DB_H */ + +/* Define to 1 if you have the declaration of `F_SETLK', and to 0 if you + don't. */ +#define HAVE_DECL_F_SETLK 0 + +/* 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 `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 0 + +/* 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 header file, and it defines `DIR'. + */ +/* #undef HAVE_DIRENT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EDITLINE_READLINE_H */ + +/* define if the compiler supports exceptions */ +#define HAVE_EXCEPTIONS + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_EXECINFO_H */ + +/* Define to 1 if you have the `flock' function. */ +/* #undef HAVE_FLOCK */ + +/* Define to 1 if you have the `getmntent' function. */ +/* #undef HAVE_GETMNTENT */ + +/* 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 `getxattr' function. */ +/* #undef HAVE_GETXATTR */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_HISTORY_H */ + +/* Define to 1 if you have the header file. */ +// #define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `kqueue' function. */ +/* #undef HAVE_KQUEUE */ + +/* Define to 1 if you have the `lchown' function. */ +/* #undef HAVE_LCHOWN */ + +/* Define to 1 if you have the `lgetxattr' function. */ +/* #undef HAVE_LGETXATTR */ + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#define HAVE_LIBCRYPTO 1 + +/* Define if you have a readline compatible library */ +/* #undef HAVE_LIBREADLINE */ + +/* 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. */ +/* #undef HAVE_LISTXATTR */ + +/* Define to 1 if you have the `llistxattr' function. */ +/* #undef HAVE_LLISTXATTR */ + +/* 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. */ +/* #undef HAVE_LSETXATTR */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MNTENT_H */ + +/* Define to 1 if this platform supports mounts */ +/* #undef HAVE_MOUNTS */ + +/* define if the compiler implements namespaces */ +#define HAVE_NAMESPACES + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETINET_IN_H */ + +/* Define to 1 if SSL is pre-0.9.7 */ +/* #undef HAVE_OLD_SSL */ + +/* Define to 1 if you have the header file. */ +#define HAVE_OPENSSL_SSL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PROCESS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PWD_H */ + +/* Define to 1 (and set RANDOM_DEVICE) if a random device is available */ +/* #undef HAVE_RANDOM_DEVICE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_READLINE_H */ + +/* Define if your readline library has add_history */ +/* #undef HAVE_READLINE_HISTORY */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_READLINE_HISTORY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_READLINE_READLINE_H */ + +/* Define to 1 if you have the header file. */ +// #define HAVE_REGEX_H 1 + +/* Define to 1 if you have the `setproctitle' function. */ +/* #undef HAVE_SETPROCTITLE */ + +/* Define to 1 if you have the `setxattr' function. */ +/* #undef HAVE_SETXATTR */ + +/* Define to 1 if you have the 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. */ +/* #undef HAVE_STATFS */ + +/* 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 header file. */ +// #define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if `d_type' is member of `struct dirent'. */ +/* #undef HAVE_STRUCT_DIRENT_D_TYPE */ + +/* Define to 1 if `mnt_dir' is member of `struct mntent'. */ +/* #undef HAVE_STRUCT_MNTENT_MNT_DIR */ + +/* 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 `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. */ +/* #undef HAVE_SYSCALL */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYSLOG_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MNTTAB_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MOUNT_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +// #define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSCALL_H */ + +/* Define to 1 if you have the header file. */ +// #define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_XATTR_H */ + +/* Define to 1 if you have the 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 header file. */ +// #define HAVE_UNISTD_H 1 + +/* Define to 1 if the system has the type `u_int16_t'. */ +/* #undef HAVE_U_INT16_T */ + +/* Define to 1 if the system has the type `u_int32_t'. */ +/* #undef HAVE_U_INT32_T */ + +/* Define to 1 if the system has the type `u_int64_t'. */ +/* #undef HAVE_U_INT64_T */ + +/* Define to 1 if the system has the type `u_int8_t'. */ +/* #undef HAVE_U_INT8_T */ + +/* 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. */ +/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ + +/* 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.09" + +/* 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.09" + +/* Define to the filename of the random device (and set HAVE_RANDOM_DEVICE) */ +/* #undef RANDOM_DEVICE */ + +/* 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 and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your 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. */ +/* #undef _FILE_OFFSET_BITS */ + +/* 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 doesn't define. */ +#define gid_t int + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `unsigned' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if doesn't define. */ +#define uid_t int diff --git a/lib/win32/config.h.win32 b/lib/win32/config.h.win32 deleted file mode 100644 index edc44a75..00000000 --- a/lib/win32/config.h.win32 +++ /dev/null @@ -1,390 +0,0 @@ -/* 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 */ - -/* Define to major version for BDB_VERSION */ -/* #undef BDB_VERSION_MAJOR */ - -/* Define to minor version for BDB_VERSION */ -/* #undef BDB_VERSION_MINOR */ - -/* Define to point version for BDB_VERSION */ -/* #undef BDB_VERSION_POINT */ - -/* Name of the 64 bit endian swapping function */ -/* #undef BSWAP64 */ - -/* Define to 1 if the `closedir' function returns void instead of `int'. */ -#define CLOSEDIR_VOID 1 - -/* 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 header file. */ -/* #undef HAVE_ASM_BYTEORDER_H */ - -/* Define to 1 if BSWAP64 is defined to the name of a valid 64 bit endian - swapping function */ -/* #undef HAVE_BSWAP64 */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DB_H */ - -/* Define to 1 if you have the declaration of `F_SETLK', and to 0 if you - don't. */ -#define HAVE_DECL_F_SETLK 0 - -/* 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 `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 0 - -/* 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 header file, and it defines `DIR'. - */ -/* #undef HAVE_DIRENT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EDITLINE_READLINE_H */ - -/* define if the compiler supports exceptions */ -#define HAVE_EXCEPTIONS - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_EXECINFO_H */ - -/* Define to 1 if you have the `flock' function. */ -/* #undef HAVE_FLOCK */ - -/* Define to 1 if you have the `getmntent' function. */ -/* #undef HAVE_GETMNTENT */ - -/* 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 `getxattr' function. */ -/* #undef HAVE_GETXATTR */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_HISTORY_H */ - -/* Define to 1 if you have the header file. */ -// #define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `kqueue' function. */ -/* #undef HAVE_KQUEUE */ - -/* Define to 1 if you have the `lchown' function. */ -/* #undef HAVE_LCHOWN */ - -/* Define to 1 if you have the `lgetxattr' function. */ -/* #undef HAVE_LGETXATTR */ - -/* Define to 1 if you have the `crypto' library (-lcrypto). */ -#define HAVE_LIBCRYPTO 1 - -/* Define if you have a readline compatible library */ -/* #undef HAVE_LIBREADLINE */ - -/* 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. */ -/* #undef HAVE_LISTXATTR */ - -/* Define to 1 if you have the `llistxattr' function. */ -/* #undef HAVE_LLISTXATTR */ - -/* 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. */ -/* #undef HAVE_LSETXATTR */ - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_MNTENT_H */ - -/* Define to 1 if this platform supports mounts */ -/* #undef HAVE_MOUNTS */ - -/* define if the compiler implements namespaces */ -#define HAVE_NAMESPACES - -/* Define to 1 if you have the header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_NETINET_IN_H */ - -/* Define to 1 if SSL is pre-0.9.7 */ -/* #undef HAVE_OLD_SSL */ - -/* Define to 1 if you have the header file. */ -#define HAVE_OPENSSL_SSL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_PROCESS_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_PWD_H */ - -/* Define to 1 (and set RANDOM_DEVICE) if a random device is available */ -/* #undef HAVE_RANDOM_DEVICE */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_READLINE_H */ - -/* Define if your readline library has add_history */ -/* #undef HAVE_READLINE_HISTORY */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_READLINE_HISTORY_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_READLINE_READLINE_H */ - -/* Define to 1 if you have the header file. */ -// #define HAVE_REGEX_H 1 - -/* Define to 1 if you have the `setproctitle' function. */ -/* #undef HAVE_SETPROCTITLE */ - -/* Define to 1 if you have the `setxattr' function. */ -/* #undef HAVE_SETXATTR */ - -/* Define to 1 if you have the 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. */ -/* #undef HAVE_STATFS */ - -/* 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 header file. */ -// #define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if `d_type' is member of `struct dirent'. */ -/* #undef HAVE_STRUCT_DIRENT_D_TYPE */ - -/* Define to 1 if `mnt_dir' is member of `struct mntent'. */ -/* #undef HAVE_STRUCT_MNTENT_MNT_DIR */ - -/* 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 `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. */ -/* #undef HAVE_SYSCALL */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYSLOG_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_ENDIAN_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MNTTAB_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_MOUNT_H */ - -/* Define to 1 if you have the header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the header file. */ -// #define HAVE_SYS_PARAM_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SOCKET_H */ - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_SYSCALL_H */ - -/* Define to 1 if you have the header file. */ -// #define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_WAIT_H */ - -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_XATTR_H */ - -/* Define to 1 if you have the 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 header file. */ -// #define HAVE_UNISTD_H 1 - -/* Define to 1 if the system has the type `u_int16_t'. */ -/* #undef HAVE_U_INT16_T */ - -/* Define to 1 if the system has the type `u_int32_t'. */ -/* #undef HAVE_U_INT32_T */ - -/* Define to 1 if the system has the type `u_int64_t'. */ -/* #undef HAVE_U_INT64_T */ - -/* Define to 1 if the system has the type `u_int8_t'. */ -/* #undef HAVE_U_INT8_T */ - -/* 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. */ -/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ - -/* 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.09" - -/* 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.09" - -/* Define to the filename of the random device (and set HAVE_RANDOM_DEVICE) */ -/* #undef RANDOM_DEVICE */ - -/* 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 and . */ -#define TIME_WITH_SYS_TIME 1 - -/* Define to 1 if your 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. */ -/* #undef _FILE_OFFSET_BITS */ - -/* 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 doesn't define. */ -#define gid_t int - -/* Define to `int' if does not define. */ -/* #undef mode_t */ - -/* Define to `long' if does not define. */ -/* #undef off_t */ - -/* Define to `int' if does not define. */ -/* #undef pid_t */ - -/* Define to `unsigned' if does not define. */ -/* #undef size_t */ - -/* Define to `int' if doesn't define. */ -#define uid_t int -- cgit v1.2.3 From bdfa935f8eec7d1e34963f3a84c7923b64640a76 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:07:15 +0000 Subject: Improved debugging when creation of sparse files fails. (refs #3) --- test/backupdiff/testbackupdiff.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp index 806ede89..a91d6dfe 100644 --- a/test/backupdiff/testbackupdiff.cpp +++ b/test/backupdiff/testbackupdiff.cpp @@ -69,10 +69,16 @@ void make_file_of_zeros(const char *filename, size_t size) #ifdef WIN32 HANDLE handle = openfile(filename, O_WRONLY | O_CREAT | O_EXCL, 0); TEST_THAT(handle != INVALID_HANDLE_VALUE); - SetFilePointer(handle, size, NULL, FILE_BEGIN); + TEST_THAT(SetFilePointer(handle, size, NULL, FILE_BEGIN) + != INVALID_SET_FILE_POINTER); TEST_THAT(GetLastError() == NO_ERROR); - TEST_THAT(SetEndOfFile(handle) == true); - TEST_THAT(CloseHandle(handle) == true); + BOOL result = SetEndOfFile(handle); + if (result != TRUE) + { + printf("Error %u\n", GetLastError()); + } + TEST_THAT(result == TRUE); + TEST_THAT(CloseHandle(handle) == TRUE); #else int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd < 0) perror(filename); -- cgit v1.2.3 From a9badc2ab3f243402c3a7638bd7942021ea1f6cc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:07:48 +0000 Subject: Updated MSVC project files. (refs #3) --- infrastructure/msvc/2003/bbackupctl.vcproj | 5 ++++- infrastructure/msvc/2003/bbackupd.vcproj | 5 ++++- infrastructure/msvc/2003/boxbackup.sln | 10 ---------- infrastructure/msvc/2003/boxquery.vcproj | 5 ++++- infrastructure/msvc/2003/common.vcproj | 21 ++++++++++++++++++++- infrastructure/msvc/2005/bbackupctl.vcproj | 4 ++++ infrastructure/msvc/2005/bbackupd.vcproj | 4 ++++ infrastructure/msvc/2005/boxquery.vcproj | 4 ++++ infrastructure/msvc/2005/common.vcproj | 20 +++++++++++++++++--- 9 files changed, 61 insertions(+), 17 deletions(-) diff --git a/infrastructure/msvc/2003/bbackupctl.vcproj b/infrastructure/msvc/2003/bbackupctl.vcproj index b46d99f7..b2249ff8 100644 --- a/infrastructure/msvc/2003/bbackupctl.vcproj +++ b/infrastructure/msvc/2003/bbackupctl.vcproj @@ -20,7 +20,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\..\..\db-4.2.52.NC\build_win32";"$(ProjectDir)..\..\..\lib\backupclient";"$(ProjectDir)..\..\..\lib\server";"$(ProjectDir)..\..\..\lib\crypto";"$(ProjectDir)..\..\..\..\openssl\include";"$(ProjectDir)..\..\..\lib\compress";"$(ProjectDir)..\..\..\..\zlib\include";"$(ProjectDir)..\..\..\lib\win32";"$(ProjectDir)..\..\..\lib\common\"" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;NDEBUG " MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -149,6 +149,9 @@ Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + + diff --git a/infrastructure/msvc/2003/bbackupd.vcproj b/infrastructure/msvc/2003/bbackupd.vcproj index 4ca3470e..8e680956 100644 --- a/infrastructure/msvc/2003/bbackupd.vcproj +++ b/infrastructure/msvc/2003/bbackupd.vcproj @@ -20,7 +20,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(SolutionDir)..\..\..\..\db-4.2.52.NC\build_win32";"$(SolutionDir)..\..\..\..\boost_1_31_0";"$(SolutionDir)..\..\..\..\openssl\include";"$(SolutionDir)..\..\..\..\zlib\include";"$(SolutionDir)..\..\..\lib\backupclient";"$(SolutionDir)..\..\..\lib\server";"$(SolutionDir)..\..\..\lib\crypto";"$(SolutionDir)..\..\..\lib\compress";"$(SolutionDir)..\..\..\lib\win32";"$(SolutionDir)..\..\..\lib\common\"" - PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING" + PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;NDEBUG " MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -200,6 +200,9 @@ Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + + diff --git a/infrastructure/msvc/2003/boxbackup.sln b/infrastructure/msvc/2003/boxbackup.sln index ede6faa1..d9a28041 100644 --- a/infrastructure/msvc/2003/boxbackup.sln +++ b/infrastructure/msvc/2003/boxbackup.sln @@ -1,7 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boxquery", "boxquery.vcproj", "{FE9EC666-4B3A-4370-B3D4-DEBD4A21F36E}" ProjectSection(ProjectDependencies) = postProject - {98598F62-FEA7-4134-AA29-0AD2315A214F} = {98598F62-FEA7-4134-AA29-0AD2315A214F} {A089CEE6-EBF0-4232-A0C0-74850A8127A6} = {A089CEE6-EBF0-4232-A0C0-74850A8127A6} EndProjectSection EndProject @@ -11,7 +10,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common.vcproj", " EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bbackupd", "bbackupd.vcproj", "{22D325FB-9131-4BD6-B390-968F0491D687}" ProjectSection(ProjectDependencies) = postProject - {98598F62-FEA7-4134-AA29-0AD2315A214F} = {98598F62-FEA7-4134-AA29-0AD2315A214F} {A089CEE6-EBF0-4232-A0C0-74850A8127A6} = {A089CEE6-EBF0-4232-A0C0-74850A8127A6} EndProjectSection EndProject @@ -25,10 +23,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bbackupctl", "bbackupctl.vc {A089CEE6-EBF0-4232-A0C0-74850A8127A6} = {A089CEE6-EBF0-4232-A0C0-74850A8127A6} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boost_regex", "lib\win32\boost_regex.vcproj", "{98598F62-FEA7-4134-AA29-0AD2315A214F}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -55,10 +49,6 @@ Global {9FD51412-E945-4457-A17A-CA3C505CF431}.Debug.Build.0 = Debug|Win32 {9FD51412-E945-4457-A17A-CA3C505CF431}.Release.ActiveCfg = Release|Win32 {9FD51412-E945-4457-A17A-CA3C505CF431}.Release.Build.0 = Release|Win32 - {98598F62-FEA7-4134-AA29-0AD2315A214F}.Debug.ActiveCfg = Debug|Win32 - {98598F62-FEA7-4134-AA29-0AD2315A214F}.Debug.Build.0 = Debug|Win32 - {98598F62-FEA7-4134-AA29-0AD2315A214F}.Release.ActiveCfg = Release|Win32 - {98598F62-FEA7-4134-AA29-0AD2315A214F}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/infrastructure/msvc/2003/boxquery.vcproj b/infrastructure/msvc/2003/boxquery.vcproj index a2962c22..8d8cf20c 100644 --- a/infrastructure/msvc/2003/boxquery.vcproj +++ b/infrastructure/msvc/2003/boxquery.vcproj @@ -21,7 +21,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\..\lib\backupclient";"$(ProjectDir)..\..\..\lib\server";"$(ProjectDir)..\..\..\lib\crypto";"$(ProjectDir)..\..\..\..\openssl\include";"$(ProjectDir)..\..\..\lib\compress";"$(ProjectDir)..\..\..\..\zlib\include";"$(ProjectDir)..\..\..\lib\win32";"$(ProjectDir)..\..\..\lib\common\";"$(SolutionDir)..\..\..\..\boost_1_31_0"" - PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING" + PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;NDEBUG " MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -161,6 +161,9 @@ Name="Resource Files" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + + diff --git a/infrastructure/msvc/2003/common.vcproj b/infrastructure/msvc/2003/common.vcproj index 553aaf1a..ab73a8fb 100644 --- a/infrastructure/msvc/2003/common.vcproj +++ b/infrastructure/msvc/2003/common.vcproj @@ -20,7 +20,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\..\lib\backupclient";"$(ProjectDir)..\..\..\lib\server";"$(ProjectDir)..\..\..\lib\crypto";"$(ProjectDir)..\..\..\..\openssl\include";"$(ProjectDir)..\..\..\lib\compress";"$(ProjectDir)..\..\..\..\zlib\include";"$(ProjectDir)..\..\..\lib\win32";"$(ProjectDir)..\..\..\lib\common\";"$(SolutionDir)..\..\..\..\boost_1_31_0\"" - PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_LIB;PLATFORM_DISABLE_MEM_LEAK_TESTING" + PreprocessorDefinitions="BOOST_REGEX_NO_LIB;WIN32;_DEBUG;_LIB;PLATFORM_DISABLE_MEM_LEAK_TESTING;NDEBUG " MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -287,6 +287,9 @@ + + + + + @@ -476,6 +483,9 @@ + + + + + + + + diff --git a/infrastructure/msvc/2005/bbackupctl.vcproj b/infrastructure/msvc/2005/bbackupctl.vcproj index 3da10702..c9507b17 100644 --- a/infrastructure/msvc/2005/bbackupctl.vcproj +++ b/infrastructure/msvc/2005/bbackupctl.vcproj @@ -210,6 +210,10 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + + diff --git a/infrastructure/msvc/2005/bbackupd.vcproj b/infrastructure/msvc/2005/bbackupd.vcproj index dbcf89d3..0f2828e0 100644 --- a/infrastructure/msvc/2005/bbackupd.vcproj +++ b/infrastructure/msvc/2005/bbackupd.vcproj @@ -275,6 +275,10 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + + + + @@ -449,6 +451,10 @@ RelativePath="..\..\..\lib\server\TLSContext.cpp" > + + @@ -504,7 +510,7 @@ > + + @@ -764,7 +774,7 @@ > @@ -835,6 +845,10 @@ RelativePath="..\..\..\lib\server\TLSContext.h" > + + -- cgit v1.2.3 From ac19a2d757e850964718a5b3b6fe9032feb20f4d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:08:13 +0000 Subject: Added a script to determine the build version on Win32 MSVC. (refs #3) --- infrastructure/msvc/getversion.pl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 infrastructure/msvc/getversion.pl diff --git a/infrastructure/msvc/getversion.pl b/infrastructure/msvc/getversion.pl new file mode 100644 index 00000000..12554d01 --- /dev/null +++ b/infrastructure/msvc/getversion.pl @@ -0,0 +1,19 @@ +#!perl + +$basedir = $0; +$basedir =~ s/\\[^\\]*$//; +$basedir =~ s/\\[^\\]*$//; +$basedir =~ s/\\[^\\]*$//; +$basedir =~ s/\\[^\\]*$//; +$basedir =~ s/\\[^\\]*$//; +-d $basedir or die "$basedir: $!"; +chdir $basedir or die "$basedir: $!"; + +require "$basedir\\infrastructure\\BoxPlatform.pm.in"; + +open VERSIONFILE, "> $basedir/lib/common/BoxVersion.h" + or die "BoxVersion.h: $!"; +print VERSIONFILE "#define BOX_VERSION \"$BoxPlatform::product_version\"\n"; +close VERSIONFILE; + +exit 0; -- cgit v1.2.3 From f9bedd322c6f1050a9743d98c747d65f953207b7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:10:08 +0000 Subject: Undefine fstat() so that we get the Win32 POSIX version, instead of our emulated version. Small code cleanup. (refs #3) --- lib/raidfile/RaidFileRead.cpp | 3 +++ lib/raidfile/RaidFileWrite.cpp | 24 +++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp index ad040c22..363c638b 100644 --- a/lib/raidfile/RaidFileRead.cpp +++ b/lib/raidfile/RaidFileRead.cpp @@ -43,6 +43,9 @@ #define READ_NUMBER_DISCS_REQUIRED 3 #define READV_MAX_BLOCKS 64 +// We want to use POSIX fstat() for now, not the emulated one +#undef fstat + // -------------------------------------------------------------------------- // // Class diff --git a/lib/raidfile/RaidFileWrite.cpp b/lib/raidfile/RaidFileWrite.cpp index 2de9dde5..66ab81c8 100644 --- a/lib/raidfile/RaidFileWrite.cpp +++ b/lib/raidfile/RaidFileWrite.cpp @@ -35,6 +35,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 @@ -567,18 +570,17 @@ void RaidFileWrite::TransformToRaidStorage() #ifdef WIN32 // Must delete before renaming - if (::unlink(stripe1Filename.c_str()) != 0 && errno != ENOENT) - { - THROW_EXCEPTION(RaidFileException, OSError); - } - if (::unlink(stripe2Filename.c_str()) != 0 && errno != ENOENT) - { - THROW_EXCEPTION(RaidFileException, OSError); - } - if (::unlink(parityFilename.c_str()) != 0 && errno != ENOENT) - { - THROW_EXCEPTION(RaidFileException, OSError); + #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 -- cgit v1.2.3 From f95f7bc1616c954043e3e5b06e2dac1f0530b5ad Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:12:24 +0000 Subject: Remove #ifdefs around geteuid(), re-enable use of fake version under Win32 as requested by Ben. Restore serialised AttrModificationTime under Win32 by passing to emu_utimes(). (refs #3) --- lib/backupclient/BackupClientFileAttributes.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp index 49bae665..ba65d57a 100644 --- a/lib/backupclient/BackupClientFileAttributes.cpp +++ b/lib/backupclient/BackupClientFileAttributes.cpp @@ -642,11 +642,7 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename) const } // If working as root, set user IDs - #ifdef WIN32 - if(0) - #else if(::geteuid() == 0) - #endif { #ifndef HAVE_LCHOWN // only if not a link, can't set their owner on this platform @@ -683,10 +679,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) -- cgit v1.2.3 From 3a9d95bd011a8a5a39f0ad9aaaf682a926cfeccf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:13:00 +0000 Subject: Delete existing entries to allow reuse of a BackupStoreDirectory object. (refs #3) --- lib/backupclient/BackupStoreDirectory.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/backupclient/BackupStoreDirectory.cpp b/lib/backupclient/BackupStoreDirectory.cpp index 61e6461d..0d06da34 100644 --- a/lib/backupclient/BackupStoreDirectory.cpp +++ b/lib/backupclient/BackupStoreDirectory.cpp @@ -149,6 +149,11 @@ void BackupStoreDirectory::ReadFromStream(IOStream &rStream, int Timeout) int count = ntohl(hdr.mNumEntries); // Clear existing list + for(std::vector::iterator i = mEntries.begin(); + i != mEntries.end(); i++) + { + delete (*i); + } mEntries.clear(); // Read them in! -- cgit v1.2.3 From 29da720afeebbb7c618355a588a1e36a7620c9a6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:13:30 +0000 Subject: Add new return codes from BackupClientRestore for use on Win32. (refs #3) --- lib/backupclient/BackupClientRestore.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/backupclient/BackupClientRestore.h b/lib/backupclient/BackupClientRestore.h index 4b382771..f7724030 100644 --- a/lib/backupclient/BackupClientRestore.h +++ b/lib/backupclient/BackupClientRestore.h @@ -16,7 +16,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, -- cgit v1.2.3 From 9513d59b275068b8376554561e67b7664cf96b6e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:17:02 +0000 Subject: Use overlapped I/O to avoid blocking. Use INVALID_HANDLE_VALUE instead of NULL everywhere to avoid bugs, and for type safety. (refs #3) --- lib/server/WinNamedPipeStream.cpp | 288 ++++++++++++++++++++++++++++++++++---- lib/server/WinNamedPipeStream.h | 8 +- 2 files changed, 264 insertions(+), 32 deletions(-) diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp index c5b7eaa5..362f3958 100644 --- a/lib/server/WinNamedPipeStream.cpp +++ b/lib/server/WinNamedPipeStream.cpp @@ -35,7 +35,9 @@ // // -------------------------------------------------------------------------- WinNamedPipeStream::WinNamedPipeStream() - : mSocketHandle(NULL), + : mSocketHandle(INVALID_HANDLE_VALUE), + mReadableEvent(INVALID_HANDLE_VALUE), + mBytesInBuffer(0), mReadClosed(false), mWriteClosed(false), mIsServer(false), @@ -53,7 +55,7 @@ WinNamedPipeStream::WinNamedPipeStream() // -------------------------------------------------------------------------- WinNamedPipeStream::~WinNamedPipeStream() { - if (mSocketHandle != NULL) + if (mSocketHandle != INVALID_HANDLE_VALUE) { Close(); } @@ -70,14 +72,15 @@ WinNamedPipeStream::~WinNamedPipeStream() // -------------------------------------------------------------------------- void WinNamedPipeStream::Accept(const wchar_t* pName) { - if (mSocketHandle != NULL || mIsConnected) + if (mSocketHandle != INVALID_HANDLE_VALUE || mIsConnected) { THROW_EXCEPTION(ServerException, SocketAlreadyOpen) } mSocketHandle = CreateNamedPipeW( pName, // pipe name - PIPE_ACCESS_DUPLEX, // read/write access + PIPE_ACCESS_DUPLEX | // read/write access + FILE_FLAG_OVERLAPPED, // enabled overlapped I/O PIPE_TYPE_MESSAGE | // message type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_WAIT, // blocking mode @@ -87,7 +90,7 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) NMPWAIT_USE_DEFAULT_WAIT, // client time-out NULL); // default security attribute - if (mSocketHandle == NULL) + if (mSocketHandle == INVALID_HANDLE_VALUE) { ::syslog(LOG_ERR, "CreateNamedPipeW failed: %d", GetLastError()); @@ -104,10 +107,42 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) 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) + { + ::syslog(LOG_ERR, "Failed to create the Readable event: " + "error %d", 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) + { + ::syslog(LOG_ERR, "Failed to start overlapped read: " + "error %d", err); + Close(); + THROW_EXCEPTION(ConnectionException, + Conn_SocketReadError) + } + } } // -------------------------------------------------------------------------- @@ -120,7 +155,7 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) // -------------------------------------------------------------------------- void WinNamedPipeStream::Connect(const wchar_t* pName) { - if (mSocketHandle != NULL || mIsConnected) + if (mSocketHandle != INVALID_HANDLE_VALUE || mIsConnected) { THROW_EXCEPTION(ServerException, SocketAlreadyOpen) } @@ -137,8 +172,17 @@ void WinNamedPipeStream::Connect(const wchar_t* pName) if (mSocketHandle == INVALID_HANDLE_VALUE) { - ::syslog(LOG_ERR, "Failed to connect to server's named pipe: " - "error %d", GetLastError()); + DWORD err = GetLastError(); + if (err == ERROR_PIPE_BUSY) + { + ::syslog(LOG_ERR, "Failed to connect to backup " + "daemon: it is busy with another connection"); + } + else + { + ::syslog(LOG_ERR, "Failed to connect to backup " + "daemon: error %d", err); + } THROW_EXCEPTION(ServerException, SocketOpenError) } @@ -159,33 +203,171 @@ void WinNamedPipeStream::Connect(const wchar_t* pName) int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) { // TODO no support for timeouts yet - ASSERT(Timeout == IOStream::TimeOutInfinite) + if (Timeout != IOStream::TimeOutInfinite) + { + THROW_EXCEPTION(CommonException, AssertFailed) + } - if (mSocketHandle == NULL || !mIsConnected) + 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; - - 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) + + if (mIsServer) { - THROW_EXCEPTION(ConnectionException, Conn_SocketReadError) + // 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) + { + ::syslog(LOG_ERR, "Control " + "client disconnected"); + } + else + { + ::syslog(LOG_ERR, + "Failed to wait for " + "ReadFile to complete: " + "error %d", 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); + memcpy(mReadBuffer, mReadBuffer + BytesToCopy, BytesRemaining); + + mBytesInBuffer = BytesRemaining; + NumBytesRead = BytesToCopy; + + // 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) + { + ::syslog(LOG_ERR, + "Control client disconnected"); + mReadClosed = true; + } + else + { + ::syslog(LOG_ERR, "Failed to start " + "overlapped read: error %d", 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. + } } - - // Closed for reading at EOF? - if (NumBytesRead == 0) + else { - mReadClosed = true; + if (!ReadFile( + mSocketHandle, // pipe handle + pBuffer, // buffer to receive reply + NBytes, // size of buffer + &NumBytesRead, // number of bytes read + NULL)) // not overlapped + { + Close(); + THROW_EXCEPTION(ConnectionException, + Conn_SocketReadError) + } + + // Closed for reading at EOF? + if (NumBytesRead == 0) + { + mReadClosed = true; + } } - + return NumBytesRead; } @@ -199,7 +381,7 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) // -------------------------------------------------------------------------- void WinNamedPipeStream::Write(const void *pBuffer, int NBytes) { - if (mSocketHandle == NULL || !mIsConnected) + if (mSocketHandle == INVALID_HANDLE_VALUE || !mIsConnected) { THROW_EXCEPTION(ServerException, BadSocketHandle) } @@ -223,7 +405,7 @@ void WinNamedPipeStream::Write(const void *pBuffer, int NBytes) if (!Success) { - mWriteClosed = true; // assume can't write again + Close(); THROW_EXCEPTION(ConnectionException, Conn_SocketWriteError) } @@ -242,20 +424,39 @@ void WinNamedPipeStream::Write(const void *pBuffer, int NBytes) // -------------------------------------------------------------------------- void WinNamedPipeStream::Close() { - if (mSocketHandle == NULL && mIsConnected) + if (mSocketHandle == INVALID_HANDLE_VALUE && mIsConnected) { fprintf(stderr, "Inconsistent connected state\n"); ::syslog(LOG_ERR, "Inconsistent connected state"); mIsConnected = false; } - if (mSocketHandle == NULL) + if (mSocketHandle == INVALID_HANDLE_VALUE) { THROW_EXCEPTION(ServerException, BadSocketHandle) } if (mIsServer) - { + { + if (!CancelIo(mSocketHandle)) + { + ::syslog(LOG_ERR, "Failed to cancel outstanding " + "I/O: error %d", GetLastError()); + } + + if (mReadableEvent == INVALID_HANDLE_VALUE) + { + ::syslog(LOG_ERR, "Failed to destroy Readable " + "event: invalid handle"); + } + else if (!CloseHandle(mReadableEvent)) + { + ::syslog(LOG_ERR, "Failed to destroy Readable " + "event: error %d", GetLastError()); + } + + mReadableEvent = INVALID_HANDLE_VALUE; + if (!FlushFileBuffers(mSocketHandle)) { ::syslog(LOG_INFO, "FlushFileBuffers failed: %d", @@ -273,8 +474,10 @@ void WinNamedPipeStream::Close() bool result = CloseHandle(mSocketHandle); - mSocketHandle = NULL; + mSocketHandle = INVALID_HANDLE_VALUE; mIsConnected = false; + mReadClosed = true; + mWriteClosed = true; if (!result) { @@ -309,4 +512,27 @@ 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)) + { + ::syslog(LOG_WARNING, "FlushFileBuffers failed: %d", + GetLastError()); + } +} + + #endif // WIN32 diff --git a/lib/server/WinNamedPipeStream.h b/lib/server/WinNamedPipeStream.h index 5a800371..aded2d59 100644 --- a/lib/server/WinNamedPipeStream.h +++ b/lib/server/WinNamedPipeStream.h @@ -36,13 +36,15 @@ public: 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;} @@ -51,6 +53,10 @@ private: { /* do not call */ } HANDLE mSocketHandle; + HANDLE mReadableEvent; + OVERLAPPED mReadOverlap; + uint8_t mReadBuffer[4096]; + size_t mBytesInBuffer; bool mReadClosed; bool mWriteClosed; bool mIsServer; -- cgit v1.2.3 From af7651a52c7a9a8c7bddabe473e5c3e8d81adb1a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:17:32 +0000 Subject: Implement LocalProcessStream on Win32. (refs #3) --- lib/server/LocalProcessStream.cpp | 80 +++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/lib/server/LocalProcessStream.cpp b/lib/server/LocalProcessStream.cpp index f1b6b2b8..fef7166b 100644 --- a/lib/server/LocalProcessStream.cpp +++ b/lib/server/LocalProcessStream.cpp @@ -18,10 +18,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 @@ -30,19 +35,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 LocalProcessStream(const char *CommandLine, pid_t &rPidOut) { +#ifndef WIN32 + // Split up command std::vector command; SplitString(std::string(CommandLine), ' ', command); -#ifndef WIN32 // Build arguments char *args[MAX_ARGUMENTS + 4]; { @@ -101,10 +109,68 @@ std::auto_ptr 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 stream; + + SECURITY_ATTRIBUTES secAttr; + secAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + secAttr.bInheritHandle = TRUE; + secAttr.lpSecurityDescriptor = NULL; + + HANDLE writeInChild, readFromChild; + if(!CreatePipe(&readFromChild, &writeInChild, &secAttr, 0)) + { + ::syslog(LOG_ERR, "Failed to CreatePipe for child process: " + "error %d", 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) + { + ::syslog(LOG_ERR, "Failed to CreateProcess: '%s': " + "error %d", CommandLine, GetLastError()); + CloseHandle(writeInChild); + CloseHandle(readFromChild); + THROW_EXCEPTION(ServerException, ServerForkError) + } + + CloseHandle(procInfo.hProcess); + CloseHandle(procInfo.hThread); + CloseHandle(writeInChild); + + rPidOut = (int)(procInfo.dwProcessId); + + std::auto_ptr stream(new FileStream(readFromChild)); return stream; + #endif // ! WIN32 } -- cgit v1.2.3 From 7d2a3c9eb51ac558c0dc70a2194f40935cc9b693 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:20:01 +0000 Subject: Use -1 for INVALID_SOCKET_HANDLE to ensure that it's always less than zero, so that non-conditional code in SocketStream.cpp works properly. Add a method to determine if a socket stream has been attached to a socket yet. (refs #3) --- lib/server/SocketStream.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/server/SocketStream.h b/lib/server/SocketStream.h index 7d5e6d93..51f2e306 100644 --- a/lib/server/SocketStream.h +++ b/lib/server/SocketStream.h @@ -14,7 +14,7 @@ #ifdef WIN32 typedef SOCKET tOSSocketHandle; - #define INVALID_SOCKET_VALUE INVALID_SOCKET + #define INVALID_SOCKET_VALUE (tOSSocketHandle)(-1) #else typedef int tOSSocketHandle; #define INVALID_SOCKET_VALUE -1 @@ -67,6 +67,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 -- cgit v1.2.3 From 75da451418ba6092424f1f7e87f75da72e99a3f5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:20:59 +0000 Subject: Use more accurate sleeps in poll() to ensure that we don't end up busy waiting for the last fraction of a second with repeated poll(..., 0). (refs #3) --- lib/server/SocketStreamTLS.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/lib/server/SocketStreamTLS.cpp b/lib/server/SocketStreamTLS.cpp index af4ad460..58dc5754 100644 --- a/lib/server/SocketStreamTLS.cpp +++ b/lib/server/SocketStreamTLS.cpp @@ -23,6 +23,7 @@ #include "SSLLib.h" #include "ServerException.h" #include "TLSContext.h" +#include "BoxTime.h" #include "MemLeakFindOn.h" @@ -244,20 +245,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) - { - // Signal. Do "time out" - return false; - } - else + int64_t now = BoxTimeToMilliSeconds(GetCurrentBoxTime()); + int poll_timeout = (int)(end - now); + if (poll_timeout < 0) poll_timeout = 0; + if (Timeout == IOStream::TimeOutInfinite) { - // 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: -- cgit v1.2.3 From 68d89b9fe9778478fa4884b4cbfa24c5b99df8ee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:21:36 +0000 Subject: Use BoxConfig-MSVC.h and BoxVersion.h when compiling with MSVC. (refs #3) --- lib/common/BoxPlatform.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h index cb83f7a9..3ae929ef 100644 --- a/lib/common/BoxPlatform.h +++ b/lib/common/BoxPlatform.h @@ -21,7 +21,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() @@ -97,8 +102,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 -- cgit v1.2.3 From 55eb800fe8eb48a13e7f45671284ce5eb536fbee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:22:17 +0000 Subject: Fix memory corruption when the number of not-leaks exceeds the table size. (refs #3) --- lib/common/DebugMemLeakFinder.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp index 17a20a6d..49199f5e 100644 --- a/lib/common/DebugMemLeakFinder.cpp +++ b/lib/common/DebugMemLeakFinder.cpp @@ -183,7 +183,9 @@ void memleakfinder_notaleak(void *ptr) } else { - sNotLeaksPre[sNotLeaksPreNum++] = ptr; + if ( sNotLeaksPreNum < + (unsigned)( sizeof(sNotLeaksPre)/sizeof(*sNotLeaksPre) ) ) + sNotLeaksPre[sNotLeaksPreNum++] = ptr; } /* { std::map::iterator i(sMallocBlocks.find(ptr)); -- cgit v1.2.3 From aa04aefdbd2fcd1fd288b78719f474e6b6fa77fb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:23:03 +0000 Subject: Match case-insensitively on Win32. (refs #3) --- lib/common/ExcludeList.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++---- lib/common/ExcludeList.h | 5 +++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp index 43991594..b13b6026 100644 --- a/lib/common/ExcludeList.cpp +++ b/lib/common/ExcludeList.cpp @@ -65,6 +65,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 // -------------------------------------------------------------------------- // @@ -88,7 +127,16 @@ 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 + + mDefinite.insert(entry); } } } @@ -123,8 +171,18 @@ 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) + if(::regcomp(pregex, entry.c_str(), + REG_EXTENDED | REG_NOSUB) != 0) { THROW_EXCEPTION(CommonException, BadRegularExpression) } @@ -132,7 +190,7 @@ void ExcludeList::AddRegexEntries(const std::string &rEntries) // 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(...) { @@ -158,10 +216,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. @@ -170,7 +234,7 @@ 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; } @@ -180,7 +244,7 @@ bool ExcludeList::IsExcluded(const std::string &rTest) const for(std::vector::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; diff --git a/lib/common/ExcludeList.h b/lib/common/ExcludeList.h index 720b6788..522ee370 100644 --- a/lib/common/ExcludeList.h +++ b/lib/common/ExcludeList.h @@ -63,6 +63,11 @@ private: std::vector 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; }; -- cgit v1.2.3 From 20c177ab912261d24d24e8bef3726a13100c956d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:24:18 +0000 Subject: Set the filename to "HANDLE" under Win32 when initialising from an existing handle. Handle ERROR_BROKEN_PIPE as EOF when using FileStream to read from a pipe in LocalProcessStream. (refs #3) --- lib/common/FileStream.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/common/FileStream.cpp b/lib/common/FileStream.cpp index 02b558bd..89ae7a1f 100644 --- a/lib/common/FileStream.cpp +++ b/lib/common/FileStream.cpp @@ -47,7 +47,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 // @@ -65,6 +65,9 @@ FileStream::FileStream(tOSFileHandle FileDescriptor) MEMLEAKFINDER_NOT_A_LEAK(this); THROW_EXCEPTION(CommonException, OSFileOpenError) } +#ifdef WIN32 + this->fileName = "HANDLE"; +#endif } #if 0 @@ -138,8 +141,14 @@ int FileStream::Read(void *pBuffer, int NBytes, int Timeout) { r = numBytesRead; } + else if (GetLastError() == ERROR_BROKEN_PIPE) + { + r = 0; + } else { + ::syslog(LOG_ERR, "Failed to read from file: error %d", + GetLastError()); r = -1; } #else @@ -307,15 +316,12 @@ void FileStream::Close() #ifdef WIN32 if(::CloseHandle(mOSFileHandle) == 0) - { - THROW_EXCEPTION(CommonException, OSFileCloseError) - } #else if(::close(mOSFileHandle) != 0) +#endif { THROW_EXCEPTION(CommonException, OSFileCloseError) } -#endif mOSFileHandle = INVALID_FILE; mIsEOF = true; -- cgit v1.2.3 From 17aeccfaa339e16e88cf9597730a6960accb9dfd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Oct 2006 23:24:56 +0000 Subject: Add a new CommonException type, AccessDenied (very useful for debugging access errors, and needed by Boxi to report a sensible error to the user). (refs #3) --- lib/common/CommonException.txt | 1 + 1 file changed, 1 insertion(+) 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. -- cgit v1.2.3 From 6e725ef45d8800908e93b095bc33ede462c0dcef Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Oct 2006 19:39:04 +0000 Subject: Wait longer for server to die in KillServer (takes about 5 seconds on my box). (refs #3) --- lib/common/Test.h | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 35e9ba58..1312241d 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -227,7 +227,7 @@ bool SendCommands(const std::string& rCmd) return statusOk; } -inline bool ServerIsAlive() +inline bool ServerIsAlive(int pid) { return SendCommands(""); } @@ -237,11 +237,9 @@ inline bool HUPServer(int pid) return SendCommands("reload"); } -inline bool KillServer(int pid) +inline bool KillServerInternal(int pid) { TEST_THAT(SendCommands("terminate")); - ::sleep(1); - return !ServerIsAlive(); } #else // !WIN32 @@ -258,17 +256,45 @@ inline bool HUPServer(int pid) return ::kill(pid, SIGHUP) != -1; } -inline bool KillServer(int pid) +inline bool KillServerInternal(int pid) { if(pid == 0 || pid == -1) return false; - bool KilledOK = ::kill(pid, SIGTERM) != -1; - TEST_THAT(KilledOK); - ::sleep(1); - return !ServerIsAlive(pid); + TEST_THAT(::kill(pid, SIGTERM) != -1); } #endif // WIN32 +inline bool KillServer(int pid) +{ + KillServerInternal(pid); + + for (int i = 0; i < 30; i++) + { + if (!ServerIsAlive(pid)) break; + ::sleep(1); + if (!ServerIsAlive(pid)) break; + + if (i == 0) + { + printf("waiting for server to die"); + } + printf("."); + fflush(stdout); + } + + if (!ServerIsAlive(pid)) + { + printf("done.\n"); + } + else + { + printf("failed!\n"); + } + fflush(stdout); + + return !ServerIsAlive(pid); +} + inline void TestRemoteProcessMemLeaks(const char *filename) { #ifdef BOX_MEMORY_LEAK_TESTING -- cgit v1.2.3 From 646f1f96f80dd16dbd83b21fbe8fcbc9db451c4e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Oct 2006 19:41:33 +0000 Subject: Update description with another possible cause of this error --- lib/server/ConnectionException.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 -- cgit v1.2.3 From 598b7bd0699b46b91a2e445338f389a14d4773e8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Oct 2006 19:44:20 +0000 Subject: Reinstate ifdefs around code that should be disabled on Win32 (fake fork() seems to be a bad idea). Comment spelling fixes. (refs #3) --- lib/server/ServerStream.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h index 67890d83..49479039 100644 --- a/lib/server/ServerStream.h +++ b/lib/server/ServerStream.h @@ -60,7 +60,7 @@ public: virtual void Run() { - // Set process title as appropraite + // Set process title as appropriate SetProcessTitle(ForkToHandleRequests?"server":"idle"); // Handle exceptions and child task quitting gracefully. @@ -217,7 +217,8 @@ public: if(connection.get()) { // Since this is a template parameter, the if() will be optimised out by the compiler - if(WillForkToHandleRequests()) + #ifndef WIN32 // no fork on Win32 + if(ForkToHandleRequests) { pid_t pid = ::fork(); switch(pid) @@ -257,18 +258,22 @@ public: } else { + #endif // !WIN32 // Just handle in this connection SetProcessTitle("handling"); HandleConnection(*connection); SetProcessTitle("idle"); + #ifndef WIN32 } + #endif // !WIN32 } } OnIdle(); + #ifndef WIN32 // Clean up child processes (if forking daemon) - if(WillForkToHandleRequests()) + if(ForkToHandleRequests) { int status = 0; int p = 0; @@ -281,6 +286,7 @@ public: } } while(p > 0); } + #endif // !WIN32 } } catch(...) @@ -301,7 +307,7 @@ 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() { -- cgit v1.2.3 From a8fe12e18fcdb50d9f6cf93d9a642e22f25c0184 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Oct 2006 19:48:50 +0000 Subject: Reinstate #ifdefs on Win32. (refs #3) --- bin/bbstored/BackupStoreDaemon.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index ce7263da..f4968a46 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -42,6 +42,7 @@ BackupStoreDaemon::BackupStoreDaemon() mExtendedLogging(false), mHaveForkedHousekeeping(false), mIsHousekeepingProcess(false), + mHousekeepingInited(false), mInterProcessComms(mInterProcessCommsSocket) { } @@ -159,6 +160,9 @@ void BackupStoreDaemon::Run() const Configuration &config(GetConfiguration()); mExtendedLogging = config.GetKeyValueBool("ExtendedLogging"); +#ifdef WIN32 + // Housekeeping runs synchronously on Win32 +#else // Fork off housekeeping daemon -- must only do this the first time Run() is called if(!mHaveForkedHousekeeping) { @@ -214,6 +218,7 @@ void BackupStoreDaemon::Run() THROW_EXCEPTION(ServerException, SocketCloseError) } } +#endif // WIN32 if(mIsHousekeepingProcess) { -- cgit v1.2.3 From db5c857339b5079d82901249af93bba2b960ee72 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Oct 2006 19:50:07 +0000 Subject: Catch exceptions from BackupStoreDaemon::Run and log them without killing the server process, on platforms where forking is disabled (Win32). (refs #3) --- bin/bbstored/BackupStoreDaemon.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index f4968a46..196cacfb 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -228,13 +228,38 @@ void BackupStoreDaemon::Run() else { // In server process -- use the base class to do the magic - ServerTLS::Run(); - + try + { + ServerTLS::Run(); + } + catch(BoxException &e) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "exception %s (%d/%d)", DaemonName(), + e.what(), e.GetType(), e.GetSubType()); + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "exception %s", DaemonName(), e.what()); + } + catch(...) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "unknown exception", DaemonName()); + } + + if (!mInterProcessCommsSocket.IsOpened()) + { + return; + } + // Why did it stop? Tell the housekeeping process to do the same if(IsReloadConfigWanted()) { mInterProcessCommsSocket.Write("h\n", 2); } + if(IsTerminateWanted()) { mInterProcessCommsSocket.Write("t\n", 2); -- cgit v1.2.3 From dee6b0ac8cf237670d63fce5f95a95effcbe6ffa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 27 Oct 2006 19:08:07 +0000 Subject: Remove double initialisation (now done in infrastructure/buildenv-testmain-template.cpp) (refs #3) --- test/backupstore/testbackupstore.cpp | 89 +++++++++++------------------------- 1 file changed, 26 insertions(+), 63 deletions(-) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index 01e7c57d..756fb03c 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -948,7 +948,7 @@ int test_server(const char *hostname) // Set the client store marker protocol.QuerySetClientStoreMarker(0x8732523ab23aLL); -#ifndef WIN32 // can't open more than one connection on Win32 +#ifndef WIN32 // Open a new connection which is read only SocketStreamTLS connReadOnly; connReadOnly.Open(context, Socket::TypeINET, hostname, BOX_PORT_BBSTORED); @@ -968,7 +968,6 @@ int test_server(const char *hostname) TEST_THAT(loginConf->GetClientStoreMarker() == 0x8732523ab23aLL); } #else // WIN32 - // we can't open a new connection, so fake it BackupProtocolClient& protocolReadOnly(protocol); #endif @@ -1531,48 +1530,35 @@ int test3(int argc, const char *argv[]) // The test block to a file { - FileStream f("testfiles" DIRECTORY_SEPARATOR - "testenc1", O_WRONLY | O_CREAT | O_EXCL); + FileStream f("testfiles/testenc1", O_WRONLY | O_CREAT | O_EXCL); f.Write(encfile, sizeof(encfile)); } // Encode it { - FileStream out("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc", O_WRONLY | O_CREAT | O_EXCL); - BackupStoreFilenameClear name("testfiles" - DIRECTORY_SEPARATOR "testenc1"); + FileStream out("testfiles/testenc1_enc", O_WRONLY | O_CREAT | O_EXCL); + BackupStoreFilenameClear name("testfiles/testenc1"); - std::auto_ptr encoded( - BackupStoreFile::EncodeFile( - "testfiles" DIRECTORY_SEPARATOR - "testenc1", 32, name)); + std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/testenc1", 32, name)); encoded->CopyStreamTo(out); } // Verify it { - FileStream enc("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc"); + FileStream enc("testfiles/testenc1_enc"); TEST_THAT(BackupStoreFile::VerifyEncodedFileFormat(enc) == true); } // Decode it { - FileStream enc("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc"); - BackupStoreFile::DecodeFile(enc, "testfiles" - DIRECTORY_SEPARATOR "testenc1_orig", - IOStream::TimeOutInfinite); + FileStream enc("testfiles/testenc1_enc"); + BackupStoreFile::DecodeFile(enc, "testfiles/testenc1_orig", IOStream::TimeOutInfinite); } // Read in rebuilt original, and compare contents { - TEST_THAT(TestGetFileSize("testfiles" - DIRECTORY_SEPARATOR "testenc1_orig") - == sizeof(encfile)); - FileStream in("testfiles" DIRECTORY_SEPARATOR - "testenc1_orig"); + TEST_THAT(TestGetFileSize("testfiles/testenc1_orig") == sizeof(encfile)); + FileStream in("testfiles/testenc1_orig"); int encfile_i[ENCFILE_SIZE]; in.Read(encfile_i, sizeof(encfile_i)); TEST_THAT(memcmp(encfile, encfile_i, sizeof(encfile)) == 0); @@ -1580,8 +1566,7 @@ int test3(int argc, const char *argv[]) // Check how many blocks it had, and test the stream based interface { - FileStream enc("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc"); + FileStream enc("testfiles/testenc1_enc"); std::auto_ptr decoded(BackupStoreFile::DecodeFileStream(enc, IOStream::TimeOutInfinite)); CollectInBufferStream d; decoded->CopyStreamTo(d, IOStream::TimeOutInfinite, 971 /* buffer block size */); @@ -1595,15 +1580,10 @@ int test3(int argc, const char *argv[]) // Test that the last block in a file, if less than 256 bytes, gets put into the last block { #define FILE_SIZE_JUST_OVER ((4096*2)+58) - FileStream f("testfiles" DIRECTORY_SEPARATOR - "testenc2", O_WRONLY | O_CREAT | O_EXCL); + FileStream f("testfiles/testenc2", O_WRONLY | O_CREAT | O_EXCL); f.Write(encfile + 2, FILE_SIZE_JUST_OVER); - f.Close(); BackupStoreFilenameClear name("testenc2"); - std::auto_ptr encoded( - BackupStoreFile::EncodeFile( - "testfiles" DIRECTORY_SEPARATOR - "testenc2", 32, name)); + std::auto_ptr encoded(BackupStoreFile::EncodeFile("testfiles/testenc2", 32, name)); CollectInBufferStream e; encoded->CopyStreamTo(e); e.SetForReading(); @@ -1619,8 +1599,7 @@ int test3(int argc, const char *argv[]) // Test that reordered streams work too { - FileStream enc("testfiles" DIRECTORY_SEPARATOR - "testenc1_enc"); + FileStream enc("testfiles/testenc1_enc"); std::auto_ptr reordered(BackupStoreFile::ReorderFileToStreamOrder(&enc, false)); std::auto_ptr decoded(BackupStoreFile::DecodeFileStream(*reordered, IOStream::TimeOutInfinite)); CollectInBufferStream d; @@ -1652,14 +1631,9 @@ int test3(int argc, const char *argv[]) // Store info { RaidFileWrite::CreateDirectory(0, "test-info"); - BackupStoreInfo::CreateNew(76, "test-info" DIRECTORY_SEPARATOR, - 0, 3461231233455433LL, 2934852487LL); - TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, - "test-info" DIRECTORY_SEPARATOR, 0, 0, 0), - RaidFileException, CannotOverwriteExistingFile); - std::auto_ptr info( - BackupStoreInfo::Load(76, - "test-info" DIRECTORY_SEPARATOR, 0, true)); + BackupStoreInfo::CreateNew(76, "test-info/", 0, 3461231233455433LL, 2934852487LL); + TEST_CHECK_THROWS(BackupStoreInfo::CreateNew(76, "test-info/", 0, 0, 0), RaidFileException, CannotOverwriteExistingFile); + std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, true)); TEST_CHECK_THROWS(info->Save(), BackupStoreException, StoreInfoIsReadOnly); TEST_CHECK_THROWS(info->ChangeBlocksUsed(1), BackupStoreException, StoreInfoIsReadOnly); TEST_CHECK_THROWS(info->ChangeBlocksInOldFiles(1), BackupStoreException, StoreInfoIsReadOnly); @@ -1668,8 +1642,7 @@ int test3(int argc, const char *argv[]) TEST_CHECK_THROWS(info->AddDeletedDirectory(2), BackupStoreException, StoreInfoIsReadOnly); } { - std::auto_ptr info(BackupStoreInfo::Load(76, - "test-info" DIRECTORY_SEPARATOR, 0, false)); + std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, false)); info->ChangeBlocksUsed(8); info->ChangeBlocksInOldFiles(9); info->ChangeBlocksInDeletedFiles(10); @@ -1687,8 +1660,7 @@ int test3(int argc, const char *argv[]) info->Save(); } { - std::auto_ptr info(BackupStoreInfo::Load(76, - "test-info" DIRECTORY_SEPARATOR, 0, true)); + std::auto_ptr info(BackupStoreInfo::Load(76, "test-info/", 0, true)); TEST_THAT(info->GetBlocksUsed() == 7); TEST_THAT(info->GetBlocksInOldFiles() == 5); TEST_THAT(info->GetBlocksInDeletedFiles() == 1); @@ -1706,9 +1678,9 @@ int test3(int argc, const char *argv[]) // Context TLSContext context; context.Initialise(false /* client */, - "testfiles" DIRECTORY_SEPARATOR "clientCerts.pem", - "testfiles" DIRECTORY_SEPARATOR "clientPrivKey.pem", - "testfiles" DIRECTORY_SEPARATOR "clientTrustedCAs.pem"); + "testfiles/clientCerts.pem", + "testfiles/clientPrivKey.pem", + "testfiles/clientTrustedCAs.pem"); // First, try logging in without an account having been created... just make sure login fails. int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); @@ -1740,7 +1712,7 @@ int test3(int argc, const char *argv[]) } // Create an account for the test client - TEST_THAT_ABORTONFAIL(RunCommand("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); + TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567")); @@ -1771,7 +1743,7 @@ int test3(int argc, const char *argv[]) // Set a new limit on the account -- leave the hard limit high to make sure the target for // freeing space is the soft limit. - TEST_THAT_ABORTONFAIL(RunCommand("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); + TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Start things up @@ -1800,7 +1772,7 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(after.old == 0); // Set a really small hard limit - TEST_THAT_ABORTONFAIL(RunCommand("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); + TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Try to upload a file and create a directory, and check an error is generated @@ -1864,11 +1836,8 @@ int multi_server() printf("Starting server for connection from remote machines...\n"); // Create an account for the test client - TEST_THAT_ABORTONFAIL(RunCommand("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); - -#ifndef WIN32 + TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); -#endif // First, try logging in without an account having been created... just make sure login fails. int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid"); @@ -1905,12 +1874,6 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName); int test(int argc, const char *argv[]) { #ifdef WIN32 - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) - // this had better work, or bbstored will die when combining diffs char* file = "foo"; std::string abs = ConvertPathToAbsoluteUnicode(file); -- cgit v1.2.3 From fcb18d47d0f362459407961fb1ce698694987630 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 27 Oct 2006 19:09:40 +0000 Subject: Remove double initialisation of winsock library. (refs #3) --- test/backupstorepatch/testbackupstorepatch.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index 8e2fa5f6..b33e8e73 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -283,14 +283,6 @@ void test_depends_in_dirs() int test(int argc, const char *argv[]) { -#ifdef WIN32 - // Under win32 we must initialise the Winsock library - // before using sockets - - WSADATA info; - TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) -#endif - // Allocate a buffer buffer = ::malloc(BUFFER_SIZE); TEST_THAT(buffer != 0); -- cgit v1.2.3 From ee4dc408e4ce8364322ea19a4fabbb5e8edf4d46 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Nov 2006 20:40:46 +0000 Subject: Compile fix --- bin/bbstored/BackupStoreDaemon.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 196cacfb..e09bd17d 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -42,7 +42,6 @@ BackupStoreDaemon::BackupStoreDaemon() mExtendedLogging(false), mHaveForkedHousekeeping(false), mIsHousekeepingProcess(false), - mHousekeepingInited(false), mInterProcessComms(mInterProcessCommsSocket) { } -- cgit v1.2.3 From 3a590d43ce5e108e42483993b3ce7bfaaa20d74d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Nov 2006 20:43:12 +0000 Subject: Added generic timer support class --- lib/common/BoxTime.h | 5 +- lib/common/Timer.cpp | 252 +++++++++++++++++++++++++++++++++++++++++++++ lib/common/Timer.h | 65 ++++++++++++ test/common/testcommon.cpp | 51 +++++++++ 4 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 lib/common/Timer.cpp create mode 100644 lib/common/Timer.h diff --git a/lib/common/BoxTime.h b/lib/common/BoxTime.h index 398e6b1c..e62a77ab 100644 --- a/lib/common/BoxTime.h +++ b/lib/common/BoxTime.h @@ -35,6 +35,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/Timer.cpp b/lib/common/Timer.cpp new file mode 100644 index 00000000..e05affb2 --- /dev/null +++ b/lib/common/Timer.cpp @@ -0,0 +1,252 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: Timer.cpp +// Purpose: Generic timers which execute arbitrary code when +// they expire. +// Created: 5/11/2006 +// +// -------------------------------------------------------------------------- + +#include "Box.h" + +#include + +#include "Timer.h" + +#include "MemLeakFindOn.h" + +std::vector Timers::sTimers; +bool Timers::sInitialised = false; + +// -------------------------------------------------------------------------- +// +// Function +// Name: static void TimerSigHandler(int) +// Purpose: Signal handler, notifies Timers class +// Created: 19/3/04 +// +// -------------------------------------------------------------------------- +static void TimerSigHandler(int iUnused) +{ + Timers::Signal(); +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: static void Timers::Init() +// Purpose: Initialise timers, prepare signal handler +// Created: 5/11/2006 +// +// -------------------------------------------------------------------------- +void Timers::Init() +{ + ASSERT(!sInitialised); + + #ifdef PLATFORM_CYGWIN + ASSERT(::signal(SIGALRM, TimerSigHandler) == 0); + #elif defined WIN32 + // no support for signals at all + InitTimer(); + SetTimerHandler(TimerSigHandler); + #else + ASSERT(::signal(SIGALRM, TimerSigHandler) == 0); + #endif // PLATFORM_CYGWIN + + sInitialised = true; +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: static void Timers::Cleanup() +// Purpose: Clean up timers, stop signal handler +// Created: 6/11/2006 +// +// -------------------------------------------------------------------------- +void Timers::Cleanup() +{ + ASSERT(sInitialised); + + #ifdef PLATFORM_CYGWIN + ASSERT(::signal(SIGALRM, NULL) == TimerSigHandler); + #elif defined WIN32 + // no support for signals at all + SetTimerHandler(NULL); + FiniTimer(); + #else + ASSERT(::signal(SIGALRM, NULL) == TimerSigHandler); + #endif // PLATFORM_CYGWIN + + sTimers.clear(); + + sInitialised = false; +} + +// -------------------------------------------------------------------------- +// +// 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(sInitialised); + sTimers.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(sInitialised); + + bool restart = true; + while (restart) + { + restart = false; + for (std::vector::iterator i = sTimers.begin(); + i != sTimers.end(); i++) + { + if (&rTimer == *i) + { + sTimers.erase(i); + restart = true; + break; + } + } + } + + Reschedule(); +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: static void Timers::Reschedule() +// Purpose: Recalculate when the next wakeup is due +// Created: 5/11/2006 +// +// -------------------------------------------------------------------------- +void Timers::Reschedule() +{ + ASSERT(sInitialised); + + box_time_t timeNow = GetCurrentBoxTime(); + box_time_t timeToNextEvent = 0; + + for (std::vector::iterator i = sTimers.begin(); + i != sTimers.end(); i++) + { + Timer& rTimer = **i; + ASSERT(!rTimer.HasExpired()); + + box_time_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; + + 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); + +#ifdef PLATFORM_CYGWIN + if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) +#else + if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) +#endif // PLATFORM_CYGWIN + { + TRACE0("WARNING: couldn't initialise timer\n"); + THROW_EXCEPTION(CommonException, Internal) + } +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: static void Timers::Signal() +// Purpose: Called by signal handler. Signals any timers which +// are due or overdue, removes them from the set, +// and reschedules next wakeup. +// Created: 5/11/2006 +// +// -------------------------------------------------------------------------- +void Timers::Signal() +{ + ASSERT(sInitialised); + + box_time_t timeNow = GetCurrentBoxTime(); + + std::vector timersCopy = sTimers; + + for (std::vector::iterator i = timersCopy.begin(); + i != timersCopy.end(); i++) + { + Timer& rTimer = **i; + ASSERT(!rTimer.HasExpired()); + + box_time_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; + + if (timeToExpiry <= 0) + { + rTimer.OnExpire(); + } + } + + Reschedule(); +} + +Timer::Timer(size_t timeoutSecs) +: mExpires(GetCurrentBoxTime() + SecondsToBoxTime(timeoutSecs)), + mExpired(false) +{ + Timers::Add(*this); +} + +Timer::~Timer() +{ + Timers::Remove(*this); +} + +Timer::Timer(const Timer& rToCopy) +: mExpires(rToCopy.mExpires), + mExpired(rToCopy.mExpired) +{ + Timers::Add(*this); +} + +Timer& Timer::operator=(const Timer& rToCopy) +{ + Timers::Remove(*this); + mExpires = rToCopy.mExpires; + mExpired = rToCopy.mExpired; + if (!mExpired) + { + Timers::Add(*this); + } +} + +void Timer::OnExpire() +{ + mExpired = true; + Timers::Remove(*this); +} diff --git a/lib/common/Timer.h b/lib/common/Timer.h new file mode 100644 index 00000000..6e4a5952 --- /dev/null +++ b/lib/common/Timer.h @@ -0,0 +1,65 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: Timer.h +// Purpose: Generic timers which execute arbitrary code when +// they expire. +// Created: 5/11/2006 +// +// -------------------------------------------------------------------------- + +#ifndef TIMER__H +#define TIMER__H + +#include + +#include + +#include "MemLeakFindOn.h" +#include "BoxTime.h" + +class Timer +{ +public: + Timer(size_t timeoutSecs); + virtual ~Timer(); + Timer(const Timer &); + Timer &operator=(const Timer &); + +public: + box_time_t GetExpiryTime() { return mExpires; } + bool HasExpired () { return mExpired; } + virtual void OnExpire (); + +private: + box_time_t mExpires; + bool mExpired; +}; + +// -------------------------------------------------------------------------- +// +// 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 sTimers; + static bool sInitialised; + static void Reschedule(); + + public: + static void Init(); + static void Cleanup(); + static void Add (Timer& rTimer); + static void Remove(Timer& rTimer); + static void Signal(); +}; + +#include "MemLeakFindOff.h" + +#endif // TIMER__H diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 4f82f587..48d6a67b 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -27,6 +27,7 @@ #include "autogen_ConversionException.h" #include "CollectInBufferStream.h" #include "Archive.h" +#include "Timer.h" #include "MemLeakFindOn.h" @@ -204,6 +205,56 @@ int test(int argc, const char *argv[]) } #endif // BOX_MEMORY_LEAK_TESTING + // Check that using timer methods without initialisation + // throws an exception + TEST_CHECK_THROWS(Timers::Add(*(Timer*)NULL), + CommonException, AssertFailed); + TEST_CHECK_THROWS(Timers::Remove(*(Timer*)NULL), + CommonException, AssertFailed); + TEST_CHECK_THROWS(Timers::Signal(), CommonException, AssertFailed); + TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, AssertFailed); + + // Check that we can initialise the timers + Timers::Init(); + + // Check that double initialisation throws an exception + TEST_CHECK_THROWS(Timers::Init(), CommonException, AssertFailed); + + // Check that we can clean up the timers + Timers::Cleanup(); + + // Check that double cleanup throws an exception + TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, AssertFailed); + + Timers::Init(); + + Timer t1(1); + Timer t2(2); + Timer t3(3); + + TEST_THAT(!t1.HasExpired()); + TEST_THAT(!t2.HasExpired()); + TEST_THAT(!t3.HasExpired()); + + sleep(1); + TEST_THAT(t1.HasExpired()); + TEST_THAT(!t2.HasExpired()); + TEST_THAT(!t3.HasExpired()); + + sleep(1); + TEST_THAT(t1.HasExpired()); + TEST_THAT(t2.HasExpired()); + TEST_THAT(!t3.HasExpired()); + + t1 = Timer(1); + t2 = Timer(2); + TEST_THAT(!t1.HasExpired()); + TEST_THAT(!t2.HasExpired()); + + sleep(1); + TEST_THAT(t1.HasExpired()); + TEST_THAT(!t2.HasExpired()); + TEST_THAT(t3.HasExpired()); static char *testfilelines[] = { -- cgit v1.2.3 From 45a95c864a32098eb9ac73b9c5fec1fa25061f3d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Nov 2006 20:45:32 +0000 Subject: Protect against double initialisation of win32 timers --- lib/win32/emu.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 6ce1790c..205ada9b 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -28,6 +28,7 @@ // 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; @@ -43,6 +44,8 @@ static void (__cdecl *gTimerFunc) (int) = NULL; int setitimer(int type, struct itimerval *timeout, void *arg) { + ASSERT(gTimerInitialised); + if (ITIMER_VIRTUAL == type) { EnterCriticalSection(&gLock); @@ -131,20 +134,25 @@ int SetTimerHandler(void (__cdecl *func ) (int)) void InitTimer(void) { + 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 -- cgit v1.2.3 From c1cdd7f245f9d8d1d26440c70689d08e4078a2a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Nov 2006 20:47:15 +0000 Subject: Fix compile warnings (refs #3) --- lib/common/DebugMemLeakFinder.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp index 49199f5e..71665102 100644 --- a/lib/common/DebugMemLeakFinder.cpp +++ b/lib/common/DebugMemLeakFinder.cpp @@ -55,7 +55,7 @@ namespace static std::set sNotLeaks; void *sNotLeaksPre[1024]; - int sNotLeaksPreNum = 0; + size_t sNotLeaksPreNum = 0; } void memleakfinder_malloc_add_block(void *b, size_t size, const char *file, int line) @@ -161,7 +161,7 @@ void memleakfinder_free(void *ptr) void memleakfinder_notaleak_insert_pre() { if(!memleakfinder_global_enable) return; - for(int l = 0; l < sNotLeaksPreNum; l++) + for(size_t l = 0; l < sNotLeaksPreNum; l++) { sNotLeaks.insert(sNotLeaksPre[l]); } @@ -184,7 +184,7 @@ void memleakfinder_notaleak(void *ptr) else { if ( sNotLeaksPreNum < - (unsigned)( sizeof(sNotLeaksPre)/sizeof(*sNotLeaksPre) ) ) + sizeof(sNotLeaksPre)/sizeof(*sNotLeaksPre) ) sNotLeaksPre[sNotLeaksPreNum++] = ptr; } /* { @@ -255,11 +255,11 @@ void memleakfinder_reportleaks_file(FILE *file) { for(std::map::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::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); } } -- cgit v1.2.3 From c2758bb493be6edb1aa509f1161c1c220b9fc90f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:13:58 +0000 Subject: Fix scoping to ensure that objects which allocate memory via the standard libraries, free it before the memleak tests, to avoid test failures (refs #3) --- test/common/testcommon.cpp | 88 +++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 48d6a67b..aa4b3ec5 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -137,56 +137,67 @@ ConfigurationVerify verify = int test(int argc, const char *argv[]) { // Test self-deleting temporary file streams - std::string tempfile("testfiles/tempfile"); - TEST_CHECK_THROWS(InvisibleTempFileStream fs(tempfile.c_str()), - CommonException, OSFileOpenError); - InvisibleTempFileStream fs(tempfile.c_str(), O_CREAT); + { + std::string tempfile("testfiles/tempfile"); + TEST_CHECK_THROWS(InvisibleTempFileStream fs(tempfile.c_str()), + CommonException, OSFileOpenError); + InvisibleTempFileStream fs(tempfile.c_str(), O_CREAT); -#ifdef WIN32 - // file is still visible under Windows - TEST_THAT(TestFileExists(tempfile.c_str())); + #ifdef WIN32 + // file is still visible under Windows + TEST_THAT(TestFileExists(tempfile.c_str())); - // opening it again should work - InvisibleTempFileStream fs2(tempfile.c_str()); - TEST_THAT(TestFileExists(tempfile.c_str())); + // opening it again should work + InvisibleTempFileStream fs2(tempfile.c_str()); + TEST_THAT(TestFileExists(tempfile.c_str())); - // opening it to create should work - InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT); - TEST_THAT(TestFileExists(tempfile.c_str())); + // opening it to create should work + InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT); + TEST_THAT(TestFileExists(tempfile.c_str())); - // opening it to create exclusively should fail - TEST_CHECK_THROWS(InvisibleTempFileStream fs4(tempfile.c_str(), - O_CREAT | O_EXCL), CommonException, OSFileOpenError); + // opening it to create exclusively should fail + TEST_CHECK_THROWS(InvisibleTempFileStream fs4(tempfile.c_str(), + O_CREAT | O_EXCL), CommonException, OSFileOpenError); - fs2.Close(); -#else - // file is not visible under Unix - TEST_THAT(!TestFileExists(tempfile.c_str())); + fs2.Close(); + #else + // file is not visible under Unix + TEST_THAT(!TestFileExists(tempfile.c_str())); - // opening it again should fail - TEST_CHECK_THROWS(InvisibleTempFileStream fs2(tempfile.c_str()), - CommonException, OSFileOpenError); + // opening it again should fail + TEST_CHECK_THROWS(InvisibleTempFileStream fs2(tempfile.c_str()), + CommonException, OSFileOpenError); - // opening it to create should work - InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT); - TEST_THAT(!TestFileExists(tempfile.c_str())); + // opening it to create should work + InvisibleTempFileStream fs3(tempfile.c_str(), O_CREAT); + TEST_THAT(!TestFileExists(tempfile.c_str())); - // opening it to create exclusively should work - InvisibleTempFileStream fs4(tempfile.c_str(), O_CREAT | O_EXCL); - TEST_THAT(!TestFileExists(tempfile.c_str())); + // opening it to create exclusively should work + InvisibleTempFileStream fs4(tempfile.c_str(), O_CREAT | O_EXCL); + TEST_THAT(!TestFileExists(tempfile.c_str())); - fs4.Close(); -#endif + fs4.Close(); + #endif - fs.Close(); - fs3.Close(); + fs.Close(); + fs3.Close(); - // now that it's closed, it should be invisible on all platforms - TEST_THAT(!TestFileExists(tempfile.c_str())); + // now that it's closed, it should be invisible on all platforms + TEST_THAT(!TestFileExists(tempfile.c_str())); + } + + // Test that memory leak detection doesn't crash + { + char *test = new char[1024]; + delete [] test; + MemBlockStream *s = new MemBlockStream(test,12); + delete s; + } - // Test memory leak detection #ifdef BOX_MEMORY_LEAK_TESTING { + Timers::Cleanup(); + TEST_THAT(memleakfinder_numleaks() == 0); void *block = ::malloc(12); TEST_THAT(memleakfinder_numleaks() == 1); @@ -202,8 +213,13 @@ int test(int argc, const char *argv[]) TEST_THAT(memleakfinder_numleaks() == 1); delete [] test; TEST_THAT(memleakfinder_numleaks() == 0); + + Timers::Init(); } #endif // BOX_MEMORY_LEAK_TESTING + + // test main() initialises timers for us, so uninitialise them + Timers::Cleanup(); // Check that using timer methods without initialisation // throws an exception -- cgit v1.2.3 From dc10cd5a1cb2814ccd9ee0c6be118c70fcacdd75 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:15:23 +0000 Subject: Added tests for timers with zero interval, which should never expire (refs #9) --- test/common/testcommon.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index aa4b3ec5..04d93bb2 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -244,34 +244,43 @@ int test(int argc, const char *argv[]) Timers::Init(); + Timer t0(0); // should never expire Timer t1(1); Timer t2(2); Timer t3(3); + TEST_THAT(!t0.HasExpired()); TEST_THAT(!t1.HasExpired()); TEST_THAT(!t2.HasExpired()); TEST_THAT(!t3.HasExpired()); sleep(1); + TEST_THAT(!t0.HasExpired()); TEST_THAT(t1.HasExpired()); TEST_THAT(!t2.HasExpired()); TEST_THAT(!t3.HasExpired()); sleep(1); + TEST_THAT(!t0.HasExpired()); TEST_THAT(t1.HasExpired()); TEST_THAT(t2.HasExpired()); TEST_THAT(!t3.HasExpired()); t1 = Timer(1); t2 = Timer(2); + TEST_THAT(!t0.HasExpired()); TEST_THAT(!t1.HasExpired()); TEST_THAT(!t2.HasExpired()); sleep(1); + TEST_THAT(!t0.HasExpired()); TEST_THAT(t1.HasExpired()); TEST_THAT(!t2.HasExpired()); TEST_THAT(t3.HasExpired()); + // Leave timers initialised for rest of test. + // Test main() will cleanup after test finishes. + static char *testfilelines[] = { "First line", -- cgit v1.2.3 From e2215d1c9d5a848aea2f8564203d8760251a6076 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:20:56 +0000 Subject: Force glibc to use new/delete to allocate memory and disable its internal pools for the unit tests, to make memory leak detection work (refs #3) --- infrastructure/makebuildenv.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index 41623bc2..75912ca1 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -422,9 +422,9 @@ __E close TESTFILE; } - writetestfile("$mod/_t", + writetestfile("$mod/_t", "GLIBCXX_FORCE_NEW=1 ". './test' . $platform_exe_ext . ' $1 $2 $3 $4 $5', $mod); - writetestfile("$mod/_t-gdb", + writetestfile("$mod/_t-gdb", "GLIBCXX_FORCE_NEW=1 ". 'gdb ./test' . $platform_exe_ext, $mod); } -- cgit v1.2.3 From b876d56a587877fbf9f98224bf97fa7d3b2622e4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:46:08 +0000 Subject: Fixed typo. --- lib/backupstore/BackupStoreCheck2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/backupstore/BackupStoreCheck2.cpp b/lib/backupstore/BackupStoreCheck2.cpp index 63e7c008..7bc9a109 100644 --- a/lib/backupstore/BackupStoreCheck2.cpp +++ b/lib/backupstore/BackupStoreCheck2.cpp @@ -653,7 +653,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); -- cgit v1.2.3 From 13def59b473a788b89c5857be0502c330d944c64 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:49:48 +0000 Subject: Fix memory leak when TLSContext is reinitialised (refs #3) --- lib/server/TLSContext.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/server/TLSContext.cpp b/lib/server/TLSContext.cpp index cc125d00..49143801 100644 --- a/lib/server/TLSContext.cpp +++ b/lib/server/TLSContext.cpp @@ -61,6 +61,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) { -- cgit v1.2.3 From c238a4fdfc485654d8b1181fbf220d8e560bddd3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:50:21 +0000 Subject: Fixed typo (refs #3) --- lib/server/ServerStream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h index 49479039..d5abccdd 100644 --- a/lib/server/ServerStream.h +++ b/lib/server/ServerStream.h @@ -259,7 +259,7 @@ public: else { #endif // !WIN32 - // Just handle in this connection + // Just handle in this process SetProcessTitle("handling"); HandleConnection(*connection); SetProcessTitle("idle"); -- cgit v1.2.3 From f0095d3b907bd38be741ceca9f5fa6998738f660 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:53:29 +0000 Subject: Declare MEMLEAKFINDER_INIT and MEMLEAKFINDER_NO_LEAKS macros which reference function and class in DebugMemLeakFinder only in debug mode (refs #3) --- lib/common/Box.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/common/Box.h b/lib/common/Box.h index eb33673c..86c34acb 100644 --- a/lib/common/Box.h +++ b/lib/common/Box.h @@ -95,16 +95,19 @@ // Memory leak testing #include "MemLeakFinder.h" #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 \ -- cgit v1.2.3 From 826c2675ec1c2cb60e0ef1842c7a5ff7a548eeaa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:54:49 +0000 Subject: Free backtrace strings even in debug mode by suppressing warnings from DebugMemLeakFinder, to avoid a memory leak (refs #3) --- lib/common/Utils.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/common/Utils.cpp b/lib/common/Utils.cpp index 63d45b5a..ae06dc70 100644 --- a/lib/common/Utils.cpp +++ b/lib/common/Utils.cpp @@ -74,11 +74,13 @@ void DumpStackBacktrace() printf ("Obtained %zd stack frames.\n", size); for(i = 0; i < size; i++) + { printf("%s\n", strings[i]); + } -#ifndef MEMLEAKFINDER_MALLOC_MONITORING_DEFINED +#include "MemLeakFindOff.h" free (strings); -#endif +#include "MemLeakFindOn.h" } #endif -- cgit v1.2.3 From 61fce5d877e6388c4422950dcabf6b4bd6d39624 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:56:09 +0000 Subject: Use a static pointer rather than a static object, to allow it to be freed in Timers::Cleanup, removing a reported memory leak (refs #9) --- lib/common/Timer.cpp | 39 +++++++++++++++++++-------------------- lib/common/Timer.h | 3 +-- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index e05affb2..cfeca3c5 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -16,8 +16,7 @@ #include "MemLeakFindOn.h" -std::vector Timers::sTimers; -bool Timers::sInitialised = false; +std::vector* Timers::spTimers = NULL; // -------------------------------------------------------------------------- // @@ -42,7 +41,7 @@ static void TimerSigHandler(int iUnused) // -------------------------------------------------------------------------- void Timers::Init() { - ASSERT(!sInitialised); + ASSERT(!spTimers); #ifdef PLATFORM_CYGWIN ASSERT(::signal(SIGALRM, TimerSigHandler) == 0); @@ -54,7 +53,7 @@ void Timers::Init() ASSERT(::signal(SIGALRM, TimerSigHandler) == 0); #endif // PLATFORM_CYGWIN - sInitialised = true; + spTimers = new std::vector; } // -------------------------------------------------------------------------- @@ -67,7 +66,7 @@ void Timers::Init() // -------------------------------------------------------------------------- void Timers::Cleanup() { - ASSERT(sInitialised); + ASSERT(spTimers); #ifdef PLATFORM_CYGWIN ASSERT(::signal(SIGALRM, NULL) == TimerSigHandler); @@ -79,9 +78,9 @@ void Timers::Cleanup() ASSERT(::signal(SIGALRM, NULL) == TimerSigHandler); #endif // PLATFORM_CYGWIN - sTimers.clear(); - - sInitialised = false; + spTimers->clear(); + delete spTimers; + spTimers = NULL; } // -------------------------------------------------------------------------- @@ -94,8 +93,8 @@ void Timers::Cleanup() // -------------------------------------------------------------------------- void Timers::Add(Timer& rTimer) { - ASSERT(sInitialised); - sTimers.push_back(&rTimer); + ASSERT(spTimers); + spTimers->push_back(&rTimer); Reschedule(); } @@ -110,18 +109,18 @@ void Timers::Add(Timer& rTimer) // -------------------------------------------------------------------------- void Timers::Remove(Timer& rTimer) { - ASSERT(sInitialised); + ASSERT(spTimers); bool restart = true; while (restart) { restart = false; - for (std::vector::iterator i = sTimers.begin(); - i != sTimers.end(); i++) + for (std::vector::iterator i = spTimers->begin(); + i != spTimers->end(); i++) { if (&rTimer == *i) { - sTimers.erase(i); + spTimers->erase(i); restart = true; break; } @@ -141,13 +140,13 @@ void Timers::Remove(Timer& rTimer) // -------------------------------------------------------------------------- void Timers::Reschedule() { - ASSERT(sInitialised); + ASSERT(spTimers); box_time_t timeNow = GetCurrentBoxTime(); box_time_t timeToNextEvent = 0; - for (std::vector::iterator i = sTimers.begin(); - i != sTimers.end(); i++) + for (std::vector::iterator i = spTimers->begin(); + i != spTimers->end(); i++) { Timer& rTimer = **i; ASSERT(!rTimer.HasExpired()); @@ -192,11 +191,11 @@ void Timers::Reschedule() // -------------------------------------------------------------------------- void Timers::Signal() { - ASSERT(sInitialised); + ASSERT(spTimers); box_time_t timeNow = GetCurrentBoxTime(); - std::vector timersCopy = sTimers; + std::vector timersCopy = *spTimers; for (std::vector::iterator i = timersCopy.begin(); i != timersCopy.end(); i++) @@ -211,7 +210,7 @@ void Timers::Signal() rTimer.OnExpire(); } } - + Reschedule(); } diff --git a/lib/common/Timer.h b/lib/common/Timer.h index 6e4a5952..e0eb34db 100644 --- a/lib/common/Timer.h +++ b/lib/common/Timer.h @@ -48,8 +48,7 @@ private: class Timers { private: - static std::vector sTimers; - static bool sInitialised; + static std::vector* spTimers; static void Reschedule(); public: -- cgit v1.2.3 From e8c11ba2cee087b5da8e9758dbc3bdb3feec5ee7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:57:20 +0000 Subject: openlog inside MAINHELPER block, to ensure that any memory leaks will be caught (refs #3) --- bin/bbackupctl/bbackupctl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index 4a5ee5a9..09984e12 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -56,15 +56,15 @@ int main(int argc, const char *argv[]) { int returnCode = 0; -#if defined WIN32 && ! defined NDEBUG - ::openlog("Box Backup (bbackupctl)", 0, 0); -#endif - MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupctl.memleaks", "bbackupctl") MAINHELPER_START +#if defined WIN32 && ! defined NDEBUG + ::openlog("Box Backup (bbackupctl)", 0, 0); +#endif + // Filename for configuraiton file? const char *configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG; -- cgit v1.2.3 From b88ecaed60a79c3a06f513a353ea277788243004 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 15:58:53 +0000 Subject: Setup MAINHELPER as early as possible, and clear it as late as possible, for consistency (refs #3) --- bin/bbackupquery/bbackupquery.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index 4b836406..1a3b8f99 100644 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -63,7 +63,10 @@ void PrintUsageAndExit() int main(int argc, const char *argv[]) { + int returnCode = 0; + MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupquery.memleaks", "bbackupquery") + MAINHELPER_START #ifdef WIN32 WSADATA info; @@ -83,10 +86,6 @@ int main(int argc, const char *argv[]) BoxDebugTraceOn = false; #endif - int returnCode = 0; - - MAINHELPER_START - FILE *logFile = 0; // Filename for configuraiton file? @@ -314,13 +313,13 @@ int main(int argc, const char *argv[]) // Let everything be cleaned up on exit. - MAINHELPER_END - #ifdef WIN32 // Clean up our sockets WSACleanup(); #endif + MAINHELPER_END + return returnCode; } -- cgit v1.2.3 From ab0b5628af0aaf7851a4ca377a25ed569d4112c2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:00:27 +0000 Subject: Fixed typo. --- bin/bbackupquery/bbackupquery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index 1a3b8f99..96374cd4 100644 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -88,7 +88,7 @@ int main(int argc, const char *argv[]) FILE *logFile = 0; - // Filename for configuraiton file? + // Filename for configuration file? const char *configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG; // Flags -- cgit v1.2.3 From c26856da8e344e7ec94d55f92ed49a09f04c5769 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:07:36 +0000 Subject: * Track memory leaks in allocations via the standard libraries, and avoid malloc/delete mismatches, by overriding standard new operator. * Added another global enable flag to memleak finder, which is used to mark the end of static allocations and the start of dynamic code, since the memory leak detection is done before cleanup of static objects. * Added a public guard class, to allow safe scoped disabling of memory leak detection. * Added InternalAllocGuard to protect against recursive loops when allocating memory inside the memory leak checker. (refs #3) --- lib/common/DebugMemLeakFinder.cpp | 139 ++++++++++++++++++++++++++++++++------ lib/common/MemLeakFinder.h | 16 ++++- 2 files changed, 133 insertions(+), 22 deletions(-) diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp index 71665102..64ea0bd3 100644 --- a/lib/common/DebugMemLeakFinder.cpp +++ b/lib/common/DebugMemLeakFinder.cpp @@ -25,6 +25,7 @@ #include #include +static bool memleakfinder_initialised = false; bool memleakfinder_global_enable = false; typedef struct @@ -58,8 +59,38 @@ namespace 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; @@ -75,11 +106,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); @@ -89,7 +122,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); } @@ -133,7 +168,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::iterator i(sMallocBlocks.find(ptr)); @@ -143,7 +180,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) @@ -160,24 +197,34 @@ void memleakfinder_free(void *ptr) void memleakfinder_notaleak_insert_pre() { + InternalAllocGuard guard; + if(!memleakfinder_global_enable) return; + 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; + memleakfinder_notaleak_insert_pre(); - if(memleakfinder_global_enable) + if(memleakfinder_global_enable && memleakfinder_initialised) { sNotLeaks.insert(ptr); } @@ -206,6 +253,9 @@ void memleakfinder_notaleak(void *ptr) // start monitoring a section of code void memleakfinder_startsectionmonitor() { + InternalAllocGuard guard; + + ASSERT(memleakfinder_initialised); sTrackMallocInSection = true; sSectionMallocBlocks.clear(); sTrackObjectsInSection = true; @@ -215,6 +265,10 @@ void memleakfinder_startsectionmonitor() // trace all blocks allocated and still allocated since memleakfinder_startsectionmonitor() called void memleakfinder_traceblocksinsection() { + InternalAllocGuard guard; + + ASSERT(memleakfinder_initialised); + std::set::iterator s(sSectionMallocBlocks.begin()); for(; s != sSectionMallocBlocks.end(); ++s) { @@ -225,17 +279,21 @@ 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::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); + int n = 0; for(std::map::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i) @@ -245,6 +303,7 @@ int memleakfinder_numleaks() for(std::map::const_iterator i(sObjectBlocks.begin()); i != sObjectBlocks.end(); ++i) { + const ObjectInfo& rInfo = i->second; if(is_leak(i->first)) ++n; } @@ -253,6 +312,8 @@ int memleakfinder_numleaks() void memleakfinder_reportleaks_file(FILE *file) { + InternalAllocGuard guard; + for(std::map::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i) { 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); @@ -265,12 +326,16 @@ void memleakfinder_reportleaks_file(FILE *file) 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) { @@ -317,7 +382,10 @@ 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; if(block != 0) { @@ -337,7 +405,10 @@ 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; std::map::iterator i(sObjectBlocks.find(block)); if(i != sObjectBlocks.end()) @@ -357,34 +428,64 @@ 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 +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/MemLeakFinder.h b/lib/common/MemLeakFinder.h index f5887dac..f47a38aa 100644 --- a/lib/common/MemLeakFinder.h +++ b/lib/common/MemLeakFinder.h @@ -20,6 +20,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); @@ -27,6 +34,8 @@ extern "C" void memleakfinder_free(void *ptr); } +void memleakfinder_init(); + int memleakfinder_numleaks(); void memleakfinder_reportleaks(); @@ -41,10 +50,12 @@ 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 new (size_t size); +void *operator new[](size_t size); -void operator delete(void *ptr) throw (); +void operator delete (void *ptr) throw (); void operator delete[](void *ptr) throw (); // define the malloc functions now, if required @@ -55,6 +66,5 @@ void operator delete[](void *ptr) throw (); #define MEMLEAKFINDER_MALLOC_MONITORING_DEFINED #endif - #endif // MEMLEAKFINDER__H -- cgit v1.2.3 From 7a5175aedfc8bdba18ae9bc9d6322303be1aa9e5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:10:00 +0000 Subject: Fix memory leak false alarms caused by modifying static objects (refs #3) --- test/backupstore/testbackupstore.cpp | 19 ++++++++++++------- test/backupstorefix/testbackupstorefix.cpp | 10 +++++++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index 756fb03c..840d004c 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -1926,14 +1926,19 @@ int test(int argc, const char *argv[]) // for seeing what's going on. BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys"); - // encode in some filenames -- can't do static initialisation because the key won't be set up when these are initialised - for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l) + // encode in some filenames -- can't do static initialisation + // because the key won't be set up when these are initialised { - ens[l].fn = BackupStoreFilenameClear(ens_filenames[l]); - } - for(unsigned int l = 0; l < sizeof(uploads_filenames) / sizeof(uploads_filenames[0]); ++l) - { - uploads[l].name = BackupStoreFilenameClear(uploads_filenames[l]); + MEMLEAKFINDER_NO_LEAKS + + for(unsigned int l = 0; l < sizeof(ens_filenames) / sizeof(ens_filenames[0]); ++l) + { + ens[l].fn = BackupStoreFilenameClear(ens_filenames[l]); + } + for(unsigned int l = 0; l < sizeof(uploads_filenames) / sizeof(uploads_filenames[0]); ++l) + { + uploads[l].name = BackupStoreFilenameClear(uploads_filenames[l]); + } } // Trace errors out diff --git a/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp index 92928cc6..0349b039 100644 --- a/test/backupstorefix/testbackupstorefix.cpp +++ b/test/backupstorefix/testbackupstorefix.cpp @@ -202,9 +202,12 @@ void check_dir_dep(BackupStoreDirectory &dir, checkdepinfoen *ck) void test_dir_fixing() { - fnames[0].SetAsClearFilename("x1"); - fnames[1].SetAsClearFilename("x2"); - fnames[2].SetAsClearFilename("x3"); + { + MEMLEAKFINDER_NO_LEAKS; + fnames[0].SetAsClearFilename("x1"); + fnames[1].SetAsClearFilename("x2"); + fnames[2].SetAsClearFilename("x3"); + } { BackupStoreDirectory dir; @@ -344,6 +347,7 @@ int test(int argc, const char *argv[]) TEST_THAT(::sscanf(line, "%x %s %s", &id, flags, name) == 3); bool isDir = (::strcmp(flags, "-d---") == 0); //TRACE3("%x,%d,%s\n", id, isDir, name); + MEMLEAKFINDER_NO_LEAKS; nameToID[std::string(name)] = id; objectIsDir[id] = isDir; } -- cgit v1.2.3 From 9bd08c8e9889b3f879723b341e2a9083c356b94f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:12:09 +0000 Subject: Initialise memleak finder at the start of every program that uses MAINHELPER (all except unit tests). (refs #3) --- lib/common/MainHelper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/common/MainHelper.h b/lib/common/MainHelper.h index ab75af96..d91bc2f9 100644 --- a/lib/common/MainHelper.h +++ b/lib/common/MainHelper.h @@ -17,6 +17,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 \ -- cgit v1.2.3 From cc104c3057f6e282a09be6b15f8aa5e931a37363 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:13:20 +0000 Subject: Initialise cross-platform timers on all platforms, remove win32-specific code (refs #9) --- bin/bbackupd/BackupDaemon.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 8f993067..56c17ed1 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -75,6 +75,7 @@ #include "IOStreamGetLine.h" #include "Conversion.h" #include "Archive.h" +#include "Timer.h" #include "MemLeakFindOn.h" @@ -429,21 +430,19 @@ void BackupDaemon::RunHelperThread(void) // -------------------------------------------------------------------------- void BackupDaemon::Run() { + // initialise global timer mechanism + Timers::Init(); + #ifdef WIN32 - // init our own timer for file diff timeouts - InitTimer(); - try { Run2(); } catch(...) { - FiniTimer(); + Timers::Cleanup(); throw; } - - FiniTimer(); #else // ! WIN32 // Ignore SIGPIPE (so that if a command connection is broken, the daemon doesn't terminate) ::signal(SIGPIPE, SIG_IGN); @@ -487,6 +486,8 @@ void BackupDaemon::Run() mpCommandSocketInfo = 0; } + Timers::Cleanup(); + throw; } @@ -497,6 +498,8 @@ void BackupDaemon::Run() mpCommandSocketInfo = 0; } #endif + + Timers::Cleanup(); } // -------------------------------------------------------------------------- -- cgit v1.2.3 From 134622028a0b4a858d407eac9822f78a0bf01920 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:14:08 +0000 Subject: Fixed control reaching end of non-void functions (refs #3) --- lib/common/Test.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 1312241d..3c7b00fd 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -239,7 +239,9 @@ inline bool HUPServer(int pid) inline bool KillServerInternal(int pid) { - TEST_THAT(SendCommands("terminate")); + bool sent = SendCommands("terminate"); + TEST_THAT(sent); + return sent; } #else // !WIN32 @@ -259,14 +261,19 @@ inline bool HUPServer(int pid) inline bool KillServerInternal(int pid) { if(pid == 0 || pid == -1) return false; - TEST_THAT(::kill(pid, SIGTERM) != -1); + bool killed = (::kill(pid, SIGTERM) == 0); + TEST_THAT(killed); + return killed; } #endif // WIN32 inline bool KillServer(int pid) { - KillServerInternal(pid); + if (!KillServerInternal(pid)) + { + return false; + } for (int i = 0; i < 30; i++) { -- cgit v1.2.3 From 8e29d16a56228d200b6d39b37506e27a037f0f6f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:16:54 +0000 Subject: Initialise memory leak finder in all unit tests (refs #3) --- infrastructure/buildenv-testmain-template.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index 7adbafa9..856c1bc4 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -114,6 +114,10 @@ int main(int argc, const char *argv[]) } try { + #ifdef BOX_MEMORY_LEAK_TESTING + memleakfinder_init(); + #endif + int returncode = test(argc, argv); // check for memory leaks, if enabled -- cgit v1.2.3 From 02f35d357c9afba3ed895115f1d0b4fff01ad41f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:18:03 +0000 Subject: Initialise timers in all unit tests (refs #9) --- infrastructure/buildenv-testmain-template.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index 856c1bc4..b6d20204 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -30,6 +30,8 @@ #include #endif +#include "Timer.h" + #include "MemLeakFindOn.h" int test(int argc, const char *argv[]); @@ -118,7 +120,9 @@ int main(int argc, const char *argv[]) memleakfinder_init(); #endif + Timers::Init(); int returncode = test(argc, argv); + Timers::Cleanup(); // check for memory leaks, if enabled #ifdef BOX_MEMORY_LEAK_TESTING -- cgit v1.2.3 From 9323f23b4f2148b2bf7c31f0b67cf2ca447eac66 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 16:19:59 +0000 Subject: Fix memory leak false alarms caused by static allocations. --- lib/raidfile/RaidFileController.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/raidfile/RaidFileController.cpp b/lib/raidfile/RaidFileController.cpp index 89ae6791..14469c68 100644 --- a/lib/raidfile/RaidFileController.cpp +++ b/lib/raidfile/RaidFileController.cpp @@ -66,6 +66,8 @@ RaidFileController::RaidFileController(const RaidFileController &rController) // -------------------------------------------------------------------------- void RaidFileController::Initialise(const char *ConfigFilename) { + MEMLEAKFINDER_NO_LEAKS; + static const ConfigurationVerifyKey verifykeys[] = { {"SetNumber", 0, ConfigTest_Exists | ConfigTest_IsInt, 0}, -- cgit v1.2.3 From 7e22c206a755fa481da252e8286251fea4d5b1ce Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 19:52:05 +0000 Subject: Revert [1096] as it causes infinite loops if the listening socket can't be opened (refs #3) --- bin/bbstored/BackupStoreDaemon.cpp | 65 +++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index e09bd17d..ca28ed57 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -227,38 +227,13 @@ void BackupStoreDaemon::Run() else { // In server process -- use the base class to do the magic - try - { - ServerTLS::Run(); - } - catch(BoxException &e) - { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "exception %s (%d/%d)", DaemonName(), - e.what(), e.GetType(), e.GetSubType()); - } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "exception %s", DaemonName(), e.what()); - } - catch(...) - { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "unknown exception", DaemonName()); - } - - if (!mInterProcessCommsSocket.IsOpened()) - { - return; - } - + ServerTLS::Run(); + // Why did it stop? Tell the housekeeping process to do the same if(IsReloadConfigWanted()) { mInterProcessCommsSocket.Write("h\n", 2); } - if(IsTerminateWanted()) { mInterProcessCommsSocket.Write("t\n", 2); @@ -266,16 +241,48 @@ void BackupStoreDaemon::Run() } } - // -------------------------------------------------------------------------- // // Function // Name: BackupStoreDaemon::Connection(SocketStreamTLS &) -// Purpose: Handles a connection +// Purpose: Handles a connection, by catching exceptions and +// delegating to Connection2 // Created: 2003/08/20 // // -------------------------------------------------------------------------- void BackupStoreDaemon::Connection(SocketStreamTLS &rStream) +{ + try + { + Connection2(rStream); + } + catch(BoxException &e) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "exception %s (%d/%d)", DaemonName(), + e.what(), e.GetType(), e.GetSubType()); + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "exception %s", DaemonName(), e.what()); + } + catch(...) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "unknown exception", DaemonName()); + } +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreDaemon::Connection2(SocketStreamTLS &) +// Purpose: Handles a connection from bbackupd +// Created: 2006/11/12 +// +// -------------------------------------------------------------------------- +void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream) { // Get the common name from the certificate std::string clientCommonName(rStream.GetPeerCommonName()); -- cgit v1.2.3 From a3583d8e0883e0232a3380e4cf1aabed6e3275eb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 20:01:39 +0000 Subject: Properly revert [1096] (refs #3) --- bin/bbstored/BackupStoreDaemon.cpp | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index ca28ed57..91d7cd12 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -241,48 +241,16 @@ void BackupStoreDaemon::Run() } } + // -------------------------------------------------------------------------- // // Function // Name: BackupStoreDaemon::Connection(SocketStreamTLS &) -// Purpose: Handles a connection, by catching exceptions and -// delegating to Connection2 +// Purpose: Handles a connection // Created: 2003/08/20 // // -------------------------------------------------------------------------- void BackupStoreDaemon::Connection(SocketStreamTLS &rStream) -{ - try - { - Connection2(rStream); - } - catch(BoxException &e) - { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "exception %s (%d/%d)", DaemonName(), - e.what(), e.GetType(), e.GetSubType()); - } - catch(std::exception &e) - { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "exception %s", DaemonName(), e.what()); - } - catch(...) - { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "unknown exception", DaemonName()); - } -} - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupStoreDaemon::Connection2(SocketStreamTLS &) -// Purpose: Handles a connection from bbackupd -// Created: 2006/11/12 -// -// -------------------------------------------------------------------------- -void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream) { // Get the common name from the certificate std::string clientCommonName(rStream.GetPeerCommonName()); -- cgit v1.2.3 From 2b2acef11f34df1420447b4fcfa7ca5c401481a9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Nov 2006 20:04:01 +0000 Subject: Don't try to write to the interprocess socket if it's not open (refs #3) --- bin/bbstored/BackupStoreDaemon.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 91d7cd12..74885c57 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -228,12 +228,18 @@ void BackupStoreDaemon::Run() { // In server process -- use the base class to do the magic ServerTLS::Run(); - + + if (!mInterProcessCommsSocket.IsOpened()) + { + return; + } + // Why did it stop? Tell the housekeeping process to do the same if(IsReloadConfigWanted()) { mInterProcessCommsSocket.Write("h\n", 2); } + if(IsTerminateWanted()) { mInterProcessCommsSocket.Write("t\n", 2); -- cgit v1.2.3 From ca0c40ce216de416cd8ada05ab369c2971ee4a71 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Nov 2006 05:12:03 +0000 Subject: Add ExtendedLogFile option to bbackupd config (refs #9) --- bin/bbackupd/BackupClientContext.cpp | 41 +++++++++++++++++++++++++-- bin/bbackupd/BackupClientContext.h | 15 ++++++++-- bin/bbackupd/BackupDaemon.cpp | 22 ++++++++++++-- lib/backupclient/BackupDaemonConfigVerify.cpp | 3 +- 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index 4b84fecb..9f6a5bd3 100644 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -35,13 +35,21 @@ // -------------------------------------------------------------------------- // // Function -// Name: BackupClientContext::BackupClientContext(BackupDaemon &, TLSContext &, const std::string &, int32_t, bool) +// Name: BackupClientContext::BackupClientContext(BackupDaemon &, TLSContext &, const std::string &, int32_t, bool, bool, std::string) // Purpose: Constructor // Created: 2003/10/08 // // -------------------------------------------------------------------------- -BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLSContext, const std::string &rHostname, - int32_t AccountNumber, bool ExtendedLogging) +BackupClientContext::BackupClientContext +( + BackupDaemon &rDaemon, + TLSContext &rTLSContext, + const std::string &rHostname, + int32_t AccountNumber, + bool ExtendedLogging, + bool ExtendedLogToFile, + std::string ExtendedLogFile +) : mrDaemon(rDaemon), mrTLSContext(rTLSContext), mHostname(rHostname), @@ -49,6 +57,9 @@ BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLS mpSocket(0), mpConnection(0), mExtendedLogging(ExtendedLogging), + mExtendedLogToFile(ExtendedLogToFile), + mExtendedLogFile(ExtendedLogFile), + mpExtendedLogFileHandle(NULL), mClientStoreMarker(ClientStoreMarker_NotKnown), mpDeleteList(0), mpCurrentIDMap(0), @@ -126,6 +137,24 @@ BackupProtocolClient &BackupClientContext::GetConnection() // Set logging option mpConnection->SetLogToSysLog(mExtendedLogging); + if (mExtendedLogToFile) + { + ASSERT(mpExtendedLogFileHandle == NULL); + + mpExtendedLogFileHandle = fopen( + mExtendedLogFile.c_str(), "w"); + + if (!mpExtendedLogFileHandle) + { + ::syslog(LOG_ERR, "Failed to open extended " + "log file: %s", strerror(errno)); + } + else + { + mpConnection->SetLogToFile(mpExtendedLogFileHandle); + } + } + // Handshake mpConnection->Handshake(); @@ -256,6 +285,12 @@ void BackupClientContext::CloseAnyOpenConnection() delete mpDeleteList; mpDeleteList = 0; } + + if (mpExtendedLogFileHandle != NULL) + { + fclose(mpExtendedLogFileHandle); + mpExtendedLogFileHandle = NULL; + } } diff --git a/bin/bbackupd/BackupClientContext.h b/bin/bbackupd/BackupClientContext.h index a0cf6e1f..74a23116 100644 --- a/bin/bbackupd/BackupClientContext.h +++ b/bin/bbackupd/BackupClientContext.h @@ -35,8 +35,16 @@ class BackupStoreFilenameClear; class BackupClientContext : public DiffTimer { public: - BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLSContext, const std::string &rHostname, - int32_t AccountNumber, bool ExtendedLogging); + BackupClientContext + ( + BackupDaemon &rDaemon, + TLSContext &rTLSContext, + const std::string &rHostname, + int32_t AccountNumber, + bool ExtendedLogging, + bool ExtendedLogToFile, + std::string ExtendedLogFile + ); virtual ~BackupClientContext(); private: BackupClientContext(const BackupClientContext &); @@ -197,6 +205,9 @@ private: SocketStreamTLS *mpSocket; BackupProtocolClient *mpConnection; bool mExtendedLogging; + bool mExtendedLogToFile; + std::string mExtendedLogFile; + FILE* mpExtendedLogFileHandle; int64_t mClientStoreMarker; BackupClientDeleteList *mpDeleteList; const BackupClientInodeToIDMap *mpCurrentIDMap; diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 56c17ed1..62e2d8e9 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -697,9 +697,25 @@ void BackupDaemon::Run2() SetState(State_Connected); ::syslog(LOG_INFO, "Beginning scan of local files"); - // Then create a client context object (don't just connect, as this may be unnecessary) - BackupClientContext clientContext(*this, tlsContext, conf.GetKeyValue("StoreHostname"), - conf.GetKeyValueInt("AccountNumber"), conf.GetKeyValueBool("ExtendedLogging")); + std::string extendedLogFile; + if (conf.KeyExists("ExtendedLogFile")) + { + extendedLogFile = conf.GetKeyValue( + "ExtendedLogFile"); + } + + // Then create a client context object (don't + // just connect, as this may be unnecessary) + BackupClientContext clientContext + ( + *this, + tlsContext, + conf.GetKeyValue("StoreHostname"), + conf.GetKeyValueInt("AccountNumber"), + conf.GetKeyValueBool("ExtendedLogging"), + conf.KeyExists("ExtendedLogFile"), + extendedLogFile + ); // Set up the sync parameters BackupClientDirectoryRecord::SyncParams params(*this, clientContext); diff --git a/lib/backupclient/BackupDaemonConfigVerify.cpp b/lib/backupclient/BackupDaemonConfigVerify.cpp index 89ad4d54..34167227 100644 --- a/lib/backupclient/BackupDaemonConfigVerify.cpp +++ b/lib/backupclient/BackupDaemonConfigVerify.cpp @@ -81,7 +81,8 @@ static const ConfigurationVerifyKey verifyrootkeys[] = {"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 {"CommandSocket", 0, 0, 0}, // not compulsory to have this {"KeepAliveTime", 0, ConfigTest_IsInt, 0}, // optional -- cgit v1.2.3 From 366574d921bf39a356d558ef8d61d78181a7af9b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 23 Nov 2006 19:54:51 +0000 Subject: Use gettimeofday() to increase accuracy of GetCurrentBoxTime() on platforms which support it. Fixes busy waits for 1 second in backup client when time for next backup is not on a 1 second boundary (which it never is). (refs #3) --- configure.ac | 2 +- lib/common/BoxTime.cpp | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 8b6221a2..99165a38 100644 --- a/configure.ac +++ b/configure.ac @@ -158,7 +158,7 @@ AC_FUNC_CLOSEDIR_VOID AC_FUNC_ERROR_AT_LINE AC_TYPE_SIGNAL AC_FUNC_STAT -AC_CHECK_FUNCS([getpeereid lchown setproctitle getpid]) +AC_CHECK_FUNCS([getpeereid lchown setproctitle getpid gettimeofday]) # NetBSD implements kqueue too differently for us to get it fixed by 0.10 # TODO: Remove this when NetBSD kqueue implementation is working netbsd_hack=`echo $target_os | sed 's/netbsd.*/netbsd/'` diff --git a/lib/common/BoxTime.cpp b/lib/common/BoxTime.cpp index 960fc329..eafb244f 100644 --- a/lib/common/BoxTime.cpp +++ b/lib/common/BoxTime.cpp @@ -9,7 +9,17 @@ #include "Box.h" -#include +#ifdef HAVE_SYS_TIME_H + #include +#endif +#ifdef HAVE_TIME_H + #include +#endif +#ifdef HAVE_SYSLOG_H + #include +#endif +#include +#include #include "BoxTime.h" @@ -19,13 +29,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) + { + ::syslog(LOG_ERR, "gettimeofday() failed (%s), " + "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)); } - - -- cgit v1.2.3 From 1f2de110c9d4e55ee4d76b46857b4e26a2671e73 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Nov 2006 19:38:07 +0000 Subject: * Allow Daemons to be created more than once per process * Don't initialise signal handler until after fork, in case the parent is actually a unit test or another complex application * Don't exit(0) in the parent, for the same reason (refs #9) --- lib/server/Daemon.cpp | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 2131bdcb..af478320 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -48,11 +48,11 @@ Daemon *Daemon::spDaemon = 0; // // -------------------------------------------------------------------------- Daemon::Daemon() - : mpConfiguration(0), + : mpConfiguration(NULL), mReloadConfigWanted(false), mTerminateWanted(false) { - if(spDaemon != 0) + if(spDaemon != NULL) { THROW_EXCEPTION(ServerException, AlreadyDaemonConstructed) } @@ -79,6 +79,9 @@ Daemon::~Daemon() delete mpConfiguration; mpConfiguration = 0; } + + ASSERT(spDaemon == this); + spDaemon = NULL; } // -------------------------------------------------------------------------- @@ -183,18 +186,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) - } -#endif // !WIN32 - // Server configuration const Configuration &serverConfig( mpConfiguration->GetSubConfiguration("Server")); @@ -232,7 +223,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) default: // parent - _exit(0); + // _exit(0); return 0; break; @@ -269,7 +260,20 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) break; } } -#endif // ! WIN32 + + // 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 // open the log ::openlog(DaemonName(), LOG_PID, LOG_LOCAL6); -- cgit v1.2.3 From acbafe4f76e88aefd0b57084c77c9b8cbbecbbc9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Nov 2006 19:38:46 +0000 Subject: Add missing newlines to protocol logging to a file (refs #9) --- lib/server/makeprotocol.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/server/makeprotocol.pl.in b/lib/server/makeprotocol.pl.in index 88177b62..f4561168 100755 --- a/lib/server/makeprotocol.pl.in +++ b/lib/server/makeprotocol.pl.in @@ -829,8 +829,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; -- cgit v1.2.3 From c83d51cd16dd979273a960f8ac9375e10fa93942 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Nov 2006 19:41:12 +0000 Subject: Separate ReadPidFile() out from LaunchServer() in test code (refs #9) --- lib/common/Test.h | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 3c7b00fd..ada42eb2 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -104,30 +104,19 @@ inline int RunCommand(const char *pCommandLine) return ::system(command.c_str()); } -inline int LaunchServer(const char *pCommandLine, const char *pidFile) +inline int ReadPidFile(const char *pidFile) { - if(RunCommand(pCommandLine) != 0) - { - printf("Server: %s\n", pCommandLine); - TEST_FAIL_WITH_MESSAGE("Couldn't start server"); - return -1; - } - // time for it to start up - ::sleep(1); - - // read pid file if(!TestFileExists(pidFile)) { - printf("Server: %s\n", pCommandLine); TEST_FAIL_WITH_MESSAGE("Server didn't save PID file"); 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", pCommandLine, pidFile); TEST_FAIL_WITH_MESSAGE("Couldn't read PID file"); return -1; } @@ -136,6 +125,30 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) return pid; } +inline int LaunchServer(const char *pCommandLine, const char *pidFile) +{ + if(RunCommand(pCommandLine) != 0) + { + printf("Server: %s\n", pCommandLine); + TEST_FAIL_WITH_MESSAGE("Couldn't start server"); + return -1; + } + + // give it time to start up + ::sleep(1); + + // read pid file + int pid = ReadPidFile(pidFile); + + if(pid == -1) + { + // helps with debugging: + printf("Server: %s (pidfile %s)\n", pCommandLine, pidFile); + } + + return pid; +} + #ifdef WIN32 #include "WinNamedPipeStream.h" @@ -335,4 +348,3 @@ inline void TestRemoteProcessMemLeaks(const char *filename) } #endif // TEST__H - -- cgit v1.2.3 From aa1e32e97f007a547e57cd6be5ecf190b4ff7cfd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Nov 2006 19:43:20 +0000 Subject: Moved intercept code to a library module to allow it to be used by test/bbackupd as well (refs #3) --- lib/intercept/intercept.cpp | 315 ++++++++++++++++++++++++++++++++++++++++++++ modules.txt | 5 +- test/raidfile/intercept.cpp | 276 -------------------------------------- 3 files changed, 318 insertions(+), 278 deletions(-) create mode 100644 lib/intercept/intercept.cpp delete mode 100644 test/raidfile/intercept.cpp diff --git a/lib/intercept/intercept.cpp b/lib/intercept/intercept.cpp new file mode 100644 index 00000000..4f8ef785 --- /dev/null +++ b/lib/intercept/intercept.cpp @@ -0,0 +1,315 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: intercept.cpp +// Purpose: Syscall interception code for the raidfile test +// Created: 2003/07/22 +// +// -------------------------------------------------------------------------- + +#include "Box.h" + +#ifdef HAVE_SYS_SYSCALL_H + #include +#endif +#include +#include + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#include + +#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 +#include + +#include "MemLeakFindOn.h" + +bool intercept_enabled = false; +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; + +#define SIZE_ALWAYS_ERROR -773 + +void intercept_clear_setup() +{ + intercept_enabled = false; + intercept_filename = 0; + intercept_filedes = -1; + intercept_errorafter = 0; + intercept_syscall = 0; + intercept_filepos = 0; + intercept_delay_ms = 0; +} + +bool intercept_triggered() +{ + return !intercept_enabled; +} + +void intercept_setup_error(const char *filename, unsigned int errorafter, int errortoreturn, int syscalltoerror) +{ + TRACE4("Setup for error: %s, after %d, err %d, syscall %d\n", filename, errorafter, errortoreturn, syscalltoerror); + intercept_enabled = true; + 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) +{ + TRACE4("Setup for delay: %s, after %d, wait %d ms, syscall %d\n", + filename, delay_after, delay_ms, syscall_to_delay); + intercept_enabled = true; + intercept_filename = filename; + intercept_filedes = -1; + intercept_errorafter = delay_after; + intercept_syscall = syscall_to_delay; + intercept_errno = 0; + intercept_filepos = 0; + intercept_delay_ms = delay_ms; +} +bool intercept_errornow(int d, int size, int syscallnum) +{ + if(intercept_filedes != -1 && d == intercept_filedes && syscallnum == intercept_syscall) + { + //printf("Checking for err, %d, %d, %d\n", d, size, syscallnum); + if(size == SIZE_ALWAYS_ERROR) + { + // Looks good for an error! + TRACE2("Returning error %d for syscall %d\n", intercept_errno, syscallnum); + return true; + } + // where are we in the file? + if(intercept_filepos >= intercept_errorafter || intercept_filepos >= ((off_t)intercept_errorafter - size)) + { + if (intercept_errno != 0) + { + TRACE3("Returning error %d for syscall %d, " + "file pos %d\n", intercept_errno, + syscallnum, (int)intercept_filepos); + } + else if (intercept_delay_ms != 0) + { + TRACE3("Delaying %d ms for syscall %d, " + "file pos %d\n", intercept_delay_ms, + syscallnum, (int)intercept_filepos); + } + + return true; + } + } + return false; // no error please! +} + +int intercept_reterr() +{ + int err = intercept_errno; + intercept_clear_setup(); + return err; +} + +#define CHECK_FOR_FAKE_ERROR_COND(D, S, CALL, FAILRES) \ + if(intercept_enabled) \ + { \ + if(intercept_errornow(D, S, CALL)) \ + { \ + if(intercept_delay_ms > 0) \ + { \ + 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) { } \ + intercept_clear_setup(); \ + } \ + else \ + { \ + errno = intercept_reterr(); \ + return FAILRES; \ + } \ + } \ + } + +extern "C" int +open(const char *path, int flags, mode_t mode) +{ + if(intercept_enabled) + { + if(intercept_syscall == SYS_open && strcmp(path, intercept_filename) == 0) + { + errno = intercept_reterr(); + return -1; + } + } +#ifdef PLATFORM_NO_SYSCALL + int r = TEST_open(path, flags, mode); +#else + int r = syscall(SYS_open, path, flags, mode); +#endif + if(intercept_enabled && intercept_filedes == -1) + { + // 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; +} + +#endif // n PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE diff --git a/modules.txt b/modules.txt index de00f08b..eb8c156d 100644 --- a/modules.txt +++ b/modules.txt @@ -18,6 +18,7 @@ lib/crypto lib/server lib/win32 lib/server lib/compress +lib/intercept test/common lib/win32 test/crypto lib/crypto lib/win32 test/compress lib/compress lib/win32 @@ -25,7 +26,7 @@ test/compress lib/compress lib/win32 OMIT:mingw32 test/basicserver lib/server lib/win32 OMIT:CYGWIN -test/raidfile lib/raidfile +test/raidfile lib/raidfile lib/intercept END-OMIT # IF_DISTRIBUTION(boxbackup) @@ -52,7 +53,7 @@ test/backupstore bin/bbstored bin/bbstoreaccounts lib/server lib/backupstore lib test/backupstorefix bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile bin/bbackupquery bin/bbackupd test/backupstorepatch bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile test/backupdiff lib/backupclient -test/bbackupd bin/bbackupd bin/bbstored bin/bbstoreaccounts bin/bbackupquery bin/bbackupctl lib/server lib/backupstore lib/backupclient +test/bbackupd bin/bbackupd bin/bbstored bin/bbstoreaccounts bin/bbackupquery bin/bbackupctl lib/server lib/backupstore lib/backupclient lib/intercept END-OMIT # END_IF_DISTRIBUTION diff --git a/test/raidfile/intercept.cpp b/test/raidfile/intercept.cpp deleted file mode 100644 index 0a5b4ab9..00000000 --- a/test/raidfile/intercept.cpp +++ /dev/null @@ -1,276 +0,0 @@ -// -------------------------------------------------------------------------- -// -// File -// Name: intercept.cpp -// Purpose: Syscall interception code for the raidfile test -// Created: 2003/07/22 -// -// -------------------------------------------------------------------------- - -#include "Box.h" - -#ifdef HAVE_SYS_SYSCALL_H - #include -#endif -#include -#include - -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#include - -#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 -#include - -#include "MemLeakFindOn.h" - -bool intercept_enabled = false; -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; - -#define SIZE_ALWAYS_ERROR -773 - -void intercept_clear_setup() -{ - intercept_enabled = false; - intercept_filename = 0; - intercept_filedes = -1; - intercept_errorafter = 0; - intercept_syscall = 0; - intercept_filepos = 0; -} - -bool intercept_triggered() -{ - return !intercept_enabled; -} - -void intercept_setup_error(const char *filename, unsigned int errorafter, int errortoreturn, int syscalltoerror) -{ - TRACE4("Setup for error: %s, after %d, err %d, syscall %d\n", filename, errorafter, errortoreturn, syscalltoerror); - intercept_enabled = true; - intercept_filename = filename; - intercept_filedes = -1; - intercept_errorafter = errorafter; - intercept_syscall = syscalltoerror; - intercept_errno = errortoreturn; - intercept_filepos = 0; -} - -bool intercept_errornow(int d, int size, int syscallnum) -{ - if(intercept_filedes != -1 && d == intercept_filedes && syscallnum == intercept_syscall) - { - //printf("Checking for err, %d, %d, %d\n", d, size, syscallnum); - if(size == SIZE_ALWAYS_ERROR) - { - // Looks good for an error! - TRACE2("Returning error %d for syscall %d\n", intercept_errno, syscallnum); - return true; - } - // where are we in the file? - if(intercept_filepos >= intercept_errorafter || intercept_filepos >= ((off_t)intercept_errorafter - size)) - { - TRACE3("Returning error %d for syscall %d, file pos %d\n", intercept_errno, syscallnum, (int)intercept_filepos); - return true; - } - } - return false; // no error please! -} - -int intercept_reterr() -{ - intercept_enabled = false; - intercept_filename = 0; - intercept_filedes = -1; - intercept_errorafter = 0; - intercept_syscall = 0; - return intercept_errno; -} - -#define CHECK_FOR_FAKE_ERROR_COND(D, S, CALL, FAILRES) \ - if(intercept_enabled) \ - { \ - if(intercept_errornow(D, S, CALL)) \ - { \ - errno = intercept_reterr(); \ - return FAILRES; \ - } \ - } - -extern "C" int -open(const char *path, int flags, mode_t mode) -{ - if(intercept_enabled) - { - if(intercept_syscall == SYS_open && strcmp(path, intercept_filename) == 0) - { - errno = intercept_reterr(); - return -1; - } - } -#ifdef PLATFORM_NO_SYSCALL - int r = TEST_open(path, flags, mode); -#else - int r = syscall(SYS_open, path, flags, mode); -#endif - if(intercept_enabled && intercept_filedes == -1) - { - // 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; -} - -#endif // n PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE -- cgit v1.2.3 From 042f6b6802eca9249670ae30919d5a398a1cc97d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Nov 2006 19:45:44 +0000 Subject: * Try to kill any daemons left over from previous tests before running new tests. * Try to kill any remaining daemons at the end of the test (refs #3) --- infrastructure/makebuildenv.pl.in | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index 75912ca1..09176c9c 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -401,24 +401,46 @@ for my $mod (@implicit_deps, @modules) sub writetestfile { my ($filename,$runcmd,$module) = @_; - open TESTFILE,">$filename" or die "Can't open test script file for $module for writing\n"; + + open TESTFILE,">$filename" or die "Can't open " . + "test script file for $module for writing\n"; print TESTFILE "#!/bin/sh\necho TEST: $module\n"; + if(-d "$module/testfiles") { print TESTFILE <<__E; +echo Killing any running daemons... +test -r testfiles/bbackupd.pid && kill `cat testfiles/bbackupd.pid` +test -r testfiles/bbstored.pid && kill `cat testfiles/bbstored.pid` + echo Removing old test files... rm -rf testfiles + echo Copying new test files... cp -p -R ../../../$module/testfiles . + __E } + if(-e "$module/testextra") { - open FL,"$module/testextra" or die "Can't open $module/testextra"; + open FL,"$module/testextra" or die + "Can't open $module/testextra"; while() {print TESTFILE} close FL; } + print TESTFILE "$runcmd\n"; + + if(-d "$module/testfiles") + { + print TESTFILE <<__E; +# echo Killing any running daemons... +test -r testfiles/bbackupd.pid && kill `cat testfiles/bbackupd.pid` +test -r testfiles/bbstored.pid && kill `cat testfiles/bbstored.pid` +__E + } + close TESTFILE; } -- cgit v1.2.3 From c05cc844114f1f2289432a9ec220e6c527adbf66 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Nov 2006 19:47:49 +0000 Subject: Catch any exceptions while handling a connection and report to user rather than terminating. Useful for non-forking servers like bbstored on Windows. (refs #3) --- bin/bbstored/BackupStoreDaemon.cpp | 36 ++++++++++++++++++++++++++++++++++-- bin/bbstored/BackupStoreDaemon.h | 3 ++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 74885c57..06d529c3 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -247,16 +247,48 @@ void BackupStoreDaemon::Run() } } - // -------------------------------------------------------------------------- // // Function // Name: BackupStoreDaemon::Connection(SocketStreamTLS &) -// Purpose: Handles a connection +// Purpose: Handles a connection, by catching exceptions and +// delegating to Connection2 // Created: 2003/08/20 // // -------------------------------------------------------------------------- void BackupStoreDaemon::Connection(SocketStreamTLS &rStream) +{ + try + { + Connection2(rStream); + } + catch(BoxException &e) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "exception %s (%d/%d)", DaemonName(), + e.what(), e.GetType(), e.GetSubType()); + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "exception %s", DaemonName(), e.what()); + } + catch(...) + { + ::syslog(LOG_ERR, "%s: disconnecting due to " + "unknown exception", DaemonName()); + } +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreDaemon::Connection2(SocketStreamTLS &) +// Purpose: Handles a connection from bbackupd +// Created: 2006/11/12 +// +// -------------------------------------------------------------------------- +void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream) { // Get the common name from the certificate std::string clientCommonName(rStream.GetPeerCommonName()); diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index 0ce6f21f..eea47284 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -52,7 +52,8 @@ protected: virtual void Run(); - void Connection(SocketStreamTLS &rStream); + virtual void Connection(SocketStreamTLS &rStream); + void Connection2(SocketStreamTLS &rStream); virtual const char *DaemonName() const; virtual const char *DaemonBanner() const; -- cgit v1.2.3 From 85b96251de8ecb23cac85e11ea5b9f57329f9270 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Nov 2006 19:49:27 +0000 Subject: Added test for keepalives being sent (refs #9) --- test/bbackupd/testbbackupd.cpp | 161 ++++++++++++++++++++++++++++++- test/bbackupd/testfiles/bbackupd.conf.in | 6 +- 2 files changed, 164 insertions(+), 3 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 51047177..eafea4c3 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -22,6 +22,10 @@ #endif #include +#ifdef HAVE_SYSCALL +#include +#endif + #include "Test.h" #include "BackupClientFileAttributes.h" #include "CommonException.h" @@ -41,6 +45,10 @@ #include "Utils.h" #include "BoxTime.h" #include "BoxTimeToUnix.h" +#include "BackupDaemon.h" +#include "Timer.h" +#include "FileStream.h" +#include "IOStreamGetLine.h" #include "MemLeakFindOn.h" @@ -500,6 +508,74 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) } } +void intercept_setup_delay(const char *filename, unsigned int delay_after, + int delay_ms, int syscall_to_delay); +bool intercept_triggered(); + +int start_internal_daemon() +{ + // ensure that no child processes end up running tests! + int own_pid = getpid(); + + BackupDaemon daemon; + const char* fake_argv[] = { "bbackupd", "testfiles/bbackupd.conf" }; + + int result = daemon.Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, 2, + fake_argv); + + TEST_THAT(result == 0); + if (result != 0) + { + printf("Daemon exited with code %d\n", result); + } + + // ensure that no child processes end up running tests! + TEST_THAT(getpid() == own_pid); + if (getpid() != own_pid) + { + // abort! + _exit(1); + } + + TEST_THAT(TestFileExists("testfiles/bbackupd.pid")); + + printf("Waiting for daemon to start"); + int pid = -1; + + for (int i = 0; i < 30; i++) + { + printf("."); + fflush(stdout); + sleep(1); + + pid = ReadPidFile("testfiles/bbackupd.pid"); + if (pid > 0) + { + break; + } + } + + printf("\n"); + + TEST_THAT(pid > 0); + return pid; +} + +void stop_internal_daemon(int pid) +{ + TEST_THAT(KillServer(pid)); + + /* + int status; + TEST_THAT(waitpid(pid, &status, 0) == pid); + TEST_THAT(WIFEXITED(status)); + + if (WIFEXITED(status)) + { + TEST_THAT(WEXITSTATUS(status) == 0); + } + */ +} int test_bbackupd() { @@ -517,6 +593,90 @@ int test_bbackupd() TEST_THAT(::system("rm -rf testfiles/TestDir1") == 0); TEST_THAT(::system("mkdir testfiles/TestDir1") == 0); TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0); + +#ifdef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE + printf("Skipping intercept-based KeepAlive tests on this platform.\n"); +#else + { + #ifdef WIN32 + #error TODO: implement threads on Win32, or this test \ + will not finish properly + #endif + + // bbackupd daemon will try to initialise timers itself + Timers::Cleanup(); + + // something to diff against (empty file doesn't work) + int fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY); + TEST_THAT(fd > 0); + char buffer[1024]; + TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd) == 0); + + int pid = start_internal_daemon(); + wait_for_backup_operation(); + stop_internal_daemon(pid); + + intercept_setup_delay("testfiles/TestDir1/spacetest/f1", + 0, 2000, SYS_read); + TEST_THAT(unlink("testfiles/bbackupd.log") == 0); + + pid = start_internal_daemon(); + + fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY); + TEST_THAT(fd > 0); + // write again, to update the file's timestamp + TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd) == 0); + + wait_for_backup_operation(); + // can't test whether intercept was triggered, because + // it's in a different process. + // TEST_THAT(intercept_triggered()); + stop_internal_daemon(pid); + + // check that keepalive was written to logs, and + // diff was not aborted, i.e. upload was a diff + FileStream fs("testfiles/bbackupd.log", O_RDONLY); + IOStreamGetLine reader(fs); + bool found1 = false; + + while (!reader.IsEOF()) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + if (line == "Send GetBlockIndexByName(0x3,\"f1\")") + { + found1 = true; + break; + } + } + + TEST_THAT(found1); + if (found1) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive Success(0xe)"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receiving stream, size 60"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Send GetIsAlive()"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive IsAlive()"); + TEST_THAT(reader.GetLine(line)); + + std::string comp = "Send StoreFile(0x3,"; + TEST_THAT(line.substr(0, comp.size()) == comp); + comp = ",0xe,\"f1\")"; + TEST_THAT(line.substr(line.size() - comp.size()) + == comp); + } + + // restore timers for rest of tests + Timers::Init(); + } +#endif // PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE int pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); TEST_THAT(pid != -1 && pid != 0); @@ -1055,4 +1215,3 @@ int test(int argc, const char *argv[]) return 0; } - diff --git a/test/bbackupd/testfiles/bbackupd.conf.in b/test/bbackupd/testfiles/bbackupd.conf.in index 6d381d5b..097cf7b7 100644 --- a/test/bbackupd/testfiles/bbackupd.conf.in +++ b/test/bbackupd/testfiles/bbackupd.conf.in @@ -17,9 +17,11 @@ MaxUploadWait = 24 FileTrackingSizeThreshold = 1024 DiffingUploadSizeThreshold = 1024 -MaximumDiffingTime = 8 +MaximumDiffingTime = 3 +KeepAliveTime = 1 -ExtendedLogging = yes +ExtendedLogging = no +ExtendedLogFile = testfiles/bbackupd.log CommandSocket = testfiles/bbackupd.sock -- cgit v1.2.3 From 065e0b531fe827c3a153a76493d11e3e2a73b9ea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 26 Nov 2006 19:54:00 +0000 Subject: * Fix timer expiry calculation when timers expire in the past * Fix handling of timers which never expire (zero deadline) (refs #9) --- lib/common/Timer.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index cfeca3c5..5ebfc133 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -143,7 +143,7 @@ void Timers::Reschedule() ASSERT(spTimers); box_time_t timeNow = GetCurrentBoxTime(); - box_time_t timeToNextEvent = 0; + int64_t timeToNextEvent = 0; for (std::vector::iterator i = spTimers->begin(); i != spTimers->end(); i++) @@ -151,7 +151,8 @@ void Timers::Reschedule() Timer& rTimer = **i; ASSERT(!rTimer.HasExpired()); - box_time_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; + int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; + if (timeToExpiry <= 0) timeToExpiry = 1; if (timeToNextEvent == 0 || timeToNextEvent > timeToExpiry) { @@ -203,7 +204,7 @@ void Timers::Signal() Timer& rTimer = **i; ASSERT(!rTimer.HasExpired()); - box_time_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; + int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; if (timeToExpiry <= 0) { @@ -218,7 +219,14 @@ Timer::Timer(size_t timeoutSecs) : mExpires(GetCurrentBoxTime() + SecondsToBoxTime(timeoutSecs)), mExpired(false) { - Timers::Add(*this); + if (timeoutSecs == 0) + { + mExpires = 0; + } + else + { + Timers::Add(*this); + } } Timer::~Timer() @@ -230,7 +238,10 @@ Timer::Timer(const Timer& rToCopy) : mExpires(rToCopy.mExpires), mExpired(rToCopy.mExpired) { - Timers::Add(*this); + if (mExpires != 0) + { + Timers::Add(*this); + } } Timer& Timer::operator=(const Timer& rToCopy) @@ -238,10 +249,11 @@ Timer& Timer::operator=(const Timer& rToCopy) Timers::Remove(*this); mExpires = rToCopy.mExpires; mExpired = rToCopy.mExpired; - if (!mExpired) + if (!mExpired && mExpires != 0) { Timers::Add(*this); } + return *this; } void Timer::OnExpire() -- cgit v1.2.3 From b166ceb019aab7583d66f69b86d7241b5fb5d5e6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 27 Nov 2006 19:19:57 +0000 Subject: Added a test for diff termination if MaximumDiffingTime is exceeded (refs #3, refs #9) --- test/bbackupd/testbbackupd.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index eafea4c3..36cf4f77 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -673,6 +673,58 @@ int test_bbackupd() == comp); } + intercept_setup_delay("testfiles/TestDir1/spacetest/f1", + 0, 4000, SYS_read); + pid = start_internal_daemon(); + + fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY); + TEST_THAT(fd > 0); + // write again, to update the file's timestamp + TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd) == 0); + + wait_for_backup_operation(); + // can't test whether intercept was triggered, because + // it's in a different process. + // TEST_THAT(intercept_triggered()); + stop_internal_daemon(pid); + + // check that the diff was aborted, i.e. upload was not a diff + found1 = false; + + while (!reader.IsEOF()) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + if (line == "Send GetBlockIndexByName(0x3,\"f1\")") + { + found1 = true; + break; + } + } + + TEST_THAT(found1); + if (found1) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive Success(0xf)"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receiving stream, size 60"); + + // delaying for 4 seconds in one step means that + // the diff timer and the keepalive timer will + // both expire, and the diff timer is honoured first, + // so there will be no keepalives. + + TEST_THAT(reader.GetLine(line)); + std::string comp = "Send StoreFile(0x3,"; + TEST_THAT(line.substr(0, comp.size()) == comp); + comp = ",0x0,\"f1\")"; + TEST_THAT(line.substr(line.size() - comp.size()) + == comp); + } + // restore timers for rest of tests Timers::Init(); } -- cgit v1.2.3 From dd0103e2465a8880cf253f2abd7e44fe3ed1590e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Nov 2006 20:28:43 +0000 Subject: Added debug tracing code for timers. --- lib/common/Timer.cpp | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index 5ebfc133..76b700d3 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -219,6 +219,24 @@ Timer::Timer(size_t timeoutSecs) : mExpires(GetCurrentBoxTime() + SecondsToBoxTime(timeoutSecs)), mExpired(false) { + #ifndef NDEBUG + struct timeval tv; + gettimeofday(&tv, NULL); + if (timeoutSecs == 0) + { + TRACE4("%d.%d: timer %p initialised for %d secs, " + "will not fire\n", tv.tv_sec, tv.tv_usec, this, + timeoutSecs); + } + else + { + TRACE6("%d.%d: timer %p initialised for %d secs, " + "to fire at %d.%d\n", tv.tv_sec, tv.tv_usec, this, + timeoutSecs, (int)(mExpires / 1000000), + (int)(mExpires % 1000000)); + } + #endif + if (timeoutSecs == 0) { mExpires = 0; @@ -231,6 +249,13 @@ Timer::Timer(size_t timeoutSecs) Timer::~Timer() { + #ifndef NDEBUG + struct timeval tv; + gettimeofday(&tv, NULL); + TRACE3("%d.%d: timer %p destroyed, will not fire\n", + tv.tv_sec, tv.tv_usec, this); + #endif + Timers::Remove(*this); } @@ -238,7 +263,31 @@ Timer::Timer(const Timer& rToCopy) : mExpires(rToCopy.mExpires), mExpired(rToCopy.mExpired) { - if (mExpires != 0) + #ifndef NDEBUG + struct timeval tv; + gettimeofday(&tv, NULL); + if (mExpired) + { + TRACE4("%d.%d: timer %p initialised from timer %p, " + "already expired, will not fire\n", tv.tv_sec, + tv.tv_usec, this, &rToCopy); + } + else if (mExpires == 0) + { + TRACE4("%d.%d: timer %p initialised from timer %p, " + "will not fire\n", tv.tv_sec, tv.tv_usec, this, + &rToCopy); + } + else + { + TRACE6("%d.%d: timer %p initialised from timer %p, " + "to fire at %d.%d\n", tv.tv_sec, tv.tv_usec, this, + &rToCopy, (int)(mExpires / 1000000), + (int)(mExpires % 1000000)); + } + #endif + + if (!mExpired && mExpires != 0) { Timers::Add(*this); } @@ -246,6 +295,30 @@ Timer::Timer(const Timer& rToCopy) Timer& Timer::operator=(const Timer& rToCopy) { + #ifndef NDEBUG + struct timeval tv; + gettimeofday(&tv, NULL); + if (rToCopy.mExpired) + { + TRACE4("%d.%d: timer %p initialised from timer %p, " + "already expired, will not fire\n", tv.tv_sec, + tv.tv_usec, this, &rToCopy); + } + else if (rToCopy.mExpires == 0) + { + TRACE4("%d.%d: timer %p initialised from timer %p, " + "will not fire\n", tv.tv_sec, tv.tv_usec, this, + &rToCopy); + } + else + { + TRACE6("%d.%d: timer %p initialised from timer %p, " + "to fire at %d.%d\n", tv.tv_sec, tv.tv_usec, this, + &rToCopy, (int)(rToCopy.mExpires / 1000000), + (int)(rToCopy.mExpires % 1000000)); + } + #endif + Timers::Remove(*this); mExpires = rToCopy.mExpires; mExpired = rToCopy.mExpired; @@ -258,6 +331,12 @@ Timer& Timer::operator=(const Timer& rToCopy) void Timer::OnExpire() { + #ifndef NDEBUG + struct timeval tv; + gettimeofday(&tv, NULL); + TRACE3("%d.%d: timer %p fired\n", tv.tv_sec, tv.tv_usec, this); + #endif + mExpired = true; Timers::Remove(*this); } -- cgit v1.2.3 From 4da1506efb2607f756ec7487eb05335294c354a3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Nov 2006 20:30:36 +0000 Subject: Added ability for delay intercepts to fire multiple times. Added test for repeat keepalives to test/bbackupd. --- lib/intercept/intercept.cpp | 29 ++++++++------- test/bbackupd/testbbackupd.cpp | 81 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 89 insertions(+), 21 deletions(-) diff --git a/lib/intercept/intercept.cpp b/lib/intercept/intercept.cpp index 4f8ef785..21220cc9 100644 --- a/lib/intercept/intercept.cpp +++ b/lib/intercept/intercept.cpp @@ -59,7 +59,7 @@ #include "MemLeakFindOn.h" -bool intercept_enabled = false; +int intercept_count = 0; const char *intercept_filename = 0; int intercept_filedes = -1; off_t intercept_errorafter = 0; @@ -72,7 +72,7 @@ int intercept_delay_ms = 0; void intercept_clear_setup() { - intercept_enabled = false; + intercept_count = 0; intercept_filename = 0; intercept_filedes = -1; intercept_errorafter = 0; @@ -83,13 +83,13 @@ void intercept_clear_setup() bool intercept_triggered() { - return !intercept_enabled; + return intercept_count == 0; } void intercept_setup_error(const char *filename, unsigned int errorafter, int errortoreturn, int syscalltoerror) { TRACE4("Setup for error: %s, after %d, err %d, syscall %d\n", filename, errorafter, errortoreturn, syscalltoerror); - intercept_enabled = true; + intercept_count = 1; intercept_filename = filename; intercept_filedes = -1; intercept_errorafter = errorafter; @@ -100,11 +100,12 @@ void intercept_setup_error(const char *filename, unsigned int errorafter, int er } void intercept_setup_delay(const char *filename, unsigned int delay_after, - int delay_ms, int syscall_to_delay) + int delay_ms, int syscall_to_delay, int num_delays) { - TRACE4("Setup for delay: %s, after %d, wait %d ms, syscall %d\n", - filename, delay_after, delay_ms, syscall_to_delay); - intercept_enabled = true; + TRACE5("Setup for delay: %s, after %d, wait %d ms, times %d, " + "syscall %d\n", filename, delay_after, delay_ms, + num_delays, syscall_to_delay); + intercept_count = num_delays; intercept_filename = filename; intercept_filedes = -1; intercept_errorafter = delay_after; @@ -154,7 +155,7 @@ int intercept_reterr() } #define CHECK_FOR_FAKE_ERROR_COND(D, S, CALL, FAILRES) \ - if(intercept_enabled) \ + if(intercept_count > 0) \ { \ if(intercept_errornow(D, S, CALL)) \ { \ @@ -166,7 +167,11 @@ int intercept_reterr() * 1000000; \ while (nanosleep(&tm, &tm) != 0 && \ errno == EINTR) { } \ - intercept_clear_setup(); \ + intercept_count --; \ + if (intercept_count == 0) \ + { \ + intercept_clear_setup(); \ + } \ } \ else \ { \ @@ -179,7 +184,7 @@ int intercept_reterr() extern "C" int open(const char *path, int flags, mode_t mode) { - if(intercept_enabled) + if(intercept_count > 0) { if(intercept_syscall == SYS_open && strcmp(path, intercept_filename) == 0) { @@ -192,7 +197,7 @@ open(const char *path, int flags, mode_t mode) #else int r = syscall(SYS_open, path, flags, mode); #endif - if(intercept_enabled && intercept_filedes == -1) + if(intercept_count > 0 && intercept_filedes == -1) { // Right file? if(strcmp(intercept_filename, path) == 0) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 36cf4f77..3190970a 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -508,8 +508,9 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) } } -void intercept_setup_delay(const char *filename, unsigned int delay_after, - int delay_ms, int syscall_to_delay); +void intercept_setup_delay(const char *filename, unsigned int delay_after, + int delay_ms, int syscall_to_delay, int num_delays); + bool intercept_triggered(); int start_internal_daemon() @@ -609,7 +610,7 @@ int test_bbackupd() // something to diff against (empty file doesn't work) int fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY); TEST_THAT(fd > 0); - char buffer[1024]; + char buffer[10000]; TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer)); TEST_THAT(close(fd) == 0); @@ -618,7 +619,7 @@ int test_bbackupd() stop_internal_daemon(pid); intercept_setup_delay("testfiles/TestDir1/spacetest/f1", - 0, 2000, SYS_read); + 0, 2000, SYS_read, 1); TEST_THAT(unlink("testfiles/bbackupd.log") == 0); pid = start_internal_daemon(); @@ -659,13 +660,13 @@ int test_bbackupd() TEST_THAT(reader.GetLine(line)); TEST_THAT(line == "Receive Success(0xe)"); TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receiving stream, size 60"); + TEST_THAT(line == "Receiving stream, size 124"); TEST_THAT(reader.GetLine(line)); TEST_THAT(line == "Send GetIsAlive()"); TEST_THAT(reader.GetLine(line)); TEST_THAT(line == "Receive IsAlive()"); - TEST_THAT(reader.GetLine(line)); + TEST_THAT(reader.GetLine(line)); std::string comp = "Send StoreFile(0x3,"; TEST_THAT(line.substr(0, comp.size()) == comp); comp = ",0xe,\"f1\")"; @@ -674,7 +675,7 @@ int test_bbackupd() } intercept_setup_delay("testfiles/TestDir1/spacetest/f1", - 0, 4000, SYS_read); + 0, 4000, SYS_read, 1); pid = start_internal_daemon(); fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY); @@ -710,7 +711,7 @@ int test_bbackupd() TEST_THAT(reader.GetLine(line)); TEST_THAT(line == "Receive Success(0xf)"); TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receiving stream, size 60"); + TEST_THAT(line == "Receiving stream, size 124"); // delaying for 4 seconds in one step means that // the diff timer and the keepalive timer will @@ -724,7 +725,69 @@ int test_bbackupd() TEST_THAT(line.substr(line.size() - comp.size()) == comp); } - + + intercept_setup_delay("testfiles/TestDir1/spacetest/f1", + 0, 1000, SYS_read, 3); + pid = start_internal_daemon(); + + fd = open("testfiles/TestDir1/spacetest/f1", O_WRONLY); + TEST_THAT(fd > 0); + // write again, to update the file's timestamp + TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd) == 0); + + wait_for_backup_operation(); + // can't test whether intercept was triggered, because + // it's in a different process. + // TEST_THAT(intercept_triggered()); + stop_internal_daemon(pid); + + // check that the diff was aborted, i.e. upload was not a diff + found1 = false; + + while (!reader.IsEOF()) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + if (line == "Send GetBlockIndexByName(0x3,\"f1\")") + { + found1 = true; + break; + } + } + + TEST_THAT(found1); + if (found1) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive Success(0x10)"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receiving stream, size 124"); + + // delaying for 3 seconds in steps of 1 second + // means that the keepalive timer will expire 3 times, + // and on the 3rd time the diff timer will expire too. + // The diff timer is honoured first, so there will be + // only two keepalives. + + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Send GetIsAlive()"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive IsAlive()"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Send GetIsAlive()"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive IsAlive()"); + + TEST_THAT(reader.GetLine(line)); + std::string comp = "Send StoreFile(0x3,"; + TEST_THAT(line.substr(0, comp.size()) == comp); + comp = ",0x0,\"f1\")"; + TEST_THAT(line.substr(line.size() - comp.size()) + == comp); + } + // restore timers for rest of tests Timers::Init(); } -- cgit v1.2.3 From 0acac971b2c2ed7ef04e64152d63cbbe2a4c66b1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Nov 2006 20:34:57 +0000 Subject: Replace old-style setitimers for KeepAliveTime and MaximumDiffingTime with new Timer objects. (refs #3, refs #9) --- bin/bbackupd/BackupClientContext.cpp | 112 ++----------------------------- bin/bbackupd/BackupClientContext.h | 7 +- lib/backupclient/BackupStoreFile.h | 6 +- lib/backupclient/BackupStoreFileDiff.cpp | 74 ++++++-------------- 4 files changed, 33 insertions(+), 166 deletions(-) diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index 9f6a5bd3..cb6d8bc7 100644 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -67,8 +67,7 @@ BackupClientContext::BackupClientContext mStorageLimitExceeded(false), mpExcludeFiles(0), mpExcludeDirs(0), - mbIsManaged(false), - mTimeMgmtEpoch(0) + mbIsManaged(false) { } @@ -142,7 +141,7 @@ BackupProtocolClient &BackupClientContext::GetConnection() ASSERT(mpExtendedLogFileHandle == NULL); mpExtendedLogFileHandle = fopen( - mExtendedLogFile.c_str(), "w"); + mExtendedLogFile.c_str(), "a+"); if (!mpExtendedLogFileHandle) { @@ -338,8 +337,8 @@ BackupClientDeleteList &BackupClientContext::GetDeleteList() // -------------------------------------------------------------------------- // // Function -// Name: -// Purpose: +// Name: BackupClientContext::PerformDeletions() +// Purpose: Perform any pending file deletions. // Created: 10/11/03 // // -------------------------------------------------------------------------- @@ -496,7 +495,6 @@ bool BackupClientContext::FindFilename(int64_t ObjectID, int64_t ContainingDirec return true; } - // maximum time to spend diffing static int sMaximumDiffTime = 600; // maximum time of SSL inactivity (keep-alive interval) @@ -514,19 +512,6 @@ void BackupClientContext::SetKeepAliveTime(int iSeconds) TRACE1("Set keep-alive time to %d seconds\n", sKeepAliveTime); } -// -------------------------------------------------------------------------- -// -// Function -// Name: static TimerSigHandler(int) -// Purpose: Signal handler -// Created: 19/3/04 -// -// -------------------------------------------------------------------------- -static void TimerSigHandler(int iUnused) -{ - BackupStoreFile::DiffTimerExpired(); -} - // -------------------------------------------------------------------------- // // Function @@ -537,59 +522,8 @@ static void TimerSigHandler(int iUnused) // -------------------------------------------------------------------------- void BackupClientContext::ManageDiffProcess() { - if (mbIsManaged || !mpConnection) - return; - - ASSERT(mTimeMgmtEpoch == 0); - -#ifdef PLATFORM_CYGWIN - ::signal(SIGALRM, TimerSigHandler); -#elif defined WIN32 - // no support for SIGVTALRM - SetTimerHandler(TimerSigHandler); -#else - ::signal(SIGVTALRM, TimerSigHandler); -#endif // PLATFORM_CYGWIN - - struct itimerval timeout; - memset(&timeout, 0, sizeof(timeout)); - - // - // - // - if (sMaximumDiffTime <= 0 && sKeepAliveTime <= 0) - { - TRACE0("Diff control not requested - letting things run wild\n"); - return; - } - else if (sMaximumDiffTime > 0 && sKeepAliveTime > 0) - { - timeout.it_value.tv_sec = sKeepAliveTime < sMaximumDiffTime ? sKeepAliveTime : sMaximumDiffTime; - timeout.it_interval.tv_sec = sKeepAliveTime < sMaximumDiffTime ? sKeepAliveTime : sMaximumDiffTime; - } - else - { - timeout.it_value.tv_sec = sKeepAliveTime > 0 ? sKeepAliveTime : sMaximumDiffTime; - timeout.it_interval.tv_sec = sKeepAliveTime > 0 ? sKeepAliveTime : sMaximumDiffTime; - } - - // avoid race - mTimeMgmtEpoch = time(NULL); - -#ifdef PLATFORM_CYGWIN - if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) -#else - if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0) -#endif // PLATFORM_CYGWIN - { - mTimeMgmtEpoch = 0; - - TRACE0("WARNING: couldn't set file diff control timeout\n"); - THROW_EXCEPTION(BackupStoreException, Internal) - } - + ASSERT(!mbIsManaged); mbIsManaged = true; - TRACE0("Initiated timer for file diff control\n"); } // -------------------------------------------------------------------------- @@ -602,26 +536,8 @@ void BackupClientContext::ManageDiffProcess() // -------------------------------------------------------------------------- void BackupClientContext::UnManageDiffProcess() { - if (!mbIsManaged /* don't test for active connection, just do it */) - return; - - struct itimerval timeout; - memset(&timeout, 0, sizeof(timeout)); - -#ifdef PLATFORM_CYGWIN - if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) -#else - if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0) -#endif // PLATFORM_CYGWIN - { - TRACE0("WARNING: couldn't clear file diff control timeout\n"); - THROW_EXCEPTION(BackupStoreException, Internal) - } - + // ASSERT(mbIsManaged); mbIsManaged = false; - mTimeMgmtEpoch = 0; - - TRACE0("Suspended timer for file diff control\n"); } // -------------------------------------------------------------------------- @@ -643,26 +559,12 @@ void BackupClientContext::DoKeepAlive() mpConnection->QueryGetIsAlive(); } -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientContext::GetTimeMgmtEpoch() -// Purpose: Returns the unix time when the diff was started, or zero -// if the diff process is unmanaged. -// Created: 04/19/2005 -// -// -------------------------------------------------------------------------- -time_t BackupClientContext::GetTimeMgmtEpoch() -{ - return mTimeMgmtEpoch; -} - int BackupClientContext::GetMaximumDiffingTime() { return sMaximumDiffTime; } -int BackupClientContext::GetKeepaliveTime() +int BackupClientContext::GetKeepAliveTime() { return sKeepAliveTime; } diff --git a/bin/bbackupd/BackupClientContext.h b/bin/bbackupd/BackupClientContext.h index 74a23116..c7e011c8 100644 --- a/bin/bbackupd/BackupClientContext.h +++ b/bin/bbackupd/BackupClientContext.h @@ -193,9 +193,9 @@ public: // // -------------------------------------------------------------------------- virtual void DoKeepAlive(); - virtual time_t GetTimeMgmtEpoch(); virtual int GetMaximumDiffingTime(); - virtual int GetKeepaliveTime(); + virtual int GetKeepAliveTime(); + virtual bool IsManaged() { return mbIsManaged; } private: BackupDaemon &mrDaemon; @@ -217,9 +217,6 @@ private: ExcludeList *mpExcludeDirs; bool mbIsManaged; - // unix time when diff was started - time_t mTimeMgmtEpoch; }; - #endif // BACKUPCLIENTCONTEXT__H diff --git a/lib/backupclient/BackupStoreFile.h b/lib/backupclient/BackupStoreFile.h index 437b4232..784320b6 100644 --- a/lib/backupclient/BackupStoreFile.h +++ b/lib/backupclient/BackupStoreFile.h @@ -51,16 +51,16 @@ public: virtual ~DiffTimer(); public: virtual void DoKeepAlive() = 0; - virtual time_t GetTimeMgmtEpoch() = 0; virtual int GetMaximumDiffingTime() = 0; - virtual int GetKeepaliveTime() = 0; + virtual int GetKeepAliveTime() = 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/BackupStoreFileDiff.cpp b/lib/backupclient/BackupStoreFileDiff.cpp index ee09f1c8..d04cda6c 100644 --- a/lib/backupclient/BackupStoreFileDiff.cpp +++ b/lib/backupclient/BackupStoreFileDiff.cpp @@ -29,6 +29,7 @@ #include "RollingChecksum.h" #include "MD5Digest.h" #include "CommonException.h" +#include "Timer.h" #include "MemLeakFindOn.h" @@ -52,31 +53,6 @@ static bool SecondStageMatch(BlocksAvailableEntry *pFirstInHashList, RollingChec BlocksAvailableEntry *pIndex, std::map &rFoundBlocks); static void GenerateRecipe(BackupStoreFileEncodeStream::Recipe &rRecipe, BlocksAvailableEntry *pIndex, int64_t NumBlocks, std::map &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 @@ -483,15 +459,13 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map 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); + Timer keepAliveTime(0); - if (pDiffTimer) + if (pDiffTimer && pDiffTimer->IsManaged()) { - TimeMgmtEpoch = pDiffTimer->GetTimeMgmtEpoch(); - MaximumDiffingTime = pDiffTimer->GetMaximumDiffingTime(); - KeepAliveTime = pDiffTimer->GetKeepaliveTime(); + maximumDiffingTime = Timer(pDiffTimer->GetMaximumDiffingTime()); + keepAliveTime = Timer(pDiffTimer->GetKeepAliveTime()); } std::map goodnessOfFit; @@ -577,29 +551,23 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map 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; + TRACE0("MaximumDiffingTime reached - " + "suspending file diff\n"); + abortSearch = true; + break; + } + + if(keepAliveTime.HasExpired()) + { + ASSERT(pDiffTimer != NULL); + TRACE0("KeepAliveTime reached - " + "initiating keep-alive\n"); + pDiffTimer->DoKeepAlive(); + keepAliveTime = Timer( + pDiffTimer->GetKeepAliveTime()); } // Load in another block of data, and record how big it is -- cgit v1.2.3 From dced05942c5a28450dfa8de02f58f8b6ac66de4e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:27:08 +0000 Subject: Search for dlfcn.h and dlsym() (needed for new intercept code) (refs #3, refs #9) --- configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 99165a38..8b0cf7d0 100644 --- a/configure.ac +++ b/configure.ac @@ -94,7 +94,7 @@ esac AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([execinfo.h process.h pwd.h signal.h]) +AC_CHECK_HEADERS([dlfcn.h execinfo.h process.h pwd.h signal.h]) AC_CHECK_HEADERS([syslog.h time.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h]) @@ -107,6 +107,8 @@ if test "$have_regex_h" = "yes"; then AC_SEARCH_LIBS([regcomp], ["pcreposix -lpcre"]) fi +AC_SEARCH_LIBS([dlsym], ["dl"]) + ### Checks for typedefs, structures, and compiler characteristics. AC_CHECK_TYPES([u_int8_t, u_int16_t, u_int32_t, u_int64_t]) -- cgit v1.2.3 From 7400293edc37751f109afc8a5516108b61474374 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:27:16 +0000 Subject: Pass any command-line parameters from t-gdb to gdb (refs #3) --- infrastructure/makebuildenv.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index 09176c9c..9d641d78 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -447,7 +447,7 @@ __E writetestfile("$mod/_t", "GLIBCXX_FORCE_NEW=1 ". './test' . $platform_exe_ext . ' $1 $2 $3 $4 $5', $mod); writetestfile("$mod/_t-gdb", "GLIBCXX_FORCE_NEW=1 ". - 'gdb ./test' . $platform_exe_ext, $mod); + 'gdb ./test' . $platform_exe_ext . ' $*', $mod); } -- cgit v1.2.3 From 4008ada60d5fdf946a8c5e5aa03ea0f01172335d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:29:01 +0000 Subject: Added a header file for including in test/bbackupd/testbbackupd.cpp and other modules which might need intercepts in future. Added opendir/readdir and lstat hook capability. (refs #3, refs #9) --- lib/intercept/intercept.cpp | 175 ++++++++++++++++++++++++++++++++++++++++++++ lib/intercept/intercept.h | 42 +++++++++++ 2 files changed, 217 insertions(+) create mode 100644 lib/intercept/intercept.h diff --git a/lib/intercept/intercept.cpp b/lib/intercept/intercept.cpp index 21220cc9..a4dfcc37 100644 --- a/lib/intercept/intercept.cpp +++ b/lib/intercept/intercept.cpp @@ -9,6 +9,8 @@ #include "Box.h" +#include "intercept.h" + #ifdef HAVE_SYS_SYSCALL_H #include #endif @@ -21,6 +23,10 @@ #include +#ifdef HAVE_DLFCN_H +#include +#endif + #ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE #if !defined(HAVE_SYSCALL) && !defined(HAVE___SYSCALL) && !defined(HAVE___SYSCALL_NEED_DEFN) @@ -317,4 +323,173 @@ lseek(int fildes, off_t offset, int whence) return r; } +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; + +void intercept_setup_readdir_hook(const char *dirname, readdir_t hookfn) +{ + if (hookfn != NULL && dirname == NULL) + { + dirname = intercept_filename; + } + + if (hookfn != NULL) + { + TRACE2("readdir hooked to %p for %s\n", hookfn, dirname); + } + else + { + 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; +} + +extern "C" +DIR *opendir(const char *dirname) +{ + if (opendir_real == NULL) + { + opendir_real = (opendir_t*)(dlsym(RTLD_NEXT, "opendir")); + } + + if (opendir_real == NULL) + { + perror("cannot find real opendir"); + return NULL; + } + + DIR* r = opendir_real(dirname); + + if(readdir_hook != 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) + { + #if readdir == readdir64 + readdir_real = (readdir_t*)(dlsym(RTLD_NEXT, "readdir64")); + #else + readdir_real = (readdir_t*)(dlsym(RTLD_NEXT, "readdir")); + #endif + } + + 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*)(dlsym(RTLD_NEXT, "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 + #if __lxstat == __lxstat64 + lstat_real = (lstat_t*)(dlsym(RTLD_NEXT, "__lxstat64")); + #else + lstat_real = (lstat_t*)(dlsym(RTLD_NEXT, "__lxstat")); + #endif + #else + #if lstat == lstat64 + lstat_real = (lstat_t*)(dlsym(RTLD_NEXT, "lstat64")); + #else + lstat_real = (lstat_t*)(dlsym(RTLD_NEXT, "lstat")); + #endif + #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..b1122434 --- /dev/null +++ b/lib/intercept/intercept.h @@ -0,0 +1,42 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: intercept.h +// Purpose: Syscall interception code for unit tests +// Created: 2006/11/29 +// +// -------------------------------------------------------------------------- + +#ifndef INTERCEPT_H +#define INTERCEPT_H + +#include + +#include +#include + +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_readdir_hook(const char *dirname, readdir_t hookfn); +void intercept_setup_lstat_hook (const char *filename, lstat_t hookfn); + +#endif // !INTERCEPT_H -- cgit v1.2.3 From d0dd0927ea58a8c2520ff1dac7f9d7ed175b2336 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:30:02 +0000 Subject: Document that restore -d can be used to restore deleted files in any directory, deleted or not. (refs #3) --- bin/bbackupquery/documentation.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupquery/documentation.txt b/bin/bbackupquery/documentation.txt index 0fb0bacb..42217edc 100644 --- a/bin/bbackupquery/documentation.txt +++ b/bin/bbackupquery/documentation.txt @@ -123,7 +123,7 @@ compare The root cannot be restored -- restore locations individually. - -d -- restore a deleted directory. + -d -- restore a deleted directory or deleted files inside -r -- resume an interrupted restoration -i -- directory name is actually an ID -- cgit v1.2.3 From cfba32e21cf52dcc85305c5cfda0a69bc29fe095 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:31:49 +0000 Subject: Log failure to rename ID map files. (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 62e2d8e9..295636aa 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1807,6 +1807,10 @@ void BackupDaemon::CommitIDMapsAfterSync() #endif if(::rename(newmap.c_str(), target.c_str()) != 0) { + ::syslog(LOG_ERR, "failed to rename ID map: " + "%s to %s: %s", + newmap.c_str(), target.c_str(), + strerror(errno)); THROW_EXCEPTION(CommonException, OSFileError) } } -- cgit v1.2.3 From 7a47551a8c2eba625a1f32c4c7dd61015ebeaa36 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:33:42 +0000 Subject: Added tests for keepalives while scanning large directories. (refs #3, refs #9) --- test/bbackupd/testbbackupd.cpp | 139 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 3190970a..8a1c711f 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -49,6 +49,7 @@ #include "Timer.h" #include "FileStream.h" #include "IOStreamGetLine.h" +#include "intercept.h" #include "MemLeakFindOn.h" @@ -578,6 +579,70 @@ void stop_internal_daemon(int pid) */ } +static struct dirent readdir_test_dirent; +static int readdir_test_counter = 0; +static int readdir_stop_time = 0; +static char stat_hook_filename[512]; + +// First test hook, during the directory scanning stage, returns empty. +// This will not match the directory on the store, so a sync will start. +// We set up the next intercept for the same directory by passing NULL. + +struct dirent *readdir_test_hook_2(DIR *dir); + +#ifdef LINUX_WEIRD_LSTAT +int lstat_test_hook(int ver, const char *file_name, struct stat *buf); +#else +int lstat_test_hook(const char *file_name, struct stat *buf); +#endif + +struct dirent *readdir_test_hook_1(DIR *dir) +{ + intercept_setup_readdir_hook(NULL, readdir_test_hook_2); + return NULL; +} + +// Second test hook, during the directory sync stage, keeps returning +// new filenames until the timer expires, then disables the intercept. + +struct dirent *readdir_test_hook_2(DIR *dir) +{ + if (time(NULL) >= readdir_stop_time) + { + intercept_setup_readdir_hook(NULL, NULL); + intercept_setup_lstat_hook (NULL, NULL); + // we will not be called again. + } + + // fill in the struct dirent appropriately + memset(&readdir_test_dirent, 0, sizeof(readdir_test_dirent)); + readdir_test_dirent.d_ino = ++readdir_test_counter; + snprintf(readdir_test_dirent.d_name, + sizeof(readdir_test_dirent.d_name), + "test.%d", readdir_test_counter); + + // ensure that when bbackupd stats the file, it gets the + // right answer + snprintf(stat_hook_filename, sizeof(stat_hook_filename), + "testfiles/TestDir1/spacetest/d1/test.%d", + readdir_test_counter); + intercept_setup_lstat_hook(stat_hook_filename, lstat_test_hook); + + return &readdir_test_dirent; +} + +#ifdef LINUX_WEIRD_LSTAT +int lstat_test_hook(int ver, const char *file_name, struct stat *buf) +#else +int lstat_test_hook(const char *file_name, struct stat *buf) +#endif +{ + // TRACE1("lstat hook triggered for %s", file_name); + memset(buf, 0, sizeof(*buf)); + buf->st_mode = S_IFREG; + return 0; +} + int test_bbackupd() { // // First, wait for a normal period to make sure the last changes attributes are within a normal backup timeframe. @@ -788,6 +853,80 @@ int test_bbackupd() == comp); } + intercept_setup_readdir_hook("testfiles/TestDir1/spacetest/d1", + readdir_test_hook_1); + + // time for at least two keepalives + readdir_stop_time = time(NULL) + 12 + 2; + + pid = start_internal_daemon(); + + std::string touchfile = + "testfiles/TestDir1/spacetest/d1/touch-me"; + + fd = open(touchfile.c_str(), O_CREAT | O_WRONLY); + TEST_THAT(fd > 0); + // write again, to update the file's timestamp + TEST_THAT(write(fd, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd) == 0); + + wait_for_backup_operation(); + // can't test whether intercept was triggered, because + // it's in a different process. + // TEST_THAT(intercept_triggered()); + stop_internal_daemon(pid); + + // check that keepalives were sent during the dir search + found1 = false; + + // skip to next login + while (!reader.IsEOF()) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + if (line == "Send ListDirectory(0x3,0xffffffff,0xc,true)") + { + found1 = true; + break; + } + } + + TEST_THAT(found1); + if (found1) + { + found1 = false; + + while (!reader.IsEOF()) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + if (line == "Send ListDirectory(0x3,0xffffffff,0xc,true)") + { + found1 = true; + break; + } + } + } + + if (found1) + { + std::string line; + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive Success(0x3)"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receiving stream, size 425"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Send GetIsAlive()"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive IsAlive()"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Send GetIsAlive()"); + TEST_THAT(reader.GetLine(line)); + TEST_THAT(line == "Receive IsAlive()"); + } + + TEST_THAT(unlink(touchfile.c_str()) == 0); + // restore timers for rest of tests Timers::Init(); } -- cgit v1.2.3 From e0a80f0da840849a5cdb38bcfea7a7e240a2aa2d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:40:26 +0000 Subject: Moved KeepAlive timer to BackupClientContext object. Made timeout initialisation non-static, and a property of the context object. (perhaps should be in rParams, I know). (refs #3, refs #9) --- bin/bbackupd/BackupClientContext.cpp | 39 ++++++++++++++++++-------------- bin/bbackupd/BackupClientContext.h | 18 ++++++++------- bin/bbackupd/BackupDaemon.cpp | 13 +++++++---- lib/backupclient/BackupStoreFile.h | 7 +++--- lib/backupclient/BackupStoreFileDiff.cpp | 13 +++-------- 5 files changed, 47 insertions(+), 43 deletions(-) diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index cb6d8bc7..516c88bc 100644 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -67,6 +67,7 @@ BackupClientContext::BackupClientContext mStorageLimitExceeded(false), mpExcludeFiles(0), mpExcludeDirs(0), + mKeepAliveTimer(0), mbIsManaged(false) { } @@ -495,21 +496,17 @@ bool BackupClientContext::FindFilename(int64_t ObjectID, int64_t ContainingDirec return true; } -// maximum time to spend diffing -static int sMaximumDiffTime = 600; -// maximum time of SSL inactivity (keep-alive interval) -static int sKeepAliveTime = 0; - void BackupClientContext::SetMaximumDiffingTime(int iSeconds) { - sMaximumDiffTime = iSeconds < 0 ? 0 : iSeconds; - TRACE1("Set maximum diffing time to %d seconds\n", sMaximumDiffTime); + mMaximumDiffingTime = iSeconds < 0 ? 0 : iSeconds; + TRACE1("Set maximum diffing time to %d seconds\n", mMaximumDiffingTime); } void BackupClientContext::SetKeepAliveTime(int iSeconds) { - sKeepAliveTime = iSeconds < 0 ? 0 : iSeconds; - TRACE1("Set keep-alive time to %d seconds\n", sKeepAliveTime); + mKeepAliveTime = iSeconds < 0 ? 0 : iSeconds; + TRACE1("Set keep-alive time to %d seconds\n", mKeepAliveTime); + mKeepAliveTimer = Timer(mKeepAliveTime); } // -------------------------------------------------------------------------- @@ -544,7 +541,8 @@ void BackupClientContext::UnManageDiffProcess() // // Function // Name: BackupClientContext::DoKeepAlive() -// Purpose: Does something inconsequential over the SSL link to keep it up +// Purpose: Check whether it's time to send a KeepAlive +// message over the SSL link, and if so, send it. // Created: 04/19/2005 // // -------------------------------------------------------------------------- @@ -552,19 +550,26 @@ void BackupClientContext::DoKeepAlive() { if (!mpConnection) { - ::syslog(LOG_ERR, "DoKeepAlive() called with no connection!"); + return; + } + + if (mKeepAliveTime == 0) + { return; } + if (!mKeepAliveTimer.HasExpired()) + { + return; + } + + TRACE0("KeepAliveTime reached, sending keep-alive message\n"); mpConnection->QueryGetIsAlive(); + + mKeepAliveTimer = Timer(mKeepAliveTime); } int BackupClientContext::GetMaximumDiffingTime() { - return sMaximumDiffTime; -} - -int BackupClientContext::GetKeepAliveTime() -{ - return sKeepAliveTime; + return mMaximumDiffingTime; } diff --git a/bin/bbackupd/BackupClientContext.h b/bin/bbackupd/BackupClientContext.h index c7e011c8..152d8556 100644 --- a/bin/bbackupd/BackupClientContext.h +++ b/bin/bbackupd/BackupClientContext.h @@ -14,6 +14,7 @@ #include "BackupClientDeleteList.h" #include "BackupStoreFile.h" #include "ExcludeList.h" +#include "Timer.h" class TLSContext; class BackupProtocolClient; @@ -151,7 +152,7 @@ public: // Created: 04/19/2005 // // -------------------------------------------------------------------------- - static void SetMaximumDiffingTime(int iSeconds); + void SetMaximumDiffingTime(int iSeconds); // -------------------------------------------------------------------------- // @@ -161,7 +162,7 @@ public: // Created: 04/19/2005 // // -------------------------------------------------------------------------- - static void SetKeepAliveTime(int iSeconds); + void SetKeepAliveTime(int iSeconds); // -------------------------------------------------------------------------- // @@ -183,18 +184,17 @@ public: // -------------------------------------------------------------------------- void UnManageDiffProcess(); - // -------------------------------------------------------------------------- + // ------------------------------------------------------------------- // // Function // Name: BackupClientContext::DoKeepAlive() - // Purpose: Does something inconsequential over the SSL link to - // keep it up, implements DiffTimer interface + // Purpose: Check whether it's time to send a KeepAlive + // message over the SSL link, and if so, send it. // Created: 04/19/2005 // - // -------------------------------------------------------------------------- + // ------------------------------------------------------------------- virtual void DoKeepAlive(); virtual int GetMaximumDiffingTime(); - virtual int GetKeepAliveTime(); virtual bool IsManaged() { return mbIsManaged; } private: @@ -215,8 +215,10 @@ private: bool mStorageLimitExceeded; ExcludeList *mpExcludeFiles; ExcludeList *mpExcludeDirs; - + Timer mKeepAliveTimer; bool mbIsManaged; + int mKeepAliveTime; + int mMaximumDiffingTime; }; #endif // BACKUPCLIENTCONTEXT__H diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 295636aa..4f9c9274 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -523,18 +523,20 @@ void BackupDaemon::Run2() // Set up the keys for various things BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile").c_str()); + // Setup various timings + int maximumDiffingTime = 600; + int keepAliveTime = 60; + // max diffing time, keep-alive time if(conf.KeyExists("MaximumDiffingTime")) { - BackupClientContext::SetMaximumDiffingTime(conf.GetKeyValueInt("MaximumDiffingTime")); + maximumDiffingTime = conf.GetKeyValueInt("MaximumDiffingTime"); } if(conf.KeyExists("KeepAliveTime")) { - BackupClientContext::SetKeepAliveTime(conf.GetKeyValueInt("KeepAliveTime")); + keepAliveTime = conf.GetKeyValueInt("KeepAliveTime"); } - // Setup various timings - // How often to connect to the store (approximate) box_time_t updateStoreInterval = SecondsToBoxTime(conf.GetKeyValueInt("UpdateStoreInterval")); @@ -725,6 +727,9 @@ void BackupDaemon::Run2() params.mFileTrackingSizeThreshold = conf.GetKeyValueInt("FileTrackingSizeThreshold"); params.mDiffingUploadSizeThreshold = conf.GetKeyValueInt("DiffingUploadSizeThreshold"); params.mMaxFileTimeInFuture = SecondsToBoxTime(conf.GetKeyValueInt("MaxFileTimeInFuture")); + + clientContext.SetMaximumDiffingTime(maximumDiffingTime); + clientContext.SetKeepAliveTime(keepAliveTime); // Set store marker clientContext.SetClientStoreMarker(clientStoreMarker); diff --git a/lib/backupclient/BackupStoreFile.h b/lib/backupclient/BackupStoreFile.h index 784320b6..3ee5ddb0 100644 --- a/lib/backupclient/BackupStoreFile.h +++ b/lib/backupclient/BackupStoreFile.h @@ -50,10 +50,9 @@ public: DiffTimer(); virtual ~DiffTimer(); public: - virtual void DoKeepAlive() = 0; - virtual int GetMaximumDiffingTime() = 0; - virtual int GetKeepAliveTime() = 0; - virtual bool IsManaged() = 0; + virtual void DoKeepAlive() = 0; + virtual int GetMaximumDiffingTime() = 0; + virtual bool IsManaged() = 0; }; // -------------------------------------------------------------------------- diff --git a/lib/backupclient/BackupStoreFileDiff.cpp b/lib/backupclient/BackupStoreFileDiff.cpp index d04cda6c..3a3f1a5e 100644 --- a/lib/backupclient/BackupStoreFileDiff.cpp +++ b/lib/backupclient/BackupStoreFileDiff.cpp @@ -460,12 +460,10 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES], DiffTimer *pDiffTimer) { Timer maximumDiffingTime(0); - Timer keepAliveTime(0); - if (pDiffTimer && pDiffTimer->IsManaged()) + if(pDiffTimer && pDiffTimer->IsManaged()) { maximumDiffingTime = Timer(pDiffTimer->GetMaximumDiffingTime()); - keepAliveTime = Timer(pDiffTimer->GetKeepAliveTime()); } std::map goodnessOfFit; @@ -560,16 +558,11 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map break; } - if(keepAliveTime.HasExpired()) + if(pDiffTimer) { - ASSERT(pDiffTimer != NULL); - TRACE0("KeepAliveTime reached - " - "initiating keep-alive\n"); pDiffTimer->DoKeepAlive(); - keepAliveTime = Timer( - pDiffTimer->GetKeepAliveTime()); } - + // Load in another block of data, and record how big it is int bytesInEndings = rFile.Read(endings, Sizes[s]); int tmp; -- cgit v1.2.3 From 3728ab83d06d0e4e7f1739ec4e7480aaeaf0846d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:41:01 +0000 Subject: Send keepalives when needed while scanning large directories (refs #3, refs #9) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 1db6cbe5..c05a23fc 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -223,6 +223,8 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn std::string filename; while((en = ::readdir(dirHandle)) != 0) { + rParams.mrContext.DoKeepAlive(); + // Don't need to use LinuxWorkaround_FinishDirentStruct(en, rLocalPath.c_str()); // on Linux, as a stat is performed to get all this info @@ -574,6 +576,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP for(std::vector::const_iterator f = rFiles.begin(); f != rFiles.end(); ++f) { + // Send keep-alive message if needed + rParams.mrContext.DoKeepAlive(); + // Filename of this file std::string filename(MakeFullPath(rLocalPath, *f)); @@ -921,6 +926,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP for(std::vector::const_iterator d = rDirs.begin(); d != rDirs.end(); ++d) { + // Send keep-alive message if needed + rParams.mrContext.DoKeepAlive(); + // Get the local filename std::string dirname(MakeFullPath(rLocalPath, *d)); -- cgit v1.2.3 From bc82918ca28737fc934c33b69e13bb2efb28d89e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 10:52:38 +0000 Subject: Make the timer test reliable by using nanosleep() instead of sleep(), since sleep() may use signals and interfere with SIGALRM, and also cannot be resumed if interrupted by a signal. (refs #3, refs #9). --- test/common/testcommon.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 04d93bb2..bac26ff3 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -9,7 +9,9 @@ #include "Box.h" +#include #include +#include #include "Test.h" #include "Configuration.h" @@ -134,6 +136,15 @@ ConfigurationVerify verify = 0 }; +void safe_sleep(int seconds) +{ + struct timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = 0; + while (nanosleep(&ts, &ts) == -1 && errno == EINTR) + { /* sleep again */ } +} + int test(int argc, const char *argv[]) { // Test self-deleting temporary file streams @@ -254,13 +265,13 @@ int test(int argc, const char *argv[]) TEST_THAT(!t2.HasExpired()); TEST_THAT(!t3.HasExpired()); - sleep(1); + safe_sleep(1); TEST_THAT(!t0.HasExpired()); TEST_THAT(t1.HasExpired()); TEST_THAT(!t2.HasExpired()); TEST_THAT(!t3.HasExpired()); - sleep(1); + safe_sleep(1); TEST_THAT(!t0.HasExpired()); TEST_THAT(t1.HasExpired()); TEST_THAT(t2.HasExpired()); @@ -272,7 +283,7 @@ int test(int argc, const char *argv[]) TEST_THAT(!t1.HasExpired()); TEST_THAT(!t2.HasExpired()); - sleep(1); + safe_sleep(1); TEST_THAT(!t0.HasExpired()); TEST_THAT(t1.HasExpired()); TEST_THAT(!t2.HasExpired()); -- cgit v1.2.3 From cff19bd8c52b58095aaf2aa35f38673c29f1aa88 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Dec 2006 13:58:14 +0000 Subject: Fixed a race condition caused by rescheduling in signal handler (refs #3, refs #9) --- lib/common/Timer.cpp | 84 ++++++++++++++++++++++++++++------------------ lib/common/Timer.h | 56 +++++++++++++++++++++---------- test/common/testcommon.cpp | 2 +- 3 files changed, 90 insertions(+), 52 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index 76b700d3..10365e03 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -17,19 +17,7 @@ #include "MemLeakFindOn.h" std::vector* Timers::spTimers = NULL; - -// -------------------------------------------------------------------------- -// -// Function -// Name: static void TimerSigHandler(int) -// Purpose: Signal handler, notifies Timers class -// Created: 19/3/04 -// -// -------------------------------------------------------------------------- -static void TimerSigHandler(int iUnused) -{ - Timers::Signal(); -} +bool Timers::sRescheduleNeeded = false; // -------------------------------------------------------------------------- // @@ -43,15 +31,13 @@ void Timers::Init() { ASSERT(!spTimers); - #ifdef PLATFORM_CYGWIN - ASSERT(::signal(SIGALRM, TimerSigHandler) == 0); - #elif defined WIN32 + #if defined WIN32 && ! defined PLATFORM_CYGWIN // no support for signals at all InitTimer(); - SetTimerHandler(TimerSigHandler); + SetTimerHandler(Timers::SignalHandler); #else - ASSERT(::signal(SIGALRM, TimerSigHandler) == 0); - #endif // PLATFORM_CYGWIN + ASSERT(::signal(SIGALRM, Timers::SignalHandler) == 0); + #endif // WIN32 && !PLATFORM_CYGWIN spTimers = new std::vector; } @@ -68,15 +54,13 @@ void Timers::Cleanup() { ASSERT(spTimers); - #ifdef PLATFORM_CYGWIN - ASSERT(::signal(SIGALRM, NULL) == TimerSigHandler); - #elif defined WIN32 + #if defined WIN32 && ! defined PLATFORM_CYGWIN // no support for signals at all SetTimerHandler(NULL); FiniTimer(); #else - ASSERT(::signal(SIGALRM, NULL) == TimerSigHandler); - #endif // PLATFORM_CYGWIN + ASSERT(::signal(SIGALRM, NULL) == Timers::SignalHandler); + #endif // WIN32 && !PLATFORM_CYGWIN spTimers->clear(); delete spTimers; @@ -142,17 +126,48 @@ void Timers::Reschedule() { ASSERT(spTimers); + // Set 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; + + // scan for and remove expired timers, which requires + // us to restart the scan each time we remove one. + bool restart = true; + while (restart) + { + restart = false; + + for (std::vector::iterator i = spTimers->begin(); + i != spTimers->end(); i++) + { + Timer& rTimer = **i; + if (rTimer.HasExpired()) + { + spTimers->erase(i); + restart = true; + break; + } + } + } + + // Now the only remaining timers should all be in the future. + // Scan to find the next one to fire (earliest deadline). + box_time_t timeNow = GetCurrentBoxTime(); int64_t timeToNextEvent = 0; - + for (std::vector::iterator i = spTimers->begin(); i != spTimers->end(); i++) { Timer& rTimer = **i; - ASSERT(!rTimer.HasExpired()); - int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; - if (timeToExpiry <= 0) timeToExpiry = 1; + + if (timeToExpiry <= 0) + { + timeToExpiry = 1; + } if (timeToNextEvent == 0 || timeToNextEvent > timeToExpiry) { @@ -183,14 +198,17 @@ void Timers::Reschedule() // -------------------------------------------------------------------------- // // Function -// Name: static void Timers::Signal() -// Purpose: Called by signal handler. Signals any timers which +// Name: static void Timers::SignalHandler(unused) +// Purpose: Called as signal handler. Signals any timers which // are due or overdue, removes them from the set, -// and reschedules next wakeup. +// and requests a reschedule event. The actual +// reschedule will happen next time someone calls +// Timer::HasExpired(), which may be rather late, +// but we can't do it from here, in signal context. // Created: 5/11/2006 // // -------------------------------------------------------------------------- -void Timers::Signal() +void Timers::SignalHandler(int iUnused) { ASSERT(spTimers); @@ -212,7 +230,7 @@ void Timers::Signal() } } - Reschedule(); + Timers::RequestReschedule(); } Timer::Timer(size_t timeoutSecs) diff --git a/lib/common/Timer.h b/lib/common/Timer.h index e0eb34db..390442df 100644 --- a/lib/common/Timer.h +++ b/lib/common/Timer.h @@ -18,23 +18,7 @@ #include "MemLeakFindOn.h" #include "BoxTime.h" -class Timer -{ -public: - Timer(size_t timeoutSecs); - virtual ~Timer(); - Timer(const Timer &); - Timer &operator=(const Timer &); - -public: - box_time_t GetExpiryTime() { return mExpires; } - bool HasExpired () { return mExpired; } - virtual void OnExpire (); - -private: - box_time_t mExpires; - bool mExpired; -}; +class Timer; // -------------------------------------------------------------------------- // @@ -50,13 +34,49 @@ class Timers private: static std::vector* 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 Signal(); + 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" diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index bac26ff3..ec33b003 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -238,7 +238,7 @@ int test(int argc, const char *argv[]) CommonException, AssertFailed); TEST_CHECK_THROWS(Timers::Remove(*(Timer*)NULL), CommonException, AssertFailed); - TEST_CHECK_THROWS(Timers::Signal(), CommonException, AssertFailed); + // TEST_CHECK_THROWS(Timers::Signal(), CommonException, AssertFailed); TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, AssertFailed); // Check that we can initialise the timers -- cgit v1.2.3 From e12cf86c104980d3138e3786d89739673792f465 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 12 Dec 2006 22:40:31 +0000 Subject: Compile fix: include MemLeakFinder.h even on release builds (refs #3) --- lib/common/DebugMemLeakFinder.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp index 64ea0bd3..26cfcbf4 100644 --- a/lib/common/DebugMemLeakFinder.cpp +++ b/lib/common/DebugMemLeakFinder.cpp @@ -25,6 +25,8 @@ #include #include +#include "MemLeakFinder.h" + static bool memleakfinder_initialised = false; bool memleakfinder_global_enable = false; -- cgit v1.2.3 From f996ca761339f4c4b5c32604e1800e683aa40930 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 12 Dec 2006 22:42:07 +0000 Subject: Compile fix: include std::string definition (refs #3) --- infrastructure/buildenv-testmain-template.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index b6d20204..01fbc11a 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef WIN32 #include "emu.h" -- cgit v1.2.3 From 5884ded87261d294842bdcceeca84411a9919ec8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 13 Dec 2006 21:54:16 +0000 Subject: Fix more deadlocks by minimising the amount of stuff that the signal handler does. (refs #3, refs #9) --- lib/common/Timer.cpp | 62 +++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index 10365e03..de01f9f0 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -126,14 +126,16 @@ void Timers::Reschedule() { ASSERT(spTimers); - // Set the reschedule-needed flag to false before we start. + // 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; - // scan for and remove expired timers, which requires - // us to restart the scan each time we remove one. + 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) { @@ -143,19 +145,36 @@ void Timers::Reschedule() i != spTimers->end(); i++) { Timer& rTimer = **i; - if (rTimer.HasExpired()) + int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; + + if (timeToExpiry <= 0) { + TRACE3("%d.%d: timer %p has expired, " + "triggering it\n", + (int)(timeNow / 1000000), + (int)(timeNow % 1000000), + *i); + rTimer.OnExpire(); spTimers->erase(i); restart = true; break; } + else + { + TRACE5("%d.%d: timer %p has not expired, " + "triggering in %d.%d seconds\n", + (int)(timeNow / 1000000), + (int)(timeNow % 1000000), + *i, + (int)(timeToExpiry / 1000000), + (int)(timeToExpiry % 1000000)); + } } } // Now the only remaining timers should all be in the future. // Scan to find the next one to fire (earliest deadline). - box_time_t timeNow = GetCurrentBoxTime(); int64_t timeToNextEvent = 0; for (std::vector::iterator i = spTimers->begin(); @@ -199,37 +218,17 @@ void Timers::Reschedule() // // Function // Name: static void Timers::SignalHandler(unused) -// Purpose: Called as signal handler. Signals any timers which -// are due or overdue, removes them from the set, -// and requests a reschedule event. The actual -// reschedule will happen next time someone calls -// Timer::HasExpired(), which may be rather late, -// but we can't do it from here, in signal context. +// 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); - - box_time_t timeNow = GetCurrentBoxTime(); - - std::vector timersCopy = *spTimers; - - for (std::vector::iterator i = timersCopy.begin(); - i != timersCopy.end(); i++) - { - Timer& rTimer = **i; - ASSERT(!rTimer.HasExpired()); - - int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; - - if (timeToExpiry <= 0) - { - rTimer.OnExpire(); - } - } - + // ASSERT(spTimers); Timers::RequestReschedule(); } @@ -356,5 +355,4 @@ void Timer::OnExpire() #endif mExpired = true; - Timers::Remove(*this); } -- cgit v1.2.3 From a794865079497b8988b87529867299d7fa057ba7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 14 Dec 2006 21:35:21 +0000 Subject: Added missing Makefile.extra to link against bbackupd objects, so that our internal daemon test code will compile. --- test/bbackupd/Makefile.extra | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/bbackupd/Makefile.extra diff --git a/test/bbackupd/Makefile.extra b/test/bbackupd/Makefile.extra new file mode 100644 index 00000000..e6e4849a --- /dev/null +++ b/test/bbackupd/Makefile.extra @@ -0,0 +1 @@ +link-extra: ../../bin/bbackupd/BackupClientContext.o ../../bin/bbackupd/BackupClientDeleteList.o ../../bin/bbackupd/BackupClientDirectoryRecord.o ../../bin/bbackupd/Win32BackupService.o ../../bin/bbackupd/BackupClientInodeToIDMap.o ../../bin/bbackupd/Win32ServiceFunctions.o ../../bin/bbackupd/BackupDaemon.o -- cgit v1.2.3 From 9c799b67a6ce53b0d999c280915e8a618ae04756 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 15 Dec 2006 09:19:27 +0000 Subject: Disable standard library memory leak debugging, as it causes hangs on FC2 --- lib/common/DebugMemLeakFinder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp index 26cfcbf4..fbc684e8 100644 --- a/lib/common/DebugMemLeakFinder.cpp +++ b/lib/common/DebugMemLeakFinder.cpp @@ -461,10 +461,14 @@ void *operator new[](size_t size, const char *file, int line) // 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) { -- cgit v1.2.3 From 86300ca399680282c05bdccf1cf2830bea1f49d7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 16 Dec 2006 16:12:35 +0000 Subject: Improved debugging when a path to a location doesn't exist or can't be opened. (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 4f9c9274..87955fa4 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1562,8 +1562,19 @@ TRACE0("new location\n"); // First, get the directory's attributes and modification time box_time_t attrModTime = 0; BackupClientFileAttributes attr; - attr.ReadAttributes(ploc->mPath.c_str(), true /* directories have zero mod times */, - 0 /* not interested in mod time */, &attrModTime /* get the attribute modification time */); + try + { + attr.ReadAttributes(ploc->mPath.c_str(), + true /* directories have zero mod times */, + 0 /* not interested in mod time */, + &attrModTime /* get the attribute modification time */); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to get attributes for path " + "'%s', skipping.", ploc->mPath.c_str()); + continue; + } // Execute create directory command MemBlockStream attrStream(attr); @@ -1587,6 +1598,8 @@ TRACE0("new location\n"); { delete ploc; ploc = 0; + ::syslog(LOG_ERR, "Failed to setup location '%s' path '%s'", + ploc->mName.c_str(), ploc->mPath.c_str()); throw; } } -- cgit v1.2.3 From 1e14bb0876a81f4168ea028dddd53e8a81c1c727 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 16 Dec 2006 16:15:07 +0000 Subject: Added implementation of getopt from BSD (refs #3) (check license!) --- lib/win32/getopt_long.cxx | 547 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 547 insertions(+) create mode 100755 lib/win32/getopt_long.cxx diff --git a/lib/win32/getopt_long.cxx b/lib/win32/getopt_long.cxx new file mode 100755 index 00000000..c6800426 --- /dev/null +++ b/lib/win32/getopt_long.cxx @@ -0,0 +1,547 @@ +/* $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 + +/* + * Copyright (c) 2002 Todd C. Miller + * + * 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 +#include +#include +#include + +#ifdef _MSC_VER +#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)); +} + -- cgit v1.2.3 From 8843ecc5b9762631f07828d562f2309defd2e956 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 16 Dec 2006 18:47:38 +0000 Subject: Initial implementation of the logging framework. --- lib/common/Logging.cpp | 192 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/common/Logging.h | 148 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 lib/common/Logging.cpp create mode 100644 lib/common/Logging.h diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp new file mode 100644 index 00000000..0e77f252 --- /dev/null +++ b/lib/common/Logging.cpp @@ -0,0 +1,192 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: Logging.cpp +// Purpose: Generic logging core routines implementation +// Created: 2006/12/16 +// +// -------------------------------------------------------------------------- + +#include "Box.h" + +#ifdef HAVE_SYSLOG_H + #include +#endif + +#include "Logging.h" + +bool Loggers::sLogToSyslog = false; +bool Loggers::sLogToConsole = false; +bool Loggers::sContextSet = false; + +void Loggers::ToSyslog(bool enabled) +{ + if (!sLogToSyslog && enabled) + { + Add(&sSyslog); + } + + if (sLogToSyslog && !enabled) + { + Remove(&sSyslog); + } + + sLogToSyslog = enabled; +} + +void Loggers::ToConsole(bool enabled) +{ + if (!sLogToConsole && enabled) + { + Add(&sConsole); + } + + if (sLogToConsole && !enabled) + { + Remove(&sConsole); + } + + sLogToConsole = enabled; +} + +void Loggers::FilterConsole(Log::Level level) +{ + sConsole.Filter(level); +} + +void Loggers::FilterSyslog(Log::Level level) +{ + sSyslog.Filter(level); +} + +void Loggers::Add(Logger* pNewLogger) +{ + for (std::vector::iterator i = sLoggers.begin(); + i != sLoggers.end(); i++) + { + if (*i == pNewLogger) + { + return; + } + } + + sLoggers.insert(sLoggers.begin(), pNewLogger); +} + +void Loggers::Remove(Logger* pOldLogger) +{ + for (std::vector::iterator i = sLoggers.begin(); + i != sLoggers.end(); i++) + { + if (*i == pOldLogger) + { + sLoggers.erase(i); + return; + } + } +} + +void Loggers::Log(Log::Level level, const std::string& rFile, + const std::string& rLine, const std::string& rMessage) +{ + std::string newMessage; + + if (sContextSet) + { + newMessage += "[" + sContext + "] "; + } + + newMessage += rMessage; + + for (std::vector::iterator i = sLoggers.begin(); + i != sLoggers.end(); i++) + { + bool result = (*i)->Log(level, rFile, rLine, newMessage); + if (!result) + { + return; + } + } +} + +void Loggers::SetContext(std::string context) +{ + sContext = context; + sContextSet = true; +} + +void Loggers::ClearContext() +{ + sContextSet = false; +} + +void Loggers::SetProgramName(const std::string& rProgramName) +{ + for (std::vector::iterator i = sLoggers.begin(); + i != sLoggers.end(); i++) + { + (*i)->SetProgramName(rProgramName); + } +} + +bool Console::Log(Log::Level level, const std::string& rFile, + const std::string& rLine, std::string& rMessage) +{ + if (level > GetLevel()) + { + return true; + } + + FILE* target = stdout; + + if (level <= Log::WARNING) + { + target = stderr; + } + + fprintf(target, "%s", rMessage.c_str()); + + return true; +} + +bool Syslog::Log(Log::Level level, const std::string& rFile, + const std::string& rLine, 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::INFO: syslogLevel = LOG_INFO; break; + case Log::TRACE: /* fall through */ + case Log::EVERYTHING: syslogLevel = LOG_DEBUG; break; + } + + syslog(syslogLevel, "%s", rMessage.c_str()); + + return true; +} + +Syslog::Syslog() +{ + ::openlog("Box Backup", LOG_PID, LOG_LOCAL6); +} + +Syslog::~Syslog() +{ + ::closelog(); +} + +void Syslog::SetProgramName(const std::string& rProgramName) +{ + ::closelog(); + ::openlog(rProgramName.c_str(), LOG_PID, LOG_LOCAL6); +} diff --git a/lib/common/Logging.h b/lib/common/Logging.h new file mode 100644 index 00000000..9fb1be4a --- /dev/null +++ b/lib/common/Logging.h @@ -0,0 +1,148 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: Logging.h +// Purpose: Generic logging core routines declarations and macros +// Created: 2006/12/16 +// +// -------------------------------------------------------------------------- + +#ifndef LOGGING__H +#define LOGGING__H + +#include +#include + +#define BOX_LOG(level, stuff) \ +{ \ + if(Log::sMaxLoggingLevelForAnyOutput >= level) \ + std::ostringstream line; \ + line << stuff; \ + Log::Write(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_INFO(stuff) BOX_LOG(Log::INFO, stuff) +#if defined NDEBUG && ! defined COMPILE_IN_TRACES + #define BOX_TRACE(stuff) +#else + #define BOX_TRACE(stuff) BOX_LOG(Log::TRACE, stuff) +#endif + +namespace Log +{ + enum Level { NOTHING = 1, FATAL, ERROR, WARNING, INFO, TRACE, EVERYTHING }; +} + +// -------------------------------------------------------------------------- +// +// Class +// Name: Logger +// Purpose: Abstract class (interface) for log targets +// Created: 2006/12/16 +// +// -------------------------------------------------------------------------- + +class Logger +{ + private: + Log::Level mCurrentLevel; + + public: + Logger() : mCurrentLevel(Log::WARNING) { } + virtual ~Logger() { } + + virtual bool Log(Log::Level level, const std::string& rFile, + const std::string& rLine, 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/12 +// +// -------------------------------------------------------------------------- + +class Console : public Logger +{ + public: + virtual bool Log(Log::Level level, const std::string& rFile, + const std::string& rLine, std::string& rMessage); + virtual const char* GetType() { return "Console"; } + virtual void SetProgramName(const std::string& rProgramName) { } +}; + +// -------------------------------------------------------------------------- +// +// Class +// Name: Syslog +// Purpose: Syslog (or Windows Event Viewer) logging target +// Created: 2006/12/12 +// +// -------------------------------------------------------------------------- + +class Syslog : public Logger +{ + public: + Syslog(); + virtual ~Syslog(); + + virtual bool Log(Log::Level level, const std::string& rFile, + const std::string& rLine, std::string& rMessage); + virtual const char* GetType() { return "Syslog"; } + virtual void SetProgramName(const std::string& rProgramName); +}; + +// -------------------------------------------------------------------------- +// +// Class +// Name: Log +// Purpose: Static logging helper, keeps track of enabled loggers +// and distributes log messages to them. +// Created: 2006/12/12 +// +// -------------------------------------------------------------------------- + +class Loggers +{ + private: + static std::vector sLoggers; + static bool sLogToSyslog, sLogToConsole; + static std::string sContext; + static bool sContextSet; + static Console sConsole; + static Syslog sSyslog; + static Log::Level sGlobalLevel; + + public: + static void Init(const std::string& rProgramName); + 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, + const std::string& rLine, const std::string& rMessage); + static void SetContext(std::string context); + static void ClearContext(); + static void SetGlobalLevel(Log::Level level) { sGlobalLevel = level; } + static void SetProgramName(const std::string& rProgramName); +}; + +#endif // LOGGING__H -- cgit v1.2.3 From a3c9642a2db8fee585c35da6525be4418f4cc5fd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 16 Dec 2006 20:26:31 +0000 Subject: * Rename Loggers class to Logging, which looks nicer. * Fix type of "line" argument to loggers to int rather than std::string to match __LINE__ * Define necessary static objects * Remove global condition on logging for now (refs #3) --- lib/common/Logging.cpp | 42 ++++++++++++++++++++++++------------------ lib/common/Logging.h | 29 +++++++++++++++++++---------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index 0e77f252..ee76cde4 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -15,11 +15,17 @@ #include "Logging.h" -bool Loggers::sLogToSyslog = false; -bool Loggers::sLogToConsole = false; -bool Loggers::sContextSet = false; +bool Logging::sLogToSyslog = false; +bool Logging::sLogToConsole = false; +bool Logging::sContextSet = false; -void Loggers::ToSyslog(bool enabled) +std::vector Logging::sLoggers; +std::string Logging::sContext; +Console Logging::sConsole; +Syslog Logging::sSyslog; +Log::Level Logging::sGlobalLevel; + +void Logging::ToSyslog(bool enabled) { if (!sLogToSyslog && enabled) { @@ -34,7 +40,7 @@ void Loggers::ToSyslog(bool enabled) sLogToSyslog = enabled; } -void Loggers::ToConsole(bool enabled) +void Logging::ToConsole(bool enabled) { if (!sLogToConsole && enabled) { @@ -49,17 +55,17 @@ void Loggers::ToConsole(bool enabled) sLogToConsole = enabled; } -void Loggers::FilterConsole(Log::Level level) +void Logging::FilterConsole(Log::Level level) { sConsole.Filter(level); } -void Loggers::FilterSyslog(Log::Level level) +void Logging::FilterSyslog(Log::Level level) { sSyslog.Filter(level); } -void Loggers::Add(Logger* pNewLogger) +void Logging::Add(Logger* pNewLogger) { for (std::vector::iterator i = sLoggers.begin(); i != sLoggers.end(); i++) @@ -73,7 +79,7 @@ void Loggers::Add(Logger* pNewLogger) sLoggers.insert(sLoggers.begin(), pNewLogger); } -void Loggers::Remove(Logger* pOldLogger) +void Logging::Remove(Logger* pOldLogger) { for (std::vector::iterator i = sLoggers.begin(); i != sLoggers.end(); i++) @@ -86,8 +92,8 @@ void Loggers::Remove(Logger* pOldLogger) } } -void Loggers::Log(Log::Level level, const std::string& rFile, - const std::string& rLine, const std::string& rMessage) +void Logging::Log(Log::Level level, const std::string& rFile, + int line, const std::string& rMessage) { std::string newMessage; @@ -101,7 +107,7 @@ void Loggers::Log(Log::Level level, const std::string& rFile, for (std::vector::iterator i = sLoggers.begin(); i != sLoggers.end(); i++) { - bool result = (*i)->Log(level, rFile, rLine, newMessage); + bool result = (*i)->Log(level, rFile, line, newMessage); if (!result) { return; @@ -109,18 +115,18 @@ void Loggers::Log(Log::Level level, const std::string& rFile, } } -void Loggers::SetContext(std::string context) +void Logging::SetContext(std::string context) { sContext = context; sContextSet = true; } -void Loggers::ClearContext() +void Logging::ClearContext() { sContextSet = false; } -void Loggers::SetProgramName(const std::string& rProgramName) +void Logging::SetProgramName(const std::string& rProgramName) { for (std::vector::iterator i = sLoggers.begin(); i != sLoggers.end(); i++) @@ -130,7 +136,7 @@ void Loggers::SetProgramName(const std::string& rProgramName) } bool Console::Log(Log::Level level, const std::string& rFile, - const std::string& rLine, std::string& rMessage) + int line, std::string& rMessage) { if (level > GetLevel()) { @@ -144,13 +150,13 @@ bool Console::Log(Log::Level level, const std::string& rFile, target = stderr; } - fprintf(target, "%s", rMessage.c_str()); + fprintf(target, "%s\n", rMessage.c_str()); return true; } bool Syslog::Log(Log::Level level, const std::string& rFile, - const std::string& rLine, std::string& rMessage) + int line, std::string& rMessage) { if (level > GetLevel()) { diff --git a/lib/common/Logging.h b/lib/common/Logging.h index 9fb1be4a..e7a11d36 100644 --- a/lib/common/Logging.h +++ b/lib/common/Logging.h @@ -13,6 +13,7 @@ #include #include +/* #define BOX_LOG(level, stuff) \ { \ if(Log::sMaxLoggingLevelForAnyOutput >= level) \ @@ -21,6 +22,14 @@ 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) @@ -41,7 +50,7 @@ namespace Log // // Class // Name: Logger -// Purpose: Abstract class (interface) for log targets +// Purpose: Abstract base class for log targets // Created: 2006/12/16 // // -------------------------------------------------------------------------- @@ -56,7 +65,7 @@ class Logger virtual ~Logger() { } virtual bool Log(Log::Level level, const std::string& rFile, - const std::string& rLine, std::string& rMessage) = 0; + int line, std::string& rMessage) = 0; void Filter(Log::Level level) { @@ -74,7 +83,7 @@ class Logger // Class // Name: Console // Purpose: Console logging target -// Created: 2006/12/12 +// Created: 2006/12/16 // // -------------------------------------------------------------------------- @@ -82,7 +91,7 @@ class Console : public Logger { public: virtual bool Log(Log::Level level, const std::string& rFile, - const std::string& rLine, std::string& rMessage); + int line, std::string& rMessage); virtual const char* GetType() { return "Console"; } virtual void SetProgramName(const std::string& rProgramName) { } }; @@ -92,7 +101,7 @@ class Console : public Logger // Class // Name: Syslog // Purpose: Syslog (or Windows Event Viewer) logging target -// Created: 2006/12/12 +// Created: 2006/12/16 // // -------------------------------------------------------------------------- @@ -103,7 +112,7 @@ class Syslog : public Logger virtual ~Syslog(); virtual bool Log(Log::Level level, const std::string& rFile, - const std::string& rLine, std::string& rMessage); + int line, std::string& rMessage); virtual const char* GetType() { return "Syslog"; } virtual void SetProgramName(const std::string& rProgramName); }; @@ -111,14 +120,14 @@ class Syslog : public Logger // -------------------------------------------------------------------------- // // Class -// Name: Log +// Name: Logging // Purpose: Static logging helper, keeps track of enabled loggers // and distributes log messages to them. -// Created: 2006/12/12 +// Created: 2006/12/16 // // -------------------------------------------------------------------------- -class Loggers +class Logging { private: static std::vector sLoggers; @@ -138,7 +147,7 @@ class Loggers static void Add (Logger* pNewLogger); static void Remove (Logger* pOldLogger); static void Log(Log::Level level, const std::string& rFile, - const std::string& rLine, const std::string& rMessage); + int line, const std::string& rMessage); static void SetContext(std::string context); static void ClearContext(); static void SetGlobalLevel(Log::Level level) { sGlobalLevel = level; } -- cgit v1.2.3 From 8b9dbce8c787890b1e74e27a06e3780515c34b65 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 16 Dec 2006 20:27:44 +0000 Subject: Change all logging to use the logging framework, as an example. (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 287 +++++++++++++++++++++--------------------- bin/bbackupd/bbackupd.cpp | 18 ++- 2 files changed, 161 insertions(+), 144 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 87955fa4..c9b9fb52 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -18,9 +18,6 @@ #ifdef HAVE_SIGNAL_H #include #endif -#ifdef HAVE_SYSLOG_H - #include -#endif #ifdef HAVE_SYS_PARAM_H #include #endif @@ -76,6 +73,7 @@ #include "Conversion.h" #include "Archive.h" #include "Timer.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -224,7 +222,7 @@ void BackupDaemon::SetupInInitialProcess() // Print a warning on this platform if the CommandSocket is used. if(GetConfiguration().KeyExists("CommandSocket")) { - printf( + BOX_WARNING( "==============================================================================\n" "SECURITY WARNING: This platform cannot check the credentials of connections to\n" "the command socket. This is a potential DoS security problem.\n" @@ -278,29 +276,21 @@ void BackupDaemon::RunHelperThread(void) } catch (BoxException &e) { - ::syslog(LOG_ERR, "Failed to open command socket: %s", + BOX_ERROR("Failed to open command socket" << e.what()); SetTerminateWanted(); break; // this is fatal to listening thread } - catch (...) - { - ::syslog(LOG_ERR, "Failed to open command socket: " - "unknown error"); - SetTerminateWanted(); - break; // this is fatal to listening thread - } - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to open command socket: " - "%s", e.what()); + BOX_ERROR("Failed to open command socket" << + e.what()); SetTerminateWanted(); break; // this is fatal to listening thread } catch(...) { - ::syslog(LOG_ERR, "Failed to open command socket: " + BOX_ERROR("Failed to open command socket: " "unknown error"); SetTerminateWanted(); break; // this is fatal to listening thread @@ -313,7 +303,7 @@ void BackupDaemon::RunHelperThread(void) // This next section comes from Ben's original function // Log - ::syslog(LOG_INFO, "Connection from command socket"); + BOX_INFO("Connection from command socket"); // Send a header line summarising the configuration // and current state @@ -337,8 +327,8 @@ void BackupDaemon::RunHelperThread(void) readLine.GetLine(command) && !IsTerminateWanted()) { - TRACE1("Received command '%s' over " - "command socket\n", command.c_str()); + BOX_TRACE("Received command '" << command + << "' over command socket"); bool sendOK = false; bool sendResponse = true; @@ -379,7 +369,9 @@ void BackupDaemon::RunHelperThread(void) } else { - ::syslog(LOG_ERR, "Received unknown command '%s' from client", command.c_str()); + BOX_ERROR("Received unknown command " + "'" << command << "' " + "from client"); sendResponse = true; sendOK = false; } @@ -404,17 +396,17 @@ void BackupDaemon::RunHelperThread(void) } catch(BoxException &e) { - ::syslog(LOG_ERR, "Communication error with " - "control client: %s", e.what()); + BOX_ERROR("Communication error with " + "control client: " << e.what()); } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error in command socket " - "thread: %s", e.what()); + BOX_ERROR("Internal error in command socket " + "thread: " << e.what()); } catch(...) { - ::syslog(LOG_ERR, "Communication error with control client"); + BOX_ERROR("Communication error with control client"); } } } @@ -473,14 +465,13 @@ void BackupDaemon::Run() } catch(std::exception &e) { - ::syslog(LOG_WARNING, "Internal error while " + BOX_WARNING("Internal error while " "closing command socket after " - "another exception: %s", e.what()); + "another exception: " << e.what()); } catch(...) { - ::syslog(LOG_WARNING, - "Error closing command socket " + BOX_WARNING("Error closing command socket " "after exception, ignored."); } mpCommandSocketInfo = 0; @@ -674,7 +665,7 @@ void BackupDaemon::Run2() if(deleteStoreObjectInfoFile && !DeleteStoreObjectInfo()) { - ::syslog(LOG_ERR, "Failed to delete the " + BOX_ERROR("Failed to delete the " "StoreObjectInfoFile, backup cannot " "continue safely."); // prevent runaway process where the logs fill up -- without this @@ -697,7 +688,7 @@ void BackupDaemon::Run2() { // Set state and log start SetState(State_Connected); - ::syslog(LOG_INFO, "Beginning scan of local files"); + BOX_INFO("Beginning scan of local files"); std::string extendedLogFile; if (conf.KeyExists("ExtendedLogFile")) @@ -810,7 +801,7 @@ void BackupDaemon::Run2() CommitIDMapsAfterSync(); // Log - ::syslog(LOG_INFO, "Finished scan of local files"); + BOX_INFO("Finished scan of local files"); // -------------------------------------------------------------------------------------------- @@ -834,8 +825,8 @@ void BackupDaemon::Run2() } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error during " - "backup run: %s", e.what()); + BOX_ERROR("Internal error during " + "backup run: " << e.what()); errorOccurred = true; } catch(...) @@ -864,26 +855,28 @@ void BackupDaemon::Run2() // Handle restart? if(StopRun()) { - ::syslog(LOG_INFO, "Exception (%d/%d) due to signal", errorCode, errorSubCode); + BOX_INFO("Exception (" << errorCode + << "/" << errorSubCode + << ") due to signal"); return; } // If the Berkely db files get corrupted, delete them and try again immediately if(isBerkelyDbFailure) { - ::syslog(LOG_ERR, "Berkely db inode map files corrupted, deleting and restarting scan. Renamed files and directories will not be tracked until after this scan.\n"); + BOX_ERROR("Berkely db inode map files corrupted, deleting and restarting scan. Renamed files and directories will not be tracked until after this scan."); ::sleep(1); } else { // Not restart/terminate, pause and retry SetState(State_Error); - ::syslog(LOG_ERR, - "Exception caught (%s %d/%d), " - "reset state and waiting " - "to retry...", - errorString, errorCode, - errorSubCode); + BOX_ERROR("Exception caught (" + << errorString + << " " << errorCode + << "/" << errorSubCode + << "), reset state and " + "waiting to retry..."); ::sleep(10); nextSyncTime = currentSyncStartTime + SecondsToBoxTime(90) + @@ -894,9 +887,12 @@ void BackupDaemon::Run2() } // Log the stats - ::syslog(LOG_INFO, "File statistics: total file size uploaded %lld, bytes already on server %lld, encoded size %lld", - BackupStoreFile::msStats.mBytesInEncodedFiles, BackupStoreFile::msStats.mBytesAlreadyOnServer, - BackupStoreFile::msStats.mTotalFileStreamSize); + BOX_INFO("File statistics: total file size uploaded " + << BackupStoreFile::msStats.mBytesInEncodedFiles + << ", bytes already on server " + << BackupStoreFile::msStats.mBytesAlreadyOnServer + << ", encoded size " + << BackupStoreFile::msStats.mTotalFileStreamSize); BackupStoreFile::ResetStats(); // Tell anything connected to the command socket @@ -966,29 +962,32 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() } catch(ConversionException &e) { - ::syslog(LOG_ERR, "Invalid output " - "from SyncAllowScript '%s': " - "'%s'", - conf.GetKeyValue("SyncAllowScript").c_str(), - line.c_str()); + BOX_ERROR("Invalid output " + "from SyncAllowScript '" + << conf.GetKeyValue("SyncAllowScript") + << "': '" << line << "'"); throw; } - ::syslog(LOG_INFO, "Delaying sync by %d seconds (SyncAllowScript '%s')", waitInSeconds, conf.GetKeyValue("SyncAllowScript").c_str()); + BOX_INFO("Delaying sync by " << waitInSeconds + << " seconds (SyncAllowScript '" + << conf.GetKeyValue("SyncAllowScript") + << "')"); } } } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error running SyncAllowScript: " - "%s", e.what()); + BOX_ERROR("Internal error running SyncAllowScript: " + << e.what()); } catch(...) { // Ignore any exceptions // Log that something bad happened - ::syslog(LOG_ERR, "Error running SyncAllowScript '%s'", conf.GetKeyValue("SyncAllowScript").c_str()); + BOX_ERROR("Error running SyncAllowScript '" + << conf.GetKeyValue("SyncAllowScript") << "'"); } // Wait and then cleanup child process, if any @@ -1040,7 +1039,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla ASSERT(mpCommandSocketInfo != 0); if(mpCommandSocketInfo == 0) {::sleep(1); return;} // failure case isn't too bad - TRACE1("Wait on command socket, delay = %lld\n", RequiredDelay); + BOX_TRACE("Wait on command socket, delay = " << RequiredDelay); try { @@ -1066,7 +1065,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla { #ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET bool uidOK = true; - ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credentials of peers connecting to the command socket. (bbackupctl)"); + BOX_WARNING("On this platform, no security check can be made on the credentials of peers connecting to the command socket. (bbackupctl)"); #else // Security check -- does the process connecting to this socket have // the same UID as this process? @@ -1091,14 +1090,14 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla if(!uidOK) { // Dump the connection - ::syslog(LOG_ERR, "Incoming command connection from peer had different user ID than this process, or security check could not be completed."); + BOX_ERROR("Incoming command connection from peer had different user ID than this process, or security check could not be completed."); mpCommandSocketInfo->mpConnectedSocket.reset(); return; } else { // Log - ::syslog(LOG_INFO, "Connection from command socket"); + BOX_INFO("Connection from command socket"); // Send a header line summarising the configuration and current state const Configuration &conf(GetConfiguration()); @@ -1136,7 +1135,8 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla while(mpCommandSocketInfo->mpGetLine != 0 && !mpCommandSocketInfo->mpGetLine->IsEOF() && mpCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout)) { - TRACE1("Receiving command '%s' over command socket\n", command.c_str()); + BOX_TRACE("Receiving command '" << command + << "' over command socket"); bool sendOK = false; bool sendResponse = true; @@ -1193,8 +1193,8 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error in command socket thread: " - "%s", e.what()); + BOX_ERROR("Internal error in command socket thread: " + << e.what()); // If an error occurs, and there is a connection active, just close that // connection and continue. Otherwise, let the error propagate. if(mpCommandSocketInfo->mpConnectedSocket.get() == 0) @@ -1238,7 +1238,7 @@ void BackupDaemon::CloseCommandConnection() #ifndef WIN32 try { - TRACE0("Closing command connection\n"); + BOX_TRACE("Closing command connection"); if(mpCommandSocketInfo->mpGetLine) { @@ -1249,8 +1249,8 @@ void BackupDaemon::CloseCommandConnection() } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error while closing command " - "socket: %s", e.what()); + BOX_ERROR("Internal error while closing command " + "socket: " << e.what()); } catch(...) { @@ -1299,8 +1299,8 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error while sending to " - "command socket client: %s", e.what()); + BOX_ERROR("Internal error while sending to " + "command socket client: " << e.what()); CloseCommandConnection(); } catch(...) @@ -1403,7 +1403,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con struct mntent *entry = 0; while((entry = ::getmntent(mountPointsFile)) != 0) { - TRACE1("Found mount point at %s\n", entry->mnt_dir); + BOX_TRACE("Found mount point at " << entry->mnt_dir); mountPoints.insert(std::string(entry->mnt_dir)); } @@ -1425,12 +1425,11 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con try { - // Read all the entries, and put them in the set struct mnttab entry; while(getmntent(mountPointsFile, &entry) == 0) { - TRACE1("Found mount point at %s\n", entry.mnt_mountp); + BOX_TRACE("Found mount point at " << entry.mnt_mountp); mountPoints.insert(std::string(entry.mnt_mountp)); } @@ -1459,7 +1458,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con for(std::list >::const_iterator i = rLocationsConf.mSubConfigurations.begin(); i != rLocationsConf.mSubConfigurations.end(); ++i) { -TRACE0("new location\n"); + BOX_TRACE("new location"); // Create a record for it Location *ploc = new Location; try @@ -1497,19 +1496,22 @@ TRACE0("new location\n"); // Warn in logs if the directory isn't absolute if(ploc->mPath[0] != '/') { - ::syslog(LOG_ERR, "Location path '%s' isn't absolute", ploc->mPath.c_str()); + BOX_WARNING("Location path '" + << ploc->mPath + << "' is not absolute"); } // Go through the mount points found, and find a suitable one std::string mountName("/"); { std::set::const_iterator i(mountPoints.begin()); - TRACE1("%d potential mount points\n", mountPoints.size()); + BOX_TRACE(mountPoints.size() + << " potential mount points"); for(; i != mountPoints.end(); ++i) { // Compare first n characters with the filename // If it matches, the file belongs in that mount point // (sorting order ensures this) - TRACE1("checking against mount point %s\n", i->c_str()); + BOX_TRACE("checking against mount point " << *i); if(::strncmp(i->c_str(), ploc->mPath.c_str(), i->size()) == 0) { // Match @@ -1517,7 +1519,9 @@ TRACE0("new location\n"); break; } } - TRACE2("mount point chosen for %s is %s\n", ploc->mPath.c_str(), mountName.c_str()); + BOX_TRACE("mount point chosen for " + << ploc->mPath << " is " + << mountName); } #endif @@ -1571,8 +1575,9 @@ TRACE0("new location\n"); } catch (BoxException &e) { - ::syslog(LOG_ERR, "Failed to get attributes for path " - "'%s', skipping.", ploc->mPath.c_str()); + BOX_ERROR("Failed to get attributes " + "for path '" << ploc->mPath + << "', skipping."); continue; } @@ -1598,8 +1603,9 @@ TRACE0("new location\n"); { delete ploc; ploc = 0; - ::syslog(LOG_ERR, "Failed to setup location '%s' path '%s'", - ploc->mName.c_str(), ploc->mPath.c_str()); + BOX_ERROR("Failed to setup location '" + << ploc->mName << "' path '" + << ploc->mPath << "'"); throw; } } @@ -1607,8 +1613,10 @@ TRACE0("new location\n"); // Any entries in the root directory which need deleting? if(dir.GetNumberOfEntries() > 0) { - ::syslog(LOG_INFO, "%d redundant locations in root directory found, will delete from store after %d seconds.", - dir.GetNumberOfEntries(), BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER); + BOX_INFO(dir.GetNumberOfEntries() << " redundant locations " + "in root directory found, will delete from store " + "after " << BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER + << " seconds."); // Store directories in list of things to delete mUnusedRootDirEntries.clear(); @@ -1621,7 +1629,7 @@ TRACE0("new location\n"); const std::string &name(clear.GetClearFilename()); mUnusedRootDirEntries.push_back(std::pair(en->GetObjectID(), name)); // Log this - ::syslog(LOG_INFO, "Unused location in root: %s", name.c_str()); + BOX_INFO("Unused location in root: " << name); } ASSERT(mUnusedRootDirEntries.size() > 0); // Time to delete them @@ -1738,14 +1746,14 @@ void BackupDaemon::DeleteCorruptBerkelyDbFiles() MakeMapBaseName(l, filename); // Delete the file - TRACE1("Deleting %s\n", filename.c_str()); + BOX_TRACE("Deleting " << filename); ::unlink(filename.c_str()); // Add a suffix for the new map filename += ".n"; // Delete that too - TRACE1("Deleting %s\n", filename.c_str()); + BOX_TRACE("Deleting " << filename); ::unlink(filename.c_str()); } } @@ -1825,10 +1833,9 @@ void BackupDaemon::CommitIDMapsAfterSync() #endif if(::rename(newmap.c_str(), target.c_str()) != 0) { - ::syslog(LOG_ERR, "failed to rename ID map: " - "%s to %s: %s", - newmap.c_str(), target.c_str(), - strerror(errno)); + BOX_ERROR("failed to rename ID map: " << newmap + << " to " << target << ": " + << strerror(errno)); THROW_EXCEPTION(CommonException, OSFileError) } } @@ -1931,8 +1938,8 @@ void BackupDaemon::SetState(int State) } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error while writing state " - "to command socket: %s", e.what()); + BOX_ERROR("Internal error while writing state " + "to command socket: " << e.what()); CloseCommandConnection(); } catch(...) @@ -1950,8 +1957,8 @@ void BackupDaemon::SetState(int State) } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error while writing state " - "to command socket: %s", e.what()); + BOX_ERROR("Internal error while writing state " + "to command socket: " << e.what()); CloseCommandConnection(); } catch(...) @@ -1996,7 +2003,7 @@ void BackupDaemon::NotifySysadmin(int Event) { static const char *sEventNames[] = {"store-full", "read-error", 0}; - TRACE1("BackupDaemon::NotifySysadmin() called, event = %d\n", Event); + BOX_TRACE("BackupDaemon::NotifySysadmin() called, event = " << Event); if(Event < 0 || Event > NotifyEvent__MAX) { @@ -2014,7 +2021,9 @@ void BackupDaemon::NotifySysadmin(int Event) if(!conf.KeyExists("NotifyScript")) { // Log, and then return - ::syslog(LOG_ERR, "Not notifying administrator about event %s -- set NotifyScript to do this in future", sEventNames[Event]); + BOX_ERROR("Not notifying administrator about event " + << sEventNames[Event] << " -- set NotifyScript " + "to do this in future"); return; } @@ -2022,12 +2031,15 @@ void BackupDaemon::NotifySysadmin(int Event) std::string script(conf.GetKeyValue("NotifyScript") + ' ' + sEventNames[Event]); // Log what we're about to do - ::syslog(LOG_INFO, "About to notify administrator about event %s, running script '%s'", sEventNames[Event], script.c_str()); + BOX_INFO("About to notify administrator about event " + << sEventNames[Event] << ", running script '" + << script << "'"); // Then do it if(::system(script.c_str()) != 0) { - ::syslog(LOG_ERR, "Notify script returned an error code. ('%s')", script.c_str()); + BOX_ERROR("Notify script returned an error code. ('" + << script << "')"); } // Flag that this is done so the administrator isn't constantly bombarded with lots of errors @@ -2059,14 +2071,15 @@ void BackupDaemon::DeleteUnusedRootDirEntries(BackupClientContext &rContext) } // Entries to delete, and it's the right time to do so... - ::syslog(LOG_INFO, "Deleting unused locations from store root..."); + BOX_INFO("Deleting unused locations from store root..."); BackupProtocolClient &connection(rContext.GetConnection()); for(std::vector >::iterator i(mUnusedRootDirEntries.begin()); i != mUnusedRootDirEntries.end(); ++i) { connection.QueryDeleteDirectory(i->first); // Log this - ::syslog(LOG_INFO, "Deleted %s (ID %08llx) from store root", i->second.c_str(), i->first); + BOX_INFO("Deleted " << i->second << " (ID " << i->first + << ") from store root"); } // Reset state @@ -2406,20 +2419,20 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time // // aFile.Close(); - ::syslog(LOG_INFO, "Saved store object info file '%s'", - StoreObjectInfoFile.c_str()); + BOX_INFO("Saved store object info file: " + << StoreObjectInfoFile); } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error writing store object " - "info file (%s): %s", - StoreObjectInfoFile.c_str(), e.what()); + BOX_ERROR("Internal error writing store object " + "info file (" << StoreObjectInfoFile << "): " + << e.what()); } catch(...) { - ::syslog(LOG_ERR, "Internal error writing store object " - "info file (%s): unknown error", - StoreObjectInfoFile.c_str()); + BOX_ERROR("Internal error writing store object " + "info file (" << StoreObjectInfoFile << "): " + "unknown error"); } return created; @@ -2470,10 +2483,10 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ if(iMagicValue != STOREOBJECTINFO_MAGIC_ID_VALUE) { - ::syslog(LOG_WARNING, "Store object info file '%s' " + BOX_WARNING("Store object info file " "is not a valid or compatible serialised " - "archive. Will re-cache from store.", - StoreObjectInfoFile.c_str()); + "archive. Will re-cache from store. " + "(" << StoreObjectInfoFile << ")"); return false; } @@ -2485,10 +2498,10 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ if(strMagicValue != STOREOBJECTINFO_MAGIC_ID_STRING) { - ::syslog(LOG_WARNING, "Store object info file '%s' " + BOX_WARNING("Store object info file " "is not a valid or compatible serialised " - "archive. Will re-cache from store.", - StoreObjectInfoFile.c_str()); + "archive. Will re-cache from store. " + "(" << StoreObjectInfoFile << ")"); return false; } @@ -2501,11 +2514,10 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ if(iVersion != STOREOBJECTINFO_VERSION) { - ::syslog(LOG_WARNING, "Store object info file '%s' " - "version %d unsupported. " - "Will re-cache from store.", - StoreObjectInfoFile.c_str(), - iVersion); + BOX_WARNING("Store object info file " + "version " << iVersion << " unsupported. " + "Will re-cache from store. " + "(" << StoreObjectInfoFile << ")"); return false; } @@ -2518,9 +2530,9 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ if(lastKnownConfigModTime != GetLoadedConfigModifiedTime()) { - ::syslog(LOG_WARNING, "Store object info file '%s' " - "out of date. Will re-cache from store", - StoreObjectInfoFile.c_str()); + BOX_WARNING("Store object info file " + "out of date. Will re-cache from store. " + "(" << StoreObjectInfoFile << ")"); return false; } @@ -2567,23 +2579,20 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ // // aFile.Close(); - ::syslog(LOG_INFO, "Loaded store object info file '%s', " - "version [%d]", StoreObjectInfoFile.c_str(), - iVersion); - + BOX_INFO("Loaded store object info file version " << iVersion + << "(" << StoreObjectInfoFile << ")"); + return true; } catch(std::exception &e) { - ::syslog(LOG_ERR, "Internal error reading store object " - "info file (%s): %s", - StoreObjectInfoFile.c_str(), e.what()); + BOX_ERROR("Internal error reading store object info file: " + << StoreObjectInfoFile << ": " << e.what()); } catch(...) { - ::syslog(LOG_ERR, "Internal error reading store object " - "info file (%s): unknown error", - StoreObjectInfoFile.c_str()); + BOX_ERROR("Internal error reading store object info file: " + << StoreObjectInfoFile << ": unknown error"); } DeleteAllLocations(); @@ -2592,11 +2601,10 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ theLastSyncTime = 0; theNextSyncTime = 0; - ::syslog(LOG_WARNING, "Requested store object info file '%s' " - "does not exist, not accessible, or inconsistent. " - "Will re-cache from store.", - StoreObjectInfoFile.c_str()); - + BOX_WARNING("Store object info file is missing, not accessible, " + "or inconsistent. Will re-cache from store. " + "(" << StoreObjectInfoFile << ")"); + return false; } @@ -2624,9 +2632,9 @@ bool BackupDaemon::DeleteStoreObjectInfo() const if(!FileExists(storeObjectInfoFile.c_str())) { // File doesn't exist -- so can't be deleted. But something isn't quite right, so log a message - ::syslog(LOG_ERR, "Expected to be able to delete " - "store object info file '%s', but the file did not exist.", - storeObjectInfoFile.c_str()); + BOX_WARNING("Store object info file did not exist when it " + "was supposed to. (" << storeObjectInfoFile << ")"); + // Return true to stop things going around in a loop return true; } @@ -2634,9 +2642,8 @@ bool BackupDaemon::DeleteStoreObjectInfo() const // Actually delete it if(::unlink(storeObjectInfoFile.c_str()) != 0) { - ::syslog(LOG_ERR, "Failed to delete the old " - "store object info file '%s': %s", - storeObjectInfoFile.c_str(), strerror(errno)); + BOX_ERROR("Failed to delete the old store object info file: " + << storeObjectInfoFile << ": "<< strerror(errno)); return false; } diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index e00d3628..1ddbf397 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -12,6 +12,7 @@ #include "MainHelper.h" #include "BoxPortsAndFiles.h" #include "BackupStoreException.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -26,9 +27,17 @@ int main(int argc, const char *argv[]) { MAINHELPER_START -#ifdef WIN32 + Logging::SetProgramName("Box Backup (bbackupd)"); + Logging::ToConsole(true); + Logging::FilterSyslog (Log::EVERYTHING); - ::openlog("Box Backup (bbackupd)", LOG_PID, LOG_LOCAL6); + #ifdef NDEBUG + Logging::FilterConsole(Log::INFO); + #else + Logging::FilterConsole(Log::EVERYTHING); + #endif + +#ifdef WIN32 if(argc == 2 && (::strcmp(argv[1], "--help") == 0 || @@ -56,6 +65,7 @@ int main(int argc, const char *argv[]) if (argc >= 2 && ::strcmp(argv[1], "--service") == 0) { runAsWin32Service = true; + Logging::ToSyslog(true); } gpDaemonService = new Win32BackupService(); @@ -66,7 +76,7 @@ int main(int argc, const char *argv[]) if (runAsWin32Service) { - syslog(LOG_INFO, "Box Backup service starting"); + BOX_INFO("Box Backup service starting"); char* config = NULL; if (argc >= 3) @@ -81,7 +91,7 @@ int main(int argc, const char *argv[]) free(config); } - syslog(LOG_INFO, "Box Backup service shut down"); + BOX_INFO("Box Backup service shut down"); } else { -- cgit v1.2.3 From 131a4c5b39d95fffe63d26446668bed40c29a197 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Dec 2006 15:29:59 +0000 Subject: Add missing include of header (refs #3) --- lib/common/Test.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index ada42eb2..7ea755f6 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -20,7 +20,8 @@ #endif #include - +#include + extern int failures; #define TEST_FAIL_WITH_MESSAGE(msg) {failures++; printf("FAILURE: " msg " at " __FILE__ "(%d)\n", __LINE__);} -- cgit v1.2.3 From 640786c33e71dd30c98068a7b82f8713f780d9f8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Dec 2006 15:31:00 +0000 Subject: Don't redefine the built-in operators new and delete unnecessarily (refs #3) --- lib/common/MemLeakFinder.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/common/MemLeakFinder.h b/lib/common/MemLeakFinder.h index f47a38aa..6bfdc3d0 100644 --- a/lib/common/MemLeakFinder.h +++ b/lib/common/MemLeakFinder.h @@ -52,11 +52,6 @@ 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); -void *operator new[](size_t size); - -void operator delete (void *ptr) throw (); -void operator delete[](void *ptr) throw (); // define the malloc functions now, if required #ifdef MEMLEAKFINDER_FULL_MALLOC_MONITORING -- cgit v1.2.3 From 34ce26dcc69416489a1520e18a657ea7e8771ae1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Dec 2006 17:18:17 +0000 Subject: Compile fix for platforms without intercept capability (refs #3) --- lib/common/BoxPlatform.h | 2 ++ lib/intercept/intercept.h | 5 +++++ test/bbackupd/testbbackupd.cpp | 12 +++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h index 3ae929ef..28822aa8 100644 --- a/lib/common/BoxPlatform.h +++ b/lib/common/BoxPlatform.h @@ -51,6 +51,8 @@ #define PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE #endif + #define PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE + // Disable memory testing under Darwin, it just doesn't like it very much. #ifdef __APPLE__ // TODO: We really should get some decent leak detection code. diff --git a/lib/intercept/intercept.h b/lib/intercept/intercept.h index b1122434..bc6557f3 100644 --- a/lib/intercept/intercept.h +++ b/lib/intercept/intercept.h @@ -9,6 +9,7 @@ #ifndef INTERCEPT_H #define INTERCEPT_H +#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE #include @@ -35,8 +36,12 @@ extern "C" 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/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 8a1c711f..d1bf4a98 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -9,6 +9,7 @@ #include "Box.h" +#include #include #include #include @@ -509,11 +510,6 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) } } -void intercept_setup_delay(const char *filename, unsigned int delay_after, - int delay_ms, int syscall_to_delay, int num_delays); - -bool intercept_triggered(); - int start_internal_daemon() { // ensure that no child processes end up running tests! @@ -598,7 +594,9 @@ int lstat_test_hook(const char *file_name, struct stat *buf); struct dirent *readdir_test_hook_1(DIR *dir) { +#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE intercept_setup_readdir_hook(NULL, readdir_test_hook_2); +#endif return NULL; } @@ -609,8 +607,10 @@ struct dirent *readdir_test_hook_2(DIR *dir) { if (time(NULL) >= readdir_stop_time) { +#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE intercept_setup_readdir_hook(NULL, NULL); intercept_setup_lstat_hook (NULL, NULL); +#endif // we will not be called again. } @@ -626,7 +626,9 @@ struct dirent *readdir_test_hook_2(DIR *dir) snprintf(stat_hook_filename, sizeof(stat_hook_filename), "testfiles/TestDir1/spacetest/d1/test.%d", readdir_test_counter); +#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE intercept_setup_lstat_hook(stat_hook_filename, lstat_test_hook); +#endif return &readdir_test_dirent; } -- cgit v1.2.3 From 44529e9be1a198e3a78b3dc3e971b9fe572d086d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Dec 2006 17:32:21 +0000 Subject: Belay that order, XO (partially revert patch [1229]) --- lib/common/BoxPlatform.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h index 28822aa8..3ae929ef 100644 --- a/lib/common/BoxPlatform.h +++ b/lib/common/BoxPlatform.h @@ -51,8 +51,6 @@ #define PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE #endif - #define PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE - // Disable memory testing under Darwin, it just doesn't like it very much. #ifdef __APPLE__ // TODO: We really should get some decent leak detection code. -- cgit v1.2.3 From d301501f11ec0f3a9fc079f995367c6deb6a5c48 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 29 Dec 2006 21:58:22 +0000 Subject: Visual Studio 2005 compile fixes, thanks to Gary. Enable (and require) PCRE when building with Visual Studio 2005. --- infrastructure/msvc/2005/bbackupctl.vcproj | 11 ++++++----- infrastructure/msvc/2005/bbackupd.vcproj | 11 ++++++----- infrastructure/msvc/2005/boxquery.vcproj | 10 +++++----- infrastructure/msvc/2005/common.vcproj | 8 ++++---- infrastructure/msvc/2005/win32test.vcproj | 11 ++++++----- lib/common/BoxConfig-MSVC.h | 4 ++-- lib/common/ExcludeList.cpp | 6 +++++- 7 files changed, 34 insertions(+), 27 deletions(-) diff --git a/infrastructure/msvc/2005/bbackupctl.vcproj b/infrastructure/msvc/2005/bbackupctl.vcproj index c9507b17..ab75480c 100644 --- a/infrastructure/msvc/2005/bbackupctl.vcproj +++ b/infrastructure/msvc/2005/bbackupctl.vcproj @@ -4,6 +4,7 @@ Version="8.00" Name="bbackupctl" ProjectGUID="{9FD51412-E945-4457-A17A-CA3C505CF431}" + RootNamespace="bbackupctl" Keyword="Win32Proj" > @@ -41,7 +42,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\..\lib\backupclient";"$(ProjectDir)..\..\..\lib\common";"$(ProjectDir)..\..\..\lib\compress";"$(ProjectDir)..\..\..\lib\crypto";"$(ProjectDir)..\..\..\lib\server";"$(ProjectDir)..\..\..\lib\win32";"$(ProjectDir)..\..\..\..\openssl\inc32";"$(ProjectDir)..\..\..\..\zlib\include"" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;NDEBUG" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -61,7 +62,7 @@ /> @@ -41,7 +42,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(SolutionDir)..\..\..\lib\backupclient";"$(SolutionDir)..\..\..\lib\common";"$(SolutionDir)..\..\..\lib\compress";"$(SolutionDir)..\..\..\lib\crypto";"$(SolutionDir)..\..\..\lib\server";"$(SolutionDir)..\..\..\lib\win32";"$(SolutionDir)..\..\..\..\openssl\inc32";"$(SolutionDir)..\..\..\..\zlib\include"" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;NDEBUG" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -61,7 +62,7 @@ /> @@ -41,7 +42,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\..\bin\bbackupd";"$(ProjectDir)..\..\..\lib\backupclient";"$(ProjectDir)..\..\..\lib\common";"$(ProjectDir)..\..\..\lib\compress";"$(ProjectDir)..\..\..\lib\crypto";"$(ProjectDir)..\..\..\lib\server";"$(ProjectDir)..\..\..\lib\win32";"$(ProjectDir)..\..\..\..\openssl\inc32";"$(ProjectDir)..\..\..\..\zlib\include"" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;NDEBUG" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PLATFORM_DISABLE_MEM_LEAK_TESTING;_CRT_SECURE_NO_DEPRECATE;PCRE_STATIC" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -61,7 +62,7 @@ /> header file. */ -// #define HAVE_REGEX_H 1 +#define HAVE_REGEX_H 1 /* Define to 1 if you have the `setproctitle' function. */ /* #undef HAVE_SETPROCTITLE */ diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp index b13b6026..842780b6 100644 --- a/lib/common/ExcludeList.cpp +++ b/lib/common/ExcludeList.cpp @@ -10,7 +10,11 @@ #include "Box.h" #ifdef HAVE_REGEX_H - #include + #ifdef WIN32 + #include + #else + #include + #endif // WIN32 #define EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED #endif -- cgit v1.2.3 From 4201fdff12c3aea7d65b17ee2a0319c81fc41799 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 11 Jan 2007 22:47:35 +0000 Subject: Added a new config option, LogAllFileAccess, which will log access to every file and scanning every directory. The current implementation is taken straight from the Boxi branch. To be extended shortly. (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 61 +++++++++++--- bin/bbackupd/BackupClientDirectoryRecord.h | 73 +++++++++++++++- bin/bbackupd/BackupDaemon.cpp | 12 ++- bin/bbackupd/BackupDaemon.h | 117 +++++++++++++++++++++++++- lib/backupclient/BackupDaemonConfigVerify.cpp | 1 + 5 files changed, 249 insertions(+), 15 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index c05a23fc..6651598a 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -164,8 +164,8 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn { // The directory has probably been deleted, so just ignore this error. // In a future scan, this deletion will be noticed, deleted from server, and this object deleted. - TRACE1("Stat failed for '%s' (directory)\n", - rLocalPath.c_str()); + rParams.GetProgressNotifier().NotifyDirStatFailed( + this, rLocalPath, strerror(errno)); return; } // Store inode number in map so directories are tracked in case they're renamed @@ -202,6 +202,19 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn dirHandle = ::opendir(rLocalPath.c_str()); if(dirHandle == 0) { + // Report the error (logs and + // eventual email to administrator) + if (errno == EACCES) + { + rParams.GetProgressNotifier().NotifyDirListFailed( + this, rLocalPath, "Access denied"); + } + else + { + rParams.GetProgressNotifier().NotifyDirListFailed(this, + rLocalPath, strerror(errno)); + } + // Report the error (logs and eventual email to administrator) SetErrorWhenReadingFilesystemObject(rParams, rLocalPath.c_str()); // Ignore this directory for now. @@ -254,6 +267,10 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn { // Report the error (logs and // eventual email to administrator) + rParams.GetProgressNotifier().NotifyFileStatFailed(this, + filename, strerror(errno)); + + // FIXME move to NotifyFileStatFailed() SetErrorWhenReadingFilesystemObject( rParams, filename.c_str()); @@ -337,8 +354,8 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn // Log that this has happened if(!rParams.mHaveLoggedWarningAboutFutureFileTimes) { - ::syslog(LOG_ERR, "Some files have modification times excessively in the future. Check clock syncronisation.\n"); - ::syslog(LOG_ERR, "Example file (only one shown) : %s\n", filename.c_str()); + rParams.GetProgressNotifier().NotifyFileModifiedInFuture( + this, filename); rParams.mHaveLoggedWarningAboutFutureFileTimes = true; } } @@ -594,6 +611,8 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP struct stat st; if(::lstat(filename.c_str(), &st) != 0) { + rParams.GetProgressNotifier().NotifyFileStatFailed(this, + filename, strerror(errno)); THROW_EXCEPTION(CommonException, OSFileError) } @@ -806,6 +825,8 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP { // Connection errors should just be passed on to the main handler, retries // would probably just cause more problems. + rParams.GetProgressNotifier().NotifyFileUploadException(this, + filename, e); throw; } catch(BoxException &e) @@ -815,7 +836,8 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP // Log it. SetErrorWhenReadingFilesystemObject(rParams, filename.c_str()); // Log error. - ::syslog(LOG_ERR, "Error code when uploading was (%d/%d), %s", e.GetType(), e.GetSubType(), e.what()); + rParams.GetProgressNotifier().NotifyFileUploadException(this, + filename, e); } // Update structures if the file was uploaded successfully. @@ -828,6 +850,11 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP } } } + else + { + rParams.GetProgressNotifier().NotifyFileSkippedServerFull(this, + filename); + } } else if(en != 0 && en->GetAttributesHash() != attributesHash) { @@ -909,6 +936,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP } } } + + rParams.GetProgressNotifier().NotifyFileSynchronised(this, + filename, fileSize); } // Erase contents of files to save space when recursing @@ -1225,7 +1255,11 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn if(diffFromID != 0) { - // Found an old version -- get the index + // Found an old version + rParams.GetProgressNotifier().NotifyFileUploadingPatch(this, + rFilename); + + // Get the index std::auto_ptr blockIndexStream(connection.ReceiveStream()); // @@ -1298,6 +1332,8 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn throw; } + rParams.GetProgressNotifier().NotifyFileUploaded(this, rFilename, FileSize); + // Return the new object ID of this file return objID; } @@ -1317,8 +1353,11 @@ void BackupClientDirectoryRecord::SetErrorWhenReadingFilesystemObject(BackupClie // Zero hash, so it gets synced properly next time round. ::memset(mStateChecksum, 0, sizeof(mStateChecksum)); - // Log the error - ::syslog(LOG_ERR, "Backup object failed, error when reading %s", Filename); + // Log the error - already done by caller + /* + rParams.GetProgressNotifier().NotifyFileReadFailed(this, + Filename, strerror(errno)); + */ // Mark that an error occured in the parameters object rParams.mReadErrorsOnFilesystemObjects = true; @@ -1334,8 +1373,10 @@ void BackupClientDirectoryRecord::SetErrorWhenReadingFilesystemObject(BackupClie // Created: 8/3/04 // // -------------------------------------------------------------------------- -BackupClientDirectoryRecord::SyncParams::SyncParams(BackupDaemon &rDaemon, BackupClientContext &rContext) - : mSyncPeriodStart(0), +BackupClientDirectoryRecord::SyncParams::SyncParams(BackupDaemon &rDaemon, + ProgressNotifier &rProgressNotifier, BackupClientContext &rContext) + : mrProgressNotifier(rProgressNotifier), + mSyncPeriodStart(0), mSyncPeriodEnd(0), mMaxUploadWait(0), mMaxFileTimeInFuture(99999999999999999LL), diff --git a/bin/bbackupd/BackupClientDirectoryRecord.h b/bin/bbackupd/BackupClientDirectoryRecord.h index b7b84984..96afde1c 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.h +++ b/bin/bbackupd/BackupClientDirectoryRecord.h @@ -22,6 +22,66 @@ class Archive; class BackupClientContext; class BackupDaemon; +// -------------------------------------------------------------------------- +// +// Class +// Name: ProgressNotifier +// Purpose: Provides methods for the backup library to inform the user +// interface about its progress with the backup +// Created: 2005/11/20 +// +// -------------------------------------------------------------------------- +class BackupClientDirectoryRecord; + +class ProgressNotifier +{ + public: + virtual ~ProgressNotifier() { } + virtual void NotifyScanDirectory( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; + virtual void NotifyDirStatFailed( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const std::string& rErrorMsg) = 0; + virtual void NotifyFileStatFailed( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const std::string& rErrorMsg) = 0; + virtual void NotifyDirListFailed( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const std::string& rErrorMsg) = 0; + virtual void NotifyFileReadFailed( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const std::string& rErrorMsg) = 0; + virtual void NotifyFileModifiedInFuture( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; + virtual void NotifyFileSkippedServerFull( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; + virtual void NotifyFileUploadException( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const BoxException& rException) = 0; + virtual void NotifyFileUploading( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; + virtual void NotifyFileUploadingPatch( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; + virtual void NotifyFileUploaded( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + int64_t FileSize) = 0; + virtual void NotifyFileSynchronised( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + int64_t FileSize) = 0; +}; + // -------------------------------------------------------------------------- // // Class @@ -59,14 +119,18 @@ public: class SyncParams { public: - SyncParams(BackupDaemon &rDaemon, BackupClientContext &rContext); + SyncParams( + BackupDaemon &rDaemon, + ProgressNotifier &rProgressNotifier, + BackupClientContext &rContext); ~SyncParams(); private: // No copying SyncParams(const SyncParams&); SyncParams &operator=(const SyncParams&); + ProgressNotifier &mrProgressNotifier; + public: - // Data members are public, as accessors are not justified here box_time_t mSyncPeriodStart; box_time_t mSyncPeriodEnd; @@ -81,6 +145,11 @@ public: // Member variables modified by syncing process box_time_t mUploadAfterThisTimeInTheFuture; bool mHaveLoggedWarningAboutFutureFileTimes; + + ProgressNotifier& GetProgressNotifier() const + { + return mrProgressNotifier; + } }; void SyncDirectory(SyncParams &rParams, int64_t ContainingDirectoryID, const std::string &rLocalPath, diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index c9b9fb52..4969a95e 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -113,7 +113,8 @@ unsigned int WINAPI HelperThread(LPVOID lpParam) BackupDaemon::BackupDaemon() : mState(BackupDaemon::State_Initialising), mpCommandSocketInfo(0), - mDeleteUnusedRootDirEntriesAfter(0) + mDeleteUnusedRootDirEntriesAfter(0), + mLogAllFileAccess(false) { // Only ever one instance of a daemon SSLLib::Initialise(); @@ -697,6 +698,13 @@ void BackupDaemon::Run2() "ExtendedLogFile"); } + if (conf.KeyExists("LogAllFileAccess")) + { + mLogAllFileAccess = + conf.GetKeyValueBool( + "LogAllFileAccess"); + } + // Then create a client context object (don't // just connect, as this may be unnecessary) BackupClientContext clientContext @@ -711,7 +719,7 @@ void BackupDaemon::Run2() ); // Set up the sync parameters - BackupClientDirectoryRecord::SyncParams params(*this, clientContext); + BackupClientDirectoryRecord::SyncParams params(*this, *this, clientContext); params.mSyncPeriodStart = syncPeriodStart; params.mSyncPeriodEnd = syncPeriodEndExtended; // use potentially extended end time params.mMaxUploadWait = maxUploadWait; diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 347c205b..9d1eab6c 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -16,9 +16,12 @@ #include "BoxTime.h" #include "Daemon.h" +#include "BackupClientDirectoryRecord.h" #include "Socket.h" #include "SocketListen.h" #include "SocketStream.h" +#include "Logging.h" + #ifdef WIN32 #include "WinNamedPipeStream.h" #endif @@ -39,7 +42,7 @@ class Archive; // Created: 2003/10/08 // // -------------------------------------------------------------------------- -class BackupDaemon : public Daemon +class BackupDaemon : public Daemon, ProgressNotifier { public: BackupDaemon(); @@ -180,6 +183,118 @@ private: box_time_t mDeleteUnusedRootDirEntriesAfter; // time to delete them std::vector > mUnusedRootDirEntries; +public: + bool StopRun() { return this->Daemon::StopRun(); } + +private: + bool mLogAllFileAccess; + + /* ProgressNotifier implementation */ +public: + virtual void NotifyScanDirectory( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + if (mLogAllFileAccess) + { + BOX_INFO("Scanning directory: " << rLocalPath); + } + } + virtual void NotifyDirStatFailed( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const std::string& rErrorMsg) + { + BOX_WARNING("Failed to access directory: " << rLocalPath + << ": " << rErrorMsg); + } + virtual void NotifyFileStatFailed( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const std::string& rErrorMsg) + { + BOX_WARNING("Failed to access file: " << rLocalPath + << ": " << rErrorMsg); + } + virtual void NotifyDirListFailed( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const std::string& rErrorMsg) + { + BOX_WARNING("Failed to list directory: " << rLocalPath + << ": " << rErrorMsg); + } + virtual void NotifyFileReadFailed( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const std::string& rErrorMsg) + { + BOX_WARNING("Error reading file: " << rLocalPath + << ": " << rErrorMsg); + } + virtual void NotifyFileModifiedInFuture( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + BOX_WARNING("Some files have modification times excessively " + "in the future. Check clock synchronisation. " + "Example file (only one shown): " << rLocalPath); + } + virtual void NotifyFileSkippedServerFull( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + BOX_WARNING("Skipped file: server is full: " << rLocalPath); + } + virtual void NotifyFileUploadException( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + const BoxException& rException) + { + BOX_ERROR("Failed to upload file: " << rLocalPath + << ": caught exception: " << rException.what() + << " (" << rException.GetType() + << "/" << rException.GetSubType() << ")"); + } + virtual void NotifyFileUploading( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + if (mLogAllFileAccess) + { + BOX_INFO("Uploading file: " << rLocalPath); + } + } + virtual void NotifyFileUploadingPatch( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + if (mLogAllFileAccess) + { + BOX_INFO("Uploading patch to file: " << rLocalPath); + } + } + virtual void NotifyFileUploaded( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + int64_t FileSize) + { + if (mLogAllFileAccess) + { + BOX_INFO("Uploaded file: " << rLocalPath); + } + } + virtual void NotifyFileSynchronised( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + int64_t FileSize) + { + if (mLogAllFileAccess) + { + BOX_INFO("Synchronised file: " << rLocalPath); + } + } + #ifdef WIN32 public: void RunHelperThread(void); diff --git a/lib/backupclient/BackupDaemonConfigVerify.cpp b/lib/backupclient/BackupDaemonConfigVerify.cpp index 34167227..9000ec6d 100644 --- a/lib/backupclient/BackupDaemonConfigVerify.cpp +++ b/lib/backupclient/BackupDaemonConfigVerify.cpp @@ -83,6 +83,7 @@ static const ConfigurationVerifyKey verifyrootkeys[] = {"StoreHostname", 0, ConfigTest_Exists, 0}, {"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 -- cgit v1.2.3 From ecd8635aecde4841daaa447cddcc395894859774 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 11 Jan 2007 23:01:30 +0000 Subject: Added logging of directory scans and excluded files. (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 21 +++++++++++++++++++++ bin/bbackupd/BackupClientDirectoryRecord.h | 9 +++++++++ bin/bbackupd/BackupDaemon.h | 24 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 6651598a..b9780fed 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -199,6 +199,9 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn DIR *dirHandle = 0; try { + rParams.GetProgressNotifier().NotifyScanDirectory( + this, rLocalPath); + dirHandle = ::opendir(rLocalPath.c_str()); if(dirHandle == 0) { @@ -288,6 +291,11 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn // Exclude it? if(rParams.mrContext.ExcludeFile(filename)) { + rParams.GetProgressNotifier() + .NotifyFileExcluded( + this, + filename); + // Next item! continue; } @@ -302,6 +310,11 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn // Exclude it? if(rParams.mrContext.ExcludeDir(filename)) { + rParams.GetProgressNotifier() + .NotifyDirExcluded( + this, + filename); + // Next item! continue; } @@ -316,6 +329,9 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn "%d (%s)", type, filename.c_str()); #endif + rParams.GetProgressNotifier() + .NotifyUnsupportedFileType( + this, filename); SetErrorWhenReadingFilesystemObject( rParams, filename.c_str()); continue; @@ -329,6 +345,11 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn // but now we need the information. if(::lstat(filename.c_str(), &st) != 0) { + rParams.GetProgressNotifier() + .NotifyFileStatFailed(this, + filename, + strerror(errno)); + // Report the error (logs and // eventual email to administrator) SetErrorWhenReadingFilesystemObject( diff --git a/bin/bbackupd/BackupClientDirectoryRecord.h b/bin/bbackupd/BackupClientDirectoryRecord.h index 96afde1c..d7673920 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.h +++ b/bin/bbackupd/BackupClientDirectoryRecord.h @@ -52,6 +52,15 @@ class ProgressNotifier const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath, const std::string& rErrorMsg) = 0; + virtual void NotifyFileExcluded( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; + virtual void NotifyDirExcluded( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; + virtual void NotifyUnsupportedFileType( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; virtual void NotifyFileReadFailed( const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath, diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 9d1eab6c..275603fc 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -224,6 +224,30 @@ public: BOX_WARNING("Failed to list directory: " << rLocalPath << ": " << rErrorMsg); } + virtual void NotifyFileExcluded( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + if (mLogAllFileAccess) + { + BOX_INFO("Skipping excluded file: " << rLocalPath); + } + } + virtual void NotifyDirExcluded( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + if (mLogAllFileAccess) + { + BOX_INFO("Skipping excluded directory: " << rLocalPath); + } + } + virtual void NotifyUnsupportedFileType( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + BOX_WARNING("Ignoring file of unknown type: " << rLocalPath); + } virtual void NotifyFileReadFailed( const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath, -- cgit v1.2.3 From 20de9f6a415e3805ef9283fafada5fe42650b755 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Jan 2007 23:14:27 +0000 Subject: Always start by logging everything to syslog, even when running on the console. Don't closelog() here, let Logging do that for us. (refs #3) --- bin/bbackupd/bbackupd.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index 1ddbf397..0fe8ee41 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -29,7 +29,8 @@ int main(int argc, const char *argv[]) Logging::SetProgramName("Box Backup (bbackupd)"); Logging::ToConsole(true); - Logging::FilterSyslog (Log::EVERYTHING); + Logging::ToSyslog (true); + Logging::FilterSyslog(Log::EVERYTHING); #ifdef NDEBUG Logging::FilterConsole(Log::INFO); @@ -65,7 +66,6 @@ int main(int argc, const char *argv[]) if (argc >= 2 && ::strcmp(argv[1], "--service") == 0) { runAsWin32Service = true; - Logging::ToSyslog(true); } gpDaemonService = new Win32BackupService(); @@ -99,8 +99,6 @@ int main(int argc, const char *argv[]) BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); } - ::closelog(); - delete gpDaemonService; return ExitCode; -- cgit v1.2.3 From 5a57914f63d84d3fcaf1566bfea8d63646ecd91b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Jan 2007 23:15:17 +0000 Subject: Cosmetic spacing fixes (refs #3) --- lib/common/Logging.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index ee76cde4..dad96126 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -21,8 +21,8 @@ bool Logging::sContextSet = false; std::vector Logging::sLoggers; std::string Logging::sContext; -Console Logging::sConsole; -Syslog Logging::sSyslog; +Console Logging::sConsole; +Syslog Logging::sSyslog; Log::Level Logging::sGlobalLevel; void Logging::ToSyslog(bool enabled) -- cgit v1.2.3 From ff67e96270885804fe3ba19376622481d6cadda2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Jan 2007 23:16:04 +0000 Subject: Convert Daemon class to new logging framework (refs #3) --- lib/server/Daemon.cpp | 86 ++++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 59 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index af478320..c0fd4c6f 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -33,6 +33,7 @@ #include "Guards.h" #include "UnixUser.h" #include "FileModificationTime.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -147,16 +148,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\n", 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_ERROR("Failed to start: failed to open " + "configuration file: " + << mConfigFileName); return 1; } @@ -167,14 +161,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_ERROR("Failed to start: errors in configuration " + "file: " << mConfigFileName << ": " << errors); // And give up return 1; } @@ -275,12 +263,9 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) } #endif // !WIN32 - // open the log - ::openlog(DaemonName(), LOG_PID, LOG_LOCAL6); - // Log the start message - ::syslog(LOG_INFO, "Starting daemon (config: %s) (version " - BOX_VERSION ")", mConfigFileName.c_str()); + BOX_INFO("Starting daemon, version " << BOX_VERSION + <<", config: " << mConfigFileName); // Write PID to file char pid[32]; @@ -293,7 +278,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if(::write(pidFile, pid, pidsize) != pidsize) { - ::syslog(LOG_ERR, "can't write pid file"); + BOX_ERROR("can't write pid file"); THROW_EXCEPTION(ServerException, DaemoniseFailed) } @@ -334,37 +319,24 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // 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); } } 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_ERROR("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_ERROR("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_ERROR("Failed to start: unknown error"); return 1; } @@ -377,7 +349,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if (WSAStartup(0x0101, &info) == SOCKET_ERROR) { // will not run without sockets - ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); + BOX_ERROR("Failed to initialise Windows Sockets"); THROW_EXCEPTION(CommonException, Internal) } #endif @@ -394,9 +366,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_INFO("Reloading configuration file: " + << mConfigFileName); std::string errors; std::auto_ptr pconfig = Configuration::LoadAndVerify( @@ -407,10 +378,9 @@ 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_ERROR("Error in configuration " + << "file: " << mConfigFileName + << ": " << errors); // And give up retcode = 1; break; @@ -434,25 +404,23 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) ::unlink(pidFileName.c_str()); // Log - ::syslog(LOG_INFO, "Terminating daemon"); + BOX_INFO("Terminating daemon"); } catch(BoxException &e) { - ::syslog(LOG_ERR, "%s: terminating due to exception %s " - "(%d/%d)", DaemonName(), e.what(), e.GetType(), - e.GetSubType()); + BOX_ERROR("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()); + BOX_ERROR("Terminating due to exception " << e.what()); retcode = 1; } catch(...) { - ::syslog(LOG_ERR, "%s: terminating due to unknown exception", - DaemonName()); + BOX_ERROR("Terminating due to unknown exception"); retcode = 1; } -- cgit v1.2.3 From b01211dc4b77264d9042f9a3d6223710953d24dd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 13 Jan 2007 01:01:27 +0000 Subject: Fix spelling (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index fbb4ee47..b752b6a2 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -254,7 +254,8 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di break; } - // Fetch the directory listing from the server -- getting a list of files which is approparite to the restore type + // 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), -- cgit v1.2.3 From bd6c2f418ce4e1d369c46840ccf89bf8b03e83bb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 13 Jan 2007 01:02:57 +0000 Subject: Ignore symlink permissions on Darwin, where they can't be set properly after symlink creation (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 5 ++++- lib/common/BoxPlatform.h | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 1781282a..9c6168d8 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1536,7 +1536,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s // Decode it std::auto_ptr fileOnServerStream; - // Got additional attibutes? + // Got additional attributes? if(i->second->HasAttributes()) { // Use these attributes @@ -1570,6 +1570,9 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s #endif if(!rParams.mIgnoreAttributes && + #ifdef PLATFORM_DISABLE_SYMLINK_ATTRIB_COMPARE + !fileOnServerStream->IsSymLink() && + #endif !localAttr.Compare(fileOnServerStream->GetAttributes(), ignoreAttrModTime, fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */)) diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h index 3ae929ef..4b58d31d 100644 --- a/lib/common/BoxPlatform.h +++ b/lib/common/BoxPlatform.h @@ -57,6 +57,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 -- cgit v1.2.3 From f66dda5e642ed73671d2a1ede0237646f52a731d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 13 Jan 2007 15:41:12 +0000 Subject: Rename makedistribution.pl to makedistribution.pl.in. Auto-generate makedistribution.pl in configure, to replace @PERL@ in shebang line. Process spec files as text files, to allow removing private parts. (refs #3) --- configure.ac | 1 + infrastructure/makedistribution.pl | 327 ---------------------------------- infrastructure/makedistribution.pl.in | 327 ++++++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+), 327 deletions(-) delete mode 100755 infrastructure/makedistribution.pl create mode 100755 infrastructure/makedistribution.pl.in diff --git a/configure.ac b/configure.ac index 8b0cf7d0..2eaa232e 100644 --- a/configure.ac +++ b/configure.ac @@ -240,6 +240,7 @@ AX_CONFIG_SCRIPTS([bin/bbackupd/bbackupd-config bin/bbstored/bbstored-config infrastructure/makebuildenv.pl infrastructure/makeparcels.pl + infrastructure/makedistribution.pl lib/common/makeexception.pl lib/raidfile/raidfile-config lib/server/makeprotocol.pl diff --git a/infrastructure/makedistribution.pl b/infrastructure/makedistribution.pl deleted file mode 100755 index 16f7409b..00000000 --- a/infrastructure/makedistribution.pl +++ /dev/null @@ -1,327 +0,0 @@ -#!@PERL@ -use strict; -use Symbol; - -# comment string for various endings -my %comment_chars = ('cpp' => '// ', 'h' => '// ', 'pl' => '# ', 'pm' => '# ', '' => '# '); - -# other extensions which need text copying, just to remove the private stuff -my %text_files = ('txt' => 1); - -# files which don't get the license added -my %no_license = (); # 'filename' => 1 - -# ---------------------------------------------- - -# filled in from the manifest file -my %no_license_dir = (); - -# distribution name -my $distribution = $ARGV[0]; -die "No distribution name specified on the command line" if $distribution eq ''; -my $dist_root = "distribution/$distribution"; - -# check distribution exists -die "Distribution '$distribution' does not exist" unless -d $dist_root; - -# get version -open VERSION,"$dist_root/VERSION.txt" or die "Can't open $dist_root/VERSION.txt"; -my $version = ; -chomp $version; -my $archive_name = ; -chomp $archive_name; -close VERSION; - -# consistency check -die "Archive name '$archive_name' is not equal to the distribution name '$distribution'" - unless $archive_name eq $distribution; - -# make initial directory -my $base_name = "$archive_name-$version"; -system "rm -rf $base_name"; -system "rm $base_name.tgz"; -mkdir $base_name,0755; - -# get license file -open LICENSE,"$dist_root/LICENSE.txt" or die "Can't open $dist_root/LICENSE.txt"; -my $license_f; -read LICENSE,$license_f,100000; -close LICENSE; -my $svnversion = `svnversion .`; -chomp $svnversion; -my @license = ('distribution '.$base_name.' (svn version: '.$svnversion.')',split(/\n/,$license_f)); - -# copy files, make a note of all the modules included -my %modules_included; -my $private_sections_removed = 0; -my $non_distribution_sections_removed = 0; -sub copy_from_list -{ - my $list = $_[0]; - open LIST,$list or die "Can't open $list"; - - while() - { - next unless m/\S/; - chomp; - my ($src,$dst) = split /\s+/; - $dst = $src if $dst eq ''; - if($src eq 'MKDIR') - { - # actually we just need to make a directory here - mkdir "$base_name/$dst",0755; - } - elsif($src eq 'NO-LICENSE-IN-DIR') - { - # record that this directory shouldn't have the license added - $no_license_dir{$dst} = 1; - } - elsif($src eq 'REPLACE-VERSION-IN') - { - replace_version_in($dst); - } - elsif($src eq 'NO-LICENSE') - { - $no_license{$dst} = 1; - } - elsif($src eq 'RUN') - { - print "Running $dst...\n"; - if(system($dst) != 0) - { - print "Error running $dst. Aborting.\n"; - exit(1); - } - } - elsif(-d $src) - { - $modules_included{$_} = 1; - copy_dir($src,$dst); - } - else - { - copy_file($src,$dst); - } - } - - close LIST; -} -copy_from_list("distribution/COMMON-MANIFEST.txt"); -copy_from_list("$dist_root/DISTRIBUTION-MANIFEST.txt"); - -# Copy in the root directory and delete the DISTRIBUTION-MANIFEST file -(system("cp $dist_root/*.* $base_name/") == 0) - or die "Copy of root extra files failed"; -unlink "$base_name/DISTRIBUTION-MANIFEST.txt" - or die "Delete of DISTRIBUTION-MANIFEST.txt file failed"; - -# produce a new modules file -my $modules = gensym; -open $modules,"modules.txt" or die "Can't open modules.txt for reading"; -open MODULES_OUT,">$base_name/modules.txt"; - -while(<$modules>) -{ - # skip lines for modules which aren't included - next if m/\A(\w+\/\w+)\s/ && !exists $modules_included{$1}; - - # skip private sections - unless(skip_non_applicable_section($_, $modules, 'modules.txt')) - { - # copy line to out files - print MODULES_OUT - } -} - -close MODULES_OUT; -close $modules; - -# report on how many private sections were removed -print "Private sections removed: $private_sections_removed\nNon-distribution sections removed: $non_distribution_sections_removed\n"; - -# tar it up -system "tar cf - $base_name | gzip -9 - > $base_name.tgz"; - -sub copy_file -{ - my ($fn,$dst_fn) = @_; - - my $ext; - $ext = $1 if $fn =~ m/\.(\w+)\Z/; - - # licenses not used in this directory? - my $license_in_dir = 1; - $dst_fn =~ m~\A(.+)/[^/]+?\Z~; - $license_in_dir = 0 if exists $no_license_dir{$1}; - - # licensed or not? - if(exists $comment_chars{$ext} && !exists $no_license{$fn} && $license_in_dir) - { - my $b = $comment_chars{$ext}; - - # copy as text, inserting license - my $in = gensym; - open $in,$fn; - open OUT,">$base_name/$dst_fn"; - - my $first = <$in>; - if($first =~ m/\A#!/) - { - print OUT $first; - $first = ''; - } - - # write license - for(@license) - { - print OUT $b,$_,"\n" - } - - if($first ne '') - { - print OUT $first; - } - - while(<$in>) - { - unless(skip_non_applicable_section($_, $in, $fn)) - { - print OUT - } - } - - close OUT; - close $in; - } - else - { - if(exists $text_files{$ext}) - { - # copy this as text, to remove private stuff - my $in = gensym; - open $in,$fn; - open OUT,">$base_name/$dst_fn"; - - while(<$in>) - { - unless(skip_non_applicable_section($_, $in, $fn)) - { - print OUT - } - } - - close OUT; - close $in; - } - else - { - # copy as binary - system 'cp',$fn,"$base_name/$dst_fn" - } - } - - # copy executable bit from src - if(-x $fn) - { - system 'chmod','a+x',"$base_name/$dst_fn" - } - else - { - system 'chmod','a-x',"$base_name/$dst_fn" - } -} - -sub skip_non_applicable_section -{ - my ($l, $filehandle, $filename) = @_; - if($l =~ m/BOX_PRIVATE_BEGIN/) - { - # skip private section - print "Removing private section from $filename\n"; - $private_sections_removed++; - while(<$filehandle>) {last if m/BOX_PRIVATE_END/} - - # skipped something - return 1; - } - elsif($l =~ m/IF_DISTRIBUTION\((.+?)\)/) - { - # which distributions does this apply to? - my $applies = 0; - for(split /,/,$1) - { - $applies = 1 if $_ eq $distribution - } - unless($applies) - { - # skip section? - print "Removing distribution specific section from $filename\n"; - $non_distribution_sections_removed++; - while(<$filehandle>) {last if m/END_IF_DISTRIBUTION/} - } - # hide this line - return 1; - } - elsif($l =~ m/END_IF_DISTRIBUTION/) - { - # hide these lines - return 1; - } - else - { - # no skipping, return this line - return 0; - } -} - -sub copy_dir -{ - my ($dir,$dst_dir) = @_; - - # copy an entire directory... first make sure it exists - my @n = split /\//,$dst_dir; - my $d = $base_name; - for(@n) - { - $d .= '/'; - $d .= $_; - mkdir $d,0755; - } - - # then do each of the files within in - opendir DIR,$dir; - my @items = readdir DIR; - closedir DIR; - - for(@items) - { - next if m/\A\./; - next if m/\A_/; - next if m/\AMakefile\Z/; - next if m/\Aautogen/; - next if !-f "$dir/$_"; - - copy_file("$dir/$_","$dst_dir/$_"); - } -} - -sub replace_version_in -{ - my ($file) = @_; - - my $fn = $base_name . '/' . $file; - open IN,$fn or die "Can't open $fn"; - open OUT,'>'.$fn.'.new' or die "Can't open $fn.new for writing"; - - while() - { - s/###DISTRIBUTION-VERSION-NUMBER###/$version/g; - print OUT - } - - close OUT; - close IN; - - rename($fn.'.new', $fn) or die "Can't rename in place $fn"; -} - diff --git a/infrastructure/makedistribution.pl.in b/infrastructure/makedistribution.pl.in new file mode 100755 index 00000000..52e1c2e4 --- /dev/null +++ b/infrastructure/makedistribution.pl.in @@ -0,0 +1,327 @@ +#!@PERL@ +use strict; +use Symbol; + +# comment string for various endings +my %comment_chars = ('cpp' => '// ', 'h' => '// ', 'pl' => '# ', 'pm' => '# ', '' => '# '); + +# other extensions which need text copying, just to remove the private stuff +my %text_files = ('txt' => 1, 'spec' => 1); + +# files which don't get the license added +my %no_license = (); # 'filename' => 1 + +# ---------------------------------------------- + +# filled in from the manifest file +my %no_license_dir = (); + +# distribution name +my $distribution = $ARGV[0]; +die "No distribution name specified on the command line" if $distribution eq ''; +my $dist_root = "distribution/$distribution"; + +# check distribution exists +die "Distribution '$distribution' does not exist" unless -d $dist_root; + +# get version +open VERSION,"$dist_root/VERSION.txt" or die "Can't open $dist_root/VERSION.txt"; +my $version = ; +chomp $version; +my $archive_name = ; +chomp $archive_name; +close VERSION; + +# consistency check +die "Archive name '$archive_name' is not equal to the distribution name '$distribution'" + unless $archive_name eq $distribution; + +# make initial directory +my $base_name = "$archive_name-$version"; +system "rm -rf $base_name"; +system "rm $base_name.tgz"; +mkdir $base_name,0755; + +# get license file +open LICENSE,"$dist_root/LICENSE.txt" or die "Can't open $dist_root/LICENSE.txt"; +my $license_f; +read LICENSE,$license_f,100000; +close LICENSE; +my $svnversion = `svnversion .`; +chomp $svnversion; +my @license = ('distribution '.$base_name.' (svn version: '.$svnversion.')',split(/\n/,$license_f)); + +# copy files, make a note of all the modules included +my %modules_included; +my $private_sections_removed = 0; +my $non_distribution_sections_removed = 0; +sub copy_from_list +{ + my $list = $_[0]; + open LIST,$list or die "Can't open $list"; + + while() + { + next unless m/\S/; + chomp; + my ($src,$dst) = split /\s+/; + $dst = $src if $dst eq ''; + if($src eq 'MKDIR') + { + # actually we just need to make a directory here + mkdir "$base_name/$dst",0755; + } + elsif($src eq 'NO-LICENSE-IN-DIR') + { + # record that this directory shouldn't have the license added + $no_license_dir{$dst} = 1; + } + elsif($src eq 'REPLACE-VERSION-IN') + { + replace_version_in($dst); + } + elsif($src eq 'NO-LICENSE') + { + $no_license{$dst} = 1; + } + elsif($src eq 'RUN') + { + print "Running $dst...\n"; + if(system($dst) != 0) + { + print "Error running $dst. Aborting.\n"; + exit(1); + } + } + elsif(-d $src) + { + $modules_included{$_} = 1; + copy_dir($src,$dst); + } + else + { + copy_file($src,$dst); + } + } + + close LIST; +} +copy_from_list("distribution/COMMON-MANIFEST.txt"); +copy_from_list("$dist_root/DISTRIBUTION-MANIFEST.txt"); + +# Copy in the root directory and delete the DISTRIBUTION-MANIFEST file +(system("cp $dist_root/*.* $base_name/") == 0) + or die "Copy of root extra files failed"; +unlink "$base_name/DISTRIBUTION-MANIFEST.txt" + or die "Delete of DISTRIBUTION-MANIFEST.txt file failed"; + +# produce a new modules file +my $modules = gensym; +open $modules,"modules.txt" or die "Can't open modules.txt for reading"; +open MODULES_OUT,">$base_name/modules.txt"; + +while(<$modules>) +{ + # skip lines for modules which aren't included + next if m/\A(\w+\/\w+)\s/ && !exists $modules_included{$1}; + + # skip private sections + unless(skip_non_applicable_section($_, $modules, 'modules.txt')) + { + # copy line to out files + print MODULES_OUT + } +} + +close MODULES_OUT; +close $modules; + +# report on how many private sections were removed +print "Private sections removed: $private_sections_removed\nNon-distribution sections removed: $non_distribution_sections_removed\n"; + +# tar it up +system "tar cf - $base_name | gzip -9 - > $base_name.tgz"; + +sub copy_file +{ + my ($fn,$dst_fn) = @_; + + my $ext; + $ext = $1 if $fn =~ m/\.(\w+)\Z/; + + # licenses not used in this directory? + my $license_in_dir = 1; + $dst_fn =~ m~\A(.+)/[^/]+?\Z~; + $license_in_dir = 0 if exists $no_license_dir{$1}; + + # licensed or not? + if(exists $comment_chars{$ext} && !exists $no_license{$fn} && $license_in_dir) + { + my $b = $comment_chars{$ext}; + + # copy as text, inserting license + my $in = gensym; + open $in,$fn; + open OUT,">$base_name/$dst_fn"; + + my $first = <$in>; + if($first =~ m/\A#!/) + { + print OUT $first; + $first = ''; + } + + # write license + for(@license) + { + print OUT $b,$_,"\n" + } + + if($first ne '') + { + print OUT $first; + } + + while(<$in>) + { + unless(skip_non_applicable_section($_, $in, $fn)) + { + print OUT + } + } + + close OUT; + close $in; + } + else + { + if(exists $text_files{$ext}) + { + # copy this as text, to remove private stuff + my $in = gensym; + open $in,$fn; + open OUT,">$base_name/$dst_fn"; + + while(<$in>) + { + unless(skip_non_applicable_section($_, $in, $fn)) + { + print OUT + } + } + + close OUT; + close $in; + } + else + { + # copy as binary + system 'cp',$fn,"$base_name/$dst_fn" + } + } + + # copy executable bit from src + if(-x $fn) + { + system 'chmod','a+x',"$base_name/$dst_fn" + } + else + { + system 'chmod','a-x',"$base_name/$dst_fn" + } +} + +sub skip_non_applicable_section +{ + my ($l, $filehandle, $filename) = @_; + if($l =~ m/BOX_PRIVATE_BEGIN/) + { + # skip private section + print "Removing private section from $filename\n"; + $private_sections_removed++; + while(<$filehandle>) {last if m/BOX_PRIVATE_END/} + + # skipped something + return 1; + } + elsif($l =~ m/IF_DISTRIBUTION\((.+?)\)/) + { + # which distributions does this apply to? + my $applies = 0; + for(split /,/,$1) + { + $applies = 1 if $_ eq $distribution + } + unless($applies) + { + # skip section? + print "Removing distribution specific section from $filename\n"; + $non_distribution_sections_removed++; + while(<$filehandle>) {last if m/END_IF_DISTRIBUTION/} + } + # hide this line + return 1; + } + elsif($l =~ m/END_IF_DISTRIBUTION/) + { + # hide these lines + return 1; + } + else + { + # no skipping, return this line + return 0; + } +} + +sub copy_dir +{ + my ($dir,$dst_dir) = @_; + + # copy an entire directory... first make sure it exists + my @n = split /\//,$dst_dir; + my $d = $base_name; + for(@n) + { + $d .= '/'; + $d .= $_; + mkdir $d,0755; + } + + # then do each of the files within in + opendir DIR,$dir; + my @items = readdir DIR; + closedir DIR; + + for(@items) + { + next if m/\A\./; + next if m/\A_/; + next if m/\AMakefile\Z/; + next if m/\Aautogen/; + next if !-f "$dir/$_"; + + copy_file("$dir/$_","$dst_dir/$_"); + } +} + +sub replace_version_in +{ + my ($file) = @_; + + my $fn = $base_name . '/' . $file; + open IN,$fn or die "Can't open $fn"; + open OUT,'>'.$fn.'.new' or die "Can't open $fn.new for writing"; + + while() + { + s/###DISTRIBUTION-VERSION-NUMBER###/$version/g; + print OUT + } + + close OUT; + close IN; + + rename($fn.'.new', $fn) or die "Can't rename in place $fn"; +} + -- cgit v1.2.3 From f77d62515cd49ac50d16f0a54f14f6086d4ff745 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 13 Jan 2007 15:43:18 +0000 Subject: Support building from an unofficial tarball (from svn) by changing %{distribution_dir} at the top (automatically in distributions made by infrastructure/makedistribution.pl) Write our RPM version number into VERSION.txt and hence compile it in (refs #3) --- distribution/boxbackup/contrib/rpm/boxbackup.spec | 52 ++++++++++++++++++----- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/distribution/boxbackup/contrib/rpm/boxbackup.spec b/distribution/boxbackup/contrib/rpm/boxbackup.spec index 12a2bb9f..eb09ecbe 100644 --- a/distribution/boxbackup/contrib/rpm/boxbackup.spec +++ b/distribution/boxbackup/contrib/rpm/boxbackup.spec @@ -1,6 +1,20 @@ %define bb_user_id 171 %define ident %{name}-%{version} +# In official distribution tarballs, distribution files are copied to +# the base directory (where configure is), so distribution_dir should be empty. +# This is the default, overridden by the following block in non-distribution +# builds. +%define distribution_dir + +# BOX_PRIVATE_BEGIN +# In unofficial tarballs, made from svn, distribution files are still in +# distribution/boxbackup, so the following line overrides the default above: +# (this section will be removed automatically from distribution tarballs +# by infrastructure/makedistribution.pl) +%define distribution_dir distribution/boxbackup +# BOX_PRIVATE_END + # Detect distribution. So far we only special-case SUSE. If you need to make # any distro specific changes to get the package building on your system # please email them to boxbackup-dev@fluffy.co.uk @@ -72,6 +86,7 @@ This package contains the server. %setup -q %build +echo -e '%{version}\n%{name}' > VERSION.txt test -e configure || ./bootstrap %configure @@ -88,19 +103,28 @@ mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/box/bbackupd mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/box/bbstored mkdir -p $RPM_BUILD_ROOT%{_var}/lib/box -install -m 644 BUGS.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 LINUX.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 VERSION.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 CONTACT.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 DOCUMENTATION.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 ExceptionCodes.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 THANKS.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 LICENSE.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 TODO.txt $RPM_BUILD_ROOT%{_docdir}/%{ident} +install -m 644 BUGS.txt \ + $RPM_BUILD_ROOT%{_docdir}/%{ident} +install -m 644 VERSION.txt \ + $RPM_BUILD_ROOT%{_docdir}/%{ident} +install -m 644 ExceptionCodes.txt \ + $RPM_BUILD_ROOT%{_docdir}/%{ident} +install -m 644 LICENSE.txt \ + $RPM_BUILD_ROOT%{_docdir}/%{ident} + +install -m 644 %{distribution_dir}/CONTACT.txt \ + $RPM_BUILD_ROOT%{_docdir}/%{ident} +install -m 644 %{distribution_dir}/DOCUMENTATION.txt \ + $RPM_BUILD_ROOT%{_docdir}/%{ident} +install -m 644 %{distribution_dir}/LINUX.txt \ + $RPM_BUILD_ROOT%{_docdir}/%{ident} +install -m 644 %{distribution_dir}/THANKS.txt \ + $RPM_BUILD_ROOT%{_docdir}/%{ident} # Client touch $RPM_BUILD_ROOT%{_sysconfdir}/box/bbackupd.conf -install -m 755 contrib/%{dist}/bbackupd $RPM_BUILD_ROOT%{init_dir} +install -m 755 %{distribution_dir}/contrib/%{dist}/bbackupd \ + $RPM_BUILD_ROOT%{init_dir} %if %{is_suse} ln -s ../../%{init_dir}/bbackupd $RPM_BUILD_ROOT%{_sbindir}/rcbbackupd %endif @@ -113,7 +137,8 @@ install %{client_dir}/bbackupd-config $RPM_BUILD_ROOT%{_sbindir} # Server touch $RPM_BUILD_ROOT%{_sysconfdir}/box/bbstored.conf touch $RPM_BUILD_ROOT%{_sysconfdir}/box/raidfile.conf -install -m 755 contrib/%{dist}/bbstored $RPM_BUILD_ROOT%{init_dir} +install -m 755 %{distribution_dir}/contrib/%{dist}/bbstored \ + $RPM_BUILD_ROOT%{init_dir} %if %{is_suse} ln -s ../../%{init_dir}/bbstored $RPM_BUILD_ROOT%{_sbindir}/rcbbstored %endif @@ -195,6 +220,11 @@ rm -rf $RPM_BUILD_ROOT %{_sbindir}/raidfile-config %changelog +* Sat Jan 13 2006 Chris Wilson +- Support building from an unofficial tarball (from svn) by changing + %{distribution_dir} at the top. +- Write our RPM version number into VERSION.txt and hence compile it in + * Wed Dec 28 2005 Martin Ebourne - Box now uses autoconf so use configure macro -- cgit v1.2.3 From 5aa08409b1a78a892f2161506be869d4c8761d6e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 14 Jan 2007 14:59:27 +0000 Subject: - Make sure timer is stopped before removing signal handler, otherwise SIGALRM will kill us. --- lib/common/Timer.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index de01f9f0..dcfe2ce2 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -56,9 +56,12 @@ void Timers::Cleanup() #if defined WIN32 && ! defined PLATFORM_CYGWIN // no support for signals at all - SetTimerHandler(NULL); FiniTimer(); + SetTimerHandler(NULL); #else + struct itimerval timeout; + memset(&timeout, 0, sizeof(timeout)); + ASSERT(::setitimer(ITIMER_REAL, &timeout, NULL) == 0); ASSERT(::signal(SIGALRM, NULL) == Timers::SignalHandler); #endif // WIN32 && !PLATFORM_CYGWIN @@ -203,11 +206,7 @@ void Timers::Reschedule() timeout.it_value.tv_usec = (int) (BoxTimeToMicroSeconds(timeToNextEvent) % MICRO_SEC_IN_SEC); -#ifdef PLATFORM_CYGWIN - if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) -#else if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) -#endif // PLATFORM_CYGWIN { TRACE0("WARNING: couldn't initialise timer\n"); THROW_EXCEPTION(CommonException, Internal) -- cgit v1.2.3 From 080a338fd865df75f9918ae7fa9255e4e9a31da9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 14 Jan 2007 16:23:49 +0000 Subject: Don't die on unreadable files (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index b9780fed..f24fc594 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -634,7 +634,14 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP { rParams.GetProgressNotifier().NotifyFileStatFailed(this, filename, strerror(errno)); - THROW_EXCEPTION(CommonException, OSFileError) + + // Report the error (logs and + // eventual email to administrator) + SetErrorWhenReadingFilesystemObject(rParams, + filename.c_str()); + + // Ignore this entry for now. + continue; } // Extract required data -- cgit v1.2.3 From 7adebdfb61eced2905d3606d829de9e129ab6e39 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 14 Jan 2007 20:28:27 +0000 Subject: Be nice to rpm that doesn't like empty macros (refs #3) --- distribution/boxbackup/contrib/rpm/boxbackup.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/boxbackup/contrib/rpm/boxbackup.spec b/distribution/boxbackup/contrib/rpm/boxbackup.spec index eb09ecbe..0de3589f 100644 --- a/distribution/boxbackup/contrib/rpm/boxbackup.spec +++ b/distribution/boxbackup/contrib/rpm/boxbackup.spec @@ -5,7 +5,7 @@ # the base directory (where configure is), so distribution_dir should be empty. # This is the default, overridden by the following block in non-distribution # builds. -%define distribution_dir +%define distribution_dir '' # BOX_PRIVATE_BEGIN # In unofficial tarballs, made from svn, distribution files are still in -- cgit v1.2.3 From 961deddb62406b1824d00c5278384b2e5d4f5988 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 14 Jan 2007 20:29:49 +0000 Subject: Don't do things with essential side effects inside ASSERT() macros (refs #3, refs #9) --- lib/common/Timer.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index dcfe2ce2..4b596931 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -13,12 +13,15 @@ #include #include "Timer.h" +#include "Logging.h" #include "MemLeakFindOn.h" std::vector* Timers::spTimers = NULL; bool Timers::sRescheduleNeeded = false; +typedef void (*sighandler_t)(int); + // -------------------------------------------------------------------------- // // Function @@ -36,7 +39,9 @@ void Timers::Init() InitTimer(); SetTimerHandler(Timers::SignalHandler); #else - ASSERT(::signal(SIGALRM, Timers::SignalHandler) == 0); + sighandler_t oldHandler = ::signal(SIGALRM, + Timers::SignalHandler); + ASSERT(oldHandler == 0); #endif // WIN32 && !PLATFORM_CYGWIN spTimers = new std::vector; @@ -61,8 +66,12 @@ void Timers::Cleanup() #else struct itimerval timeout; memset(&timeout, 0, sizeof(timeout)); - ASSERT(::setitimer(ITIMER_REAL, &timeout, NULL) == 0); - ASSERT(::signal(SIGALRM, NULL) == Timers::SignalHandler); + + int result = ::setitimer(ITIMER_REAL, &timeout, NULL); + ASSERT(result == 0); + + sighandler_t oldHandler = ::signal(SIGALRM, NULL); + ASSERT(oldHandler == Timers::SignalHandler); #endif // WIN32 && !PLATFORM_CYGWIN spTimers->clear(); @@ -128,6 +137,14 @@ void Timers::Remove(Timer& rTimer) void Timers::Reschedule() { ASSERT(spTimers); + if (spTimers == NULL) + { + THROW_EXCEPTION(CommonException, Internal) + } + if (::signal(SIGALRM, Timers::SignalHandler) != Timers::SignalHandler) + { + THROW_EXCEPTION(CommonException, Internal) + } // Clear the reschedule-needed flag to false before we start. // If a timer event occurs while we are scheduling, then we -- cgit v1.2.3 From a00db5b2b4824e4fe213a568b2ac7e45733a3d45 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 14 Jan 2007 20:53:10 +0000 Subject: Fix building from distribution tarballs again (refs #3) --- distribution/boxbackup/contrib/rpm/boxbackup.spec | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/distribution/boxbackup/contrib/rpm/boxbackup.spec b/distribution/boxbackup/contrib/rpm/boxbackup.spec index 0de3589f..111a00ff 100644 --- a/distribution/boxbackup/contrib/rpm/boxbackup.spec +++ b/distribution/boxbackup/contrib/rpm/boxbackup.spec @@ -12,7 +12,7 @@ # distribution/boxbackup, so the following line overrides the default above: # (this section will be removed automatically from distribution tarballs # by infrastructure/makedistribution.pl) -%define distribution_dir distribution/boxbackup +%define distribution_dir distribution/boxbackup/ # BOX_PRIVATE_END # Detect distribution. So far we only special-case SUSE. If you need to make @@ -112,18 +112,18 @@ install -m 644 ExceptionCodes.txt \ install -m 644 LICENSE.txt \ $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 %{distribution_dir}/CONTACT.txt \ +install -m 644 %{distribution_dir}CONTACT.txt \ $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 %{distribution_dir}/DOCUMENTATION.txt \ +install -m 644 %{distribution_dir}DOCUMENTATION.txt \ $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 %{distribution_dir}/LINUX.txt \ +install -m 644 %{distribution_dir}LINUX.txt \ $RPM_BUILD_ROOT%{_docdir}/%{ident} -install -m 644 %{distribution_dir}/THANKS.txt \ +install -m 644 %{distribution_dir}THANKS.txt \ $RPM_BUILD_ROOT%{_docdir}/%{ident} # Client touch $RPM_BUILD_ROOT%{_sysconfdir}/box/bbackupd.conf -install -m 755 %{distribution_dir}/contrib/%{dist}/bbackupd \ +install -m 755 %{distribution_dir}contrib/%{dist}/bbackupd \ $RPM_BUILD_ROOT%{init_dir} %if %{is_suse} ln -s ../../%{init_dir}/bbackupd $RPM_BUILD_ROOT%{_sbindir}/rcbbackupd @@ -137,7 +137,7 @@ install %{client_dir}/bbackupd-config $RPM_BUILD_ROOT%{_sbindir} # Server touch $RPM_BUILD_ROOT%{_sysconfdir}/box/bbstored.conf touch $RPM_BUILD_ROOT%{_sysconfdir}/box/raidfile.conf -install -m 755 %{distribution_dir}/contrib/%{dist}/bbstored \ +install -m 755 %{distribution_dir}contrib/%{dist}/bbstored \ $RPM_BUILD_ROOT%{init_dir} %if %{is_suse} ln -s ../../%{init_dir}/bbstored $RPM_BUILD_ROOT%{_sbindir}/rcbbstored -- cgit v1.2.3 From bfe704b6e84cd4ba52ff35e78170c408a7b594dd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 14 Jan 2007 20:54:15 +0000 Subject: Add missing files to manifest, required by configure (refs #3) --- distribution/COMMON-MANIFEST.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/distribution/COMMON-MANIFEST.txt b/distribution/COMMON-MANIFEST.txt index be5ef416..cb3543da 100644 --- a/distribution/COMMON-MANIFEST.txt +++ b/distribution/COMMON-MANIFEST.txt @@ -17,9 +17,12 @@ docs/common/lib_crypto notes/lib_crypto docs/common/lib_server notes/lib_server MKDIR infrastructure infrastructure/buildenv-testmain-template.cpp -infrastructure/makebuildenv.pl +infrastructure/makebuildenv.pl.in +infrastructure/makedistribution.pl.in +infrastructure/makeparcels.pl.in infrastructure/BoxPlatform.pm.in -infrastructure/makeparcels.pl +infrastructure/mingw +infrastructure/msvc configure.ac NO-LICENSE config.sub config.sub @@ -27,7 +30,7 @@ NO-LICENSE config.guess config.guess bootstrap parcels.txt -runtest.pl +runtest.pl.in NO-LICENSE-IN-DIR infrastructure/m4 infrastructure/m4 configure -- cgit v1.2.3 From d0acc07e0f1ec76f8fea3a3801d254565568d275 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 14 Jan 2007 23:47:29 +0000 Subject: Spacing (refs #3) --- lib/server/Daemon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index c0fd4c6f..69a488d0 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -265,7 +265,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // Log the start message BOX_INFO("Starting daemon, version " << BOX_VERSION - <<", config: " << mConfigFileName); + << ", config: " << mConfigFileName); // Write PID to file char pid[32]; -- cgit v1.2.3 From b8e98d8ef95d57d81535e6c6e5dcbd411990669a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2007 21:38:53 +0000 Subject: Detect reparse points and change the device number (refs #3) --- lib/win32/emu.cpp | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 205ada9b..da4ecb2a 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -46,24 +46,21 @@ int setitimer(int type, struct itimerval *timeout, void *arg) { ASSERT(gTimerInitialised); - if (ITIMER_VIRTUAL == type) + EnterCriticalSection(&gLock); + // we only need seconds for the mo! + if (timeout->it_value.tv_sec == 0 && + timeout->it_value.tv_usec == 0) { - 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); + 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; @@ -674,6 +671,22 @@ int emu_fstat(HANDLE hdir, struct stat * st) st->st_mode |= S_IWRITE; } + // st_dev is nroammly 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; } -- cgit v1.2.3 From e04804ca2f08402ac6b8fa7d043767eb42738de7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2007 22:10:30 +0000 Subject: Skip mount points and NTFS reparse points inside a location, even if not excluded (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 38 ++++++++++++++++++++++++---- bin/bbackupd/BackupClientDirectoryRecord.h | 3 +++ bin/bbackupd/BackupDaemon.h | 12 +++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index f24fc594..3ed974b8 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -193,6 +193,23 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn std::vector dirs; std::vector files; bool downloadDirectoryRecordBecauseOfFutureFiles = false; + + struct stat dir_st; + if(::lstat(rLocalPath.c_str(), &dir_st) != 0) + { + // Report the error (logs and + // eventual email to administrator) + rParams.GetProgressNotifier().NotifyFileStatFailed(this, + rLocalPath, strerror(errno)); + + // FIXME move to NotifyFileStatFailed() + SetErrorWhenReadingFilesystemObject(rParams, + rLocalPath.c_str()); + + // This shouldn't happen, so we'd better not continue + THROW_EXCEPTION(CommonException, OSFileError) + } + // BLOCK { // read the contents... @@ -281,6 +298,14 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn continue; } + if(st.st_dev != dir_st.st_dev) + { + rParams.GetProgressNotifier() + .NotifyMountPointSkipped(this, + filename); + continue; + } + int type = st.st_mode & S_IFMT; #endif @@ -324,11 +349,6 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn } else { - #ifdef WIN32 - ::syslog(LOG_ERR, "Unknown file type: " - "%d (%s)", type, - filename.c_str()); - #endif rParams.GetProgressNotifier() .NotifyUnsupportedFileType( this, filename); @@ -358,6 +378,14 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn // Ignore this entry for now. continue; } + + if(st.st_dev != dir_st.st_dev) + { + rParams.GetProgressNotifier() + .NotifyMountPointSkipped(this, + filename); + continue; + } #endif checksum_info.mModificationTime = FileModificationTime(st); diff --git a/bin/bbackupd/BackupClientDirectoryRecord.h b/bin/bbackupd/BackupClientDirectoryRecord.h index d7673920..39797466 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.h +++ b/bin/bbackupd/BackupClientDirectoryRecord.h @@ -52,6 +52,9 @@ class ProgressNotifier const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath, const std::string& rErrorMsg) = 0; + virtual void NotifyMountPointSkipped( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) = 0; virtual void NotifyFileExcluded( const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath) = 0; diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 275603fc..5e3728d0 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -224,6 +224,18 @@ public: BOX_WARNING("Failed to list directory: " << rLocalPath << ": " << rErrorMsg); } + virtual void NotifyMountPointSkipped( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath) + { + BOX_WARNING("Ignored directory: " << rLocalPath << ": " + #ifdef WIN32 + "is an NTFS junction/reparse point; " + #else + "is a mount point; " + #endif + "create a new location if you want to back it up"); + } virtual void NotifyFileExcluded( const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath) -- cgit v1.2.3 From 60e8f1ea15e69b987ec916fd006174b345444644 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2007 23:48:12 +0000 Subject: Add a new logging level, NOTICE, between INFO and WARNING (justification: we need two levels of output for LogAllFileAccess, neither of which are warnings, one is very verbose, but must not be compiled out like TRACE). Make Loggers default to logging everything. Make the global log level filter work. (refs #3) --- lib/common/Logging.cpp | 7 ++++++- lib/common/Logging.h | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index dad96126..3e2062da 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -23,7 +23,7 @@ std::vector Logging::sLoggers; std::string Logging::sContext; Console Logging::sConsole; Syslog Logging::sSyslog; -Log::Level Logging::sGlobalLevel; +Log::Level Logging::sGlobalLevel = Log::EVERYTHING; void Logging::ToSyslog(bool enabled) { @@ -95,6 +95,11 @@ void Logging::Remove(Logger* pOldLogger) 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) diff --git a/lib/common/Logging.h b/lib/common/Logging.h index e7a11d36..c85b4586 100644 --- a/lib/common/Logging.h +++ b/lib/common/Logging.h @@ -34,6 +34,7 @@ #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) #if defined NDEBUG && ! defined COMPILE_IN_TRACES #define BOX_TRACE(stuff) @@ -43,7 +44,8 @@ namespace Log { - enum Level { NOTHING = 1, FATAL, ERROR, WARNING, INFO, TRACE, EVERYTHING }; + enum Level { NOTHING = 1, FATAL, ERROR, WARNING, NOTICE, INFO, TRACE, + EVERYTHING }; } // -------------------------------------------------------------------------- @@ -61,7 +63,7 @@ class Logger Log::Level mCurrentLevel; public: - Logger() : mCurrentLevel(Log::WARNING) { } + Logger() : mCurrentLevel(Log::EVERYTHING) { } virtual ~Logger() { } virtual bool Log(Log::Level level, const std::string& rFile, -- cgit v1.2.3 From 9b85a157eb5d883f13b94a19dcca84f4eb8a0eae Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2007 23:49:34 +0000 Subject: Log important output at NOTICE level, instead of INFO (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 4969a95e..aa56fddf 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -689,7 +689,7 @@ void BackupDaemon::Run2() { // Set state and log start SetState(State_Connected); - BOX_INFO("Beginning scan of local files"); + BOX_NOTICE("Beginning scan of local files"); std::string extendedLogFile; if (conf.KeyExists("ExtendedLogFile")) @@ -809,7 +809,7 @@ void BackupDaemon::Run2() CommitIDMapsAfterSync(); // Log - BOX_INFO("Finished scan of local files"); + BOX_NOTICE("Finished scan of local files"); // -------------------------------------------------------------------------------------------- @@ -863,7 +863,7 @@ void BackupDaemon::Run2() // Handle restart? if(StopRun()) { - BOX_INFO("Exception (" << errorCode + BOX_NOTICE("Exception (" << errorCode << "/" << errorSubCode << ") due to signal"); return; @@ -895,7 +895,7 @@ void BackupDaemon::Run2() } // Log the stats - BOX_INFO("File statistics: total file size uploaded " + BOX_NOTICE("File statistics: total file size uploaded " << BackupStoreFile::msStats.mBytesInEncodedFiles << ", bytes already on server " << BackupStoreFile::msStats.mBytesAlreadyOnServer @@ -977,7 +977,7 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() throw; } - BOX_INFO("Delaying sync by " << waitInSeconds + BOX_NOTICE("Delaying sync by " << waitInSeconds << " seconds (SyncAllowScript '" << conf.GetKeyValue("SyncAllowScript") << "')"); @@ -1621,7 +1621,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con // Any entries in the root directory which need deleting? if(dir.GetNumberOfEntries() > 0) { - BOX_INFO(dir.GetNumberOfEntries() << " redundant locations " + BOX_NOTICE(dir.GetNumberOfEntries() << " redundant locations " "in root directory found, will delete from store " "after " << BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER << " seconds."); @@ -2039,7 +2039,7 @@ void BackupDaemon::NotifySysadmin(int Event) std::string script(conf.GetKeyValue("NotifyScript") + ' ' + sEventNames[Event]); // Log what we're about to do - BOX_INFO("About to notify administrator about event " + BOX_NOTICE("About to notify administrator about event " << sEventNames[Event] << ", running script '" << script << "'"); @@ -2079,14 +2079,14 @@ void BackupDaemon::DeleteUnusedRootDirEntries(BackupClientContext &rContext) } // Entries to delete, and it's the right time to do so... - BOX_INFO("Deleting unused locations from store root..."); + BOX_NOTICE("Deleting unused locations from store root..."); BackupProtocolClient &connection(rContext.GetConnection()); for(std::vector >::iterator i(mUnusedRootDirEntries.begin()); i != mUnusedRootDirEntries.end(); ++i) { connection.QueryDeleteDirectory(i->first); // Log this - BOX_INFO("Deleted " << i->second << " (ID " << i->first + BOX_NOTICE("Deleted " << i->second << " (ID " << i->first << ") from store root"); } -- cgit v1.2.3 From bc79aea4297aa986e1810b56e19497c7beb0f6a2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2007 23:51:12 +0000 Subject: Allow Loggers to log everything, as is their wont. Master level will be set in Daemon, patch to follow. (refs #3) --- bin/bbackupd/bbackupd.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index 0fe8ee41..f7091140 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -30,13 +30,6 @@ int main(int argc, const char *argv[]) Logging::SetProgramName("Box Backup (bbackupd)"); Logging::ToConsole(true); Logging::ToSyslog (true); - Logging::FilterSyslog(Log::EVERYTHING); - - #ifdef NDEBUG - Logging::FilterConsole(Log::INFO); - #else - Logging::FilterConsole(Log::EVERYTHING); - #endif #ifdef WIN32 -- cgit v1.2.3 From 573891c9d60d0556e8caa09f0580d0f7c0e9b320 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2007 23:52:14 +0000 Subject: Throw CommonException AccessDenied if we didn't get access to the file, for better error description (refs #3) --- lib/common/FileStream.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/common/FileStream.cpp b/lib/common/FileStream.cpp index 89ae7a1f..8040cab4 100644 --- a/lib/common/FileStream.cpp +++ b/lib/common/FileStream.cpp @@ -11,6 +11,8 @@ #include "FileStream.h" #include "CommonException.h" +#include + #include "MemLeakFindOn.h" // -------------------------------------------------------------------------- @@ -36,7 +38,15 @@ FileStream::FileStream(const char *Filename, int flags, int mode) #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; -- cgit v1.2.3 From f8254ace970d5d922716bc3fa0a5049c57023ce7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jan 2007 23:55:53 +0000 Subject: Add option parsing with getopt() Add "-D" flag as SINGLEPROCESS equivalent Add "-q" and "-v" options to control master logging level Log fatal errors as FATAL rather than ERROR Log daemon start and stop as NOTICE rather than INFO (refs #3) --- lib/server/Daemon.cpp | 162 +++++++++++++++++++++++++++++++++++++------------- lib/server/Daemon.h | 1 + 2 files changed, 122 insertions(+), 41 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 69a488d0..f4abe4e2 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -89,50 +89,130 @@ Daemon::~Daemon() // // Function // Name: Daemon::Main(const char *, int, const char *[]) -// Purpose: Starts the daemon off -- equivalent of C main() function +// 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[]) { - // Banner (optional) + // Find filename of config file + mConfigFileName = DefaultConfigFile; + bool haveConfigFile = false; + bool singleProcess = false; + Log::Level masterLevel = Log::NOTICE; + char c; + + while((c = getopt(argc, (char * const *)argv, "c:Dqv")) != -1) { - const char *banner = DaemonBanner(); - if(banner != 0) + switch(c) { - printf("%s", banner); - } - } + case 'c': + { + mConfigFileName = optarg; + haveConfigFile = true; + } + break; - std::string pidFileName; + case 'D': + { + singleProcess = true; + } + break; - try - { - // Find filename of config file - mConfigFileName = DefaultConfigFile; - if(argc >= 2) - { - // 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) + case 'q': + { + if(masterLevel == Log::NOTHING) + { + BOX_FATAL("Too many '-q': " + "Cannot reduce logging " + "level any more"); + return 2; + } + ((int)masterLevel)--; + } + break; + + case 'v': { - mConfigFileName = argv[2]; + if(masterLevel == Log::EVERYTHING) + { + BOX_FATAL("Too many '-v': " + "Cannot increase logging " + "level any more"); + return 2; + } + ((int)masterLevel)++; } - else + break; + + case '?': { - mConfigFileName = argv[1]; + BOX_FATAL("Unknown option on command line: " + << "'" << optopt << "'"); + return 2; } - } - - // Test mode with no daemonisation? - bool asDaemon = true; - if(argc >= 3) - { - if(::strcmp(argv[2], "SINGLEPROCESS") == 0) + break; + + default: { - asDaemon = false; + BOX_FATAL("Unknown error in getopt: returned " + << "'" << c << "'"); + return 1; } } + } + if (argc > optind && !haveConfigFile) + { + mConfigFileName = argv[optind]; optind++; + } + + if (argc > optind && ::strcmp(argv[optind], "SINGLEPROCESS") == 0) + { + singleProcess = true; optind++; + } + + if (argc > optind) + { + BOX_FATAL("Unknown parameter on command line: " + << "'" << std::string(argv[optind]) << "'"); + return 2; + } + + Logging::SetGlobalLevel(masterLevel); + + return Main(mConfigFileName, singleProcess); +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: Daemon::Main(const std::string& rConfigFileName, +// bool singleProcess) +// Purpose: Starts the daemon off -- equivalent of C main() function +// Created: 2003/07/29 +// +// -------------------------------------------------------------------------- +int Daemon::Main(const std::string &rConfigFileName, bool singleProcess) +{ + // Banner (optional) + { + const char *banner = DaemonBanner(); + if(banner != 0) + { + BOX_NOTICE(banner); + } + } + + std::string pidFileName; + + mConfigFileName = rConfigFileName; + bool asDaemon = !singleProcess; + + try + { // Load the configuration file. std::string errors; std::auto_ptr pconfig; @@ -148,7 +228,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if(e.GetType() == CommonException::ExceptionType && e.GetSubType() == CommonException::OSFileOpenError) { - BOX_ERROR("Failed to start: failed to open " + BOX_FATAL("Failed to start: failed to open " "configuration file: " << mConfigFileName); return 1; @@ -161,7 +241,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if(pconfig.get() == 0 || !errors.empty()) { // Tell user about errors - BOX_ERROR("Failed to start: errors in configuration " + BOX_FATAL("Failed to start: errors in configuration " "file: " << mConfigFileName << ": " << errors); // And give up return 1; @@ -264,7 +344,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) #endif // !WIN32 // Log the start message - BOX_INFO("Starting daemon, version " << BOX_VERSION + BOX_NOTICE("Starting daemon, version " << BOX_VERSION << ", config: " << mConfigFileName); // Write PID to file @@ -278,7 +358,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if(::write(pidFile, pid, pidsize) != pidsize) { - BOX_ERROR("can't write pid file"); + BOX_FATAL("can't write pid file"); THROW_EXCEPTION(ServerException, DaemoniseFailed) } @@ -324,19 +404,19 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) } catch(BoxException &e) { - BOX_ERROR("Failed to start: exception " << e.what() + BOX_FATAL("Failed to start: exception " << e.what() << " (" << e.GetType() << "/" << e.GetSubType() << ")"); return 1; } catch(std::exception &e) { - BOX_ERROR("Failed to start: exception " << e.what()); + BOX_FATAL("Failed to start: exception " << e.what()); return 1; } catch(...) { - BOX_ERROR("Failed to start: unknown error"); + BOX_FATAL("Failed to start: unknown error"); return 1; } @@ -349,7 +429,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if (WSAStartup(0x0101, &info) == SOCKET_ERROR) { // will not run without sockets - BOX_ERROR("Failed to initialise Windows Sockets"); + BOX_FATAL("Failed to initialise Windows Sockets"); THROW_EXCEPTION(CommonException, Internal) } #endif @@ -366,7 +446,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if(mReloadConfigWanted && !mTerminateWanted) { // Need to reload that config file... - BOX_INFO("Reloading configuration file: " + BOX_NOTICE("Reloading configuration file: " << mConfigFileName); std::string errors; std::auto_ptr pconfig = @@ -378,7 +458,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if(pconfig.get() == 0 || !errors.empty()) { // Tell user about errors - BOX_ERROR("Error in configuration " + BOX_FATAL("Error in configuration " << "file: " << mConfigFileName << ": " << errors); // And give up @@ -404,23 +484,23 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) ::unlink(pidFileName.c_str()); // Log - BOX_INFO("Terminating daemon"); + BOX_NOTICE("Terminating daemon"); } catch(BoxException &e) { - BOX_ERROR("Terminating due to exception " << e.what() + BOX_FATAL("Terminating due to exception " << e.what() << " (" << e.GetType() << "/" << e.GetSubType() << ")"); retcode = 1; } catch(std::exception &e) { - BOX_ERROR("Terminating due to exception " << e.what()); + BOX_FATAL("Terminating due to exception " << e.what()); retcode = 1; } catch(...) { - BOX_ERROR("Terminating due to unknown exception"); + BOX_FATAL("Terminating due to unknown exception"); retcode = 1; } diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h index dbc83e98..b28d752a 100644 --- a/lib/server/Daemon.h +++ b/lib/server/Daemon.h @@ -41,6 +41,7 @@ private: public: int Main(const char *DefaultConfigFile, int argc, const char *argv[]); + int Main(const std::string &rConfigFile, bool singleProcess); virtual void Run(); const Configuration &GetConfiguration() const; -- cgit v1.2.3 From abe09d202e16b8a168be63de3c1fc6818066288d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 16 Jan 2007 00:12:05 +0000 Subject: Log AccessDenied errors in a more concise form than general exceptions (refs #3) --- bin/bbackupd/BackupDaemon.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 5e3728d0..cf812001 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -287,10 +287,19 @@ public: const std::string& rLocalPath, const BoxException& rException) { - BOX_ERROR("Failed to upload file: " << rLocalPath - << ": caught exception: " << rException.what() - << " (" << rException.GetType() - << "/" << rException.GetSubType() << ")"); + if (rException.GetType() == CommonException::ExceptionType && + rException.GetSubType() == CommonException::AccessDenied) + { + BOX_ERROR("Failed to upload file: " << rLocalPath + << ": Access denied"); + } + else + { + BOX_ERROR("Failed to upload file: " << rLocalPath + << ": caught exception: " << rException.what() + << " (" << rException.GetType() + << "/" << rException.GetSubType() << ")"); + } } virtual void NotifyFileUploading( const BackupClientDirectoryRecord* pDirRecord, -- cgit v1.2.3 From 9044ec5463e938ce67ffdf84479d1c5fe903b007 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 16 Jan 2007 00:12:52 +0000 Subject: Cosmetic whitespace fix (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 3ed974b8..217359e5 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -881,8 +881,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP { // Connection errors should just be passed on to the main handler, retries // would probably just cause more problems. - rParams.GetProgressNotifier().NotifyFileUploadException(this, - filename, e); + rParams.GetProgressNotifier() + .NotifyFileUploadException( + this, filename, e); throw; } catch(BoxException &e) @@ -891,9 +892,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP allUpdatedSuccessfully = false; // Log it. SetErrorWhenReadingFilesystemObject(rParams, filename.c_str()); - // Log error. - rParams.GetProgressNotifier().NotifyFileUploadException(this, - filename, e); + rParams.GetProgressNotifier() + .NotifyFileUploadException( + this, filename, e); } // Update structures if the file was uploaded successfully. -- cgit v1.2.3 From 4df0e43009eeceb8e824122d068853d37279d179 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 16 Jan 2007 20:36:04 +0000 Subject: Compile fix for RHEL4 ([NICK]) (refs #3) --- lib/server/Daemon.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index f4abe4e2..f50a9c9a 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -101,7 +101,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) mConfigFileName = DefaultConfigFile; bool haveConfigFile = false; bool singleProcess = false; - Log::Level masterLevel = Log::NOTICE; + int masterLevel = Log::NOTICE; // need an int to do math with char c; while((c = getopt(argc, (char * const *)argv, "c:Dqv")) != -1) @@ -130,7 +130,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) "level any more"); return 2; } - ((int)masterLevel)--; + masterLevel--; } break; @@ -143,7 +143,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) "level any more"); return 2; } - ((int)masterLevel)++; + masterLevel++; } break; @@ -181,7 +181,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) return 2; } - Logging::SetGlobalLevel(masterLevel); + Logging::SetGlobalLevel((Log::Level)masterLevel); return Main(mConfigFileName, singleProcess); } -- cgit v1.2.3 From c65a71fb2ab2484525ba702bd219bc36d57156ea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 16 Jan 2007 23:04:03 +0000 Subject: Check for exclude entries that end in a path separator, and log a warning (refs #3) --- lib/common/ExcludeList.cpp | 9 ++++++++ test/common/testcommon.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp index 842780b6..3edbc291 100644 --- a/lib/common/ExcludeList.cpp +++ b/lib/common/ExcludeList.cpp @@ -22,6 +22,7 @@ #include "Utils.h" #include "Configuration.h" #include "Archive.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -140,6 +141,14 @@ void ExcludeList::AddDefiniteEntries(const std::string &rEntries) 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); } } diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index ec33b003..45473425 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -30,6 +30,7 @@ #include "CollectInBufferStream.h" #include "Archive.h" #include "Timer.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -145,6 +146,40 @@ void safe_sleep(int seconds) { /* sleep again */ } } +class TestLogger : public Logger +{ + private: + bool mTriggered; + Log::Level mTargetLevel; + + public: + TestLogger(Log::Level targetLevel) + : mTriggered(false), mTargetLevel(targetLevel) + { + Logging::Add(this); + } + ~TestLogger() + { + Logging::Remove(this); + } + + bool IsTriggered() { return mTriggered; } + void Reset() { mTriggered = false; } + + virtual bool Log(Log::Level level, const std::string& rFile, + int line, std::string& rMessage) + { + if (level == mTargetLevel) + { + mTriggered = true; + } + return true; + } + + virtual const char* GetType() { return "Test"; } + virtual void SetProgramName(const std::string& rProgramName) { } +}; + int test(int argc, const char *argv[]) { // Test self-deleting temporary file streams @@ -664,6 +699,8 @@ int test(int argc, const char *argv[]) // Test ExcludeList { + TestLogger logger(Log::WARNING); + ExcludeList elist; // Check assumption TEST_THAT(Configuration::MultiValueSeparator == '\x01'); @@ -721,6 +758,24 @@ int test(int argc, const char *argv[]) #endif #undef CASE_SENSITIVE + + TEST_THAT(!logger.IsTriggered()); + elist.AddDefiniteEntries(std::string("/foo")); + TEST_THAT(!logger.IsTriggered()); + elist.AddDefiniteEntries(std::string("/foo/")); + TEST_THAT(logger.IsTriggered()); + logger.Reset(); + elist.AddDefiniteEntries(std::string("/foo" + DIRECTORY_SEPARATOR)); + TEST_THAT(logger.IsTriggered()); + logger.Reset(); + elist.AddDefiniteEntries(std::string("/foo" + DIRECTORY_SEPARATOR "bar\x01/foo")); + TEST_THAT(!logger.IsTriggered()); + elist.AddDefiniteEntries(std::string("/foo" + DIRECTORY_SEPARATOR "bar\x01/foo" + DIRECTORY_SEPARATOR)); + TEST_THAT(logger.IsTriggered()); } test_conversions(); -- cgit v1.2.3 From e2589c461b68ad47b417e4969e1b51ef4f40447c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 16 Jan 2007 23:05:20 +0000 Subject: Automatically initialise logging at startup, with a static object, to log to console and syslog. All logging objects automatically register themselves with the global logging system. (refs #3) --- lib/common/Logging.cpp | 49 +++++++++++++++++++++++++++++++++++++++++-------- lib/common/Logging.h | 12 +++++++----- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index 3e2062da..5ecadc72 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -21,20 +21,41 @@ bool Logging::sContextSet = false; std::vector Logging::sLoggers; std::string Logging::sContext; -Console Logging::sConsole; -Syslog Logging::sSyslog; +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(&sSyslog); + Add(spSyslog); } if (sLogToSyslog && !enabled) { - Remove(&sSyslog); + Remove(spSyslog); } sLogToSyslog = enabled; @@ -44,12 +65,12 @@ void Logging::ToConsole(bool enabled) { if (!sLogToConsole && enabled) { - Add(&sConsole); + Add(spConsole); } if (sLogToConsole && !enabled) { - Remove(&sConsole); + Remove(spConsole); } sLogToConsole = enabled; @@ -57,12 +78,12 @@ void Logging::ToConsole(bool enabled) void Logging::FilterConsole(Log::Level level) { - sConsole.Filter(level); + spConsole->Filter(level); } void Logging::FilterSyslog(Log::Level level) { - sSyslog.Filter(level); + spSyslog->Filter(level); } void Logging::Add(Logger* pNewLogger) @@ -140,6 +161,17 @@ void Logging::SetProgramName(const std::string& rProgramName) } } +Logger::Logger() +: mCurrentLevel(Log::EVERYTHING) +{ + Logging::Add(this); +} + +Logger::~Logger() +{ + Logging::Remove(this); +} + bool Console::Log(Log::Level level, const std::string& rFile, int line, std::string& rMessage) { @@ -176,6 +208,7 @@ bool Syslog::Log(Log::Level level, const std::string& rFile, 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; diff --git a/lib/common/Logging.h b/lib/common/Logging.h index c85b4586..3a7b18b7 100644 --- a/lib/common/Logging.h +++ b/lib/common/Logging.h @@ -63,8 +63,8 @@ class Logger Log::Level mCurrentLevel; public: - Logger() : mCurrentLevel(Log::EVERYTHING) { } - virtual ~Logger() { } + Logger(); + virtual ~Logger(); virtual bool Log(Log::Level level, const std::string& rFile, int line, std::string& rMessage) = 0; @@ -136,12 +136,14 @@ class Logging static bool sLogToSyslog, sLogToConsole; static std::string sContext; static bool sContextSet; - static Console sConsole; - static Syslog sSyslog; + static Console* spConsole; + static Syslog* spSyslog; static Log::Level sGlobalLevel; + static Logging sGlobalLogging; public: - static void Init(const std::string& rProgramName); + Logging (); + ~Logging(); static void ToSyslog (bool enabled); static void ToConsole (bool enabled); static void FilterSyslog (Log::Level level); -- cgit v1.2.3 From aa42fa6e400d0f682e7dc9b1cd78e6575457f2d7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 16 Jan 2007 23:25:44 +0000 Subject: Allow suppressing warnings about unsupported file types by excluding those files by name, using ExcludeFile (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 217359e5..1cc10d99 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -349,11 +349,22 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn } else { - rParams.GetProgressNotifier() - .NotifyUnsupportedFileType( - this, filename); - SetErrorWhenReadingFilesystemObject( - rParams, filename.c_str()); + if(rParams.mrContext.ExcludeFile(filename)) + { + rParams.GetProgressNotifier() + .NotifyFileExcluded( + this, + filename); + } + else + { + rParams.GetProgressNotifier() + .NotifyUnsupportedFileType( + this, filename); + SetErrorWhenReadingFilesystemObject( + rParams, filename.c_str()); + } + continue; } -- cgit v1.2.3 From 83c3656651028ab8854dcc95ecc6a49e5ad71a08 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 17 Jan 2007 20:41:24 +0000 Subject: Added a BufferedStream class that can be wrapped around an IOStream to improve read performance when many small reads will be performed, e.g. while reading directories and during housekeeping. (refs #3) --- lib/common/BufferedStream.cpp | 207 ++++++++++++++++++++++++++++++++++++++++++ lib/common/BufferedStream.h | 43 +++++++++ 2 files changed, 250 insertions(+) create mode 100644 lib/common/BufferedStream.cpp create mode 100644 lib/common/BufferedStream.h diff --git a/lib/common/BufferedStream.cpp b/lib/common/BufferedStream.cpp new file mode 100644 index 00000000..288e1ed1 --- /dev/null +++ b/lib/common/BufferedStream.cpp @@ -0,0 +1,207 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: BufferedStream.cpp +// Purpose: Buffering wrapper around IOStreams +// Created: 2007/01/16 +// +// -------------------------------------------------------------------------- + +#include "Box.h" +#include "BufferedStream.h" +#include "CommonException.h" + +#include + +#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..234061c4 --- /dev/null +++ b/lib/common/BufferedStream.h @@ -0,0 +1,43 @@ +// -------------------------------------------------------------------------- +// +// 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 + + -- cgit v1.2.3 From 3dc6cc0f31914aecc0900583dff6c80b00987611 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 17 Jan 2007 20:42:44 +0000 Subject: Use BufferedStream to speed up housekeeping by about ten times. (refs #3) --- bin/bbstored/HousekeepStoreAccount.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp index 91945306..8d2d9e4c 100644 --- a/bin/bbstored/HousekeepStoreAccount.cpp +++ b/bin/bbstored/HousekeepStoreAccount.cpp @@ -23,6 +23,7 @@ #include "NamedLock.h" #include "autogen_BackupStoreException.h" #include "BackupStoreFile.h" +#include "BufferedStream.h" #include "MemLeakFindOn.h" @@ -252,7 +253,8 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) // Read the directory in BackupStoreDirectory dir; - dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite); + BufferedStream buf(*dirStream); + dir.ReadFromStream(buf, IOStream::TimeOutInfinite); dirStream->Close(); // Is it empty? -- cgit v1.2.3 From 5035fdfe9be9ce82d3f6c6affa310e8763d7b102 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 17 Jan 2007 21:59:13 +0000 Subject: Moved MakeFullPath into its own library file so that we can share it (BackupQueries needs it too) (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 28 +---------------------- lib/common/PathUtils.cpp | 34 ++++++++++++++++++++++++++++ lib/common/PathUtils.h | 26 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 lib/common/PathUtils.cpp create mode 100644 lib/common/PathUtils.h diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 1cc10d99..43824130 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -29,6 +29,7 @@ #include "BackupDaemon.h" #include "BackupStoreException.h" #include "Archive.h" +#include "PathUtils.h" #include "MemLeakFindOn.h" @@ -94,33 +95,6 @@ void BackupClientDirectoryRecord::DeleteSubDirectories() mSubDirectories.clear(); } -// -------------------------------------------------------------------------- -// -// Function -// Name: MakeFullPath(const std::string& rDir, const std::string& rFile) -// Purpose: Combine directory and file name -// Created: 2006/08/10 -// -// -------------------------------------------------------------------------- -static std::string MakeFullPath(const std::string& rDir, - const std::string& rFile) -{ - std::string result; - - if (rDir.size() > 0 && - rDir[rDir.size()-1] == DIRECTORY_SEPARATOR_ASCHAR) - { - result = rDir + rFile; - } - else - { - result = rDir + DIRECTORY_SEPARATOR + rFile; - } - - return result; -} - - // -------------------------------------------------------------------------- // // Function diff --git a/lib/common/PathUtils.cpp b/lib/common/PathUtils.cpp new file mode 100644 index 00000000..924d47d2 --- /dev/null +++ b/lib/common/PathUtils.cpp @@ -0,0 +1,34 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: PathUtils.cpp +// Purpose: Platform-independent path manipulation +// Created: 2007/01/17 +// +// -------------------------------------------------------------------------- + +#include "Box.h" +#include + +// -------------------------------------------------------------------------- +// +// 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..1cf2e507 --- /dev/null +++ b/lib/common/PathUtils.h @@ -0,0 +1,26 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: PathUtils.h +// Purpose: Platform-independent path manipulation +// Created: 2007/01/17 +// +// -------------------------------------------------------------------------- + +#ifndef PATHUTILS_H +#define PATHUTILS_H + +#include + +// -------------------------------------------------------------------------- +// +// 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 -- cgit v1.2.3 From ad5d488c8d95051ae2fd9ede98f40f20abf5075f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 17 Jan 2007 22:13:23 +0000 Subject: When comparing, don't recurse into excluded directories, as their contents will not be on the store. Fix display of filenames during compare when backing up the root directory (double slash) (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 79 +++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 9c6168d8..ad4aeb93 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -46,6 +46,7 @@ #include "BackupStoreException.h" #include "ExcludeList.h" #include "BackupClientMakeExcludeList.h" +#include "PathUtils.h" #include "MemLeakFindOn.h" @@ -1400,9 +1401,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s } #ifndef HAVE_VALID_DIRENT_D_TYPE - std::string fn(rLocalDir); - fn += DIRECTORY_SEPARATOR_ASCHAR; - fn += localDirEn->d_name; + std::string fn(MakeFullPath + (rLocalDir, localDirEn->d_name)); struct stat st; if(::lstat(fn.c_str(), &st) != 0) { @@ -1486,10 +1486,12 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s const std::string& fileNameDisplay(i->first); #endif - std::string localPathDisplay = localDirDisplay + - DIRECTORY_SEPARATOR + fileNameDisplay; - std::string storePathDisplay = storeDirDisplay + - "/" + fileNameDisplay; + std::string localPath(MakeFullPath + (rLocalDir, fileName)); + std::string localPathDisplay(MakeFullPath + (localDirDisplay, fileNameDisplay)); + std::string storePathDisplay + (storeDirDisplay + "/" + fileNameDisplay); // Does the file exist locally? string_set_iter_t local(localFiles.find(fileName)); @@ -1506,9 +1508,6 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s { try { - // make local name of file for comparison - std::string localPath(rLocalDir + DIRECTORY_SEPARATOR + fileName); - // Files the same flag? bool equal = true; @@ -1692,12 +1691,12 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s const std::string& fileNameDisplay(*i); #endif - std::string localPath(rLocalDir + - DIRECTORY_SEPARATOR + *i); - std::string localPathDisplay(localDirDisplay + - DIRECTORY_SEPARATOR + fileNameDisplay); - std::string storePathDisplay(storeDirDisplay + - "/" + fileNameDisplay); + std::string localPath(MakeFullPath + (rLocalDir, *i)); + std::string localPathDisplay(MakeFullPath + (localDirDisplay, fileNameDisplay)); + std::string storePathDisplay + (storeDirDisplay + "/" + fileNameDisplay); // Should this be ignored (ie is excluded)? if(rParams.mpExcludeFiles == 0 || @@ -1733,7 +1732,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s localFiles.clear(); storeFiles.clear(); - // Now do the directories, recusively to check subdirectories + // Now do the directories, recursively to check subdirectories for(std::set >::const_iterator i = storeDirs.begin(); i != storeDirs.end(); ++i) { #ifdef WIN32 @@ -1747,14 +1746,27 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s const std::string& subdirNameDisplay(i->first); #endif - std::string localPathDisplay = localDirDisplay + - DIRECTORY_SEPARATOR + subdirNameDisplay; - std::string storePathDisplay = storeDirDisplay + - "/" + subdirNameDisplay; + std::string localPath(MakeFullPath + (rLocalDir, i->first)); + std::string localPathDisplay(MakeFullPath + (localDirDisplay, subdirNameDisplay)); + std::string storePathDisplay + (storeDirDisplay + "/" + subdirNameDisplay); // Does the directory exist locally? string_set_iter_t local(localDirs.find(i->first)); - if(local == localDirs.end()) + if(local == localDirs.end() && + rParams.mpExcludeDirs != NULL && + rParams.mpExcludeDirs->IsExcluded(localPath)) + { + // Not found -- report + printf("Local directory '%s' is excluded, but " + "store directory '%s' still exists.\n", + localPathDisplay.c_str(), + storePathDisplay.c_str()); + rParams.mDifferences ++; + } + else if(local == localDirs.end()) { // Not found -- report printf("Local directory '%s' does not exist, " @@ -1763,10 +1775,15 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s storePathDisplay.c_str()); rParams.mDifferences ++; } + else if(rParams.mpExcludeDirs != NULL && + rParams.mpExcludeDirs->IsExcluded(localPath)) + { + // don't recurse into excluded directories + } else { // Compare directory - Compare(i->second->GetObjectID(), rStoreDir + "/" + i->first, rLocalDir + DIRECTORY_SEPARATOR + i->first, rParams); + Compare(i->second->GetObjectID(), rStoreDir + "/" + i->first, localPath, rParams); // Remove from set so that we know it's been compared localDirs.erase(local); @@ -1786,15 +1803,15 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s const std::string& fileNameDisplay(*i); #endif - std::string localPath = rLocalDir + - DIRECTORY_SEPARATOR + *i; - std::string storePath = rStoreDir + - "/" + *i; + std::string localPath(MakeFullPath + (rLocalDir, *i)); + std::string localPathDisplay(MakeFullPath + (localDirDisplay, fileNameDisplay)); - std::string localPathDisplay = localDirDisplay + - DIRECTORY_SEPARATOR + fileNameDisplay; - std::string storePathDisplay = storeDirDisplay + - "/" + fileNameDisplay; + std::string storePath + (rStoreDir + "/" + *i); + std::string storePathDisplay + (storeDirDisplay + "/" + fileNameDisplay); // Should this be ignored (ie is excluded)? if(rParams.mpExcludeDirs == 0 || !(rParams.mpExcludeDirs->IsExcluded(localPath))) -- cgit v1.2.3 From 7f228e13623761c744f98d9cfde8144439085e59 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 17 Jan 2007 22:23:04 +0000 Subject: Buffer directory reads (refs #3) --- bin/bbstored/BackupContext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupContext.cpp index fa1d88a6..16388099 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupContext.cpp @@ -25,6 +25,7 @@ #include "RaidFileController.h" #include "FileStream.h" #include "InvisibleTempFileStream.h" +#include "BufferedStream.h" #include "MemLeakFindOn.h" @@ -306,7 +307,8 @@ BackupStoreDirectory &BackupContext::GetDirectoryInternal(int64_t ObjectID) std::auto_ptr dir(new BackupStoreDirectory); // Read it from the stream, then set it's revision ID - dir->ReadFromStream(*objectFile, IOStream::TimeOutInfinite); + BufferedStream buf(*objectFile); + dir->ReadFromStream(buf, IOStream::TimeOutInfinite); dir->SetRevisionID(revID); // Make sure the size of the directory is available for writing the dir back -- cgit v1.2.3 From 782e1cfe59bc1d819c549a2d7a3459448c1a088d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 17 Jan 2007 22:23:36 +0000 Subject: Buffer store file integrity checks (refs #3) --- bin/bbstored/BackupCommands.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index cf8025e4..fd19713d 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -30,6 +30,7 @@ #include "RaidFileController.h" #include "FileStream.h" #include "InvisibleTempFileStream.h" +#include "BufferedStream.h" #include "MemLeakFindOn.h" @@ -388,9 +389,10 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto // Open the object std::auto_ptr object(rContext.OpenObject(mObjectID)); + BufferedStream buf(*object); // Verify it - if(!BackupStoreFile::VerifyEncodedFileFormat(*object)) + if(!BackupStoreFile::VerifyEncodedFileFormat(buf)) { return std::auto_ptr(new BackupProtocolServerError( BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_FileDoesNotVerify)); -- cgit v1.2.3 From 1a1888edda630b2e60ff274bd6938a38c21a0886 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 21 Jan 2007 13:53:51 +0000 Subject: Improve error message when server fails to start (refs #3) --- lib/common/Test.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 7ea755f6..69517752 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -109,7 +109,8 @@ inline int ReadPidFile(const char *pidFile) { if(!TestFileExists(pidFile)) { - 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; } -- cgit v1.2.3 From 277b5be1d6b04b9176c691659149db0402f14cc5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 25 Jan 2007 20:48:12 +0000 Subject: Stop locations from being deleted from the store just because their local directory can't be found, as suggested by Gary (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index aa56fddf..0ab676eb 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1478,7 +1478,23 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con // Read the exclude lists from the Configuration ploc->mpExcludeFiles = BackupClientMakeExcludeList_Files(i->second); ploc->mpExcludeDirs = BackupClientMakeExcludeList_Dirs(i->second); - + // Does this exist on the server? + // Remove from dir object early, so that if we fail + // to stat the local directory, we still don't + // consider to remote one for deletion. + BackupStoreDirectory::Iterator iter(dir); + BackupStoreFilenameClear dirname(ploc->mName); // generate the filename + BackupStoreDirectory::Entry *en = iter.FindMatchingClearName(dirname); + int64_t oid = 0; + if(en != 0) + { + oid = en->GetObjectID(); + + // Delete the entry from the directory, so we get a list of + // unused root directories at the end of this. + dir.DeleteEntry(oid); + } + // Do a fsstat on the pathname to find out which mount it's on { @@ -1556,19 +1572,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con } // Does this exist on the server? - BackupStoreDirectory::Iterator iter(dir); - BackupStoreFilenameClear dirname(ploc->mName); // generate the filename - BackupStoreDirectory::Entry *en = iter.FindMatchingClearName(dirname); - int64_t oid = 0; - if(en != 0) - { - oid = en->GetObjectID(); - - // Delete the entry from the directory, so we get a list of - // unused root directories at the end of this. - dir.DeleteEntry(oid); - } - else + if(en == 0) { // Doesn't exist, so it has to be created on the server. Let's go! // First, get the directory's attributes and modification time -- cgit v1.2.3 From 6779d3cb4ffcc9fa7d860a6f4abaa5bed009098c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Feb 2007 22:30:15 +0000 Subject: Catch errors during restore (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index b752b6a2..65ee377c 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "BackupClientRestore.h" #include "autogen_BackupProtocolClient.h" @@ -225,9 +226,36 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di // 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. + + int exists; + + try + { + exists = ObjectExists(rLocalDirectoryName.c_str()); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to check existence for %s: %s", + rLocalDirectoryName.c_str(), e.what()); + return Restore_UnknownError; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to check existence for %s: %s", + rLocalDirectoryName.c_str(), e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to check existence for %s: " + "unknown error", rLocalDirectoryName.c_str()); + return Restore_UnknownError; + } - // Create the local directory (if not already done) -- path and owner set later, just use restrictive owner mode - switch(ObjectExists(rLocalDirectoryName.c_str())) + switch(exists) { case ObjectExists_Dir: // Do nothing -- cgit v1.2.3 From 57a36f04af1ae81cec83ab706cdfd76ff445c664 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Feb 2007 22:34:21 +0000 Subject: Check whether the restore target parent directory exists before trying to create the target directory or save restore info in the parent (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 101 ++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 65ee377c..9c1a5346 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -224,9 +224,6 @@ 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. @@ -270,17 +267,105 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di } TRACE1("In restore, directory name collision with file %s", rLocalDirectoryName.c_str()); } - // 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; } + + std::string parentDirectoryName(rLocalDirectoryName); + if(parentDirectoryName[parentDirectoryName.size() - 1] == + DIRECTORY_SEPARATOR_ASCHAR) + { + parentDirectoryName.resize(parentDirectoryName.size() - 1); + } + + int 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); + + int parentExists; + + try + { + parentExists = ObjectExists(parentDirectoryName.c_str()); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to check existence for %s: " + "%s", parentDirectoryName.c_str(), e.what()); + return Restore_UnknownError; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to check existence for %s: " + "%s", parentDirectoryName.c_str(), e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to check existence for %s: " + "unknown error", parentDirectoryName.c_str()); + return Restore_UnknownError; + } + + switch(parentExists) + { + case ObjectExists_Dir: + // this is fine, do nothing + break; + + case ObjectExists_File: + fprintf(stderr, "Failed to restore: '%s' " + "is a file, but should be a " + "directory.\n", + parentDirectoryName.c_str()); + return Restore_TargetPathNotFound; + + case ObjectExists_NoObject: + fprintf(stderr, "Failed to restore: " + "parent '%s' of target directory " + "does not exist.\n", + parentDirectoryName.c_str()); + return Restore_TargetPathNotFound; + + default: + fprintf(stderr, "Failed to restore: " + "unknown result from " + "ObjectExists('%s').\n", + parentDirectoryName.c_str()); + return Restore_UnknownError; + } + } + + if((exists == ObjectExists_NoObject || + exists == ObjectExists_File) && + ::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0) + { + ::syslog(LOG_ERR, "Failed to create directory %s: %s", + rLocalDirectoryName.c_str(), + strerror(errno)); + return Restore_UnknownError; + } + + // Save the resumption information + Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename); // Fetch the directory listing from the server -- getting a list // of files which is appropriate to the restore type -- cgit v1.2.3 From 786da28ab1f04a2386c9545f106ad0dd1ec65af5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Feb 2007 22:35:56 +0000 Subject: Make BackupClientRestoreDir return a result code compatible with BackupClientRestore (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 9c1a5346..019c53dd 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -207,7 +207,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 @@ -478,7 +478,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(); @@ -487,7 +494,9 @@ static void BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Di rLevel.mRestoredObjects.insert(en->GetObjectID()); } } - } + } + + return Restore_Complete; } @@ -558,7 +567,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) -- cgit v1.2.3 From 270bdff4312add7816e095d06adf7b58f13fb28b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Feb 2007 22:36:18 +0000 Subject: Spelling fix (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 019c53dd..baf33002 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -461,7 +461,7 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir } - // Recuse to directories + // Recurse to directories { BackupStoreDirectory::Iterator i(dir); BackupStoreDirectory::Entry *en = 0; -- cgit v1.2.3 From 9341f476c713f44d471083b7f67e31dcd93eb1dd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Feb 2007 22:51:04 +0000 Subject: Don't throw an exception if we fail to delete a file in the way of restore, just log the error and return an error code (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index baf33002..194c50ad 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -263,7 +263,11 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir ::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()); if(::unlink(rLocalDirectoryName.c_str()) != 0) { - THROW_EXCEPTION(CommonException, OSFileError); + ::syslog(LOG_ERR, "Failed to delete " + "directory %s: %s", + rLocalDirectoryName.c_str(), + strerror(errno)); + return Restore_UnknownError; } TRACE1("In restore, directory name collision with file %s", rLocalDirectoryName.c_str()); } -- cgit v1.2.3 From a80d8dd666cb0476ac4b9c60ad8b5ad991c25a9d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Feb 2007 23:06:53 +0000 Subject: Catch exceptions while writing files, attributes, resume info and checking file existence (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 192 ++++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 18 deletions(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 194c50ad..8f29f8ba 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -367,12 +367,34 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir strerror(errno)); return Restore_UnknownError; } - - // Save the resumption information - Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename); - - // Fetch the directory listing from the server -- getting a list - // of files which is appropriate to the restore type + + // Save the restore info, in case it's needed later + try + { + Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to save resume info file %s: %s", + Params.mRestoreResumeInfoFilename.c_str(), e.what()); + return Restore_UnknownError; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to save resume info file %s: %s", + Params.mRestoreResumeInfoFilename.c_str(), e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to save resume info file %s: " + "unknown error", + Params.mRestoreResumeInfoFilename.c_str()); + 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), @@ -387,7 +409,29 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir // Apply attributes to the directory const StreamableMemBlock &dirAttrBlock(dir.GetAttributes()); BackupClientFileAttributes dirAttr(dirAttrBlock); - dirAttr.WriteAttributes(rLocalDirectoryName.c_str()); + + try + { + dirAttr.WriteAttributes(rLocalDirectoryName.c_str()); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to restore attributes for %s: %s", + rLocalDirectoryName.c_str(), e.what()); + return Restore_UnknownError; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to restore attributes for %s: %s", + rLocalDirectoryName.c_str(), e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to restore attributes for %s: " + "unknown error", rLocalDirectoryName.c_str()); + return Restore_UnknownError; + } int64_t bytesWrittenSinceLastRestoreInfoSave = 0; @@ -415,17 +459,43 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir // 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()); + } + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to restore " + "file %s: %s", + localFilename.c_str(), + e.what()); + return Restore_UnknownError; } - else + catch(std::exception &e) { - // Use attributes stored in file - BackupStoreFile::DecodeFile(*objectStream, localFilename.c_str(), rConnection.GetTimeout()); + ::syslog(LOG_ERR, "Failed to restore " + "file %s: %s", + localFilename.c_str(), + e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to restore " + "file %s: unknown error", + localFilename.c_str()); + return Restore_UnknownError; } // Progress display? @@ -440,7 +510,42 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir // 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 (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to determine " + "whether file exists: %s: %s", + localFilename.c_str(), + e.what()); + return Restore_UnknownError; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to determine " + "whether file exists: %s: %s", + localFilename.c_str(), + e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to determine " + "whether file exists: %s: " + "unknown error", + localFilename.c_str()); + return Restore_UnknownError; + } + + if(exists) { // File exists... bytesWrittenSinceLastRestoreInfoSave += fileSize; @@ -448,7 +553,30 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir 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 (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to save resume info file %s: %s", + Params.mRestoreResumeInfoFilename.c_str(), e.what()); + return Restore_UnknownError; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to save resume info file %s: %s", + Params.mRestoreResumeInfoFilename.c_str(), e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to save resume info file %s: " + "unknown error", + Params.mRestoreResumeInfoFilename.c_str()); + return Restore_UnknownError; + } + bytesWrittenSinceLastRestoreInfoSave = 0; } } @@ -460,7 +588,35 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir 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 (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to save resume info file " + "%s: %s", + Params.mRestoreResumeInfoFilename.c_str(), + e.what()); + return Restore_UnknownError; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to save resume info file " + "%s: %s", + Params.mRestoreResumeInfoFilename.c_str(), + e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to save resume info file " + "%s: unknown error", + Params.mRestoreResumeInfoFilename.c_str()); + return Restore_UnknownError; + } + bytesWrittenSinceLastRestoreInfoSave = 0; } -- cgit v1.2.3 From e429add69506b45e73123990f38667551acbe3ec Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Feb 2007 23:10:25 +0000 Subject: Log failure to delete files and directories (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 8f29f8ba..e7fdd5fa 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -264,7 +264,7 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir if(::unlink(rLocalDirectoryName.c_str()) != 0) { ::syslog(LOG_ERR, "Failed to delete " - "directory %s: %s", + "file %s: %s", rLocalDirectoryName.c_str(), strerror(errno)); return Restore_UnknownError; @@ -449,7 +449,14 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir 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()); + if(::unlink(localFilename.c_str()) == 0) + { + ::syslog(LOG_ERR, "Failed to delete " + "file %s: %s", + localFilename.c_str(), + strerror(errno)); + return Restore_UnknownError; + } // Request it from the store rConnection.QueryGetFile(DirectoryID, en->GetObjectID()); -- cgit v1.2.3 From 4106a7dd54f442a009cadbf5a9ee1bf823d70b32 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 9 Feb 2007 23:10:47 +0000 Subject: Fix compile warning --- lib/backupclient/BackupClientRestore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index e7fdd5fa..ec4ca681 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -288,7 +288,7 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir parentDirectoryName.resize(parentDirectoryName.size() - 1); } - int lastSlash = parentDirectoryName.rfind(DIRECTORY_SEPARATOR_ASCHAR); + size_t lastSlash = parentDirectoryName.rfind(DIRECTORY_SEPARATOR_ASCHAR); if(lastSlash == std::string::npos) { -- cgit v1.2.3 From 8c8bdcd7d23f6cf1cdf533a03e2987abb4011087 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 21:38:25 +0000 Subject: Typo fix --- bin/bbackupctl/bbackupctl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index 09984e12..9fb8f259 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -65,7 +65,7 @@ int main(int argc, const char *argv[]) ::openlog("Box Backup (bbackupctl)", 0, 0); #endif - // Filename for configuraiton file? + // Filename for configuration file? const char *configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG; // Quiet? -- cgit v1.2.3 From afe9f791b6f0a8a3819a53e9fc0a8676b3b6b9f8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 22:47:59 +0000 Subject: Simplify check for PERL Define substitution TARGET_PERL and preprocessor PERL_EXECUTABLE to a native Perl (not Cygwin) on Win32, since Cygwin perl will not run inside bbackupd for unit tests (e.g. SyncAllowScript). (refs #3) --- configure.ac | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 2eaa232e..e0958219 100644 --- a/configure.ac +++ b/configure.ac @@ -26,13 +26,21 @@ if test "x$GXX" = "xyes"; then # Use -rdynamic if we have gcc. This is needed for backtrace AC_SUBST([LDADD_RDYNAMIC], ['-rdynamic']) fi -AC_PATH_PROG([PERL], [perl], [no]) -if test "x$PERL" != "xno"; then - AC_DEFINE_UNQUOTED([PERL_EXECUTABLE], ["$PERL"], [Location of the perl executable]) -else - AC_MSG_ERROR([[perl executable was not found]]) -fi +AC_PATH_PROG([PERL], [perl], [AC_MSG_ERROR([[perl executable was not found]])]) + +case $target_os in +mingw*) + TARGET_PERL=perl + ;; +*) + TARGET_PERL=$PERL + ;; +esac + +AC_SUBST([TARGET_PERL]) +AC_DEFINE_UNQUOTED([PERL_EXECUTABLE], ["$TARGET_PERL"], + [Location of the perl executable]) ### Checks for libraries. -- cgit v1.2.3 From 307279a20e14201b283308639c1bb029077d61f8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 22:48:42 +0000 Subject: Update build instructions for Cygwin/Win32 (refs #3) --- docs/backup/win32_build_on_linux_using_mingw.txt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/backup/win32_build_on_linux_using_mingw.txt b/docs/backup/win32_build_on_linux_using_mingw.txt index 12261d51..407096b1 100644 --- a/docs/backup/win32_build_on_linux_using_mingw.txt +++ b/docs/backup/win32_build_on_linux_using_mingw.txt @@ -28,11 +28,27 @@ Unpack and configure: tar xzvf openssl-0.9.8b.tar.gz cd openssl-0.9.8b - ./Configure mingw + ./Configure --prefix=/usr/local/i386-mingw32 mingw make makefile.one wget http://bbdev.fluffy.co.uk/svn/box/chris/win32/support/openssl-0.9.8b-mingw-cross.patch patch -p1 < openssl-0.9.8b-mingw-cross.patch make -f makefile.one + make -f makefile.one install + +Download PCRE from +[http://prdownloads.sourceforge.net/pcre/pcre-6.3.tar.bz2?download] + +Unpack: + + tar xjvf pcre-6.3.tar.bz2 + cd pcre-6.3 + +Configure and make: + + ./configure --host=i586-mingw32msvc --prefix=/usr/i386-mingw32/ + make winshared wininstall + cp .libs/libpcreposix.a /usr/i386-pc-mingw32/lib + cp pcreposix.h /usr/i386-pc-mingw32/include/regex.h Configure Box with: -- cgit v1.2.3 From ba61e64d38900324728cc028766564fe2d021057 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 22:57:15 +0000 Subject: #include Test.h to fix compile (needed for TEST_THAT) Improved error message Improved comments (refs #3, merges parts of [712], [1289] and [1337]) --- infrastructure/buildenv-testmain-template.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index 01fbc11a..bffd46d1 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -2,6 +2,9 @@ // AUTOMATICALLY GENERATED FILE // do not edit // +// Note that infrastructure/buildenv-testmain-template.cpp is NOT +// auto-generated, but test/*/_main.cpp are generated from it. +// // -------------------------------------------------------------------------- @@ -31,6 +34,7 @@ #include #endif +#include "Test.h" #include "Timer.h" #include "MemLeakFindOn.h" @@ -78,7 +82,8 @@ bool checkfilesleftopen() { if(filedes_open_at_beginning == -1) { - // Not used correctly, pretend that there were things left open so this gets invesitgated + // Not used correctly, pretend that there were things + // left open so this gets investigated return true; } @@ -130,7 +135,7 @@ int main(int argc, const char *argv[]) if(memleakfinder_numleaks() != 0) { failures++; - printf("FAILURE: Memory leaks detected\n"); + printf("FAILURE: Memory leaks detected in test code\n"); printf("==== MEMORY LEAKS =================================\n"); memleakfinder_reportleaks(); printf("===================================================\n"); -- cgit v1.2.3 From 1953c377019e084e41898d4831f71c651839e82d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 22:59:22 +0000 Subject: Fix make error when optional file doesn't exist (refs #3, merges [1098]) --- infrastructure/makeparcels.pl.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infrastructure/makeparcels.pl.in b/infrastructure/makeparcels.pl.in index e70dcf29..a8eceb8a 100755 --- a/infrastructure/makeparcels.pl.in +++ b/infrastructure/makeparcels.pl.in @@ -123,7 +123,8 @@ for my $parcel (@parcels) { if ($optional) { - print MAKE "\ttest -r $name && cp $name $dir\n"; + print MAKE "\ttest -r $name " . + "&& cp $name $dir || true\n"; } else { -- cgit v1.2.3 From 66812fbfd051698922970220cfa9cfc0db7dbc40 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 23:04:02 +0000 Subject: Declare that we have O_BINARY but not for MSVC (refs #3, merges [760] and [763]) --- lib/common/BoxConfig-MSVC.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/common/BoxConfig-MSVC.h b/lib/common/BoxConfig-MSVC.h index ff7bf14e..01fc9c63 100644 --- a/lib/common/BoxConfig-MSVC.h +++ b/lib/common/BoxConfig-MSVC.h @@ -56,6 +56,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 */ @@ -268,7 +272,7 @@ // #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 +// #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_WAIT_H */ @@ -318,6 +322,12 @@ /* 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 */ -- cgit v1.2.3 From e59d7dac529849bdb8f2c19b2134ac937c5fc325 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 23:06:18 +0000 Subject: Watch out for our leak tracking data being destroyed and don't crash when subsequent objects are destroyed. (refs #3, merges [1341]) --- lib/common/DebugMemLeakFinder.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp index fbc684e8..a99b2072 100644 --- a/lib/common/DebugMemLeakFinder.cpp +++ b/lib/common/DebugMemLeakFinder.cpp @@ -49,6 +49,17 @@ namespace { static std::map sMallocBlocks; static std::map sObjectBlocks; + static bool sTrackingDataDestroyed = false; + + static class DestructionWatchdog + { + public: + ~DestructionWatchdog() + { + sTrackingDataDestroyed = true; + } + } + sWatchdog; static bool sTrackMallocInSection = false; static std::set sSectionMallocBlocks; @@ -225,6 +236,8 @@ void memleakfinder_notaleak(void *ptr) { InternalAllocGuard guard; + ASSERT(!sTrackingDataDestroyed); + memleakfinder_notaleak_insert_pre(); if(memleakfinder_global_enable && memleakfinder_initialised) { @@ -258,6 +271,8 @@ void memleakfinder_startsectionmonitor() InternalAllocGuard guard; ASSERT(memleakfinder_initialised); + ASSERT(!sTrackingDataDestroyed); + sTrackMallocInSection = true; sSectionMallocBlocks.clear(); sTrackObjectsInSection = true; @@ -270,6 +285,7 @@ void memleakfinder_traceblocksinsection() InternalAllocGuard guard; ASSERT(memleakfinder_initialised); + ASSERT(!sTrackingDataDestroyed); std::set::iterator s(sSectionMallocBlocks.begin()); for(; s != sSectionMallocBlocks.end(); ++s) @@ -295,6 +311,7 @@ int memleakfinder_numleaks() InternalAllocGuard guard; ASSERT(memleakfinder_initialised); + ASSERT(!sTrackingDataDestroyed); int n = 0; @@ -316,6 +333,8 @@ void memleakfinder_reportleaks_file(FILE *file) { InternalAllocGuard guard; + ASSERT(!sTrackingDataDestroyed); + for(std::map::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i) { 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); @@ -388,6 +407,7 @@ void add_object_block(void *block, size_t size, const char *file, int line, bool if(!memleakfinder_global_enable) return; if(!memleakfinder_initialised) return; + ASSERT(!sTrackingDataDestroyed); if(block != 0) { @@ -411,6 +431,7 @@ void remove_object_block(void *block) if(!memleakfinder_global_enable) return; if(!memleakfinder_initialised) return; + if(sTrackingDataDestroyed) return; std::map::iterator i(sObjectBlocks.find(block)); if(i != sObjectBlocks.end()) -- cgit v1.2.3 From e937c5734e249b19bcc8c59ecd1721c541d764f1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 23:38:03 +0000 Subject: Add logging in remaining places where Common OSFileOpenError can be thrown. (refs #3, merges part of [1099] and [1359]) --- lib/common/EventWatchFilesystemObject.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/common/EventWatchFilesystemObject.cpp b/lib/common/EventWatchFilesystemObject.cpp index a9508c22..4282f1e3 100644 --- a/lib/common/EventWatchFilesystemObject.cpp +++ b/lib/common/EventWatchFilesystemObject.cpp @@ -17,6 +17,7 @@ #include "EventWatchFilesystemObject.h" #include "autogen_CommonException.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -37,6 +38,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 -- cgit v1.2.3 From 3bd5d45687714bd7402c26f1aea915bcc15f0481 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 4 Mar 2007 23:41:22 +0000 Subject: Update to match new recommended installation of pcreposix.h as regex.h. (refs #3, merges [1281], reverting [1233]) --- lib/common/ExcludeList.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp index 3edbc291..e24246c8 100644 --- a/lib/common/ExcludeList.cpp +++ b/lib/common/ExcludeList.cpp @@ -10,11 +10,7 @@ #include "Box.h" #ifdef HAVE_REGEX_H - #ifdef WIN32 - #include - #else - #include - #endif // WIN32 + #include #define EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED #endif -- cgit v1.2.3 From d17445865a24087fc7df683a957783c529a232c1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Mar 2007 00:06:26 +0000 Subject: Add logging in remaining places where Common OSFileOpenError can be thrown. Fix compile warning (signed vs unsigned comparison) (refs #3, merges part of [1099], and [1368]) --- lib/common/FileStream.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/common/FileStream.cpp b/lib/common/FileStream.cpp index 8040cab4..e0806e10 100644 --- a/lib/common/FileStream.cpp +++ b/lib/common/FileStream.cpp @@ -10,6 +10,7 @@ #include "Box.h" #include "FileStream.h" #include "CommonException.h" +#include "Logging.h" #include @@ -73,6 +74,7 @@ FileStream::FileStream(tOSFileHandle FileDescriptor) #endif { MEMLEAKFINDER_NOT_A_LEAK(this); + BOX_ERROR("FileStream: called with invalid file handle"); THROW_EXCEPTION(CommonException, OSFileOpenError) } #ifdef WIN32 @@ -100,6 +102,7 @@ FileStream::FileStream(const FileStream &rToCopy) #endif { MEMLEAKFINDER_NOT_A_LEAK(this); + BOX_ERROR("FileStream: copying unopened file"); THROW_EXCEPTION(CommonException, OSFileOpenError) } } @@ -157,8 +160,8 @@ int FileStream::Read(void *pBuffer, int NBytes, int Timeout) } else { - ::syslog(LOG_ERR, "Failed to read from file: error %d", - GetLastError()); + BOX_ERROR("Failed to read from file: " << + GetErrorMessage(GetLastError())); r = -1; } #else @@ -222,7 +225,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) -- cgit v1.2.3 From d2852f68a7e7c4f3154ba5d0521c9f9c1c8f535a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Mar 2007 00:14:55 +0000 Subject: Add logging in remaining places where Common OSFileOpenError can be thrown. (refs #3, merges part of [1099], and [1370]) --- lib/common/Guards.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/common/Guards.h b/lib/common/Guards.h index b1bca0fa..52018493 100644 --- a/lib/common/Guards.h +++ b/lib/common/Guards.h @@ -21,6 +21,7 @@ #include #include "CommonException.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -33,6 +34,8 @@ public: { if(mOSFileHandle < 0) { + BOX_ERROR("FileHandleGuard: failed to open file '" << + filename << "': " << strerror(errno)); THROW_EXCEPTION(CommonException, OSFileOpenError) } } -- cgit v1.2.3 From 93332d84c85aeec5fb4461325ef1e0af0c55e7c1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 5 Mar 2007 00:16:29 +0000 Subject: Win32 compile fix (refs #3, merges [1306]) --- lib/common/Logging.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/common/Logging.h b/lib/common/Logging.h index 3a7b18b7..04aed1cf 100644 --- a/lib/common/Logging.h +++ b/lib/common/Logging.h @@ -42,10 +42,21 @@ #define BOX_TRACE(stuff) BOX_LOG(Log::TRACE, stuff) #endif +#undef ERROR + namespace Log { - enum Level { NOTHING = 1, FATAL, ERROR, WARNING, NOTICE, INFO, TRACE, - EVERYTHING }; + enum Level + { + NOTHING = 1, + FATAL, + ERROR, + WARNING, + NOTICE, + INFO, + TRACE, + EVERYTHING + }; } // -------------------------------------------------------------------------- -- cgit v1.2.3 From 5ccb219180e3e057d08342dffccb5a1759a67971 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2007 22:20:31 +0000 Subject: Count a difference when a local directory does not exist, but it does exist on the server (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index ad4aeb93..acece91d 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1317,6 +1317,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s "(compared to server directory '%s')\n", localDirDisplay.c_str(), storeDirDisplay.c_str()); + rParams.mDifferences ++; } else { -- cgit v1.2.3 From d9f8b29cd22545460f52026442b69f20da97cc9f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2007 22:22:56 +0000 Subject: Catch exceptions during restore and report them, rather than aborting bbackupquery (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index acece91d..08e1422f 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1908,10 +1908,33 @@ void BackupQueries::CommandRestore(const std::vector &args, const b #endif // Go and restore... - switch(BackupClientRestore(mrConnection, dirID, localName.c_str(), - true /* print progress dots */, restoreDeleted, - false /* don't undelete after restore! */, - opts['r'] /* resume? */)) + int result; + + try + { + result = BackupClientRestore(mrConnection, dirID, + localName.c_str(), + true /* print progress dots */, restoreDeleted, + false /* don't undelete after restore! */, + opts['r'] /* resume? */); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to restore: %s", e.what()); + return; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to restore: %s", e.what()); + return; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to restore: unknown error"); + return; + } + + switch(result) { case Restore_Complete: printf("Restore complete\n"); -- cgit v1.2.3 From c4b6715d0dec121d5e2f1a2ed95a169dbc36f7d8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2007 22:27:39 +0000 Subject: Report an appropriate error if the target path of the restore operation is not found (refs #3, merges [514]) --- bin/bbackupquery/BackupQueries.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 08e1422f..d491fac6 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1948,6 +1948,14 @@ void BackupQueries::CommandRestore(const std::vector &args, const b printf("The target directory exists. You cannot restore over an existing directory.\n"); break; + #ifdef WIN32 + case Restore_TargetPathNotFound: + printf("The target directory path does not exist.\n" + "To restore to a directory whose parent " + "does not exist, create the parent first.\n"); + break; + #endif + default: printf("ERROR: Unknown restore result.\n"); break; -- cgit v1.2.3 From 9b2936484eab81f77eae0a64ca843fde0fd00f7e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2007 22:47:29 +0000 Subject: Report number of files and directories which could not be compared separately from compare failures, and report the appropriate return code (refs #3, merges [651]) --- bin/bbackupquery/BackupQueries.cpp | 29 +++++++++++++++++++++++++---- bin/bbackupquery/BackupQueries.h | 1 + 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index d491fac6..1726b960 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1054,6 +1054,7 @@ BackupQueries::CompareParams::CompareParams() mIgnoreAttributes(false), mDifferences(0), mDifferencesExplainedByModTime(0), + mUncheckedFiles(0), mExcludedDirs(0), mExcludedFiles(0), mpExcludeFiles(0), @@ -1177,13 +1178,29 @@ void BackupQueries::CommandCompare(const std::vector &args, const b return; } - printf("\n[ %d (of %d) differences probably due to file modifications after the last upload ]\nDifferences: %d (%d dirs excluded, %d files excluded)\n", - params.mDifferencesExplainedByModTime, params.mDifferences, params.mDifferences, params.mExcludedDirs, params.mExcludedFiles); + printf("\n[ %d (of %d) differences probably due to file " + "modifications after the last upload ]\n" + "Differences: %d (%d dirs excluded, %d files excluded, " + "%d files not checked)\n", + params.mDifferencesExplainedByModTime, params.mDifferences, + params.mDifferences, params.mExcludedDirs, + params.mExcludedFiles, params.mUncheckedFiles); // Set return code? if(opts['c']) { - SetReturnCode((params.mDifferences == 0)?COMPARE_RETURN_SAME:COMPARE_RETURN_DIFFERENT); + if (params.mUncheckedFiles != 0) + { + SetReturnCode(COMPARE_RETURN_ERROR); + } + else if (params.mDifferences != 0) + { + SetReturnCode(COMPARE_RETURN_DIFFERENT); + } + else + { + SetReturnCode(COMPARE_RETURN_SAME); + } } } @@ -1323,6 +1340,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s { printf("ERROR: stat on local dir '%s'\n", localDirDisplay.c_str()); + rParams.mUncheckedFiles ++; } return; } @@ -1372,6 +1390,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s { printf("ERROR: opendir on local dir '%s'\n", localDirDisplay.c_str()); + rParams.mUncheckedFiles ++; return; } try @@ -1668,10 +1687,12 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s e.GetType(), e.GetSubType(), storePathDisplay.c_str()); + rParams.mUncheckedFiles ++; } catch(...) - { + { printf("ERROR: (unknown) during file fetch and comparison for '%s'\n", storePathDisplay.c_str()); + rParams.mUncheckedFiles ++; } // Remove from set so that we know it's been compared diff --git a/bin/bbackupquery/BackupQueries.h b/bin/bbackupquery/BackupQueries.h index 17043b61..c9540110 100644 --- a/bin/bbackupquery/BackupQueries.h +++ b/bin/bbackupquery/BackupQueries.h @@ -71,6 +71,7 @@ private: bool mIgnoreAttributes; int mDifferences; int mDifferencesExplainedByModTime; + int mUncheckedFiles; int mExcludedDirs; int mExcludedFiles; const ExcludeList *mpExcludeFiles; -- cgit v1.2.3 From 9cc598dc355819a99b1d3a9a15e44bd4468a33b9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2007 22:59:11 +0000 Subject: Run housekeeping in idle time on Win32 (refs #3) --- bin/bbstored/BBStoreDHousekeeping.cpp | 22 +++++++++++++++++++++- bin/bbstored/BackupStoreDaemon.cpp | 1 + bin/bbstored/BackupStoreDaemon.h | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp index 8c725b0f..a4b26a93 100644 --- a/bin/bbstored/BBStoreDHousekeeping.cpp +++ b/bin/bbstored/BBStoreDHousekeeping.cpp @@ -50,7 +50,8 @@ void BackupStoreDaemon::HousekeepingProcess() { RunHousekeepingIfNeeded(); - // Calculate how long should wait before doing the next housekeeping run + // Calculate how long should wait before doing the next + // housekeeping run int64_t timeNow = GetCurrentBoxTime(); time_t secondsToGo = BoxTimeToSeconds( (mLastHousekeepingRun + housekeepingInterval) - @@ -72,6 +73,7 @@ void BackupStoreDaemon::RunHousekeepingIfNeeded() // Time now int64_t timeNow = GetCurrentBoxTime(); + // Do housekeeping if the time interval has elapsed since the last check if((timeNow - mLastHousekeepingRun) < housekeepingInterval) { @@ -148,6 +150,19 @@ void BackupStoreDaemon::RunHousekeepingIfNeeded() SetProcessTitle("housekeeping, idle"); } +void BackupStoreDaemon::OnIdle() +{ + #ifdef WIN32 + if (!mHousekeepingInited) + { + HousekeepingInit(); + mHousekeepingInited = true; + } + + RunHousekeepingIfNeeded(); + #endif +} + // -------------------------------------------------------------------------- // // Function @@ -159,6 +174,11 @@ void BackupStoreDaemon::RunHousekeepingIfNeeded() // -------------------------------------------------------------------------- bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitTime) { + if(!mInterProcessCommsSocket.IsOpened()) + { + return false; + } + // First, check to see if it's EOF -- this means something has gone wrong, and the housekeeping should terminate. if(mInterProcessComms.IsEOF()) { diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 06d529c3..335135ce 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -42,6 +42,7 @@ BackupStoreDaemon::BackupStoreDaemon() mExtendedLogging(false), mHaveForkedHousekeeping(false), mIsHousekeepingProcess(false), + mHousekeepingInited(false), mInterProcessComms(mInterProcessCommsSocket) { } diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index eea47284..eb665440 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -72,10 +72,12 @@ private: bool mExtendedLogging; bool mHaveForkedHousekeeping; bool mIsHousekeepingProcess; + bool mHousekeepingInited; SocketStream mInterProcessCommsSocket; IOStreamGetLine mInterProcessComms; + virtual void OnIdle(); void HousekeepingInit(); void RunHousekeepingIfNeeded(); int64_t mLastHousekeepingRun; -- cgit v1.2.3 From c4cb9a7355efd4790116c9b38cab5fae3fb3b707 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2007 23:03:32 +0000 Subject: Check for d_ino member in struct dirent (refs #3, merges [1351]) --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index e0958219..4294658c 100644 --- a/configure.ac +++ b/configure.ac @@ -156,6 +156,7 @@ winnt*) ;; AX_CHECK_MOUNT_POINT(,[ AC_MSG_ERROR([[cannot work out how to discover mount points on your platform]]) ]) + AC_CHECK_MEMBERS([struct dirent.d_ino],,, [[#include ]]) ;; esac -- cgit v1.2.3 From 9b85fab48fcbe222fbb49f0d90f6326b0934dbf5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 8 Mar 2007 23:09:08 +0000 Subject: Record the file and line of first test failure (refs #3, merges [593]) --- lib/common/Test.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 69517752..b7b96c06 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -23,14 +23,26 @@ #include extern int failures; +extern int first_fail_line; +extern std::string first_fail_file; + +#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; \ -- cgit v1.2.3 From 61af1d8fe20580d59a760f53e63cc984861e7324 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 15:31:25 +0000 Subject: Check for return code 3 (unreadable files) instead of return code 2 (refs #3, depends on [1378]) --- test/bbackupd/testbbackupd.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index d1bf4a98..ea96a220 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1131,14 +1131,23 @@ int test_bbackupd() TEST_THAT(fd != -1); ::close(fd); } + // Wait and test... wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 2*256); // should find differences + + // Check that unreadable files were found + TEST_THAT(compareReturnValue == 3*256); + + // Check for memory leaks during compare TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // Check that it was reported correctly TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1")); + + // Check that the error was only reorted once TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2")); + // Set permissions on file and dir to stop errors in the future ::chmod("testfiles/TestDir1/sub23/read-fail-test-dir", 0770); ::chmod("testfiles/TestDir1/read-fail-test-file", 0770); -- cgit v1.2.3 From 7ee217c02aa7265f3253781b1a4eece198fb6e3d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 16:12:01 +0000 Subject: Moved SendCommands(), HUPServer(), KillServer() to lib/server/ServerCommands.h. All of these use lib/server/WinNamedPipeStream on Win32, so they don't belong in lib/common. Made LaunchServer() work on Win32. Added constants for paths to executables, for use in tests, removing the need for #ifdefs and clumsy DIRECTORY_SEPARATORs in paths. Added terminate_bbackupd() and wait_for_operation() functions. Update unit tests to #include "ServerControl.h" if they need it. (refs #3) --- lib/common/ServerControl.h | 177 +++++++++++++ lib/common/Test.h | 331 +++++++++++++------------ test/backupstore/testbackupstore.cpp | 1 + test/backupstorefix/testbackupstorefix.cpp | 15 +- test/backupstorepatch/testbackupstorepatch.cpp | 1 + test/basicserver/testbasicserver.cpp | 1 + test/bbackupd/testbbackupd.cpp | 1 + 7 files changed, 359 insertions(+), 168 deletions(-) create mode 100644 lib/common/ServerControl.h diff --git a/lib/common/ServerControl.h b/lib/common/ServerControl.h new file mode 100644 index 00000000..a8477900 --- /dev/null +++ b/lib/common/ServerControl.h @@ -0,0 +1,177 @@ +#ifndef SERVER_CONTROL_H +#define SERVER_CONTROL_H + +#ifdef WIN32 + +#include "WinNamedPipeStream.h" +#include "IOStreamGetLine.h" +#include "BoxPortsAndFiles.h" +#include "Test.h" + +static bool SendCommands(const std::string& rCmd) +{ + WinNamedPipeStream connection; + + try + { + connection.Connect(BOX_NAMED_PIPE_NAME); + } + catch(...) + { + printf("Failed to connect to daemon control socket.\n"); + return false; + } + + // 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; + } + + // Was the connection rejected by the server? + if(getLine.IsEOF()) + { + printf("Server rejected the connection.\n"); + return false; + } + + // Decode it + int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait; + if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", + &autoBackup, &updateStoreInterval, + &minimumFileAge, &maxUploadWait) != 4) + { + printf("Config summary didn't decode\n"); + 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") + { + printf("ERROR (%s)\n", rCmd.c_str()); + break; + } + else + { + printf("WARNING: Unexpected response to command '%s': " + "%s", rCmd.c_str(), line.c_str()); + } + } + + 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) + { + printf("Failed to open process %d: error %d\n", + pid, (int)GetLastError()); + return false; + } + + if (!TerminateProcess(hProcess, 1)) + { + printf("Failed to terminate process %d: error %d\n", + pid, (int)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); + 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 (!ServerIsAlive(pid)) break; + ::sleep(1); + if (!ServerIsAlive(pid)) break; + + if (i == 0) + { + printf("waiting for server to die"); + } + + printf("."); + fflush(stdout); + } + + if (!ServerIsAlive(pid)) + { + printf("done.\n"); + } + else + { + printf("failed!\n"); + } + + fflush(stdout); + + return !ServerIsAlive(pid); +} + +#endif // SERVER_CONTROL_H diff --git a/lib/common/Test.h b/lib/common/Test.h index b7b96c06..6a517b1a 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -92,7 +92,7 @@ inline int TestGetFileSize(const char *Filename) return -1; } -inline int RunCommand(const char *pCommandLine) +inline std::string ConvertPaths(const char *pCommandLine) { #ifdef WIN32 // convert UNIX paths to native @@ -114,7 +114,37 @@ inline int RunCommand(const char *pCommandLine) std::string command = pCommandLine; #endif - return ::system(command.c_str()); + return command; +} + +inline int RunCommand(const char *pCommandLine) +{ + return ::system(ConvertPaths(pCommandLine).c_str()); +} + +#ifdef WIN32 +#include +#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) @@ -141,192 +171,136 @@ inline int ReadPidFile(const char *pidFile) inline int LaunchServer(const char *pCommandLine, const char *pidFile) { - if(RunCommand(pCommandLine) != 0) - { - printf("Server: %s\n", pCommandLine); - TEST_FAIL_WITH_MESSAGE("Couldn't start server"); - return -1; - } - - // give it time to start up - ::sleep(1); - - // read pid file - int pid = ReadPidFile(pidFile); +#ifdef WIN32 - if(pid == -1) + 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(pCommandLine); + 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) { - // helps with debugging: - printf("Server: %s (pidfile %s)\n", pCommandLine, pidFile); + DWORD err = GetLastError(); + printf("Launch failed: %s: error %d\n", pCommandLine, (int)err); + return -1; } - return pid; -} - -#ifdef WIN32 - -#include "WinNamedPipeStream.h" -#include "IOStreamGetLine.h" -#include "BoxPortsAndFiles.h" + CloseHandle(procInfo.hProcess); + CloseHandle(procInfo.hThread); -bool SendCommands(const std::string& rCmd) -{ - WinNamedPipeStream connection; +#else // !WIN32 - try - { - connection.Connect(BOX_NAMED_PIPE_NAME); - } - catch(...) + if(RunCommand(pCommandLine) != 0) { - printf("Failed to connect to daemon control socket.\n"); - return false; + printf("Server: %s\n", pCommandLine); + TEST_FAIL_WITH_MESSAGE("Couldn't start server"); + 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; - } +#endif // WIN32 - // Was the connection rejected by the server? - if(getLine.IsEOF()) - { - printf("Server rejected the connection.\n"); - return false; - } + #ifdef WIN32 + // on other platforms there is no other way to get + // the PID, so a NULL pidFile doesn't make sense. - // Decode it - int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait; - if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", - &autoBackup, &updateStoreInterval, - &minimumFileAge, &maxUploadWait) != 4) + if (pidFile == NULL) { - printf("Config summary didn't decode\n"); - return false; + return (int)procInfo.dwProcessId; } + #endif - 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; + // time for it to start up + ::fprintf(stdout, "Starting server: %s\n", pCommandLine); + ::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; } - } - - return statusOk; -} + #endif -inline bool ServerIsAlive(int pid) -{ - return SendCommands(""); -} - -inline bool HUPServer(int pid) -{ - return SendCommands("reload"); -} - -inline bool KillServerInternal(int pid) -{ - bool sent = SendCommands("terminate"); - TEST_THAT(sent); - return sent; -} - -#else // !WIN32 - -inline bool ServerIsAlive(int pid) -{ - if(pid == 0) return false; - return ::kill(pid, 0) != -1; -} - -inline bool HUPServer(int pid) -{ - if(pid == 0) return false; - return ::kill(pid, SIGHUP) != -1; -} - -inline bool KillServerInternal(int pid) -{ - if(pid == 0 || pid == -1) return false; - bool killed = (::kill(pid, SIGTERM) == 0); - TEST_THAT(killed); - return killed; -} + ::fprintf(stdout, "."); + ::fflush(stdout); + ::sleep(1); + } -#endif // WIN32 + #ifdef WIN32 + // on Win32 we can check whether the process is alive + // without even checking the PID file -inline bool KillServer(int pid) -{ - if (!KillServerInternal(pid)) + if (!ServerIsAlive((int)procInfo.dwProcessId)) { - return false; + ::fprintf(stdout, "server died!\n"); + TEST_FAIL_WITH_MESSAGE("Server died!"); + return -1; } + #endif - for (int i = 0; i < 30; i++) + if (!TestFileExists(pidFile)) { - if (!ServerIsAlive(pid)) break; - ::sleep(1); - if (!ServerIsAlive(pid)) break; - - if (i == 0) - { - printf("waiting for server to die"); - } - printf("."); - fflush(stdout); + ::fprintf(stdout, "timed out!\n"); + TEST_FAIL_WITH_MESSAGE("Server didn't save PID file"); + return -1; } - - if (!ServerIsAlive(pid)) + else { - printf("done.\n"); + ::fprintf(stdout, "done.\n"); } - else + + // wait a second for the pid to be written to the file + ::sleep(1); + + // read pid file + int pid = ReadPidFile(pidFile); + + #ifdef WIN32 + // On Win32 we can check whether the PID in the pidFile matches + // the one returned by the system, which it always should. + + if (pid != (int)procInfo.dwProcessId) { - printf("failed!\n"); + 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; } - fflush(stdout); + #endif - return !ServerIsAlive(pid); + return pid; } inline void TestRemoteProcessMemLeaks(const char *filename) @@ -361,4 +335,53 @@ inline void TestRemoteProcessMemLeaks(const char *filename) #endif } +#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/bbackupd/bbstored" +#define BBACKUPQUERY "../../bin/bbackupquery/bbackupquery" +#define BBSTOREACCOUNTS "../../bin/bbstoreaccounts/bbstoreaccounts" +#define TEST_RETURN(actual, expected) TEST_THAT(actual == expected*256); +#endif + +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("\n"); +} + #endif // TEST__H diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index 840d004c..da66af60 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -33,6 +33,7 @@ #include "MemBlockStream.h" #include "BackupClientFileAttributes.h" #include "BackupClientCryptoKeys.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" diff --git a/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp index 0349b039..dd8251c5 100644 --- a/test/backupstorefix/testbackupstorefix.cpp +++ b/test/backupstorefix/testbackupstorefix.cpp @@ -29,6 +29,7 @@ #include "RaidFileException.h" #include "StoreStructure.h" #include "BackupStoreFileWire.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" @@ -68,20 +69,6 @@ std::map objectIsDir; ::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf check 01234567"); \ ::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf check 01234567 fix"); -// Wait a given number of seconds for something to complete -void wait_for_operation(int seconds) -{ - printf("waiting: "); - fflush(stdout); - for(int l = 0; l < seconds; ++l) - { - sleep(1); - printf("."); - fflush(stdout); - } - printf("\n"); -} - // Get ID of an object given a filename int32_t getID(const char *name) { diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index b33e8e73..6b93a3aa 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -35,6 +35,7 @@ #include "MemBlockStream.h" #include "BackupClientFileAttributes.h" #include "BackupClientCryptoKeys.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index 3360cd20..c56e6a0b 100644 --- a/test/basicserver/testbasicserver.cpp +++ b/test/basicserver/testbasicserver.cpp @@ -28,6 +28,7 @@ #include "TestContext.h" #include "autogen_TestProtocolClient.h" #include "autogen_TestProtocolServer.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index ea96a220..a99783e8 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -51,6 +51,7 @@ #include "FileStream.h" #include "IOStreamGetLine.h" #include "intercept.h" +#include "ServerControl.h" #include "MemLeakFindOn.h" -- cgit v1.2.3 From a80c159997a4ec2eb79ec06f9363d73c3189ee95 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 16:23:12 +0000 Subject: Report file and line of memory leak test failures (refs #3, merges [714]) --- lib/common/Test.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 6a517b1a..3b7b28e4 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -303,12 +303,21 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) return pid; } -inline void TestRemoteProcessMemLeaks(const char *filename) +#define TestRemoteProcessMemLeaks(filename) \ + TestRemoteProcessMemLeaksFunc(filename, __FILE__, __LINE__) + +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); } @@ -317,8 +326,14 @@ inline void TestRemoteProcessMemLeaks(const char *filename) // 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)\n==========\n", filename); FILE *f = fopen(filename, "r"); char line[512]; while(::fgets(line, sizeof(line), f) != 0) -- cgit v1.2.3 From 88f1bb6bff3e12118d945e614992ab38f65ddd0d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 16:49:34 +0000 Subject: Throw an assertion error if a NULL timer is added (refs #3, merges [1367]) --- lib/common/Timer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index 4b596931..add827f7 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -90,6 +90,7 @@ void Timers::Cleanup() void Timers::Add(Timer& rTimer) { ASSERT(spTimers); + ASSERT(&rTimer); spTimers->push_back(&rTimer); Reschedule(); } @@ -106,11 +107,13 @@ void Timers::Add(Timer& rTimer) void Timers::Remove(Timer& rTimer) { ASSERT(spTimers); + ASSERT(&rTimer); bool restart = true; while (restart) { restart = false; + for (std::vector::iterator i = spTimers->begin(); i != spTimers->end(); i++) { -- cgit v1.2.3 From 23d8a877503763ce761a502bf7f0e79a2f5f07f5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 16:53:56 +0000 Subject: Win32 compile fixes (no gettimeofday(), no signal()) (refs #3) --- lib/common/Timer.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index add827f7..c24f38f9 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -144,10 +144,13 @@ void Timers::Reschedule() { THROW_EXCEPTION(CommonException, Internal) } + + #ifndef WIN32 if (::signal(SIGALRM, Timers::SignalHandler) != 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 @@ -255,7 +258,7 @@ Timer::Timer(size_t timeoutSecs) : mExpires(GetCurrentBoxTime() + SecondsToBoxTime(timeoutSecs)), mExpired(false) { - #ifndef NDEBUG + #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); if (timeoutSecs == 0) @@ -285,7 +288,7 @@ Timer::Timer(size_t timeoutSecs) Timer::~Timer() { - #ifndef NDEBUG + #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); TRACE3("%d.%d: timer %p destroyed, will not fire\n", @@ -299,7 +302,7 @@ Timer::Timer(const Timer& rToCopy) : mExpires(rToCopy.mExpires), mExpired(rToCopy.mExpired) { - #ifndef NDEBUG + #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); if (mExpired) @@ -331,7 +334,7 @@ Timer::Timer(const Timer& rToCopy) Timer& Timer::operator=(const Timer& rToCopy) { - #ifndef NDEBUG + #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); if (rToCopy.mExpired) @@ -367,7 +370,7 @@ Timer& Timer::operator=(const Timer& rToCopy) void Timer::OnExpire() { - #ifndef NDEBUG + #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); TRACE3("%d.%d: timer %p fired\n", tv.tv_sec, tv.tv_usec, this); -- cgit v1.2.3 From f6f5feee78b3d6cf865b34bb479301d7258ddeeb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 16:59:30 +0000 Subject: Code formatting (cosmetic) (refs #3, merges [1345]) --- lib/raidfile/RaidFileRead.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp index 363c638b..58aecfb1 100644 --- a/lib/raidfile/RaidFileRead.cpp +++ b/lib/raidfile/RaidFileRead.cpp @@ -9,12 +9,13 @@ #include "Box.h" -#include -#include -#include #include -#include +#include #include +#include + +#include +#include #ifdef HAVE_SYS_UIO_H #include @@ -41,7 +42,7 @@ #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 -- cgit v1.2.3 From 072bc3c19d7f2b02f61ef3e28cf728caa661336a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:03:13 +0000 Subject: Catch exceptions thrown by closing the WinNamedPipeStream during shutdown and suppress them. (refs #3, merges [1284]) --- lib/server/WinNamedPipeStream.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp index 362f3958..e4a675a7 100644 --- a/lib/server/WinNamedPipeStream.cpp +++ b/lib/server/WinNamedPipeStream.cpp @@ -57,7 +57,15 @@ WinNamedPipeStream::~WinNamedPipeStream() { if (mSocketHandle != INVALID_HANDLE_VALUE) { - Close(); + try + { + Close(); + } + catch (std::exception &e) + { + ::syslog(LOG_ERR, "Caught exception while destroying " + "named pipe, ignored."); + } } } -- cgit v1.2.3 From 07be2b3a2181d97c393d79f731e3d564733d58bd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:06:13 +0000 Subject: Always include process.h, as we don't know whether it was detected or not (we don't have access to lib/common/BoxConfig.h in lib/win32) (refs #3) --- lib/win32/emu.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index da4ecb2a..16c4a2ef 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -9,14 +9,12 @@ #include #include +#include #include #ifdef HAVE_UNISTD_H #include #endif -#ifdef HAVE_PROCESS_H - #include -#endif #include #include -- cgit v1.2.3 From a0a9f969a6831739e9a9dc325b5d2e4048635bd7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:12:01 +0000 Subject: Our timer code only supports ITIMER_REAL (refs #3) --- lib/win32/emu.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 16c4a2ef..7ee2b5a1 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -44,7 +44,14 @@ int setitimer(int type, struct itimerval *timeout, void *arg) { ASSERT(gTimerInitialised); + if (ITIMER_REAL != type) + { + 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) @@ -58,6 +65,7 @@ int setitimer(int type, struct itimerval *timeout, void *arg) ourTimer.interval = timeout->it_interval.tv_sec; gTimerList.push_back(ourTimer); } + LeaveCriticalSection(&gLock); // indicate success -- cgit v1.2.3 From a9c4ae701ac2e2a5d5d62d82be4059e96fb6cb64 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:15:03 +0000 Subject: We can't use lib/common here, so we don't have ASSERT() (refs #3) --- lib/win32/emu.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 7ee2b5a1..cfe73ddd 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -42,7 +42,7 @@ static void (__cdecl *gTimerFunc) (int) = NULL; int setitimer(int type, struct itimerval *timeout, void *arg) { - ASSERT(gTimerInitialised); + assert(gTimerInitialised); if (ITIMER_REAL != type) { @@ -137,7 +137,8 @@ int SetTimerHandler(void (__cdecl *func ) (int)) void InitTimer(void) { - ASSERT(!gTimerInitialised); + assert(!gTimerInitialised); + InitializeCriticalSection(&gLock); // create our thread @@ -151,7 +152,7 @@ void InitTimer(void) void FiniTimer(void) { - ASSERT(gTimerInitialised); + assert(gTimerInitialised); gFinishTimer = true; EnterCriticalSection(&gLock); DeleteCriticalSection(&gLock); -- cgit v1.2.3 From dd1026364150b2b80194015aa5ffafdd86b50fdb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:20:40 +0000 Subject: Expanded character set conversion API to allow arbitrary conversions (needed to handle command lines with international encodings) (refs #3, merges [1038]) --- lib/win32/emu.cpp | 62 ++++++++++++++++++++++--------------------------------- lib/win32/emu.h | 8 ++++++- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index cfe73ddd..7e6cbcd0 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -374,23 +374,25 @@ 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 = ConvertUtf8ToWideString(pString); + WCHAR* pWide = ConvertToWideString(rSource.c_str(), sourceCodePage); if (pWide == NULL) { return false; } - char* pConsole = ConvertFromWideString(pWide, GetConsoleOutputCP()); + char* pConsole = ConvertFromWideString(pWide, destCodePage); delete [] pWide; if (!pConsole) @@ -404,39 +406,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()); +} // -------------------------------------------------------------------------- // diff --git a/lib/win32/emu.h b/lib/win32/emu.h index d898968a..5b3e2280 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -254,7 +254,7 @@ struct itimerval int emu_mkdir(const char* pPathName); -inline int mkdir(const char *pPathName, mode_t mode) +inline int mkdir(const char *pPathName, mode_t mode = 0) { return emu_mkdir(pPathName); } @@ -398,6 +398,12 @@ bool ConvertTime_tToFileTime(const time_t from, FILETIME *pTo); 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); -- cgit v1.2.3 From f54474874ae06d72963d560cd17b1fe0f0c82106 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:27:31 +0000 Subject: Print localised error messages rather than error codes for all errors (refs #3, merges [1046]) --- lib/win32/emu.cpp | 100 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 7e6cbcd0..0a7b8ed6 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -482,6 +482,32 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName) 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"); + } + + std::string out(pMsgBuf); + LocalFree(pMsgBuf); + + return out; +} + // -------------------------------------------------------------------------- // // Function @@ -560,8 +586,9 @@ HANDLE openfile(const char *pFileName, int flags, int mode) if (hdir == INVALID_HANDLE_VALUE) { - ::syslog(LOG_WARNING, "Failed to open file %s: " - "error %i", pFileName, GetLastError()); + ::syslog(LOG_WARNING, "Failed to open file '%s': " + "%s", pFileName, + GetErrorMessage(GetLastError()).c_str()); return INVALID_HANDLE_VALUE; } @@ -589,7 +616,7 @@ 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; } @@ -597,7 +624,7 @@ int emu_fstat(HANDLE hdir, struct stat * st) if (INVALID_FILE_ATTRIBUTES == fi.dwFileAttributes) { ::syslog(LOG_WARNING, "Failed to get file attributes: " - "error %d", GetLastError()); + "%s", GetErrorMessage(GetLastError()).c_str()); errno = EACCES; return -1; } @@ -628,7 +655,7 @@ int emu_fstat(HANDLE hdir, struct stat * st) if (!GetFileSizeEx(hdir, &st_size)) { ::syslog(LOG_WARNING, "Failed to get file size: " - "error %d", GetLastError()); + "%s", GetErrorMessage(GetLastError()).c_str()); errno = EACCES; return -1; } @@ -751,8 +778,9 @@ HANDLE OpenFileByNameUtf8(const char* pFileName, DWORD flags) } 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; } @@ -820,7 +848,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; @@ -873,8 +902,8 @@ int emu_utimes(const char * pName, const struct timeval times[]) if (!SetFileTime(handle, &creationTime, NULL, &modificationTime)) { - ::syslog(LOG_ERR, "Failed to set times on '%s': error %d", - pName, GetLastError()); + ::syslog(LOG_ERR, "Failed to set times on '%s': %s", pName, + GetErrorMessage(GetLastError()).c_str()); CloseHandle(handle); return 1; } @@ -916,8 +945,8 @@ int emu_chmod(const char * pName, mode_t mode) DWORD attribs = GetFileAttributesW(pBuffer); if (attribs == INVALID_FILE_ATTRIBUTES) { - ::syslog(LOG_ERR, "Failed to get file attributes of '%s': " - "error %d", pName, GetLastError()); + ::syslog(LOG_ERR, "Failed to get file attributes of '%s': %s", + pName, GetErrorMessage(GetLastError()).c_str()); errno = EACCES; free(pBuffer); return -1; @@ -934,8 +963,8 @@ int emu_chmod(const char * pName, mode_t mode) if (!SetFileAttributesW(pBuffer, attribs)) { - ::syslog(LOG_ERR, "Failed to set file attributes of '%s': " - "error %d", pName, GetLastError()); + ::syslog(LOG_ERR, "Failed to set file attributes of '%s': %s", + pName, GetErrorMessage(GetLastError()).c_str()); errno = EACCES; free(pBuffer); return -1; @@ -1204,8 +1233,8 @@ BOOL AddEventSource char cmd[MAX_PATH]; if (GetModuleFileName(NULL, cmd, sizeof(cmd)-1) == 0) { - ::syslog(LOG_ERR, "Failed to get the program file name: " - "error %d", GetLastError()); + ::syslog(LOG_ERR, "Failed to get the program file name: %s", + GetErrorMessage(GetLastError()).c_str()); return FALSE; } cmd[sizeof(cmd)-1] = 0; @@ -1224,8 +1253,8 @@ BOOL AddEventSource 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hk, &dwDisp)) { - ::syslog(LOG_ERR, "Failed to create the registry key: " - "error %d", GetLastError()); + ::syslog(LOG_ERR, "Failed to create the registry key: %s", + GetErrorMessage(GetLastError()).c_str()); return FALSE; } @@ -1238,8 +1267,8 @@ BOOL AddEventSource (LPBYTE) exepath.c_str(), // pointer to value data (DWORD) (exepath.size()))) // data size { - ::syslog(LOG_ERR, "Failed to set the event message file: " - "error %d", GetLastError()); + ::syslog(LOG_ERR, "Failed to set the event message file: %s", + GetErrorMessage(GetLastError()).c_str()); RegCloseKey(hk); return FALSE; } @@ -1256,8 +1285,8 @@ BOOL AddEventSource (LPBYTE) &dwData, // pointer to value data sizeof(DWORD))) // length of value data { - ::syslog(LOG_ERR, "Failed to set the supported types: " - "error %d", GetLastError()); + ::syslog(LOG_ERR, "Failed to set the supported types: %s", + GetErrorMessage(GetLastError()).c_str()); RegCloseKey(hk); return FALSE; } @@ -1272,7 +1301,7 @@ BOOL AddEventSource (DWORD) (exepath.size()))) // data size { ::syslog(LOG_ERR, "Failed to set the category message file: " - "error %d", GetLastError()); + "%s", GetErrorMessage(GetLastError()).c_str()); RegCloseKey(hk); return FALSE; } @@ -1284,8 +1313,8 @@ BOOL AddEventSource (LPBYTE) &dwNum, // pointer to value data sizeof(DWORD))) // length of value data { - ::syslog(LOG_ERR, "Failed to set the category count: " - "error %d", GetLastError()); + ::syslog(LOG_ERR, "Failed to set the category count: %s", + GetErrorMessage(GetLastError()).c_str()); RegCloseKey(hk); return FALSE; } @@ -1318,7 +1347,7 @@ void openlog(const char * daemonName, int, int) if (newSyslogH == NULL) { ::syslog(LOG_ERR, "Failed to register our own event source: " - "error %d", GetLastError()); + "%s", GetErrorMessage(GetLastError()).c_str()); return; } @@ -1417,8 +1446,8 @@ void syslog(int loglevel, const char *frmt, ...) } 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); } } @@ -1562,7 +1591,8 @@ int emu_unlink(const char* pFileName) else { ::syslog(LOG_WARNING, "Failed to delete file " - "'%s': error %d", pFileName, (int)err); + "'%s': %s", pFileName, + GetErrorMessage(err).c_str()); errno = ENOSYS; } return -1; @@ -1578,7 +1608,7 @@ 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; } @@ -1601,8 +1631,8 @@ int console_read(char* pBuffer, size_t BufferSize) 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; } @@ -1698,13 +1728,13 @@ bool ConvertTime_tToFileTime(const time_t from, FILETIME *pTo) // Convert the last-write time to local time. if (!SystemTimeToFileTime(&stUTC, pTo)) { - syslog(LOG_ERR, "Failed to convert between time formats: " - "error %d", GetLastError()); + syslog(LOG_ERR, "Failed to convert between time formats: %s", + GetErrorMessage(GetLastError()).c_str()); return false; } return true; } - #endif // WIN32 + -- cgit v1.2.3 From a936147b531d87060e61dec21342d32d05d2f0a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:29:31 +0000 Subject: Improve GetErrorMessage() by including the error number/code in the message (helps debugging on foreign langauge versions of Windows) (refs #3, merges [1364]) --- lib/win32/emu.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 0a7b8ed6..b201a9e0 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -18,6 +18,7 @@ #include #include +#include // message resource definitions for syslog() @@ -502,10 +503,11 @@ std::string GetErrorMessage(DWORD errorCode) return std::string("failed to get error message"); } - std::string out(pMsgBuf); + std::ostringstream line; + line << pMsgBuf << " (" << errorCode << ")"; LocalFree(pMsgBuf); - return out; + return line.str(); } // -------------------------------------------------------------------------- -- cgit v1.2.3 From a67d2d4364280ffa21f8054afde91af027f4214b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:32:44 +0000 Subject: Fix handling of O_EXCL to behave just like Unix, not abused to lock files. Add a new constant which specifies that files are to be locked open. (refs #3, merges [1288]) --- lib/win32/emu.cpp | 18 ++++++++++++------ lib/win32/emu.h | 3 +++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index b201a9e0..3de83517 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -541,30 +541,37 @@ HANDLE openfile(const char *pFileName, int flags, int mode) // 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) { accessRights = FILE_WRITE_DATA; - shareMode = FILE_SHARE_WRITE; } else if (flags & O_RDWR) { accessRights |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA; - shareMode |= FILE_SHARE_WRITE; } if (flags & O_CREAT) { createDisposition = OPEN_ALWAYS; } + 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; } @@ -573,7 +580,6 @@ HANDLE openfile(const char *pFileName, int flags, int mode) if (flags & O_TEMPORARY) { winFlags |= FILE_FLAG_DELETE_ON_CLOSE; - shareMode |= FILE_SHARE_DELETE; } HANDLE hdir = CreateFileW(pBuffer, diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 5b3e2280..0612e441 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -290,6 +290,9 @@ 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_INFO 6 -- cgit v1.2.3 From be2a8857bf807f347f3b6a1bf68ee672c0963963 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:36:54 +0000 Subject: We don't have access to DIRECTORY_SEPARATOR_ASCHAR in lib/win32 (refs #3, merges [1362]) --- lib/win32/emu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 3de83517..a9390e90 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -867,7 +867,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 -- cgit v1.2.3 From fc15dd1a4f59addd990c3f86f32b80b3376be8f7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:37:30 +0000 Subject: Typo fix (refs #3) --- lib/win32/emu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index a9390e90..c03e491a 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -701,7 +701,7 @@ int emu_fstat(HANDLE hdir, struct stat * st) st->st_mode |= S_IWRITE; } - // st_dev is nroammly zero, regardless of the drive letter, + // 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 -- cgit v1.2.3 From 3b161e80a045f1ebb11e196b7f514b96c302b746 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:38:48 +0000 Subject: Fix two memory leaks and one buffer overflow in codepage conversion code. (refs #3, merges [1340]) --- lib/win32/emu.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index c03e491a..112b1c9f 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -978,7 +978,7 @@ int emu_chmod(const char * pName, mode_t mode) return -1; } - free(pBuffer); + delete [] pBuffer; return 0; } @@ -1621,7 +1621,7 @@ int console_read(char* pBuffer, size_t BufferSize) } size_t WideSize = BufferSize / 5; - WCHAR* pWideBuffer = new WCHAR [WideSize]; + WCHAR* pWideBuffer = new WCHAR [WideSize + 1]; if (!pWideBuffer) { @@ -1647,6 +1647,8 @@ int console_read(char* pBuffer, size_t BufferSize) pWideBuffer[numCharsRead] = 0; char* pUtf8 = ConvertFromWideString(pWideBuffer, GetConsoleCP()); + delete [] pWideBuffer; + strncpy(pBuffer, pUtf8, BufferSize); delete [] pUtf8; -- cgit v1.2.3 From 28195d8d1da7a34fbff4c9d217f6333c5472ed7c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 17:50:33 +0000 Subject: First attempt to achieve a more logical order in this chaos: reordered all typedefs to be clearer and more readable (refs #3, merges [766]) --- lib/win32/emu.h | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 0612e441..206e1f70 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -6,27 +6,24 @@ // basic types, may be required by other headers since we // don't include sys/types.h -#ifdef __MINGW32__ - #include - typedef uint32_t u_int32_t; -#else // MSVC - typedef __int64 int64_t; - typedef __int32 int32_t; - typedef __int16 int16_t; - typedef __int8 int8_t; - +#ifndef __MINGW32__ typedef unsigned __int64 u_int64_t; - typedef unsigned __int32 u_int32_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 _MSC_VER +#ifdef __MINGW32__ + typedef uint32_t u_int32_t; +#else typedef unsigned int mode_t; typedef unsigned int pid_t; -- cgit v1.2.3 From cb0dae3a34f9409780905c075e82b46ed18576c0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 18:01:07 +0000 Subject: Added d_type member to struct dirent, initialise with S_IFDIR or S_IFREG MinGW compile fix (refs #3, merges [775]) --- lib/win32/emu.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 206e1f70..25bff02c 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -6,7 +6,9 @@ // basic types, may be required by other headers since we // don't include sys/types.h -#ifndef __MINGW32__ +#ifdef __MINGW32__ + #include +#else // MSVC typedef unsigned __int64 u_int64_t; typedef unsigned __int64 uint64_t; typedef __int64 int64_t; -- cgit v1.2.3 From 1013fe643a8a3ada3049b011ba8363ab73caeeab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 18:52:15 +0000 Subject: Compile fix for [1397] (refs #3) --- lib/win32/emu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 25bff02c..ca461c95 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -65,7 +65,7 @@ ( *(_result) = *gmtime( (_clock) ), \ (_result) ) -#define ITIMER_VIRTUAL 0 +#define ITIMER_REAL 0 #ifdef _MSC_VER // Microsoft decided to deprecate the standard POSIX functions. Great! -- cgit v1.2.3 From 13d90d5a6f528952c7574e8e2529732fcc6ab044 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 18:57:00 +0000 Subject: Use #defines to replace POSIX functions with emulated ones on MinGW, like we do on MSVC. This allows us to #undef them when we really need to use the original platform function (if available). Disable emulated fstat() in raidfile (and use the platform one) by undefining fstat, since it doesn't use the other emulated file handling functions, or need Unicode support, and it can't take a filehandle returned by open() (only openfile()). (refs #3, merges [1045]) --- lib/win32/emu.h | 84 ++++++++++++++------------------------------------------- 1 file changed, 20 insertions(+), 64 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index ca461c95..7ce4b831 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -147,41 +147,6 @@ 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); -int emu_utimes(const char* pName, const struct timeval[]); -int emu_chmod (const char* pName, mode_t mode); - -#define utimes(buffer, times) emu_utimes(buffer, times) - -#ifdef _MSC_VER - #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 * pName, mode_t mode) - { - return emu_chmod(pName, mode); - } - - 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 inline int setegid(int) @@ -251,13 +216,6 @@ struct itimerval #define vsnprintf _vsnprintf -int emu_mkdir(const char* pPathName); - -inline int mkdir(const char *pPathName, mode_t mode = 0) -{ - return emu_mkdir(pPathName); -} - #ifndef __MINGW32__ inline int strcasecmp(const char *s1, const char *s2) { @@ -370,32 +328,30 @@ struct stat { }; #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 conversions time_t ConvertFileTimeToTime_t(FILETIME *fileTime); bool ConvertTime_tToFileTime(const time_t from, FILETIME *pTo); -#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 +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); + +#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) + +int statfs(const char * name, struct statfs * s); int poll(struct pollfd *ufds, unsigned long nfds, int timeout); bool EnableBackupRights( void ); -- cgit v1.2.3 From 8ef165b887dfb88514e4d00a07fa4e3d0c53fbc1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 19:01:11 +0000 Subject: Remove #define BOX_VERSION since we now get it from BoxVersion.h via BoxPlatform.h when building with MSVC, and from the Makefiles when building with MinGW. (refs #3, merges part of [634]) --- lib/win32/emu.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index 7ce4b831..c8e15f3c 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -199,11 +199,6 @@ struct itimerval 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 -- cgit v1.2.3 From 40d737e975070ba43d15866b1b24e6e2d0922984 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 19:05:52 +0000 Subject: Reorder for clarity Expose GetErrorMessage() Improve comments (refs #3, merges [1365]) --- lib/win32/emu.h | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index c8e15f3c..f8bccb02 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -321,7 +321,7 @@ struct stat { time_t st_mtime; time_t st_ctime; }; -#endif +#endif // 0 // need this for conversions time_t ConvertFileTimeToTime_t(FILETIME *fileTime); @@ -349,6 +349,19 @@ char* emu_getcwd (char* pBuffer, int BufSize); int statfs(const char * name, struct statfs * s); int poll(struct pollfd *ufds, unsigned long nfds, int timeout); + +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. + bool EnableBackupRights( void ); bool ConvertEncoding (const std::string& rSource, int sourceCodePage, @@ -360,15 +373,12 @@ bool ConvertFromUtf8 (const std::string& rSource, std::string& rDest, bool ConvertUtf8ToConsole(const char* pString, std::string& rDest); bool ConvertConsoleToUtf8(const char* pString, std::string& rDest); -// replacement for _cgetws which requires a relatively recent C runtime lib -int console_read(char* pBuffer, size_t BufferSize); - -struct iovec { - void *iov_base; /* Starting address */ - size_t iov_len; /* Number of bytes */ -}; +// GetErrorMessage() returns a system error message, like strerror() +// but for Windows error codes. +std::string GetErrorMessage(DWORD errorCode); -int readv (int filedes, const struct iovec *vector, size_t count); -int writev(int filedes, const struct iovec *vector, size_t count); +// console_read() is a replacement for _cgetws which requires a +// relatively recent C runtime lib +int console_read(char* pBuffer, size_t BufferSize); #endif // !EMU_INCLUDE && WIN32 -- cgit v1.2.3 From 0beaa1cd614b55d27a409cd7727a793b0757cfdf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 19:09:09 +0000 Subject: Add new syslog level emulations (refs #3, merges remainder of [1299]) --- lib/win32/emu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index f8bccb02..fc88737d 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -247,9 +247,12 @@ int closedir(DIR *dp); 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 -- cgit v1.2.3 From 50f4c4a76a07ce1d34c4e50094d570a5087084cb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 19:12:57 +0000 Subject: Group remaining set*id() and get*id() functions. Improve comments about why they are being retained. (refs #3, related to [634]) --- lib/win32/emu.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index fc88737d..a4af6e64 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -83,12 +83,6 @@ 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; @@ -147,8 +141,9 @@ inline int chown(const char * Filename, u_int32_t uid, u_int32_t gid) return 0; } -//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; @@ -173,6 +168,10 @@ inline int getuid(void) { return 0; } +inline int geteuid(void) +{ + return 0; +} #ifndef PATH_MAX #define PATH_MAX MAX_PATH -- cgit v1.2.3 From f6cbd5bfc97fb701685dc17b0cfcbbbdb0ff1bcd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 19:26:02 +0000 Subject: Remove #ifdefs, no longer required (refs #3, merges [1418]) --- lib/common/UnixUser.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/lib/common/UnixUser.cpp b/lib/common/UnixUser.cpp index 1ec9608d..f81b474c 100644 --- a/lib/common/UnixUser.cpp +++ b/lib/common/UnixUser.cpp @@ -78,12 +78,7 @@ UnixUser::~UnixUser() if(mRevertOnDestruction) { // Revert to "real" user and group id of the process - #ifdef WIN32 - if(0) - #else - if(::setegid(::getgid()) != 0 - || ::seteuid(::getuid()) != 0) - #endif + if(::setegid(::getgid()) != 0 || ::seteuid(::getuid()) != 0) { THROW_EXCEPTION(CommonException, CouldNotRestoreProcessUser) } @@ -105,12 +100,7 @@ void UnixUser::ChangeProcessUser(bool Temporary) if(Temporary) { // Change temporarily (change effective only) - #ifdef WIN32 - if(0) - #else - if(::setegid(mGID) != 0 - || ::seteuid(mUID) != 0) - #endif + if(::setegid(mGID) != 0 || ::seteuid(mUID) != 0) { THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser) } @@ -121,12 +111,7 @@ void UnixUser::ChangeProcessUser(bool Temporary) else { // Change permanently (change all UIDs and GIDs) - #ifdef WIN32 - if(0) - #else - if(::setgid(mGID) != 0 - || ::setuid(mUID) != 0) - #endif + if(::setgid(mGID) != 0 || ::setuid(mUID) != 0) { THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser) } -- cgit v1.2.3 From eeb55dfde4ed53b40c3aa4eab3aaa9a97861959b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 10 Mar 2007 19:35:38 +0000 Subject: Fixes for cross-compiling from Ubuntu Breezy (refs #3, merges [573]) --- modules.txt | 4 ++++ parcels.txt | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/modules.txt b/modules.txt index eb8c156d..0cb67add 100644 --- a/modules.txt +++ b/modules.txt @@ -10,6 +10,7 @@ # Generic support code and modules OMIT:mingw32 +OMIT:mingw32msvc OMIT:CYGWIN lib/raidfile END-OMIT @@ -24,6 +25,7 @@ test/crypto lib/crypto lib/win32 test/compress lib/compress lib/win32 OMIT:mingw32 +OMIT:mingw32msvc test/basicserver lib/server lib/win32 OMIT:CYGWIN test/raidfile lib/raidfile lib/intercept @@ -36,6 +38,7 @@ END-OMIT lib/backupclient lib/server lib/crypto lib/compress OMIT:mingw32 +OMIT:mingw32msvc OMIT:CYGWIN lib/backupstore lib/server lib/raidfile lib/backupclient bin/bbstored lib/raidfile lib/server lib/backupstore lib/backupclient lib/win32 @@ -48,6 +51,7 @@ bin/bbackupquery lib/server lib/backupclient lib/win32 bin/bbackupctl lib/server lib/backupclient lib/win32 OMIT:mingw32 +OMIT:mingw32msvc OMIT:CYGWIN test/backupstore bin/bbstored bin/bbstoreaccounts lib/server lib/backupstore lib/backupclient lib/raidfile test/backupstorefix bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile bin/bbackupquery bin/bbackupd diff --git a/parcels.txt b/parcels.txt index 13328e55..f9669900 100644 --- a/parcels.txt +++ b/parcels.txt @@ -9,16 +9,20 @@ backup-client bin bbackupctl script bin/bbackupd/bbackupd-config -ONLY:mingw32 +ONLY:mingw32,mingw32msvc script bin/bbackupd/win32/installer.iss script bin/bbackupd/win32/ReadMe.txt script bin/bbackupd/win32/bbackupd.conf +END-ONLY + +ONLY:mingw32 script /bin/mgwz.dll script /bin/mingwm10.dll optional script /bin/pcreposix.dll END-ONLY OMIT:mingw32 +OMIT:mingw32msvc OMIT:CYGWIN backup-server -- cgit v1.2.3 From a384f7c938c69b4e8ff67e4365d3114c5c647608 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:14:23 +0000 Subject: Simplify wait code (refs #3) --- test/bbackupd/testbbackupd.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index a99783e8..60e7fbbe 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -65,15 +65,7 @@ void wait_for_backup_operation(int seconds = TIME_TO_WAIT_FOR_BACKUP_OPERATION) { - printf("waiting: "); - fflush(stdout); - for(int l = 0; l < seconds; ++l) - { - sleep(1); - printf("."); - fflush(stdout); - } - printf("\n"); + wait_for_operation(seconds); } int bbstored_pid = 0; -- cgit v1.2.3 From 36fdc8f40a2db1bfefd54c32760b87d39587dce4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:15:22 +0000 Subject: Improve output messages when waiting for daemon to start (refs #3) --- test/bbackupd/testbbackupd.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 60e7fbbe..2338b1a4 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -530,7 +530,7 @@ int start_internal_daemon() TEST_THAT(TestFileExists("testfiles/bbackupd.pid")); - printf("Waiting for daemon to start"); + printf("Waiting for backup daemon to start: "); int pid = -1; for (int i = 0; i < 30; i++) @@ -546,7 +546,8 @@ int start_internal_daemon() } } - printf("\n"); + printf(" done.\n"); + fflush(stdout); TEST_THAT(pid > 0); return pid; -- cgit v1.2.3 From 209e3b91d07ea9f7b72369da73367fb4a791d52b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:19:19 +0000 Subject: Test expected behaviour for modifying a file without changing its modtime, both tracked and untracked (refs #3) --- test/bbackupd/testbbackupd.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 2338b1a4..f4f53002 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1050,6 +1050,79 @@ int test_bbackupd() TEST_THAT(compareReturnValue == 1*256); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // rename an untracked file over an + // existing untracked file + printf("Rename over existing untracked file\n"); + int fd1 = open("testfiles/TestDir1/untracked-1", + O_CREAT | O_EXCL | O_WRONLY, 0700); + int fd2 = open("testfiles/TestDir1/untracked-2", + O_CREAT | O_EXCL | O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(fd2 > 0); + TEST_THAT(write(fd1, "hello", 5) == 5); + TEST_THAT(close(fd1) == 0); + sleep(1); + TEST_THAT(write(fd2, "world", 5) == 5); + TEST_THAT(close(fd2) == 0); + TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-1")); + TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-2")); + wait_for_operation(5); + // back up both files + wait_for_backup_operation(); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf -l testfiles/query3t.log " + "\"compare -ac\" quit"); + TEST_THAT(compareReturnValue == 1*256); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(::rename("testfiles/TestDir1/untracked-1", + "testfiles/TestDir1/untracked-2") == 0); + TEST_THAT(!TestFileExists("testfiles/TestDir1/untracked-1")); + TEST_THAT( TestFileExists("testfiles/TestDir1/untracked-2")); + wait_for_backup_operation(); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf -l testfiles/query3t.log " + "\"compare -ac\" quit"); + TEST_THAT(compareReturnValue == 1*256); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // case which went wrong: rename a tracked file over an + // existing tracked file + printf("Rename over existing tracked file\n"); + fd1 = open("testfiles/TestDir1/tracked-1", + O_CREAT | O_EXCL | O_WRONLY, 0700); + fd2 = open("testfiles/TestDir1/tracked-2", + O_CREAT | O_EXCL | O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(fd2 > 0); + char buffer[1024]; + TEST_THAT(write(fd1, "hello", 5) == 5); + TEST_THAT(write(fd1, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd1) == 0); + sleep(1); + TEST_THAT(write(fd2, "world", 5) == 5); + TEST_THAT(write(fd2, buffer, sizeof(buffer)) == sizeof(buffer)); + TEST_THAT(close(fd2) == 0); + TEST_THAT(TestFileExists("testfiles/TestDir1/tracked-1")); + TEST_THAT(TestFileExists("testfiles/TestDir1/tracked-2")); + wait_for_operation(5); + // back up both files + wait_for_backup_operation(); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf -l testfiles/query3u.log " + "\"compare -ac\" quit"); + TEST_THAT(compareReturnValue == 1*256); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(::rename("testfiles/TestDir1/tracked-1", + "testfiles/TestDir1/tracked-2") == 0); + TEST_THAT(!TestFileExists("testfiles/TestDir1/tracked-1")); + TEST_THAT( TestFileExists("testfiles/TestDir1/tracked-2")); + wait_for_backup_operation(); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf -l testfiles/query3v.log " + "\"compare -ac\" quit"); + TEST_THAT(compareReturnValue == 1*256); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // case which went wrong: rename a tracked file over a deleted file printf("Rename an existing file over a deleted file\n"); TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); -- cgit v1.2.3 From faa7f9c501bc1b042bb0f344f8e112a8f67d53b7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:20:19 +0000 Subject: Flush stdout after writing to it (refs #3) --- test/bbackupd/testbbackupd.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index f4f53002..80219806 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1242,6 +1242,7 @@ int test_bbackupd() ::fclose(f); } printf("\n"); + fflush(stdout); // Check there's a difference compareReturnValue = ::system("testfiles/extcheck1.pl"); @@ -1262,6 +1263,7 @@ int test_bbackupd() ::fclose(f); } printf("\n"); + fflush(stdout); compareReturnValue = ::system("testfiles/extcheck2.pl"); TEST_THAT(compareReturnValue == 1*256); -- cgit v1.2.3 From cdf4474b46bd25b126707bf84d1517d6cb4984d8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:20:57 +0000 Subject: Use unique name for compare log (refs #3) --- test/bbackupd/testbbackupd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 80219806..9ac6f94b 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1127,7 +1127,7 @@ int test_bbackupd() printf("Rename an existing file over a deleted file\n"); TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); + compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3w.log \"compare -ac\" quit"); TEST_THAT(compareReturnValue == 1*256); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); -- cgit v1.2.3 From 2528fa9f1ae3bc50dfb060c088250244a7334567 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:21:38 +0000 Subject: Test that bbackupd reports an error when the backup failed due to an exception (refs #3) --- test/bbackupd/testbbackupd.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 9ac6f94b..ecc942b9 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1007,6 +1007,39 @@ int test_bbackupd() TEST_THAT(compareReturnValue == 1*256); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // Check that store errors are reported neatly + printf("Create store error\n"); + TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf", + "testfiles/0_0/backup/01234567/info.rf.bak") == 0); + TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf", + "testfiles/0_1/backup/01234567/info.rf.bak") == 0); + TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf", + "testfiles/0_2/backup/01234567/info.rf.bak") == 0); + // Create a file to trigger an upload + { + int fd1 = open("testfiles/TestDir1/force-upload", + O_CREAT | O_EXCL | O_WRONLY, 0700); + TEST_THAT(fd1 > 0); + TEST_THAT(write(fd1, "just do it", 10) == 10); + TEST_THAT(close(fd1) == 0); + wait_for_backup_operation(4); + } + // Wait and test... + wait_for_backup_operation(); + // Check that it was reported correctly + TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.1")); + // Check that the error was only reorted once + TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.2")); + // Fix the store + TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf.bak", + "testfiles/0_0/backup/01234567/info.rf") == 0); + TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf.bak", + "testfiles/0_1/backup/01234567/info.rf") == 0); + TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf.bak", + "testfiles/0_2/backup/01234567/info.rf") == 0); + // wait until bbackupd recovers from the exception + wait_for_backup_operation(100); + // Bad case: delete a file/symlink, replace it with a directory printf("Replace symlink with directory, add new directory\n"); TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir") == 0); -- cgit v1.2.3 From 5461fbd6ccf29b092900bcecd3a30c4c6c201e02 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:22:30 +0000 Subject: Flush stdout when writing to it (refs #3) --- lib/common/Test.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/common/Test.h b/lib/common/Test.h index 3b7b28e4..746684df 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -397,6 +397,7 @@ inline void wait_for_operation(int seconds) fflush(stdout); } printf("\n"); + fflush(stdout); } #endif // TEST__H -- cgit v1.2.3 From eee4907406d6292b215a2d7453cfaa144a3da336 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:26:37 +0000 Subject: Add a new notification constant, NotifyEvent_BackupError, for use when an exception occurs during the backup. Make bbackupd notify sysadmin when an exception occurs during the backup, using this error code, and the notification string "backup-error". Change NotifyEvent__MAX to be one greater than the highest notification constant, makes code more maintainable. (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 16 ++++++++++++---- bin/bbackupd/BackupDaemon.h | 7 ++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 0ab676eb..a56003d1 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -119,8 +119,8 @@ BackupDaemon::BackupDaemon() // Only ever one instance of a daemon SSLLib::Initialise(); - // Initialise notifcation sent status - for(int l = 0; l <= NotifyEvent__MAX; ++l) + // Initialise notification sent status + for(int l = 0; l < NotifyEvent__MAX; ++l) { mNotificationsSent[l] = false; } @@ -878,6 +878,8 @@ void BackupDaemon::Run2() else { // Not restart/terminate, pause and retry + // Notify administrator + NotifySysadmin(NotifyEvent_BackupError); SetState(State_Error); BOX_ERROR("Exception caught (" << errorString @@ -2013,11 +2015,17 @@ void BackupDaemon::TouchFileInWorkingDir(const char *Filename) // -------------------------------------------------------------------------- void BackupDaemon::NotifySysadmin(int Event) { - static const char *sEventNames[] = {"store-full", "read-error", 0}; + static const char *sEventNames[] = + { + "store-full", + "read-error", + "backup-error", + 0 + }; BOX_TRACE("BackupDaemon::NotifySysadmin() called, event = " << Event); - if(Event < 0 || Event > NotifyEvent__MAX) + if(Event < 0 || Event >= NotifyEvent__MAX) { THROW_EXCEPTION(BackupStoreException, BadNotifySysadminEventCode); } diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index cf812001..64b06949 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -82,8 +82,9 @@ public: enum { NotifyEvent_StoreFull = 0, - NotifyEvent_ReadError = 1, - NotifyEvent__MAX = 1 + NotifyEvent_ReadError, + NotifyEvent_BackupError, + NotifyEvent__MAX // When adding notifications, remember to add strings to NotifySysadmin() }; void NotifySysadmin(int Event); @@ -177,7 +178,7 @@ private: CommandSocketInfo *mpCommandSocketInfo; // Stop notifications being repeated. - bool mNotificationsSent[NotifyEvent__MAX + 1]; + bool mNotificationsSent[NotifyEvent__MAX]; // Unused entries in the root directory wait a while before being deleted box_time_t mDeleteUnusedRootDirEntriesAfter; // time to delete them -- cgit v1.2.3 From 961baf88f51f0c58f1de373b5bcf5eb551403bc9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:27:18 +0000 Subject: Log at trace level by default in debug builds (refs #3) --- lib/server/Daemon.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index f50a9c9a..07ca705b 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -101,7 +101,13 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) mConfigFileName = DefaultConfigFile; bool haveConfigFile = false; bool singleProcess = false; + + #ifdef NDEBUG int masterLevel = Log::NOTICE; // need an int to do math with + #else + int masterLevel = Log::TRACE; // need an int to do math with + #endif + char c; while((c = getopt(argc, (char * const *)argv, "c:Dqv")) != -1) -- cgit v1.2.3 From 1c28c07ef9651fa381b6469dc541a12891f8ba18 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:28:07 +0000 Subject: Trace reasons for uploading (or not) each file --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 43824130..22861f76 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -30,6 +30,7 @@ #include "BackupStoreException.h" #include "Archive.h" #include "PathUtils.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -793,10 +794,14 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP if (pDirOnStore != 0 && en == 0) { doUpload = true; + BOX_TRACE(filename << ": will upload " + "(not on server)"); } else if (modTime >= rParams.mSyncPeriodStart) { doUpload = true; + BOX_TRACE(filename << ": will upload " + "(modified since last sync)"); } } @@ -813,6 +818,8 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP > rParams.mMaxUploadWait) { doUpload = true; + BOX_TRACE(filename << ": will upload " + "(continually modified)"); } // Then make sure that if files are added with a @@ -828,6 +835,8 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP en->GetModificationTime() != modTime) { doUpload = true; + BOX_TRACE(filename << ": will upload " + "(mod time changed)"); } // And just to catch really badly off clocks in @@ -838,9 +847,20 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP rParams.mUploadAfterThisTimeInTheFuture) { doUpload = true; + BOX_TRACE(filename << ": will upload " + "(mod time in the future)"); } } + if (!doUpload) + { + BOX_TRACE(filename << ": will not upload " + "(no reason to upload, mod time is " + << modTime << " versus sync period " + << rParams.mSyncPeriodStart << " to " + << rParams.mSyncPeriodEnd << ")"); + } + if (doUpload) { // Make sure we're connected -- must connect here so we know whether -- cgit v1.2.3 From b9fec05c7692aeb993e67b50e6f0b5f8249325d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2007 23:48:12 +0000 Subject: Move lib/common/ServerControl.h to lib/server where it belongs, since it uses server functions (WinNamedPipeStream on win32) (refs #3) --- lib/common/ServerControl.h | 177 --------------------------------------------- lib/server/ServerControl.h | 177 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 177 deletions(-) delete mode 100644 lib/common/ServerControl.h create mode 100644 lib/server/ServerControl.h diff --git a/lib/common/ServerControl.h b/lib/common/ServerControl.h deleted file mode 100644 index a8477900..00000000 --- a/lib/common/ServerControl.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef SERVER_CONTROL_H -#define SERVER_CONTROL_H - -#ifdef WIN32 - -#include "WinNamedPipeStream.h" -#include "IOStreamGetLine.h" -#include "BoxPortsAndFiles.h" -#include "Test.h" - -static bool SendCommands(const std::string& rCmd) -{ - WinNamedPipeStream connection; - - try - { - connection.Connect(BOX_NAMED_PIPE_NAME); - } - catch(...) - { - printf("Failed to connect to daemon control socket.\n"); - return false; - } - - // 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; - } - - // Was the connection rejected by the server? - if(getLine.IsEOF()) - { - printf("Server rejected the connection.\n"); - return false; - } - - // Decode it - int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait; - if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", - &autoBackup, &updateStoreInterval, - &minimumFileAge, &maxUploadWait) != 4) - { - printf("Config summary didn't decode\n"); - 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") - { - printf("ERROR (%s)\n", rCmd.c_str()); - break; - } - else - { - printf("WARNING: Unexpected response to command '%s': " - "%s", rCmd.c_str(), line.c_str()); - } - } - - 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) - { - printf("Failed to open process %d: error %d\n", - pid, (int)GetLastError()); - return false; - } - - if (!TerminateProcess(hProcess, 1)) - { - printf("Failed to terminate process %d: error %d\n", - pid, (int)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); - 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 (!ServerIsAlive(pid)) break; - ::sleep(1); - if (!ServerIsAlive(pid)) break; - - if (i == 0) - { - printf("waiting for server to die"); - } - - printf("."); - fflush(stdout); - } - - if (!ServerIsAlive(pid)) - { - printf("done.\n"); - } - else - { - printf("failed!\n"); - } - - fflush(stdout); - - return !ServerIsAlive(pid); -} - -#endif // SERVER_CONTROL_H diff --git a/lib/server/ServerControl.h b/lib/server/ServerControl.h new file mode 100644 index 00000000..a8477900 --- /dev/null +++ b/lib/server/ServerControl.h @@ -0,0 +1,177 @@ +#ifndef SERVER_CONTROL_H +#define SERVER_CONTROL_H + +#ifdef WIN32 + +#include "WinNamedPipeStream.h" +#include "IOStreamGetLine.h" +#include "BoxPortsAndFiles.h" +#include "Test.h" + +static bool SendCommands(const std::string& rCmd) +{ + WinNamedPipeStream connection; + + try + { + connection.Connect(BOX_NAMED_PIPE_NAME); + } + catch(...) + { + printf("Failed to connect to daemon control socket.\n"); + return false; + } + + // 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; + } + + // Was the connection rejected by the server? + if(getLine.IsEOF()) + { + printf("Server rejected the connection.\n"); + return false; + } + + // Decode it + int autoBackup, updateStoreInterval, minimumFileAge, maxUploadWait; + if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", + &autoBackup, &updateStoreInterval, + &minimumFileAge, &maxUploadWait) != 4) + { + printf("Config summary didn't decode\n"); + 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") + { + printf("ERROR (%s)\n", rCmd.c_str()); + break; + } + else + { + printf("WARNING: Unexpected response to command '%s': " + "%s", rCmd.c_str(), line.c_str()); + } + } + + 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) + { + printf("Failed to open process %d: error %d\n", + pid, (int)GetLastError()); + return false; + } + + if (!TerminateProcess(hProcess, 1)) + { + printf("Failed to terminate process %d: error %d\n", + pid, (int)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); + 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 (!ServerIsAlive(pid)) break; + ::sleep(1); + if (!ServerIsAlive(pid)) break; + + if (i == 0) + { + printf("waiting for server to die"); + } + + printf("."); + fflush(stdout); + } + + if (!ServerIsAlive(pid)) + { + printf("done.\n"); + } + else + { + printf("failed!\n"); + } + + fflush(stdout); + + return !ServerIsAlive(pid); +} + +#endif // SERVER_CONTROL_H -- cgit v1.2.3 From 7cc40f79b9c0297956358bb8aa401110b52c9f6b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 00:40:59 +0000 Subject: Fix compilation error reported by Torsten Boob (refs #3) --- lib/common/Guards.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/common/Guards.h b/lib/common/Guards.h index 52018493..fbcfedaf 100644 --- a/lib/common/Guards.h +++ b/lib/common/Guards.h @@ -15,9 +15,12 @@ #include #endif +#include #include #include +#include #include + #include #include "CommonException.h" -- cgit v1.2.3 From ca2ba680bb5d112eccc1a152704945d89db8c733 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 21:50:37 +0000 Subject: Reinitialise the OVERLAPPED structure each time we start a new overlapped read. Thanks to Charles Lecklider for pointing this out. (refs #3, merges part of [1458]) --- lib/server/WinNamedPipeStream.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp index e4a675a7..6ef174c8 100644 --- a/lib/server/WinNamedPipeStream.cpp +++ b/lib/server/WinNamedPipeStream.cpp @@ -298,6 +298,13 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) 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, -- cgit v1.2.3 From 9a5063929192a9f47cc72420b8b33c85e3ec3627 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 21:51:58 +0000 Subject: Use memmove() for overlapping source and destination buffer. Thanks to Charles Lecklider for pointing this out. (refs #3, merges [1442]) --- lib/server/WinNamedPipeStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp index 6ef174c8..34263683 100644 --- a/lib/server/WinNamedPipeStream.cpp +++ b/lib/server/WinNamedPipeStream.cpp @@ -293,7 +293,7 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) } memcpy(pBuffer, mReadBuffer, BytesToCopy); - memcpy(mReadBuffer, mReadBuffer + BytesToCopy, BytesRemaining); + memmove(mReadBuffer, mReadBuffer + BytesToCopy, BytesRemaining); mBytesInBuffer = BytesRemaining; NumBytesRead = BytesToCopy; -- cgit v1.2.3 From 96070af8205f85db802a7aed81979e7f2cf92d29 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 21:53:01 +0000 Subject: Change named pipe from message to byte mode. Thanks to Charles Lecklider for pointing this out. --- lib/server/WinNamedPipeStream.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp index 34263683..7d372517 100644 --- a/lib/server/WinNamedPipeStream.cpp +++ b/lib/server/WinNamedPipeStream.cpp @@ -89,8 +89,8 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) pName, // pipe name PIPE_ACCESS_DUPLEX | // read/write access FILE_FLAG_OVERLAPPED, // enabled overlapped I/O - PIPE_TYPE_MESSAGE | // message type pipe - PIPE_READMODE_MESSAGE | // message-read mode + PIPE_TYPE_BYTE | // message type pipe + PIPE_READMODE_BYTE | // message-read mode PIPE_WAIT, // blocking mode 1, // max. instances 4096, // output buffer size -- cgit v1.2.3 From 198d823a23f6fbece6a4792c6d7f7f787555ae1e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 22:53:45 +0000 Subject: Add emulated rename() with path conversion. (refs #3, merges [1436] and [1438]) --- lib/win32/emu.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/win32/emu.h | 2 ++ 2 files changed, 68 insertions(+) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 112b1c9f..0aedffc7 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1609,6 +1609,72 @@ int emu_unlink(const char* pFileName) 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; + } + + return 0; +} + int console_read(char* pBuffer, size_t BufferSize) { HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE); diff --git a/lib/win32/emu.h b/lib/win32/emu.h index a4af6e64..ec6c0918 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -337,6 +337,7 @@ 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) @@ -347,6 +348,7 @@ char* emu_getcwd (char* pBuffer, int BufSize); #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) int statfs(const char * name, struct statfs * s); -- cgit v1.2.3 From bdb64683f2bb8279c91770869370a0717bb45098 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 22:54:30 +0000 Subject: Initialise logging framework and set our program name to Box Backup (bbstored) (refs #3, merges [1462]) --- lib/win32/emu.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 0aedffc7..818c6a6b 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1345,13 +1345,17 @@ void openlog(const char * daemonName, int, int) { } - if (!AddEventSource("Box Backup", 0)) + 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, "Box Backup"); + HANDLE newSyslogH = RegisterEventSource(NULL, daemonName); if (newSyslogH == NULL) { ::syslog(LOG_ERR, "Failed to register our own event source: " -- cgit v1.2.3 From e9f3450fb12f26b20ae06816a01fb9f78c613857 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 22:56:13 +0000 Subject: Use logging framework to reduce noise for those who don't want it (refs #3, merges [1439] [1440] [1443]) --- lib/backupclient/BackupStoreFile.cpp | 6 +++--- lib/backupclient/BackupStoreFilenameClear.cpp | 7 ++++--- lib/server/Protocol.cpp | 4 +++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp index 278bf50a..5c621f38 100644 --- a/lib/backupclient/BackupStoreFile.cpp +++ b/lib/backupclient/BackupStoreFile.cpp @@ -46,6 +46,7 @@ #include "ReadGatherStream.h" #include "Random.h" #include "BackupStoreFileEncodeStream.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -1485,9 +1486,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/BackupStoreFilenameClear.cpp b/lib/backupclient/BackupStoreFilenameClear.cpp index c415b9bb..9114fdd1 100644 --- a/lib/backupclient/BackupStoreFilenameClear.cpp +++ b/lib/backupclient/BackupStoreFilenameClear.cpp @@ -13,6 +13,7 @@ #include "CipherContext.h" #include "CipherBlowfish.h" #include "Guards.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -203,9 +204,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/server/Protocol.cpp b/lib/server/Protocol.cpp index 988d44c8..4398a58f 100644 --- a/lib/server/Protocol.cpp +++ b/lib/server/Protocol.cpp @@ -22,6 +22,7 @@ #include "ServerException.h" #include "PartialReadStream.h" #include "ProtocolUncertainStream.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -55,7 +56,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); } // -------------------------------------------------------------------------- -- cgit v1.2.3 From 30eec391b1be077b6ef7f97337b36ef204f10666 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 22:58:16 +0000 Subject: Reduce default logging level in debug builds from TRACE back down to INFO, to reduce noise in tests. (refs #3, merges [1441]) --- lib/server/Daemon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 07ca705b..5ee45378 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -105,7 +105,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) #ifdef NDEBUG int masterLevel = Log::NOTICE; // need an int to do math with #else - int masterLevel = Log::TRACE; // need an int to do math with + int masterLevel = Log::INFO; // need an int to do math with #endif char c; -- cgit v1.2.3 From 93738627ce25b28ce377fc6802ef1fa7390a58a7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 22:58:55 +0000 Subject: Trivial code simplification. (refs #3, merges [1444]) --- lib/common/Test.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 746684df..f5b5698b 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -275,10 +275,8 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) TEST_FAIL_WITH_MESSAGE("Server didn't save PID file"); return -1; } - else - { - ::fprintf(stdout, "done.\n"); - } + + ::fprintf(stdout, "done.\n"); // wait a second for the pid to be written to the file ::sleep(1); -- cgit v1.2.3 From 48d14baa75532373e84d26200022116afc6e49ab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 22:59:26 +0000 Subject: Use logging framework to remove timer noise for those who don't want it. (refs #3, merges [1445]) --- lib/common/Timer.cpp | 83 +++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index c24f38f9..c5b90ec2 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -175,11 +175,10 @@ void Timers::Reschedule() if (timeToExpiry <= 0) { - TRACE3("%d.%d: timer %p has expired, " - "triggering it\n", - (int)(timeNow / 1000000), - (int)(timeNow % 1000000), - *i); + BOX_TRACE((int)(timeNow / 1000000) << "." << + (int)(timeNow % 1000000) << + ": timer " << *i << " has expired, " + "triggering it"); rTimer.OnExpire(); spTimers->erase(i); restart = true; @@ -187,13 +186,13 @@ void Timers::Reschedule() } else { - TRACE5("%d.%d: timer %p has not expired, " - "triggering in %d.%d seconds\n", - (int)(timeNow / 1000000), - (int)(timeNow % 1000000), - *i, - (int)(timeToExpiry / 1000000), - (int)(timeToExpiry % 1000000)); + BOX_TRACE((int)(timeNow / 1000000) << "." << + (int)(timeNow % 1000000) << + ": timer " << *i << " has not " + "expired, triggering in " << + (int)(timeToExpiry / 1000000) << "." << + (int)(timeToExpiry % 1000000) << + " seconds"); } } } @@ -231,7 +230,7 @@ void Timers::Reschedule() if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) { - TRACE0("WARNING: couldn't initialise timer\n"); + BOX_ERROR("Failed to initialise timer\n"); THROW_EXCEPTION(CommonException, Internal) } } @@ -263,15 +262,16 @@ Timer::Timer(size_t timeoutSecs) gettimeofday(&tv, NULL); if (timeoutSecs == 0) { - TRACE4("%d.%d: timer %p initialised for %d secs, " - "will not fire\n", tv.tv_sec, tv.tv_usec, this, - timeoutSecs); + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " initialised for " << + timeoutSecs << " secs, will not fire"); } else { - TRACE6("%d.%d: timer %p initialised for %d secs, " - "to fire at %d.%d\n", tv.tv_sec, tv.tv_usec, this, - timeoutSecs, (int)(mExpires / 1000000), + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " initialised for " << + timeoutSecs << " secs, to fire at " << + (int)(mExpires / 1000000) << "." << (int)(mExpires % 1000000)); } #endif @@ -291,8 +291,8 @@ Timer::~Timer() #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); - TRACE3("%d.%d: timer %p destroyed, will not fire\n", - tv.tv_sec, tv.tv_usec, this); + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " destroyed"); #endif Timers::Remove(*this); @@ -307,21 +307,22 @@ Timer::Timer(const Timer& rToCopy) gettimeofday(&tv, NULL); if (mExpired) { - TRACE4("%d.%d: timer %p initialised from timer %p, " - "already expired, will not fire\n", tv.tv_sec, - tv.tv_usec, this, &rToCopy); + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " initialised from timer " << + &rToCopy << ", already expired, will not fire"); } else if (mExpires == 0) { - TRACE4("%d.%d: timer %p initialised from timer %p, " - "will not fire\n", tv.tv_sec, tv.tv_usec, this, - &rToCopy); + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " initialised from timer " << + &rToCopy << ", no expiry, will not fire"); } else { - TRACE6("%d.%d: timer %p initialised from timer %p, " - "to fire at %d.%d\n", tv.tv_sec, tv.tv_usec, this, - &rToCopy, (int)(mExpires / 1000000), + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " initialised from timer " << + &rToCopy << " to fire at " << + (int)(mExpires / 1000000) << "." << (int)(mExpires % 1000000)); } #endif @@ -339,21 +340,22 @@ Timer& Timer::operator=(const Timer& rToCopy) gettimeofday(&tv, NULL); if (rToCopy.mExpired) { - TRACE4("%d.%d: timer %p initialised from timer %p, " - "already expired, will not fire\n", tv.tv_sec, - tv.tv_usec, this, &rToCopy); + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " initialised from timer " << + &rToCopy << ", already expired, will not fire"); } else if (rToCopy.mExpires == 0) { - TRACE4("%d.%d: timer %p initialised from timer %p, " - "will not fire\n", tv.tv_sec, tv.tv_usec, this, - &rToCopy); + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " initialised from timer " << + &rToCopy << ", no expiry, will not fire"); } else { - TRACE6("%d.%d: timer %p initialised from timer %p, " - "to fire at %d.%d\n", tv.tv_sec, tv.tv_usec, this, - &rToCopy, (int)(rToCopy.mExpires / 1000000), + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " initialised from timer " << + &rToCopy << " to fire at " << + (int)(rToCopy.mExpires / 1000000) << "." << (int)(rToCopy.mExpires % 1000000)); } #endif @@ -373,7 +375,8 @@ void Timer::OnExpire() #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); - TRACE3("%d.%d: timer %p fired\n", tv.tv_sec, tv.tv_usec, this); + BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + ": timer " << this << " fired"); #endif mExpired = true; -- cgit v1.2.3 From e630d8ed665c44bb00009970decdb4a6470897b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 22:59:53 +0000 Subject: Fix header include order. (refs #3, merges [1446]) --- lib/common/Timer.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/common/Timer.h b/lib/common/Timer.h index 390442df..8e229a0a 100644 --- a/lib/common/Timer.h +++ b/lib/common/Timer.h @@ -15,9 +15,10 @@ #include -#include "MemLeakFindOn.h" #include "BoxTime.h" +#include "MemLeakFindOn.h" + class Timer; // -------------------------------------------------------------------------- -- cgit v1.2.3 From 86a9d5654378efc3dfedb627d28af5324f0edc52 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:00:41 +0000 Subject: Remove newlines from syslog() messages. (refs #3, merges [1447]) --- bin/bbstored/BackupStoreDaemon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 335135ce..c9601575 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -295,7 +295,7 @@ void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream) std::string clientCommonName(rStream.GetPeerCommonName()); // Log the name - ::syslog(LOG_INFO, "Certificate CN: %s\n", clientCommonName.c_str()); + ::syslog(LOG_INFO, "Certificate CN: %s", clientCommonName.c_str()); // Check it int32_t id; @@ -342,7 +342,7 @@ void BackupStoreDaemon::LogConnectionStats(const char *commonName, { // Log the amount of data transferred ::syslog(LOG_INFO, "Connection statistics for %s: " - "IN=%lld OUT=%lld TOTAL=%lld\n", commonName, + "IN=%lld OUT=%lld TOTAL=%lld", commonName, (long long)s.GetBytesRead(), (long long)s.GetBytesWritten(), (long long)s.GetBytesRead() + -- cgit v1.2.3 From 874c6893abb3278cbfeb3c2b948518e36982a620 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:01:37 +0000 Subject: Initialise logging framework and set sensible default verbosity levels in bbackupquery (refs #3, merges [1449]) --- bin/bbackupquery/bbackupquery.cpp | 47 ++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index 96374cd4..37025d39 100644 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -45,6 +45,7 @@ #include "FdGetLine.h" #include "BackupClientCryptoKeys.h" #include "BannerText.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -95,11 +96,19 @@ int main(int argc, const char *argv[]) bool quiet = false; bool readWrite = false; + Logging::SetProgramName("Box Backup (bbackupquery)"); + + #ifdef NDEBUG + int masterLevel = Log::NOTICE; // need an int to do math with + #else + int masterLevel = Log::INFO; // need an int to do math with + #endif + #ifdef WIN32 - const char* validOpts = "qwuc:l:"; + const char* validOpts = "qvwuc:l:"; bool unicodeConsole = false; #else - const char* validOpts = "qwc:l:"; + const char* validOpts = "qvwc:l:"; #endif // See if there's another entry on the command line @@ -108,11 +117,35 @@ int main(int argc, const char *argv[]) { switch(c) { - case 'q': - // Quiet mode - quiet = true; + case 'q': + { + // Quiet mode + quiet = true; + + if(masterLevel == Log::NOTHING) + { + BOX_FATAL("Too many '-q': " + "Cannot reduce logging " + "level any more"); + return 2; + } + masterLevel--; + } break; - + + case 'v': + { + if(masterLevel == Log::EVERYTHING) + { + BOX_FATAL("Too many '-v': " + "Cannot increase logging " + "level any more"); + return 2; + } + masterLevel++; + } + break; + case 'w': // Read/write mode readWrite = true; @@ -147,6 +180,8 @@ int main(int argc, const char *argv[]) argc -= optind; argv += optind; + Logging::SetGlobalLevel((Log::Level)masterLevel); + // Print banner? if(!quiet) { -- cgit v1.2.3 From 5bd0cf5c9a2e583f2f88998fe3c5ac980e5d485e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:02:36 +0000 Subject: Add new exception codes for use in bbackupd, and possibly other clients. (refs #3, merges [1455]) --- bin/bbackupd/ClientException.txt | 11 +++++++++++ bin/bbackupd/Makefile.extra | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 bin/bbackupd/ClientException.txt create mode 100644 bin/bbackupd/Makefile.extra diff --git a/bin/bbackupd/ClientException.txt b/bin/bbackupd/ClientException.txt new file mode 100644 index 00000000..04f88620 --- /dev/null +++ b/bin/bbackupd/ClientException.txt @@ -0,0 +1,11 @@ + +# NOTE: Exception descriptions are for public distributions of Box Backup only -- do not rely for other applications. + + +EXCEPTION Client 13 + +Internal 0 +AssertFailed 1 +ClockWentBackwards 2 Invalid (negative) sync period: perhaps your clock is going backwards? +FailedToDeleteStoreObjectInfoFile 3 Failed to delete the StoreObjectInfoFile, backup cannot continue safely. +CorruptStoreObjectInfoFile 4 The store object info file contained an invalid value and is probably corrupt. Try deleting it. diff --git a/bin/bbackupd/Makefile.extra b/bin/bbackupd/Makefile.extra new file mode 100644 index 00000000..52e21366 --- /dev/null +++ b/bin/bbackupd/Makefile.extra @@ -0,0 +1,7 @@ + +MAKEEXCEPTION = ../../lib/common/makeexception.pl + +# AUTOGEN SEEDING +autogen_ClientException.h autogen_ClientException.cpp: $(MAKEEXCEPTION) ClientException.txt + $(PERL) $(MAKEEXCEPTION) ClientException.txt + -- cgit v1.2.3 From ae0656933dc98d1728683cf5862df932fcac35a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:03:11 +0000 Subject: Add autogen_ClientException.o to testbbackupd extra objects, because it links against bbackupd objects which need this. (refs #3, merges [1456]) --- test/bbackupd/Makefile.extra | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bbackupd/Makefile.extra b/test/bbackupd/Makefile.extra index e6e4849a..1d3f5103 100644 --- a/test/bbackupd/Makefile.extra +++ b/test/bbackupd/Makefile.extra @@ -1 +1 @@ -link-extra: ../../bin/bbackupd/BackupClientContext.o ../../bin/bbackupd/BackupClientDeleteList.o ../../bin/bbackupd/BackupClientDirectoryRecord.o ../../bin/bbackupd/Win32BackupService.o ../../bin/bbackupd/BackupClientInodeToIDMap.o ../../bin/bbackupd/Win32ServiceFunctions.o ../../bin/bbackupd/BackupDaemon.o +link-extra: ../../bin/bbackupd/autogen_ClientException.o ../../bin/bbackupd/BackupClientContext.o ../../bin/bbackupd/BackupClientDeleteList.o ../../bin/bbackupd/BackupClientDirectoryRecord.o ../../bin/bbackupd/Win32BackupService.o ../../bin/bbackupd/BackupClientInodeToIDMap.o ../../bin/bbackupd/Win32ServiceFunctions.o ../../bin/bbackupd/BackupDaemon.o -- cgit v1.2.3 From d05891e8c6856896e1bec719e60726ee2fbc3af2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:07:13 +0000 Subject: Improve logging of pipe errors by including the error message. (refs #3, merges part of [1458]) --- lib/server/WinNamedPipeStream.cpp | 51 ++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp index 7d372517..ad5764ec 100644 --- a/lib/server/WinNamedPipeStream.cpp +++ b/lib/server/WinNamedPipeStream.cpp @@ -100,8 +100,8 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) if (mSocketHandle == INVALID_HANDLE_VALUE) { - ::syslog(LOG_ERR, "CreateNamedPipeW failed: %d", - GetLastError()); + ::syslog(LOG_ERR, "CreateNamedPipeW failed: %s", + GetErrorMessage(GetLastError()).c_str()); THROW_EXCEPTION(ServerException, SocketOpenError) } @@ -109,8 +109,8 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) if (!connected) { - ::syslog(LOG_ERR, "ConnectNamedPipe failed: %d", - GetLastError()); + ::syslog(LOG_ERR, "ConnectNamedPipe failed: %s", + GetErrorMessage(GetLastError()).c_str()); Close(); THROW_EXCEPTION(ServerException, SocketOpenError) } @@ -126,8 +126,8 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) if (mReadableEvent == INVALID_HANDLE_VALUE) { - ::syslog(LOG_ERR, "Failed to create the Readable event: " - "error %d", GetLastError()); + ::syslog(LOG_ERR, "Failed to create the Readable event: %s", + GetErrorMessage(GetLastError()).c_str()); Close(); THROW_EXCEPTION(CommonException, Internal) } @@ -145,7 +145,7 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) if (err != ERROR_IO_PENDING) { ::syslog(LOG_ERR, "Failed to start overlapped read: " - "error %d", err); + "%s", GetErrorMessage(err).c_str()); Close(); THROW_EXCEPTION(ConnectionException, Conn_SocketReadError) @@ -189,7 +189,7 @@ void WinNamedPipeStream::Connect(const wchar_t* pName) else { ::syslog(LOG_ERR, "Failed to connect to backup " - "daemon: error %d", err); + "daemon: %s", GetErrorMessage(err).c_str()); } THROW_EXCEPTION(ServerException, SocketOpenError) } @@ -269,7 +269,8 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) ::syslog(LOG_ERR, "Failed to wait for " "ReadFile to complete: " - "error %d", err); + "%s", + GetErrorMessage(err).c_str()); } Close(); @@ -332,7 +333,8 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) else { ::syslog(LOG_ERR, "Failed to start " - "overlapped read: error %d", err); + "overlapped read: %s", + GetErrorMessage(err).c_str()); Close(); THROW_EXCEPTION(ConnectionException, Conn_SocketReadError) @@ -420,6 +422,9 @@ void WinNamedPipeStream::Write(const void *pBuffer, int NBytes) if (!Success) { + DWORD err = GetLastError(); + ::syslog(LOG_ERR, "Failed to write to control socket: " + "%s", GetErrorMessage(err).c_str()); Close(); THROW_EXCEPTION(ConnectionException, Conn_SocketWriteError) @@ -456,7 +461,8 @@ void WinNamedPipeStream::Close() if (!CancelIo(mSocketHandle)) { ::syslog(LOG_ERR, "Failed to cancel outstanding " - "I/O: error %d", GetLastError()); + "I/O: %s", + GetErrorMessage(GetLastError()).c_str()); } if (mReadableEvent == INVALID_HANDLE_VALUE) @@ -467,21 +473,27 @@ void WinNamedPipeStream::Close() else if (!CloseHandle(mReadableEvent)) { ::syslog(LOG_ERR, "Failed to destroy Readable " - "event: error %d", GetLastError()); + "event: %s", + GetErrorMessage(GetLastError()).c_str()); } mReadableEvent = INVALID_HANDLE_VALUE; if (!FlushFileBuffers(mSocketHandle)) { - ::syslog(LOG_INFO, "FlushFileBuffers failed: %d", - GetLastError()); + ::syslog(LOG_INFO, "FlushFileBuffers failed: %s", + GetErrorMessage(GetLastError()).c_str()); } if (!DisconnectNamedPipe(mSocketHandle)) { - ::syslog(LOG_ERR, "DisconnectNamedPipe failed: %d", - GetLastError()); + DWORD err = GetLastError(); + if (err != ERROR_PIPE_NOT_CONNECTED) + { + ::syslog(LOG_ERR, "DisconnectNamedPipe " + "failed: %s", + GetErrorMessage(err).c_str()); + } } mIsServer = false; @@ -496,7 +508,8 @@ void WinNamedPipeStream::Close() if (!result) { - ::syslog(LOG_ERR, "CloseHandle failed: %d", GetLastError()); + ::syslog(LOG_ERR, "CloseHandle failed: %s", + GetErrorMessage(GetLastError()).c_str()); THROW_EXCEPTION(ServerException, SocketCloseError) } } @@ -544,8 +557,8 @@ void WinNamedPipeStream::WriteAllBuffered() if (!FlushFileBuffers(mSocketHandle)) { - ::syslog(LOG_WARNING, "FlushFileBuffers failed: %d", - GetLastError()); + ::syslog(LOG_WARNING, "FlushFileBuffers failed: %s", + GetErrorMessage(GetLastError()).c_str()); } } -- cgit v1.2.3 From bde7b631acbfd48271e88268eb7734a680a7deb6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:12:20 +0000 Subject: iUse our new ClientException codes for clock skew and archive problems. (refs #3, merges part of [1459]) --- bin/bbackupd/BackupDaemon.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index a56003d1..894d6b1f 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -74,6 +74,7 @@ #include "Archive.h" #include "Timer.h" #include "Logging.h" +#include "autogen_ClientException.h" #include "MemLeakFindOn.h" @@ -642,7 +643,19 @@ void BackupDaemon::Run2() // Calculate the sync period of files to examine box_time_t syncPeriodStart = lastSyncTime; - box_time_t syncPeriodEnd = currentSyncStartTime - minimumFileAge; + box_time_t syncPeriodEnd = currentSyncStartTime - + minimumFileAge; + + if(syncPeriodStart >= syncPeriodEnd) + { + BOX_ERROR("Invalid (negative) sync period: " + "perhaps your clock is going " + "backwards (" << syncPeriodStart << + " to " << syncPeriodEnd << ")"); + THROW_EXCEPTION(ClientException, + ClockWentBackwards); + } + // Check logic ASSERT(syncPeriodEnd > syncPeriodStart); // Paranoid check on sync times @@ -669,10 +682,8 @@ void BackupDaemon::Run2() BOX_ERROR("Failed to delete the " "StoreObjectInfoFile, backup cannot " "continue safely."); - // prevent runaway process where the logs fill up -- without this - // the log message will be emitted in a tight loop. - ::sleep(60); - continue; + THROW_EXCEPTION(ClientException, + FailedToDeleteStoreObjectInfoFile); } // In case the backup throws an exception, @@ -836,6 +847,7 @@ void BackupDaemon::Run2() BOX_ERROR("Internal error during " "backup run: " << e.what()); errorOccurred = true; + errorString = e.what(); } catch(...) { @@ -2215,7 +2227,7 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) else { // there is something going on here - THROW_EXCEPTION(CommonException, Internal) + THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile); } // @@ -2240,7 +2252,7 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) else { // there is something going on here - THROW_EXCEPTION(CommonException, Internal) + THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile); } // @@ -2265,7 +2277,7 @@ void BackupDaemon::Location::Deserialize(Archive &rArchive) else { // there is something going on here - THROW_EXCEPTION(CommonException, Internal) + THROW_EXCEPTION(ClientException, CorruptStoreObjectInfoFile); } } -- cgit v1.2.3 From 0a27e02fbc371d46a66e128100935d488eb4d472 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:14:27 +0000 Subject: Better handle a case where a force-sync command comes in immediately after (or during) a sync, i.e. less than MinimumFileAge seconds after the last one. In this case, just move back the syncPeriodStart by 1 second. (refs #3, merges part if [1459]) --- bin/bbackupd/BackupDaemon.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 894d6b1f..a24d7824 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -646,6 +646,18 @@ void BackupDaemon::Run2() box_time_t syncPeriodEnd = currentSyncStartTime - minimumFileAge; + if(syncPeriodStart >= syncPeriodEnd && + syncPeriodStart - syncPeriodEnd < minimumFileAge) + { + // This can happen if we receive a force-sync + // command less than minimumFileAge after + // the last sync. Deal with it by moving back + // syncPeriodStart, which should not do any + // damage. + syncPeriodStart = syncPeriodEnd - + SecondsToBoxTime(1); + } + if(syncPeriodStart >= syncPeriodEnd) { BOX_ERROR("Invalid (negative) sync period: " -- cgit v1.2.3 From c8f1f7f46616be81b4b6ec679ea5228e5a03ac7c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:16:58 +0000 Subject: Reformat long lines for readability. (refs #3, merges remainder of [1459]) --- bin/bbackupd/BackupDaemon.cpp | 169 ++++++++++++++++++++++++++++++------------ 1 file changed, 122 insertions(+), 47 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index a24d7824..370535fa 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -579,38 +579,64 @@ void BackupDaemon::Run2() box_time_t currentTime; do { - // Need to check the stop run thing here too, so this loop isn't run if we should be stopping + // Check whether we should be stopping, + // and don't run a sync if so. if(StopRun()) break; currentTime = GetCurrentBoxTime(); - // Pause a while, but no more than MAX_SLEEP_TIME seconds (use the conditional because times are unsigned) - box_time_t requiredDelay = (nextSyncTime < currentTime)?(0):(nextSyncTime - currentTime); - // If there isn't automatic backup happening, set a long delay. And limit delays at the same time. - if(!automaticBackup || requiredDelay > SecondsToBoxTime(MAX_SLEEP_TIME)) - requiredDelay = SecondsToBoxTime(MAX_SLEEP_TIME); + // Pause a while, but no more than + // MAX_SLEEP_TIME seconds (use the conditional + // because times are unsigned) + box_time_t requiredDelay = + (nextSyncTime < currentTime) + ? (0) + : (nextSyncTime - currentTime); + + // If there isn't automatic backup happening, + // set a long delay. And limit delays at the + // same time. + if(!automaticBackup || requiredDelay > + SecondsToBoxTime(MAX_SLEEP_TIME)) + { + requiredDelay = SecondsToBoxTime( + MAX_SLEEP_TIME); + } - // Only do the delay if there is a delay required + // Only delay if necessary if(requiredDelay > 0) { - // Sleep somehow. There are choices on how this should be done, depending on the state of the control connection + // Sleep somehow. There are choices + // on how this should be done, + // depending on the state of the + // control connection if(mpCommandSocketInfo != 0) { - // A command socket exists, so sleep by handling connections with it - WaitOnCommandSocket(requiredDelay, doSync, doSyncForcedByCommand); + // A command socket exists, + // so sleep by waiting on it + WaitOnCommandSocket( + requiredDelay, doSync, + doSyncForcedByCommand); } else { - // No command socket or connection, just do a normal sleep - time_t sleepSeconds = BoxTimeToSeconds(requiredDelay); - ::sleep((sleepSeconds <= 0)?1:sleepSeconds); + // No command socket or + // connection, just do a + // normal sleep + time_t sleepSeconds = + BoxTimeToSeconds( + requiredDelay); + ::sleep((sleepSeconds <= 0) + ? 1 + : sleepSeconds); } } } while((!automaticBackup || (currentTime < nextSyncTime)) && !doSync && !StopRun()); } - // Time of sync start, and if it's time for another sync (and we're doing automatic syncs), set the flag + // Time of sync start, and if it's time for another sync + // (and we're doing automatic syncs), set the flag box_time_t currentSyncStartTime = GetCurrentBoxTime(); if(automaticBackup && currentSyncStartTime >= nextSyncTime) { @@ -624,12 +650,14 @@ void BackupDaemon::Run2() if(d > 0) { // Script has asked for a delay - nextSyncTime = GetCurrentBoxTime() + SecondsToBoxTime(d); + nextSyncTime = GetCurrentBoxTime() + + SecondsToBoxTime(d); doSync = false; } } - // Ready to sync? (but only if we're not supposed to be stopping) + // Ready to sync? (but only if we're not supposed + // to be stopping) if(doSync && !StopRun()) { // Touch a file to record times in filesystem @@ -673,16 +701,21 @@ void BackupDaemon::Run2() // Paranoid check on sync times if(syncPeriodStart >= syncPeriodEnd) continue; - // Adjust syncPeriodEnd to emulate snapshot behaviour properly + // Adjust syncPeriodEnd to emulate snapshot + // behaviour properly box_time_t syncPeriodEndExtended = syncPeriodEnd; // Using zero min file age? if(minimumFileAge == 0) { - // Add a year on to the end of the end time, to make sure we sync - // files which are modified after the scan run started. - // Of course, they may be eligable to be synced again the next time round, - // but this should be OK, because the changes only upload should upload no data. - syncPeriodEndExtended += SecondsToBoxTime((time_t)(356*24*3600)); + // Add a year on to the end of the end time, + // to make sure we sync files which are + // modified after the scan run started. + // Of course, they may be eligible to be + // synced again the next time round, + // but this should be OK, because the changes + // only upload should upload no data. + syncPeriodEndExtended += SecondsToBoxTime( + (time_t)(356*24*3600)); } // Delete the serialised store object file, @@ -742,13 +775,22 @@ void BackupDaemon::Run2() ); // Set up the sync parameters - BackupClientDirectoryRecord::SyncParams params(*this, *this, clientContext); + BackupClientDirectoryRecord::SyncParams params( + *this, *this, clientContext); params.mSyncPeriodStart = syncPeriodStart; - params.mSyncPeriodEnd = syncPeriodEndExtended; // use potentially extended end time + params.mSyncPeriodEnd = syncPeriodEndExtended; + // use potentially extended end time params.mMaxUploadWait = maxUploadWait; - params.mFileTrackingSizeThreshold = conf.GetKeyValueInt("FileTrackingSizeThreshold"); - params.mDiffingUploadSizeThreshold = conf.GetKeyValueInt("DiffingUploadSizeThreshold"); - params.mMaxFileTimeInFuture = SecondsToBoxTime(conf.GetKeyValueInt("MaxFileTimeInFuture")); + params.mFileTrackingSizeThreshold = + conf.GetKeyValueInt( + "FileTrackingSizeThreshold"); + params.mDiffingUploadSizeThreshold = + conf.GetKeyValueInt( + "DiffingUploadSizeThreshold"); + params.mMaxFileTimeInFuture = + SecondsToBoxTime( + conf.GetKeyValueInt( + "MaxFileTimeInFuture")); clientContext.SetMaximumDiffingTime(maximumDiffingTime); clientContext.SetKeepAliveTime(keepAliveTime); @@ -756,12 +798,17 @@ void BackupDaemon::Run2() // Set store marker clientContext.SetClientStoreMarker(clientStoreMarker); - // Set up the locations, if necessary -- need to do it here so we have a (potential) connection to use + // Set up the locations, if necessary -- + // need to do it here so we have a + // (potential) connection to use if(mLocations.empty()) { - const Configuration &locations(conf.GetSubConfiguration("BackupLocations")); + const Configuration &locations( + conf.GetSubConfiguration( + "BackupLocations")); - // Make sure all the directory records are set up + // Make sure all the directory records + // are set up SetupLocations(clientContext, locations); } @@ -772,16 +819,25 @@ void BackupDaemon::Run2() DeleteUnusedRootDirEntries(clientContext); // Go through the records, syncing them - for(std::vector::const_iterator i(mLocations.begin()); i != mLocations.end(); ++i) + for(std::vector::const_iterator + i(mLocations.begin()); + i != mLocations.end(); ++i) { - // Set current and new ID map pointers in the context + // Set current and new ID map pointers + // in the context clientContext.SetIDMaps(mCurrentIDMaps[(*i)->mIDMapIndex], mNewIDMaps[(*i)->mIDMapIndex]); - // Set exclude lists (context doesn't take ownership) - clientContext.SetExcludeLists((*i)->mpExcludeFiles, (*i)->mpExcludeDirs); + // Set exclude lists (context doesn't + // take ownership) + clientContext.SetExcludeLists( + (*i)->mpExcludeFiles, + (*i)->mpExcludeDirs); // Sync the directory - (*i)->mpDirectoryRecord->SyncDirectory(params, BackupProtocolClientListDirectory::RootDirectory, (*i)->mPath); + (*i)->mpDirectoryRecord->SyncDirectory( + params, + BackupProtocolClientListDirectory::RootDirectory, + (*i)->mPath); // Unset exclude lists (just in case) clientContext.SetExcludeLists(0, 0); @@ -795,13 +851,14 @@ void BackupDaemon::Run2() } else { - // Unset the read error flag, so the error is - // reported again in the future + // Unset the read error flag, so the // error is reported again if it + // happens again mNotificationsSent[NotifyEvent_ReadError] = false; } - // Perform any deletions required -- these are delayed until the end - // to allow renaming to happen neatly. + // Perform any deletions required -- these are + // delayed until the end to allow renaming to + // happen neatly. clientContext.PerformDeletions(); // Close any open connection @@ -818,15 +875,25 @@ void BackupDaemon::Run2() } else { - // The start time of the next run is the end time of this run - // This is only done if the storage limit wasn't exceeded (as things won't have been done properly if it was) + // The start time of the next run is + // the end time of this run. + // This is only done if the storage + // limit wasn't exceeded (as things + // won't have been done properly if + // it was) lastSyncTime = syncPeriodEnd; - // unflag the storage full notify flag so that next time the store is full, and alert will be sent + + // unflag the storage full notify flag + // so that next time the store is full, + // an alert will be sent mNotificationsSent[NotifyEvent_StoreFull] = false; } // Calculate when the next sync run should be - nextSyncTime = currentSyncStartTime + updateStoreInterval + Random::RandomInt(updateStoreInterval >> SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY); + nextSyncTime = currentSyncStartTime + + updateStoreInterval + + Random::RandomInt(updateStoreInterval >> + SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY); // Commit the ID Maps CommitIDMapsAfterSync(); @@ -863,15 +930,22 @@ void BackupDaemon::Run2() } catch(...) { - // TODO: better handling of exceptions here... need to be very careful + // TODO: better handling of exceptions here... + // need to be very careful errorOccurred = true; } if(errorOccurred) { // Is it a berkely db failure? - bool isBerkelyDbFailure = (errorCode == BackupStoreException::ExceptionType - && errorSubCode == BackupStoreException::BerkelyDBFailure); + bool isBerkelyDbFailure = false; + + if (errorCode == BackupStoreException::ExceptionType + && errorSubCode == BackupStoreException::BerkelyDBFailure) + { + isBerkelyDbFailure = true; + } + if(isBerkelyDbFailure) { // Delete corrupt files @@ -879,7 +953,8 @@ void BackupDaemon::Run2() } // Clear state data - syncPeriodStart = 0; // go back to beginning of time + syncPeriodStart = 0; + // go back to beginning of time clientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown; // no store marker, so download everything DeleteAllLocations(); DeleteAllIDMaps(); -- cgit v1.2.3 From d54680e632e0d5b142568e620dde069820a9476d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:35:33 +0000 Subject: Compile fix to [1448] (refs #3) --- lib/common/Timer.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index c5b90ec2..fe565c21 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -262,13 +262,13 @@ Timer::Timer(size_t timeoutSecs) gettimeofday(&tv, NULL); if (timeoutSecs == 0) { - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " initialised for " << timeoutSecs << " secs, will not fire"); } else { - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " initialised for " << timeoutSecs << " secs, to fire at " << (int)(mExpires / 1000000) << "." << @@ -291,7 +291,7 @@ Timer::~Timer() #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " destroyed"); #endif @@ -307,19 +307,19 @@ Timer::Timer(const Timer& rToCopy) gettimeofday(&tv, NULL); if (mExpired) { - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " initialised from timer " << &rToCopy << ", already expired, will not fire"); } else if (mExpires == 0) { - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " initialised from timer " << &rToCopy << ", no expiry, will not fire"); } else { - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " initialised from timer " << &rToCopy << " to fire at " << (int)(mExpires / 1000000) << "." << @@ -340,19 +340,19 @@ Timer& Timer::operator=(const Timer& rToCopy) gettimeofday(&tv, NULL); if (rToCopy.mExpired) { - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " initialised from timer " << &rToCopy << ", already expired, will not fire"); } else if (rToCopy.mExpires == 0) { - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " initialised from timer " << &rToCopy << ", no expiry, will not fire"); } else { - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " initialised from timer " << &rToCopy << " to fire at " << (int)(rToCopy.mExpires / 1000000) << "." << @@ -375,7 +375,7 @@ void Timer::OnExpire() #if !defined NDEBUG && !defined WIN32 struct timeval tv; gettimeofday(&tv, NULL); - BOX_TRACE(tv.tv_secs << "." << tv.tv_usecs << + BOX_TRACE(tv.tv_sec << "." << tv.tv_usec << ": timer " << this << " fired"); #endif -- cgit v1.2.3 From 2634fe0205981c5a7606d1fdc426f966f272c3d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:40:19 +0000 Subject: Move all command socket communications to the worker thread, to avoid deadlocks. Use events, and a message list protected by a critical section, to pass messages between threads. (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 219 ++++++++++++++++++++++++++++-------------- bin/bbackupd/BackupDaemon.h | 5 +- 2 files changed, 153 insertions(+), 71 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 370535fa..9789558f 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -127,6 +127,29 @@ BackupDaemon::BackupDaemon() } #ifdef WIN32 + // Create the event object to signal from main thread to worker + // when new messages are queued to be sent to the command socket. + mhMessageToSendEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(mhMessageToSendEvent == INVALID_HANDLE_VALUE) + { + BOX_ERROR("Failed to create event object: error " << + GetLastError()); + exit(1); + } + + // Create the event object to signal from worker to main thread + // when a command has been received on the command socket. + mhCommandReceivedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(mhCommandReceivedEvent == INVALID_HANDLE_VALUE) + { + BOX_ERROR("Failed to create event object: error " << + GetLastError()); + exit(1); + } + + // Create the critical section to protect the message queue + InitializeCriticalSection(&mMessageQueueLock); + // Create a thread to handle the named pipe HANDLE hThread; unsigned int dwThreadId; @@ -264,7 +287,6 @@ void BackupDaemon::DeleteAllLocations() #ifdef WIN32 void BackupDaemon::RunHelperThread(void) { - this->mReceivedCommandConn = false; mpCommandSocketInfo = new CommandSocketInfo; WinNamedPipeStream& rSocket(mpCommandSocketInfo->mListeningSocket); @@ -322,16 +344,74 @@ void BackupDaemon::RunHelperThread(void) rSocket.Write(summary, summarySize); rSocket.Write("ping\n", 5); + // old queued messages are not useful + EnterCriticalSection(&mMessageQueueLock); + mMessageList.clear(); + ResetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); + IOStreamGetLine readLine(rSocket); std::string command; - while (rSocket.IsConnected() && - readLine.GetLine(command) && - !IsTerminateWanted()) + while (rSocket.IsConnected() && !IsTerminateWanted()) { + HANDLE handles[2]; + handles[0] = mhMessageToSendEvent; + handles[1] = rSocket.GetReadableEvent(); + BOX_TRACE("Received command '" << command << "' over command socket"); + DWORD result = WaitForMultipleObjects( + sizeof(handles)/sizeof(*handles), + handles, FALSE, 1000); + + if(result == 0) + { + ResetEvent(mhMessageToSendEvent); + + EnterCriticalSection(&mMessageQueueLock); + try + { + while (mMessageList.size() > 0) + { + std::string message = *(mMessageList.begin()); + mMessageList.erase(mMessageList.begin()); + printf("Sending '%s' to waiting client... ", message.c_str()); + message += "\n"; + rSocket.Write(message.c_str(), + message.length()); + + printf("done.\n"); + } + } + catch (...) + { + LeaveCriticalSection(&mMessageQueueLock); + throw; + } + LeaveCriticalSection(&mMessageQueueLock); + continue; + } + else if(result == WAIT_TIMEOUT) + { + continue; + } + else if(result != 1) + { + BOX_ERROR("WaitForMultipleObjects returned invalid result " << result); + continue; + } + + if(!readLine.GetLine(command)) + { + BOX_ERROR("Failed to read line"); + continue; + } + + BOX_INFO("Received command " << command << + " from client"); + bool sendOK = false; bool sendResponse = true; bool disconnect = false; @@ -349,6 +429,7 @@ void BackupDaemon::RunHelperThread(void) this->mDoSyncFlagOut = true; this->mSyncIsForcedOut = false; sendOK = true; + SetEvent(mhCommandReceivedEvent); } else if(command == "force-sync") { @@ -356,18 +437,21 @@ void BackupDaemon::RunHelperThread(void) this->mDoSyncFlagOut = true; this->mSyncIsForcedOut = true; sendOK = true; + SetEvent(mhCommandReceivedEvent); } else if(command == "reload") { // Reload the configuration SetReloadConfigWanted(); sendOK = true; + SetEvent(mhCommandReceivedEvent); } else if(command == "terminate") { // Terminate the daemon cleanly SetTerminateWanted(); sendOK = true; + SetEvent(mhCommandReceivedEvent); } else { @@ -390,8 +474,6 @@ void BackupDaemon::RunHelperThread(void) { break; } - - this->mReceivedCommandConn = true; } rSocket.Close(); @@ -411,6 +493,9 @@ void BackupDaemon::RunHelperThread(void) BOX_ERROR("Communication error with control client"); } } + + CloseHandle(mhCommandReceivedEvent); + CloseHandle(mhMessageToSendEvent); } #endif @@ -1123,25 +1208,27 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut) { #ifdef WIN32 - // Really could use some interprocess protection, mutex etc - // any side effect should be too bad???? :) - DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay); + DWORD requiredDelayMs = BoxTimeToMilliSeconds(RequiredDelay); - while ( this->mReceivedCommandConn == false ) - { - Sleep(1); + DWORD result = WaitForSingleObject(mhCommandReceivedEvent, + (DWORD)requiredDelayMs); - if( timeout == 0 ) - { - DoSyncFlagOut = false; - SyncIsForcedOut = false; - return; - } - timeout--; + if(result == WAIT_OBJECT_0) + { + DoSyncFlagOut = this->mDoSyncFlagOut; + SyncIsForcedOut = this->mSyncIsForcedOut; + ResetEvent(mhCommandReceivedEvent); + } + else if(result == WAIT_TIMEOUT) + { + DoSyncFlagOut = false; + SyncIsForcedOut = false; + } + else + { + BOX_ERROR("Unexpected result from WaitForSingleObject: " + "error " << GetLastError()); } - this->mReceivedCommandConn = false; - DoSyncFlagOut = this->mDoSyncFlagOut; - SyncIsForcedOut = this->mSyncIsForcedOut; return; #else // ! WIN32 @@ -1383,10 +1470,6 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) // The bbackupctl program can't rely on a state change, because it // may never change if the server doesn't need to be contacted. -#ifdef __MINGW32__ -#warning race condition: what happens if socket is closed? -#endif - if(mpCommandSocketInfo != NULL && #ifdef WIN32 mpCommandSocketInfo->mListeningSocket.IsConnected() @@ -1395,15 +1478,18 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart) #endif ) { - const char* message = SendStart ? "start-sync\n" : "finish-sync\n"; + std::string message = SendStart ? "start-sync" : "finish-sync"; try { #ifdef WIN32 - mpCommandSocketInfo->mListeningSocket.Write(message, - (int)strlen(message)); + EnterCriticalSection(&mMessageQueueLock); + mMessageList.push_back(message); + SetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); #else - mpCommandSocketInfo->mpConnectedSocket->Write(message, - strlen(message)); + message += "\n"; + mpCommandSocketInfo->mpConnectedSocket->Write( + message.c_str(), message.size()); #endif } catch(std::exception &e) @@ -2033,51 +2119,44 @@ void BackupDaemon::SetState(int State) // command socket if there's an error char newState[64]; - char newStateSize = sprintf(newState, "state %d\n", State); + sprintf(newState, "state %d", State); + std::string message = newState; #ifdef WIN32 - #ifndef _MSC_VER - #warning FIX ME: race condition - #endif + EnterCriticalSection(&mMessageQueueLock); + mMessageList.push_back(newState); + SetEvent(mhMessageToSendEvent); + LeaveCriticalSection(&mMessageQueueLock); +#else + message += "\n"; - // what happens if the socket is closed by the other thread before - // we can write to it? Null pointer deref at best. - if(mpCommandSocketInfo && - mpCommandSocketInfo->mListeningSocket.IsConnected()) + if(mpCommandSocketInfo == 0) { - try - { - mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize); - } - catch(std::exception &e) - { - BOX_ERROR("Internal error while writing state " - "to command socket: " << e.what()); - CloseCommandConnection(); - } - catch(...) - { - CloseCommandConnection(); - } + return; } -#else - if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0) + + if(mpCommandSocketInfo->mpConnectedSocket.get() == 0) { - // Something connected to the command socket, tell it about the new state - try - { - mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize); - } - catch(std::exception &e) - { - BOX_ERROR("Internal error while writing state " - "to command socket: " << e.what()); - CloseCommandConnection(); - } - catch(...) - { - CloseCommandConnection(); - } + return; + } + + // Something connected to the command socket, tell it about the new state + try + { + mpCommandSocketInfo->mpConnectedSocket->Write(message.c_str(), + message.length()); + } + catch(std::exception &e) + { + BOX_ERROR("Internal error while writing state " + "to command socket: " << e.what()); + CloseCommandConnection(); + } + catch(...) + { + BOX_ERROR("Internal error while writing state " + "to command socket: unknown error"); + CloseCommandConnection(); } #endif } diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 64b06949..8895019d 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -346,7 +346,10 @@ public: void RunHelperThread(void); private: - bool mDoSyncFlagOut, mSyncIsForcedOut, mReceivedCommandConn; + bool mDoSyncFlagOut, mSyncIsForcedOut; + HANDLE mhMessageToSendEvent, mhCommandReceivedEvent; + CRITICAL_SECTION mMessageQueueLock; + std::vector mMessageList; #endif }; -- cgit v1.2.3 From cdc320f5b75497c0ac909a36e435110fa1177400 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:41:06 +0000 Subject: Add a quiet mode to compare command, to make test output easier to read. (refs #3, merges [1460]) --- bin/bbackupquery/BackupQueries.cpp | 18 ++++++++++++------ bin/bbackupquery/BackupQueries.h | 1 + 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 1726b960..7ab23441 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -207,7 +207,7 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) { "sh", "" }, { "getobject", "" }, { "get", "i" }, - { "compare", "alcqAE" }, + { "compare", "alcqAEQ" }, { "restore", "dri" }, { "help", "" }, { "usage", "" }, @@ -1114,6 +1114,7 @@ void BackupQueries::CommandCompare(const std::vector &args, const b // Parameters, including count of differences BackupQueries::CompareParams params; params.mQuickCompare = opts['q']; + params.mQuietCompare = opts['Q']; params.mIgnoreExcludes = opts['E']; params.mIgnoreAttributes = opts['A']; @@ -1177,12 +1178,17 @@ void BackupQueries::CommandCompare(const std::vector &args, const b printf("Incorrect usage.\ncompare -a\n or compare -l \n or compare \n"); return; } - - printf("\n[ %d (of %d) differences probably due to file " - "modifications after the last upload ]\n" - "Differences: %d (%d dirs excluded, %d files excluded, " + + if (!params.mQuietCompare) + { + printf("\n[ %d (of %d) differences probably due to file " + "modifications after the last upload ]\n", + params.mDifferencesExplainedByModTime, + params.mDifferences); + } + + printf("Differences: %d (%d dirs excluded, %d files excluded, " "%d files not checked)\n", - params.mDifferencesExplainedByModTime, params.mDifferences, params.mDifferences, params.mExcludedDirs, params.mExcludedFiles, params.mUncheckedFiles); diff --git a/bin/bbackupquery/BackupQueries.h b/bin/bbackupquery/BackupQueries.h index c9540110..b2ef8cc2 100644 --- a/bin/bbackupquery/BackupQueries.h +++ b/bin/bbackupquery/BackupQueries.h @@ -67,6 +67,7 @@ private: ~CompareParams(); void DeleteExcludeLists(); bool mQuickCompare; + bool mQuietCompare; bool mIgnoreExcludes; bool mIgnoreAttributes; int mDifferences; -- cgit v1.2.3 From 718b0a1122e0067187d991b52927c1eeef68ec50 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:41:48 +0000 Subject: Initialise logging framework and set our program name to "Box Backup (bbstored)". (refs #3, merges [1462]) --- bin/bbstored/bbstored.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/bbstored/bbstored.cpp b/bin/bbstored/bbstored.cpp index 3eaf2639..c0ea1199 100644 --- a/bin/bbstored/bbstored.cpp +++ b/bin/bbstored/bbstored.cpp @@ -10,6 +10,7 @@ #include "Box.h" #include "BackupStoreDaemon.h" #include "MainHelper.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -17,6 +18,10 @@ int main(int argc, const char *argv[]) { MAINHELPER_START + Logging::SetProgramName("Box Backup (bbstored)"); + Logging::ToConsole(true); + Logging::ToSyslog (true); + BackupStoreDaemon daemon; return daemon.Main(BOX_FILE_BBSTORED_DEFAULT_CONFIG, argc, argv); -- cgit v1.2.3 From 6085a460fa1943df13188b6def02716a48357b06 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:45:04 +0000 Subject: Use logging framework to remove timer noise for those who don't want it. (refs #3, merges [1448]) --- bin/bbackupd/BackupClientContext.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index 516c88bc..c18bcfd6 100644 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -29,6 +29,7 @@ #include "BackupDaemon.h" #include "autogen_BackupProtocolClient.h" #include "BackupStoreFile.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -499,13 +500,14 @@ bool BackupClientContext::FindFilename(int64_t ObjectID, int64_t ContainingDirec void BackupClientContext::SetMaximumDiffingTime(int iSeconds) { mMaximumDiffingTime = iSeconds < 0 ? 0 : iSeconds; - TRACE1("Set maximum diffing time to %d seconds\n", mMaximumDiffingTime); + BOX_TRACE("Set maximum diffing time to " << mMaximumDiffingTime << + " seconds"); } void BackupClientContext::SetKeepAliveTime(int iSeconds) { mKeepAliveTime = iSeconds < 0 ? 0 : iSeconds; - TRACE1("Set keep-alive time to %d seconds\n", mKeepAliveTime); + BOX_TRACE("Set keep-alive time to " << mKeepAliveTime << " seconds"); mKeepAliveTimer = Timer(mKeepAliveTime); } @@ -563,7 +565,7 @@ void BackupClientContext::DoKeepAlive() return; } - TRACE0("KeepAliveTime reached, sending keep-alive message\n"); + BOX_TRACE("KeepAliveTime reached, sending keep-alive message"); mpConnection->QueryGetIsAlive(); mKeepAliveTimer = Timer(mKeepAliveTime); -- cgit v1.2.3 From 52f1df78c0585f64ce7e3eb17b7903907c92e54d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:48:17 +0000 Subject: Merge new m4 from trunk. (refs #3, merges [1453]) --- infrastructure/m4/ax_check_llong_minmax.m4 | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 infrastructure/m4/ax_check_llong_minmax.m4 diff --git a/infrastructure/m4/ax_check_llong_minmax.m4 b/infrastructure/m4/ax_check_llong_minmax.m4 new file mode 100644 index 00000000..f3f99c53 --- /dev/null +++ b/infrastructure/m4/ax_check_llong_minmax.m4 @@ -0,0 +1,76 @@ +dnl @synopsis AX_CHECK_LLONG_MINMAX +dnl +dnl This macro will fix up LLONG_MIN and LLONG_MAX as appropriate. I'm finding +dnl it quite difficult to believe that so many hoops are necessary. The world +dnl seems to have gone quite mad. +dnl +dnl This gem is adapted from the OpenSSH configure script so here's +dnl the original copyright notice: +dnl +dnl Copyright (c) 1999-2004 Damien Miller +dnl +dnl Permission to use, copy, modify, and distribute this software for any +dnl purpose with or without fee is hereby granted, provided that the above +dnl copyright notice and this permission notice appear in all copies. +dnl +dnl @category C +dnl @author Martin Ebourne and Damien Miller +dnl @version 2005/07/07 + +AC_DEFUN([AX_CHECK_LLONG_MINMAX], [ + AC_CHECK_DECL([LLONG_MAX], [have_llong_max=1], , [[#include ]]) + if test -z "$have_llong_max"; then + AC_MSG_CHECKING([[for max value of long long]]) + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #include + /* Why is this so damn hard? */ + #undef __GNUC__ + #undef __USE_ISOC99 + #define __USE_ISOC99 + #include + #define DATA "conftest.llminmax" + int main(void) { + FILE *f; + long long i, llmin, llmax = 0; + + if((f = fopen(DATA,"w")) == NULL) + exit(1); + + #if defined(LLONG_MIN) && defined(LLONG_MAX) + fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n"); + llmin = LLONG_MIN; + llmax = LLONG_MAX; + #else + fprintf(stderr, "Calculating LLONG_MIN and LLONG_MAX\n"); + /* This will work on one's complement and two's complement */ + for (i = 1; i > llmax; i <<= 1, i++) + llmax = i; + llmin = llmax + 1LL; /* wrap */ + #endif + + /* Sanity check */ + if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax || llmax - 1 > llmax) { + fprintf(f, "unknown unknown\n"); + exit(2); + } + + if (fprintf(f ,"%lld %lld", llmin, llmax) < 0) + exit(3); + + exit(0); + } + ]])], [ + read llong_min llong_max < conftest.llminmax + AC_MSG_RESULT([$llong_max]) + AC_DEFINE_UNQUOTED([LLONG_MAX], [${llong_max}LL], + [max value of long long calculated by configure]) + AC_MSG_CHECKING([[for min value of long long]]) + AC_MSG_RESULT([$llong_min]) + AC_DEFINE_UNQUOTED([LLONG_MIN], [${llong_min}LL], + [min value of long long calculated by configure]) + ], + [AC_MSG_RESULT(not found)], + [AC_MSG_WARN([[cross compiling: not checking]])] + ) + fi + ])dnl -- cgit v1.2.3 From 5381e926eab8d4124f26cac01c5a8690c5bba929 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:50:26 +0000 Subject: Indent cleanup (refs #3) --- lib/intercept/intercept.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/intercept/intercept.cpp b/lib/intercept/intercept.cpp index a4dfcc37..a93a5a3b 100644 --- a/lib/intercept/intercept.cpp +++ b/lib/intercept/intercept.cpp @@ -18,7 +18,7 @@ #include #ifdef HAVE_SYS_UIO_H -#include + #include #endif #include -- cgit v1.2.3 From a5d88b13e3358afeeaf77242d6a8a47c098a5d01 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 24 Mar 2007 23:52:52 +0000 Subject: Added precompiled output from message compiler, for those who don't have it, e.g. using MinGW instead of MSVC. (refs #3, merges [526]) --- lib/win32/MSG00001.bin | Bin 0 -> 32 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 lib/win32/MSG00001.bin diff --git a/lib/win32/MSG00001.bin b/lib/win32/MSG00001.bin new file mode 100755 index 00000000..b4377b85 Binary files /dev/null and b/lib/win32/MSG00001.bin differ -- cgit v1.2.3 From 88b92d7258c02aaed1bd6fc2a3f52912f1ff63ae Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 25 Mar 2007 00:12:01 +0000 Subject: Fix unix path to bbstored (refs #3) --- lib/common/Test.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index f5b5698b..e6a05220 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -358,7 +358,7 @@ inline void TestRemoteProcessMemLeaksFunc(const char *filename, #else #define BBACKUPCTL "../../bin/bbackupctl/bbackupctl" #define BBACKUPD "../../bin/bbackupd/bbackupd" -#define BBSTORED "../../bin/bbackupd/bbstored" +#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); -- cgit v1.2.3 From d34f6ff675a9a5bad93bba8dbdde04b874485947 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 25 Mar 2007 00:15:46 +0000 Subject: Use #defined paths for applications to fix cross unix/win32 compatibility. Fix memory leak. Reformat comments. (refs #3) --- test/backupstore/testbackupstore.cpp | 46 ++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp index da66af60..ca29cdff 100644 --- a/test/backupstore/testbackupstore.cpp +++ b/test/backupstore/testbackupstore.cpp @@ -1684,7 +1684,10 @@ int test3(int argc, const char *argv[]) "testfiles/clientTrustedCAs.pem"); // First, try logging in without an account having been created... just make sure login fails. - int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + + int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -1713,12 +1716,17 @@ int test3(int argc, const char *argv[]) } // Create an account for the test client - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf create 01234567 0 " + "10000B 20000B") == 0); + TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); + TEST_THAT(TestDirExists("testfiles/0_0/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_1/backup/01234567")); TEST_THAT(TestDirExists("testfiles/0_2/backup/01234567")); - TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8); // make sure something is written to it + TEST_THAT(TestGetFileSize("testfiles/accounts.txt") > 8); + // make sure something is written to it TEST_THAT(ServerIsAlive(pid)); @@ -1742,13 +1750,18 @@ int test3(int argc, const char *argv[]) TestRemoteProcessMemLeaks("bbstored.memleaks"); #endif - // Set a new limit on the account -- leave the hard limit high to make sure the target for - // freeing space is the soft limit. - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20000B") == 0); + // Set a new limit on the account -- leave the hard limit + // high to make sure the target for freeing space is the + // soft limit. + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf setlimit 01234567 " + "10B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Start things up - pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); + ::sleep(1); TEST_THAT(ServerIsAlive(pid)); @@ -1764,8 +1777,9 @@ int test3(int argc, const char *argv[]) // Count the objects again recursive_count_objects_results after = {0,0,0}; - recursive_count_objects("localhost", BackupProtocolClientListDirectory::RootDirectory, after); -printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after.deleted, after.old); + recursive_count_objects("localhost", + BackupProtocolClientListDirectory::RootDirectory, + after); // If these tests fail then try increasing the timeout above TEST_THAT(after.objectsNotDel == before.objectsNotDel); @@ -1773,7 +1787,9 @@ printf("after.objectsNotDel=%i, deleted=%i, old=%i\n",after.objectsNotDel, after TEST_THAT(after.old == 0); // Set a really small hard limit - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 20B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf setlimit 01234567 " + "10B 20B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Try to upload a file and create a directory, and check an error is generated @@ -1837,11 +1853,16 @@ int multi_server() printf("Starting server for connection from remote machines...\n"); // Create an account for the test client - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 30000B 40000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf create 01234567 0 " + "30000B 40000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // First, try logging in without an account having been created... just make sure login fails. - int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored_multi.conf", "testfiles/bbstored.pid"); + + int pid = LaunchServer(BBSTORED " testfiles/bbstored_multi.conf", + "testfiles/bbstored.pid"); + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -1900,6 +1921,7 @@ int test(int argc, const char *argv[]) CloseHandle(h2); CloseHandle(h1); + delete [] wfile; h1 = openfile("foo", O_CREAT | O_RDWR, 0); TEST_THAT(h1 != INVALID_HANDLE_VALUE); -- cgit v1.2.3 From fb4e179a2f4440f25f379a23c0d94744d34c4f66 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 25 Mar 2007 00:37:54 +0000 Subject: Fix spurious/suprious typos. Use #defined paths for executables to remove win32/unix differences. Don't check for bbstored memory leaks on win32. Wrap long lines for readability. (refs #3) --- test/backupstorefix/testbackupstorefix.cpp | 92 ++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp index dd8251c5..318bea47 100644 --- a/test/backupstorefix/testbackupstorefix.cpp +++ b/test/backupstorefix/testbackupstorefix.cpp @@ -43,7 +43,7 @@ make some BackupDirectoryStore objects, CheckAndFix(), then verify - all old flags delete store info -add suprious file +add spurious file delete directory (should appear again) change container ID of directory delete a file @@ -66,8 +66,8 @@ std::map nameToID; std::map objectIsDir; #define RUN_CHECK \ - ::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf check 01234567"); \ - ::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf check 01234567 fix"); + ::system(BBSTOREACCOUNTS " -c testfiles/bbstored.conf check 01234567"); \ + ::system(BBSTOREACCOUNTS " -c testfiles/bbstored.conf check 01234567 fix"); // Get ID of an object given a filename int32_t getID(const char *name) @@ -265,7 +265,7 @@ void test_dir_fixing() TEST_THAT(dir.CheckAndFix() == false); check_dir_dep(dir, c1); - // Check that a suprious depends older ref is undone + // Check that a spurious depends older ref is undone e2->SetDependsOlder(1); TEST_THAT(dir.CheckAndFix() == true); TEST_THAT(dir.CheckAndFix() == false); @@ -290,37 +290,52 @@ int test(int argc, const char *argv[]) rcontroller.Initialise("testfiles/raidfile.conf"); // Create an account - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 10000B 20000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf " + "create 01234567 0 10000B 20000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Start the bbstored server - int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); TEST_THAT(pid != -1 && pid != 0); + if(pid > 0) { ::sleep(1); TEST_THAT(ServerIsAlive(pid)); // Run the perl script to create the initial directories - TEST_THAT_ABORTONFAIL(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl init") == 0); + TEST_THAT_ABORTONFAIL(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl init") == 0); - int bbackupd_pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); + int bbackupd_pid = LaunchServer(BBACKUPD + " testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); + if(bbackupd_pid > 0) { ::sleep(1); TEST_THAT(ServerIsAlive(bbackupd_pid)); // Create a nice store directory - wait_for_operation(30); + wait_for_operation(14); // That'll do nicely, stop the server - TEST_THAT(KillServer(bbackupd_pid)); - TestRemoteProcessMemLeaks("bbackupd.memleaks"); + #ifdef WIN32 + terminate_bbackupd(bbackupd_pid); + // implicit check for memory leaks + #else + TEST_THAT(KillServer(bbackupd_pid)); + TestRemoteProcessMemLeaks("bbackupd.memleaks"); + #endif } // Generate a list of all the object IDs - TEST_THAT_ABORTONFAIL(::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf \"list -r\" quit > testfiles/initial-listing.txt") == 0); + TEST_THAT_ABORTONFAIL(::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf \"list -r\" quit " + "> testfiles/initial-listing.txt") == 0); + // And load it in { FILE *f = ::fopen("testfiles/initial-listing.txt", "r"); @@ -331,7 +346,8 @@ int test(int argc, const char *argv[]) char name[256]; while(::fgets(line, sizeof(line), f) != 0) { - TEST_THAT(::sscanf(line, "%x %s %s", &id, flags, name) == 3); + TEST_THAT(::sscanf(line, "%x %s %s", &id, + flags, name) == 3); bool isDir = (::strcmp(flags, "-d---") == 0); //TRACE3("%x,%d,%s\n", id, isDir, name); MEMLEAKFINDER_NO_LEAKS; @@ -349,19 +365,24 @@ int test(int argc, const char *argv[]) del.Delete(); } { - // Add a suprious file - RaidFileWrite random(discSetNum, storeRoot + "randomfile"); + // Add a spurious file + RaidFileWrite random(discSetNum, + storeRoot + "randomfile"); random.Open(); random.Write("test", 4); random.Commit(true); } + // Fix it RUN_CHECK + // Check everything is as it was - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 0") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 0") == 0); // Check the random file doesn't exist { - TEST_THAT(!RaidFileRead::FileExists(discSetNum, storeRoot + "01/randomfile")); + TEST_THAT(!RaidFileRead::FileExists(discSetNum, + storeRoot + "01/randomfile")); } // ------------------------------------------------------------------------------------------------ @@ -401,6 +422,8 @@ int test(int argc, const char *argv[]) file_BlockIndexEntry e[2]; } h; TEST_THAT(file->Read(&h, sizeof(h)) == sizeof(h)); + file->Close(); + // Modify TEST_THAT(box_ntoh64(h.hdr.mOtherFileID) == 0); TEST_THAT(box_ntoh64(h.hdr.mNumBlocks) >= 2); @@ -416,7 +439,9 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 1") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 1") + == 0); // Check the modified file doesn't exist TEST_THAT(!RaidFileRead::FileExists(discSetNum, fn)); @@ -431,7 +456,7 @@ int test(int argc, const char *argv[]) SaveDirectory("Test1/foreomizes/stemptinevidate/ict", dir); } int64_t duplicatedID = 0; - int64_t notSupriousFileSize = 0; + int64_t notSpuriousFileSize = 0; { BackupStoreDirectory dir; LoadDirectory("Test1/cannes/ict/peep", dir); @@ -449,7 +474,7 @@ int test(int argc, const char *argv[]) BackupStoreDirectory::Iterator i(dir); BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File); TEST_THAT(en != 0); - notSupriousFileSize = en->GetSizeInBlocks(); + notSpuriousFileSize = en->GetSizeInBlocks(); en->SetSizeInBlocks(3473874); TEST_THAT(en->GetSizeInBlocks() == 3473874); } @@ -462,7 +487,8 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check everything is as it should be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 2") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 2") == 0); { BackupStoreDirectory dir; LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir); @@ -488,7 +514,7 @@ int test(int argc, const char *argv[]) BackupStoreDirectory::Iterator i(dir); BackupStoreDirectory::Entry *en = i.Next(BackupStoreDirectory::Entry::Flags_File); TEST_THAT(en != 0); - TEST_THAT(en->GetSizeInBlocks() == notSupriousFileSize); + TEST_THAT(en->GetSizeInBlocks() == notSpuriousFileSize); } } @@ -518,7 +544,8 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check everything is as it should be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 3") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 3") == 0); { BackupStoreDirectory dir; LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir); @@ -532,18 +559,22 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check everything is where it is predicted to be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 4") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 4") == 0); // ------------------------------------------------------------------------------------------------ ::printf(" === Corrupt file and dir\n"); // File - CorruptObject("Test1/foreomizes/stemptinevidate/algoughtnerge", 33, "34i729834298349283479233472983sdfhasgs"); + CorruptObject("Test1/foreomizes/stemptinevidate/algoughtnerge", + 33, "34i729834298349283479233472983sdfhasgs"); // Dir - CorruptObject("Test1/cannes/imulatrougge/foreomizes", 23, "dsf32489sdnadf897fd2hjkesdfmnbsdfcsfoisufio2iofe2hdfkjhsf"); + CorruptObject("Test1/cannes/imulatrougge/foreomizes",23, + "dsf32489sdnadf897fd2hjkesdfmnbsdfcsfoisufio2iofe2hdfkjhsf"); // Fix it RUN_CHECK // Check everything is where it should be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl check 5") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl check 5") == 0); // ------------------------------------------------------------------------------------------------ ::printf(" === Overwrite root with a file\n"); @@ -557,13 +588,16 @@ int test(int argc, const char *argv[]) // Fix it RUN_CHECK // Check everything is where it should be - TEST_THAT(::system(PERL_EXECUTABLE " testfiles/testbackupstorefix.pl reroot 6") == 0); + TEST_THAT(::system(PERL_EXECUTABLE + " testfiles/testbackupstorefix.pl reroot 6") == 0); // ------------------------------------------------------------------------------------------------ // Stop server TEST_THAT(KillServer(pid)); - TestRemoteProcessMemLeaks("bbstored.memleaks"); + #ifndef WIN32 + TestRemoteProcessMemLeaks("bbstored.memleaks"); + #endif } return 0; -- cgit v1.2.3 From 31b785a3d39a2cb0723cee52091def603ba7ebd6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 25 Mar 2007 00:42:41 +0000 Subject: Use #defined paths for executables to remove win32/unix differences. (refs #3) --- test/backupstorepatch/testbackupstorepatch.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp index 6b93a3aa..4fbf296a 100644 --- a/test/backupstorepatch/testbackupstorepatch.cpp +++ b/test/backupstorepatch/testbackupstorepatch.cpp @@ -310,9 +310,8 @@ int test(int argc, const char *argv[]) "testfiles/clientTrustedCAs.pem"); // Create an account - TEST_THAT_ABORTONFAIL(RunCommand( - "../../bin/bbstoreaccounts/bbstoreaccounts " - "-c testfiles/bbstored.conf " + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS + " -c testfiles/bbstored.conf " "create 01234567 0 30000B 40000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); @@ -323,7 +322,8 @@ int test(int argc, const char *argv[]) test_depends_in_dirs(); // First, try logging in without an account having been created... just make sure login fails. - int pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { -- cgit v1.2.3 From e38812f20e0c86b147e330d1d158b3b828c97ffe Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 25 Mar 2007 00:49:16 +0000 Subject: Close RaidFile before committing, so that commit can work on win32. Typo fix. (refs #3) --- test/backupstorefix/testbackupstorefix.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/backupstorefix/testbackupstorefix.cpp b/test/backupstorefix/testbackupstorefix.cpp index 318bea47..97ff70f3 100644 --- a/test/backupstorefix/testbackupstorefix.cpp +++ b/test/backupstorefix/testbackupstorefix.cpp @@ -125,6 +125,7 @@ void CorruptObject(const char *name, int start, const char *rubbish) w.Write(rubbish, rubbish_len); // Copy rest of file r->CopyStreamTo(w); + r->Close(); // Commit w.Commit(true /* convert now */); } @@ -448,7 +449,7 @@ int test(int argc, const char *argv[]) } // ------------------------------------------------------------------------------------------------ - ::printf(" === Delete directory, change container ID of another, duplicate entry in dir, supurious file size, delete file\n"); + ::printf(" === Delete directory, change container ID of another, duplicate entry in dir, spurious file size, delete file\n"); { BackupStoreDirectory dir; LoadDirectory("Test1/foreomizes/stemptinevidate/ict", dir); -- cgit v1.2.3 From 62da6b0279326d5ab5d63df486e4475878ac4d9c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 25 Mar 2007 00:50:44 +0000 Subject: Allow '/' as a path separator on all platforms, even Win32 (refs #3, merges [1496]) --- lib/backupstore/BackupStoreInfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/backupstore/BackupStoreInfo.cpp b/lib/backupstore/BackupStoreInfo.cpp index ce785dde..3588cc00 100644 --- a/lib/backupstore/BackupStoreInfo.cpp +++ b/lib/backupstore/BackupStoreInfo.cpp @@ -124,7 +124,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 -- cgit v1.2.3 From bbe43660740a2f6fc52bf9a2003f269dee04978d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 25 Mar 2007 01:16:53 +0000 Subject: Win32 fixes (paths to executables, and don't try things that don't work on Windows, like sending HUP signals) (refs #3) --- test/basicserver/testbasicserver.cpp | 194 ++++++++++++++++++++++++++--------- 1 file changed, 147 insertions(+), 47 deletions(-) diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index c56e6a0b..f7ec5e0a 100644 --- a/test/basicserver/testbasicserver.cpp +++ b/test/basicserver/testbasicserver.cpp @@ -431,84 +431,149 @@ int test(int argc, const char *argv[]) } } -//printf("SKIPPING TESTS------------------------\n"); -//goto protocolserver; + //printf("SKIPPING TESTS------------------------\n"); + //goto protocolserver; // Launch a basic server { - int pid = LaunchServer("./test srv1 testfiles/srv1.conf", "testfiles/srv1.pid"); + #ifdef WIN32 + int pid = LaunchServer("test srv1 testfiles\\srv1.conf", + "testfiles\\srv1.pid"); + #else + int pid = LaunchServer("./test srv1 testfiles/srv1.conf", + "testfiles/srv1.pid"); + #endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Check that it's written the expected file - TEST_THAT(TestFileExists("testfiles/srv1.test1")); + TEST_THAT(TestFileExists("testfiles" + DIRECTORY_SEPARATOR "srv1.test1")); TEST_THAT(ServerIsAlive(pid)); + // Move the config file over - TEST_THAT(::rename("testfiles/srv1b.conf", "testfiles/srv1.conf") != -1); - // Get it to reread the config file - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); - // Check that new file exists - TEST_THAT(TestFileExists("testfiles/srv1.test2")); + #ifdef WIN32 + TEST_THAT(::unlink("testfiles/srv1.conf") + != -1); + #endif + TEST_THAT(::rename( + "testfiles" DIRECTORY_SEPARATOR "srv1b.conf", + "testfiles" DIRECTORY_SEPARATOR "srv1.conf") + != -1); + + #ifndef WIN32 + // Get it to reread the config file + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + // Check that new file exists + TEST_THAT(TestFileExists("testfiles" + DIRECTORY_SEPARATOR "srv1.test2")); + #endif // !WIN32 + // Kill it off TEST_THAT(KillServer(pid)); - TestRemoteProcessMemLeaks("generic-daemon.memleaks"); + #ifndef WIN32 + TestRemoteProcessMemLeaks( + "generic-daemon.memleaks"); + #endif // !WIN32 } } // Launch a test forking server { - int pid = LaunchServer("./test srv2 testfiles/srv2.conf", "testfiles/srv2.pid"); + #ifdef WIN32 + int pid = LaunchServer("test srv2 testfiles\\srv2.conf", + "testfiles\\srv2.pid"); + #else + int pid = LaunchServer("./test srv2 testfiles/srv2.conf", + "testfiles/srv2.pid"); + #endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Will it restart? TEST_THAT(ServerIsAlive(pid)); - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + + #ifndef WIN32 + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + #endif // !WIN32 + // Make some connections { SocketStream conn1; conn1.Open(Socket::TypeINET, "localhost", 2003); - SocketStream conn2; - conn2.Open(Socket::TypeUNIX, "testfiles/srv2.sock"); - SocketStream conn3; - conn3.Open(Socket::TypeINET, "localhost", 2003); + + #ifndef WIN32 + SocketStream conn2; + conn2.Open(Socket::TypeUNIX, + "testfiles/srv2.sock"); + SocketStream conn3; + conn3.Open(Socket::TypeINET, + "localhost", 2003); + #endif // !WIN32 + // Quick check that reconnections fail - TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX, "testfiles/srv2.sock");, ServerException, SocketAlreadyOpen); + TEST_CHECK_THROWS(conn1.Open(Socket::TypeUNIX, + "testfiles/srv2.sock");, + ServerException, SocketAlreadyOpen); + // Stuff some data around std::vector conns; conns.push_back(&conn1); - conns.push_back(&conn2); - conns.push_back(&conn3); + + #ifndef WIN32 + conns.push_back(&conn2); + conns.push_back(&conn3); + #endif // !WIN32 Srv2TestConversations(conns); // Implicit close } - // HUP again - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + + #ifndef WIN32 + // HUP again + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + #endif // !WIN32 + // Kill it TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("test-srv2.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks("test-srv2.memleaks"); + #endif // !WIN32 } } // Launch a test SSL server { - int pid = LaunchServer("./test srv3 testfiles/srv3.conf", "testfiles/srv3.pid"); + #ifdef WIN32 + int pid = LaunchServer("test srv3 testfiles\\srv3.conf", + "testfiles\\srv3.pid"); + #else + int pid = LaunchServer("./test srv3 testfiles/srv3.conf", + "testfiles/srv3.pid"); + #endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { // Will it restart? TEST_THAT(ServerIsAlive(pid)); - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + + #ifndef WIN32 + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + #endif + // Make some connections { // SSL library @@ -523,36 +588,63 @@ int test(int argc, const char *argv[]) SocketStreamTLS conn1; conn1.Open(context, Socket::TypeINET, "localhost", 2003); - SocketStreamTLS conn2; - conn2.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock"); - SocketStreamTLS conn3; - conn3.Open(context, Socket::TypeINET, "localhost", 2003); + #ifndef WIN32 + SocketStreamTLS conn2; + conn2.Open(context, Socket::TypeUNIX, + "testfiles/srv3.sock"); + SocketStreamTLS conn3; + conn3.Open(context, Socket::TypeINET, + "localhost", 2003); + #endif + // Quick check that reconnections fail - TEST_CHECK_THROWS(conn1.Open(context, Socket::TypeUNIX, "testfiles/srv3.sock");, ServerException, SocketAlreadyOpen); + TEST_CHECK_THROWS(conn1.Open(context, + Socket::TypeUNIX, + "testfiles/srv3.sock"), + ServerException, SocketAlreadyOpen); + // Stuff some data around std::vector conns; conns.push_back(&conn1); - conns.push_back(&conn2); - conns.push_back(&conn3); + + #ifndef WIN32 + conns.push_back(&conn2); + conns.push_back(&conn3); + #endif + Srv2TestConversations(conns); // Implicit close } - // HUP again - TEST_THAT(HUPServer(pid)); - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + + #ifndef WIN32 + // HUP again + TEST_THAT(HUPServer(pid)); + ::sleep(1); + TEST_THAT(ServerIsAlive(pid)); + #endif + // Kill it TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("test-srv3.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks("test-srv3.memleaks"); + #endif } } //protocolserver: // Launch a test protocol handling server { - int pid = LaunchServer("./test srv4 testfiles/srv4.conf", "testfiles/srv4.pid"); + #ifdef WIN32 + int pid = LaunchServer("test srv4 testfiles\\srv4.conf", + "testfiles\\srv4.pid"); + #else + int pid = LaunchServer("./test srv4 testfiles/srv4.conf", + "testfiles/srv4.pid"); + #endif + TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -561,7 +653,12 @@ int test(int argc, const char *argv[]) // Open a connection to it SocketStream conn; - conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock"); + #ifdef WIN32 + conn.Open(Socket::TypeINET, "localhost", 2003); + #else + conn.Open(Socket::TypeUNIX, + "testfiles/srv4.sock"); + #endif // Create a protocol TestProtocolClient protocol(conn); @@ -624,7 +721,10 @@ int test(int argc, const char *argv[]) TEST_THAT(KillServer(pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("test-srv4.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks("test-srv4.memleaks"); + #endif } } -- cgit v1.2.3 From 7453e503fe10e447ad852375bf2beb2aae0cd86d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 25 Mar 2007 15:53:39 +0000 Subject: Only include headers on systems which have them --- test/bbackupd/testbbackupd.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index ecc942b9..385269a2 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -9,22 +9,33 @@ #include "Box.h" -#include +// do not include MinGW's dirent.h on Win32, +// as we override some of it in lib/win32. + +#ifndef WIN32 + #include +#endif + #include #include #include #include #include -#include #include + +#ifdef HAVE_SYS_WAIT_H + #include +#endif + #ifdef HAVE_SYS_XATTR_H -#include -#include + #include + #include #endif + #include #ifdef HAVE_SYSCALL -#include + #include #endif #include "Test.h" -- cgit v1.2.3 From 906311fbbe8515c0c742eda3a525d32f8c53c00c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 1 Apr 2007 12:44:46 +0000 Subject: Test for restoring to a directory whose parent does not exist (refs #3, merges [517]) --- test/bbackupd/testbbackupd.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 385269a2..58439937 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1353,6 +1353,13 @@ int test_bbackupd() // Make sure you can't restore a restored directory TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-Test1", true /* print progress dots */) == Restore_TargetExists); + // Make sure you can't restore to a nonexistant path + printf("Try to restore to a path that doesn't exist\n"); + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/no-such-path/subdir", + true /* print progress dots */) + == Restore_TargetPathNotFound); + // Find ID of the deleted directory deldirid = GetDirID(protocol, "x1", restoredirid); TEST_THAT(deldirid != 0); -- cgit v1.2.3 From 7eba0435de6484f40f230f61bc05d21ffb610403 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 2 Apr 2007 23:07:03 +0000 Subject: Disable symlink tests on win32. (refs #3, merges part of [623]) --- test/bbackupd/testbbackupd.cpp | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 58439937..e7566488 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -266,6 +266,9 @@ bool attrmatch(const char *f1, const char *f2) // if link, just make sure other file is a link too, and that the link to names match if((s1.st_mode & S_IFMT) == S_IFLNK) { +#ifdef WIN32 + TEST_FAIL_WITH_MESSAGE("No symlinks on win32!") +#else if((s2.st_mode & S_IFMT) != S_IFLNK) return false; char p1[PATH_MAX], p2[PATH_MAX]; @@ -276,6 +279,7 @@ bool attrmatch(const char *f1, const char *f2) p1[p1l] = '\0'; p2[p2l] = '\0'; return strcmp(p1, p2) == 0; +#endif } // modification times @@ -294,12 +298,15 @@ int test_basics() BackupClientFileAttributes t1; t1.ReadAttributes("testfiles/test1"); TEST_THAT(!t1.IsSymLink()); + +#ifndef WIN32 BackupClientFileAttributes t2; t2.ReadAttributes("testfiles/test2"); TEST_THAT(t2.IsSymLink()); // Check that it's actually been encrypted (search for symlink name encoded in it) void *te = ::memchr(t2.GetBuffer(), 't', t2.GetSize() - 3); TEST_THAT(te == 0 || ::memcmp(te, "test", 4) != 0); +#endif BackupClientFileAttributes t3; TEST_CHECK_THROWS(t3.ReadAttributes("doesn't exist"), CommonException, OSFileError); @@ -312,13 +319,20 @@ int test_basics() // Apply attributes to these new files t1.WriteAttributes("testfiles/test1_n"); +#ifdef WIN32 + t1.WriteAttributes("testfiles/test2_n"); +#else t2.WriteAttributes("testfiles/test2_n"); +#endif + +#ifndef WIN32 TEST_CHECK_THROWS(t1.WriteAttributes("testfiles/test1_nXX"), CommonException, OSFileError); TEST_CHECK_THROWS(t3.WriteAttributes("doesn't exist"), BackupStoreException, AttributesNotLoaded); - // Test that atttributes are vaguely similar + // Test that attributes are vaguely similar TEST_THAT(attrmatch("testfiles/test1", "testfiles/test1_n")); TEST_THAT(attrmatch("testfiles/test2", "testfiles/test2_n")); +#endif // Check encryption, and recovery from encryption // First, check that two attributes taken from the same thing have different encrypted values (think IV) @@ -992,9 +1006,11 @@ int test_bbackupd() // Delete a file TEST_THAT(::unlink("testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); +#ifndef WIN32 // New symlink TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/symlink-to-dir") == 0); - +#endif + // Update a file (will be uploaded as a diff) { // Check that the file is over the diffing threshold in the bbstored.conf file @@ -1053,11 +1069,16 @@ int test_bbackupd() // Bad case: delete a file/symlink, replace it with a directory printf("Replace symlink with directory, add new directory\n"); +#ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir") == 0); +#endif TEST_THAT(::mkdir("testfiles/TestDir1/symlink-to-dir", 0755) == 0); TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) == 0); // NOTE: create a file within the directory to avoid deletion by the housekeeping process later +#ifndef WIN32 TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents") == 0); +#endif + wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); TEST_THAT(compareReturnValue == 1*256); @@ -1065,9 +1086,13 @@ int test_bbackupd() // And the inverse, replace a directory with a file/symlink printf("Replace directory with symlink\n"); +#ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents") == 0); +#endif TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0); +#ifndef WIN32 TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); +#endif wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); TEST_THAT(compareReturnValue == 1*256); @@ -1075,9 +1100,13 @@ int test_bbackupd() // And then, put it back to how it was before. printf("Replace symlink with directory (which was a symlink)\n"); +#ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file") == 0); +#endif TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) == 0); +#ifndef WIN32 TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents2") == 0); +#endif wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); TEST_THAT(compareReturnValue == 1*256); @@ -1086,9 +1115,13 @@ int test_bbackupd() // And finally, put it back to how it was before it was put back to how it was before // This gets lots of nasty things in the store with directories over other old directories. printf("Put it all back to how it was\n"); +#ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents2") == 0); +#endif TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0); +#ifndef WIN32 TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); +#endif wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); TEST_THAT(compareReturnValue == 1*256); -- cgit v1.2.3 From 0410cee17471dbced2e755960a22ffbd389c398d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 6 Apr 2007 16:00:46 +0000 Subject: Disable interrupted restore test on Win32 (uses fork) (refs #3, merges part of [623]) --- test/bbackupd/testbbackupd.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index e7566488..73b5ae5f 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -465,6 +465,7 @@ void terminate_on_alarm(int sigraised) abort(); } +#ifndef WIN32 void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) { int pid = 0; @@ -527,6 +528,7 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) } } } +#endif // !WIN32 int start_internal_daemon() { @@ -1514,8 +1516,9 @@ int test_bbackupd() compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); TEST_THAT(compareReturnValue == 2*256); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - - printf("Interrupted restore\n"); + +#ifndef WIN32 + printf("\n==== Interrupted restore\n"); { do_interrupted_restore(context, restoredirid); int64_t resumesize = 0; @@ -1543,6 +1546,7 @@ int test_bbackupd() TEST_THAT(compareReturnValue == 1*256); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } +#endif // !WIN32 printf("Check restore deleted files\n"); { -- cgit v1.2.3 From c62266309264de2981e8887fa94e4be1b1a59dda Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 6 Apr 2007 16:29:33 +0000 Subject: Use the old way to unzip files on win32/cygwin, since the pipe method doesn't seem to work here. (refs #3, merges part of [623]) --- test/bbackupd/testbbackupd.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 73b5ae5f..5ca5cba0 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -972,7 +972,11 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Unpack some more files +#ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/spacetest2.tgz -C testfiles/TestDir1") == 0); +#else TEST_THAT(::system("gzip -d < testfiles/spacetest2.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0); +#endif // Delete a file and a directory TEST_THAT(::unlink("testfiles/TestDir1/spacetest/d1/f3") == 0); TEST_THAT(::system("rm -rf testfiles/TestDir1/spacetest/d3/d4") == 0); @@ -993,7 +997,11 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2")); // unpack the initial files again +#ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test_base.tgz -C testfiles") == 0); +#else TEST_THAT(::system("gzip -d < testfiles/test_base.tgz | ( cd testfiles && tar xf - )") == 0); +#endif // wait for it to do it's stuff wait_for_backup_operation(); @@ -1218,8 +1226,12 @@ int test_bbackupd() // Add some more files // Because the 'm' option is not used, these files will look very old to the daemon. // Lucky it'll upload them then! +#ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test2.tgz -C testfiles") == 0); +#else TEST_THAT(::system("gzip -d < testfiles/test2.tgz | ( cd testfiles && tar xf - )") == 0); ::chmod("testfiles/TestDir1/sub23/dhsfdss/blf.h", 0415); +#endif // Wait and test wait_for_backup_operation(); @@ -1255,7 +1267,12 @@ int test_bbackupd() // Add some files and directories which are marked as excluded printf("Add files and dirs for exclusion test\n"); +#ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/testexclude.tgz -C testfiles") == 0); +#else TEST_THAT(::system("gzip -d < testfiles/testexclude.tgz | ( cd testfiles && tar xf - )") == 0); +#endif + // Wait and test wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3c.log \"compare -ac\" quit"); @@ -1410,7 +1427,11 @@ int test_bbackupd() // Add some more files and modify others // Use the m flag this time so they have a recent modification time +#ifdef WIN32 + TEST_THAT(::system("tar xzvmf testfiles/test3.tgz -C testfiles") == 0); +#else TEST_THAT(::system("gzip -d < testfiles/test3.tgz | ( cd testfiles && tar xmf - )") == 0); +#endif // Wait and test wait_for_backup_operation(); @@ -1617,7 +1638,11 @@ int test(int argc, const char *argv[]) BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys"); // Initial files +#ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test_base.tgz -C testfiles") == 0); +#else TEST_THAT(::system("gzip -d < testfiles/test_base.tgz | ( cd testfiles && tar xf - )") == 0); +#endif // Do the tests -- cgit v1.2.3 From a67a101d016147f2cb2410fd8695dc356cbc443a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 6 Apr 2007 17:08:59 +0000 Subject: Check return value using the macro, because ::system works differently on Windows than on Unix (refs #3, merges part of [623]) --- test/bbackupd/testbbackupd.cpp | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 5ca5cba0..a61d755d 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -984,7 +984,7 @@ int test_bbackupd() // Make sure there are some differences int compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query0a.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 2*256); + TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Put the limit back @@ -1009,7 +1009,7 @@ int test_bbackupd() // Check that the contents of the store are the same as the contents // of the disc (-a = all, -c = give result in return code) compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query1.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); printf("Delete file and update another, create symlink.\n"); @@ -1037,11 +1037,11 @@ int test_bbackupd() // wait for backup daemon to do it's stuff, and compare again wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query2.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Try a quick compare, just for fun compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query2q.log \"compare -acq\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Check that store errors are reported neatly @@ -1091,7 +1091,7 @@ int test_bbackupd() wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // And the inverse, replace a directory with a file/symlink @@ -1105,7 +1105,7 @@ int test_bbackupd() #endif wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // And then, put it back to how it was before. @@ -1119,7 +1119,7 @@ int test_bbackupd() #endif wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // And finally, put it back to how it was before it was put back to how it was before @@ -1134,7 +1134,7 @@ int test_bbackupd() #endif wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // rename an untracked file over an @@ -1159,7 +1159,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf -l testfiles/query3t.log " "\"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(::rename("testfiles/TestDir1/untracked-1", "testfiles/TestDir1/untracked-2") == 0); @@ -1169,7 +1169,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf -l testfiles/query3t.log " "\"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // case which went wrong: rename a tracked file over an @@ -1197,7 +1197,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf -l testfiles/query3u.log " "\"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_THAT(::rename("testfiles/TestDir1/tracked-1", "testfiles/TestDir1/tracked-2") == 0); @@ -1207,7 +1207,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf -l testfiles/query3v.log " "\"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // case which went wrong: rename a tracked file over a deleted file @@ -1215,7 +1215,7 @@ int test_bbackupd() TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3w.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); printf("Add files with old times, update attributes of one to latest time\n"); @@ -1236,7 +1236,7 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Check that modifying files with old timestamps still get added @@ -1262,7 +1262,7 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Add some files and directories which are marked as excluded @@ -1276,10 +1276,10 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3c.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3d.log \"compare -acE\" quit"); - TEST_THAT(compareReturnValue == 2*256); // should find differences + TEST_RETURN(compareReturnValue, 2); // should find differences TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // These tests only work as non-root users. @@ -1300,7 +1300,7 @@ int test_bbackupd() compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); // Check that unreadable files were found - TEST_THAT(compareReturnValue == 3*256); + TEST_RETURN(compareReturnValue, 3); // Check for memory leaks during compare TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1342,7 +1342,7 @@ int test_bbackupd() // Check there's a difference compareReturnValue = ::system("testfiles/extcheck1.pl"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); printf("Keep on continuously updating file, check it is uploaded eventually\n"); @@ -1362,7 +1362,7 @@ int test_bbackupd() fflush(stdout); compareReturnValue = ::system("testfiles/extcheck2.pl"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } @@ -1376,7 +1376,7 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); printf("Restore files and directories\n"); @@ -1399,7 +1399,7 @@ int test_bbackupd() // Compare it compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query10.log \"compare -cE Test1 testfiles/restore-Test1\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Make sure you can't restore a restored directory @@ -1436,7 +1436,7 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query5.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Rename directory @@ -1444,11 +1444,11 @@ int test_bbackupd() TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", "testfiles/TestDir1/renamed-dir") == 0); wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // and again, but with quick flag compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6q.log \"compare -acq\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Rename some files -- one under the threshold, others above @@ -1458,7 +1458,7 @@ int test_bbackupd() TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", "testfiles/TestDir1/find2perl-ren") == 0); wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Check that modifying files with madly in the future timestamps still get added @@ -1483,7 +1483,7 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); printf("Change client store marker\n"); @@ -1535,7 +1535,7 @@ int test_bbackupd() // Wait and test that there *are* differences wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); // little bit longer than usual compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 2*256); + TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); #ifndef WIN32 @@ -1564,7 +1564,7 @@ int test_bbackupd() // Then check it has restored the correct stuff compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query14.log \"compare -cE Test1 testfiles/restore-interrupt\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } #endif // !WIN32 @@ -1584,7 +1584,7 @@ int test_bbackupd() // Do a compare with the now undeleted files compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query11.log \"compare -cE Test1/x1 testfiles/restore-Test1-x1-2\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } @@ -1606,7 +1606,7 @@ int test_bbackupd() // Wait and comapre wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); // little bit longer than usual compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit"); - TEST_THAT(compareReturnValue == 1*256); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Kill it again -- cgit v1.2.3 From 56dbaefb199b9324774fd10151c1280acba98c25 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Apr 2007 20:00:30 +0000 Subject: Added commentary to RaidFileDoesntExist exception. --- lib/raidfile/RaidFileException.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/raidfile/RaidFileException.txt b/lib/raidfile/RaidFileException.txt index 6ad74563..26d3ca4b 100644 --- a/lib/raidfile/RaidFileException.txt +++ b/lib/raidfile/RaidFileException.txt @@ -11,7 +11,8 @@ 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 -- cgit v1.2.3 From 95b988a17f61ca456bf53f24daa8c45aad2ddfb1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Apr 2007 21:13:50 +0000 Subject: Fix erroneous line break. --- lib/raidfile/RaidFileException.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/raidfile/RaidFileException.txt b/lib/raidfile/RaidFileException.txt index 26d3ca4b..c69dc2a2 100644 --- a/lib/raidfile/RaidFileException.txt +++ b/lib/raidfile/RaidFileException.txt @@ -11,8 +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 Error when accessing a -file on the store. Check the store with bbstoreaccounts check. +RaidFileDoesntExist 11 Error when accessing a file on the store. Check the store with bbstoreaccounts check. ErrorOpeningFileForRead 12 FileIsDamagedNotRecoverable 13 InvalidRaidFile 14 -- cgit v1.2.3 From c585fec3d8c28c82892ecf0c802d86f712e35603 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Apr 2007 22:03:09 +0000 Subject: Add a warning that comparing locations with a final directory separator may fail (Stefan Tauner) (refs #3, merges [1512]) --- bin/bbackupquery/BackupQueries.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 7ab23441..0e4a7cd1 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1229,6 +1229,19 @@ void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries: return; } const Configuration &loc(locations.GetSubConfiguration(rLocation.c_str())); + + #ifdef WIN32 + { + std::string path = loc.GetKeyValue("Path"); + if (path.size() > 0 && path[path.size()-1] == + DIRECTORY_SEPARATOR_ASCHAR) + { + fprintf(stderr, "Warning: location '%s' path ends " + "with '%s', compare may fail!", + rLocation, DIRECTORY_SEPARATOR); + } + } + #endif try { -- cgit v1.2.3 From e7a6b4627a28c510a745d191150d0185e2480b6d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Apr 2007 22:08:07 +0000 Subject: Don't log errors or throw exceptions when we get ERROR_NO_DATA, which just means that the pipe is being closed. Treat it as a normal remote close (EOF) instead. Don't log an error if DisconnectNamedPipe tells us that the remote end already closed the pipe (ERROR_PIPE_NOT_CONNECTED). Treat ERR_PIPE_NOT_CONNECTED during pipe reads as EOF as well. Improve logging of pipe errors by including the error message. (refs #3, merges [1458] and [1463]) --- lib/server/WinNamedPipeStream.cpp | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/server/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp index ad5764ec..32ae42f2 100644 --- a/lib/server/WinNamedPipeStream.cpp +++ b/lib/server/WinNamedPipeStream.cpp @@ -373,9 +373,26 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) &NumBytesRead, // number of bytes read NULL)) // not overlapped { + DWORD err = GetLastError(); + Close(); - THROW_EXCEPTION(ConnectionException, - Conn_SocketReadError) + + // 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 + { + ::syslog(LOG_ERR, "Failed to read from " + "control socket: %s", + GetErrorMessage(err).c_str()); + THROW_EXCEPTION(ConnectionException, + Conn_SocketReadError) + } } // Closed for reading at EOF? @@ -426,8 +443,19 @@ void WinNamedPipeStream::Write(const void *pBuffer, int NBytes) ::syslog(LOG_ERR, "Failed to write to control socket: " "%s", GetErrorMessage(err).c_str()); Close(); - THROW_EXCEPTION(ConnectionException, - Conn_SocketWriteError) + + // 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; -- cgit v1.2.3 From 763b9fa1ff5777ad4405c6b52f20b1194f322196 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Apr 2007 22:25:52 +0000 Subject: Rearrange #includes in alphabetical order. (refs #3) --- test/bbackupd/testbbackupd.cpp | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index a61d755d..d4f6a42a 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -38,29 +38,34 @@ #include #endif -#include "Test.h" +#include "BackupClientCryptoKeys.h" #include "BackupClientFileAttributes.h" -#include "CommonException.h" -#include "BackupStoreException.h" -#include "FileModificationTime.h" -#include "autogen_BackupProtocolClient.h" -#include "SSLLib.h" -#include "TLSContext.h" -#include "SocketStreamTLS.h" -#include "BoxPortsAndFiles.h" -#include "BackupStoreConstants.h" -#include "Socket.h" #include "BackupClientRestore.h" +#include "BackupDaemon.h" +#include "BackupDaemonConfigVerify.h" +#include "BackupStoreConstants.h" #include "BackupStoreDirectory.h" -#include "BackupClientCryptoKeys.h" -#include "CollectInBufferStream.h" -#include "Utils.h" +#include "BackupStoreException.h" +#include "BoxPortsAndFiles.h" #include "BoxTime.h" #include "BoxTimeToUnix.h" -#include "BackupDaemon.h" -#include "Timer.h" +#include "CollectInBufferStream.h" +#include "CommonException.h" +#include "Configuration.h" +#include "FileModificationTime.h" #include "FileStream.h" #include "IOStreamGetLine.h" +#include "LocalProcessStream.h" +#include "SSLLib.h" +#include "ServerControl.h" +#include "Socket.h" +#include "SocketStreamTLS.h" +#include "TLSContext.h" +#include "Test.h" +#include "Timer.h" +#include "Utils.h" + +#include "autogen_BackupProtocolClient.h" #include "intercept.h" #include "ServerControl.h" -- cgit v1.2.3 From 8b64e99905ec557863ce218a6dfff1e9159fe75e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 10:52:54 +0000 Subject: Compile fix, always include Test.h (refs #3) --- lib/server/ServerControl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/server/ServerControl.h b/lib/server/ServerControl.h index a8477900..c51dd4e2 100644 --- a/lib/server/ServerControl.h +++ b/lib/server/ServerControl.h @@ -1,12 +1,13 @@ #ifndef SERVER_CONTROL_H #define SERVER_CONTROL_H +#include "Test.h" + #ifdef WIN32 #include "WinNamedPipeStream.h" #include "IOStreamGetLine.h" #include "BoxPortsAndFiles.h" -#include "Test.h" static bool SendCommands(const std::string& rCmd) { -- cgit v1.2.3 From b15fa8a765c40e799b606f00325cd47e89d0c593 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 10:54:25 +0000 Subject: Use #defined constants rather than hard-coded paths for launching programs. (refs #3) --- test/bbackupd/testbbackupd.cpp | 188 +++++++++++++++++++++++++++++++---------- 1 file changed, 144 insertions(+), 44 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index d4f6a42a..885b5107 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -410,15 +410,19 @@ int test_basics() int test_setupaccount() { - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf create 01234567 0 1000B 2000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " + "testfiles/bbstored.conf create 01234567 0 1000B 2000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); return 0; } int test_run_bbstored() { - bbstored_pid = LaunchServer("../../bin/bbstored/bbstored testfiles/bbstored.conf", "testfiles/bbstored.pid"); + bbstored_pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", + "testfiles/bbstored.pid"); + TEST_THAT(bbstored_pid != -1 && bbstored_pid != 0); + if(bbstored_pid > 0) { ::sleep(1); @@ -960,7 +964,8 @@ int test_bbackupd() } #endif // PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE - int pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); + int pid = LaunchServer(BBACKUPD " testfiles/bbackupd.conf", + "testfiles/bbackupd.pid"); TEST_THAT(pid != -1 && pid != 0); if(pid > 0) { @@ -969,11 +974,15 @@ int test_bbackupd() // First, check storage space handling -- wait for file to be uploaded wait_for_backup_operation(); - //TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf info 01234567") == 0); + // Set limit to something very small - // About 28 blocks will be used at this point. bbackupd will only pause if the size used is - // greater than soft limit + 1/3 of (hard - soft). Set small values for limits accordingly. - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 10B 40B") == 0); + // About 28 blocks will be used at this point. bbackupd + // will only pause if the size used is greater than + // soft limit + 1/3 of (hard - soft). Set small values + // for limits accordingly. + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " + "testfiles/bbstored.conf setlimit 01234567 10B 40B") + == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Unpack some more files @@ -988,12 +997,17 @@ int test_bbackupd() wait_for_backup_operation(); // Make sure there are some differences - int compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query0a.log \"compare -ac\" quit"); + int compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query0a.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Put the limit back - TEST_THAT_ABORTONFAIL(::system("../../bin/bbstoreaccounts/bbstoreaccounts -c testfiles/bbstored.conf setlimit 01234567 1000B 2000B") == 0); + TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " + "testfiles/bbstored.conf setlimit 01234567 " + "1000B 2000B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Check that the notify script was run @@ -1011,9 +1025,13 @@ int test_bbackupd() // wait for it to do it's stuff wait_for_backup_operation(); - // Check that the contents of the store are the same as the contents - // of the disc (-a = all, -c = give result in return code) - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query1.log \"compare -ac\" quit"); + // Check that the contents of the store are the same + // as the contents of the disc + // (-a = all, -c = give result in return code) + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query1.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1041,11 +1059,18 @@ int test_bbackupd() // wait for backup daemon to do it's stuff, and compare again wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query2.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query2.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // Try a quick compare, just for fun - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query2q.log \"compare -acq\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query2q.log " + "\"compare -acq\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1095,7 +1120,10 @@ int test_bbackupd() #endif wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3c.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1109,7 +1137,10 @@ int test_bbackupd() TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); #endif wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3d.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1123,7 +1154,10 @@ int test_bbackupd() TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents2") == 0); #endif wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3e.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1138,7 +1172,10 @@ int test_bbackupd() TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); #endif wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3s.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3f.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1162,7 +1199,8 @@ int test_bbackupd() // back up both files wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " - "-c testfiles/bbackupd.conf -l testfiles/query3t.log " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3g.log " "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1172,7 +1210,8 @@ int test_bbackupd() TEST_THAT( TestFileExists("testfiles/TestDir1/untracked-2")); wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " - "-c testfiles/bbackupd.conf -l testfiles/query3t.log " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3g.log " "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1219,7 +1258,10 @@ int test_bbackupd() printf("Rename an existing file over a deleted file\n"); TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3w.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3j.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1240,7 +1282,10 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3k.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1266,7 +1311,10 @@ int test_bbackupd() } // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3l.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1280,11 +1328,21 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3c.log \"compare -ac\" quit"); + + // compare with exclusions, should not find differences + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3m.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3d.log \"compare -acE\" quit"); - TEST_RETURN(compareReturnValue, 2); // should find differences + + // compare without exclusions, should find differences + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3n.log " + "\"compare -acE\" quit"); + TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // These tests only work as non-root users. @@ -1302,7 +1360,10 @@ int test_bbackupd() // Wait and test... wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3o.log " + "\"compare -ac\" quit"); // Check that unreadable files were found TEST_RETURN(compareReturnValue, 3); @@ -1380,7 +1441,10 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query4.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1440,7 +1504,10 @@ int test_bbackupd() // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query5.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query5.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1448,11 +1515,18 @@ int test_bbackupd() printf("Rename directory\n"); TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", "testfiles/TestDir1/renamed-dir") == 0); wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query6.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // and again, but with quick flag - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6q.log \"compare -acq\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query6q.log " + "\"compare -acq\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1462,7 +1536,10 @@ int test_bbackupd() TEST_THAT(rename("testfiles/TestDir1/df324", "testfiles/TestDir1/df324-ren") == 0); TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", "testfiles/TestDir1/find2perl-ren") == 0); wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query6.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1487,7 +1564,10 @@ int test_bbackupd() } // Wait and test wait_for_backup_operation(); - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query3e.log \"compare -ac\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3e.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1528,8 +1608,8 @@ int test_bbackupd() printf("Check change of store marker pauses daemon\n"); - // Make a change to a file, to detect whether or not it's hanging around - // waiting to retry. + // Make a change to a file, to detect whether or not + // it's hanging around waiting to retry. { FILE *f = ::fopen("testfiles/TestDir1/fileaftermarker", "w"); TEST_THAT(f != 0); @@ -1538,8 +1618,12 @@ int test_bbackupd() } // Wait and test that there *are* differences - wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); // little bit longer than usual - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query6.log \"compare -ac\" quit"); + wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION * + 3) / 2); // little bit longer than usual + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query6.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1568,7 +1652,11 @@ int test_bbackupd() protocol.QueryFinished(); // Then check it has restored the correct stuff - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query14.log \"compare -cE Test1 testfiles/restore-interrupt\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query14.log " + "\"compare -cE Test1 " + "testfiles/restore-interrupt\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } @@ -1588,7 +1676,11 @@ int test_bbackupd() protocol.QueryFinished(); // Do a compare with the now undeleted files - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query11.log \"compare -cE Test1/x1 testfiles/restore-Test1-x1-2\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query11.log " + "\"compare -cE Test1/x1 " + "testfiles/restore-Test1-x1-2\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } @@ -1604,13 +1696,20 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbackupd.memleaks"); // Start it again - pid = LaunchServer("../../bin/bbackupd/bbackupd testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); + pid = LaunchServer(BBACKUPD " testfiles/bbackupd.conf", + "testfiles/bbackupd.pid"); + TEST_THAT(pid != -1 && pid != 0); + if(pid != -1 && pid != 0) { - // Wait and comapre - wait_for_backup_operation((TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); // little bit longer than usual - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac\" quit"); + // Wait and compare (a little bit longer than usual) + wait_for_backup_operation( + (TIME_TO_WAIT_FOR_BACKUP_OPERATION*3) / 2); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query4a.log " + "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1623,7 +1722,8 @@ int test_bbackupd() } // List the files on the server - ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/queryLIST.log \"list -rotdh\" quit"); + ::system(BBACKUPQUERY " -q -c testfiles/bbackupd.conf " + "-l testfiles/queryLIST.log \"list -rotdh\" quit"); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); if(::getuid() == 0) -- cgit v1.2.3 From 8f79193f922a0727bcf47d22deef028ae940c846 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 11:12:37 +0000 Subject: Comment out some tests that don't work on Win32 (refs #3) --- test/bbackupd/testbbackupd.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 885b5107..c2c4a3ec 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -438,7 +438,11 @@ int test_kill_bbstored() TEST_THAT(KillServer(bbstored_pid)); ::sleep(1); TEST_THAT(!ServerIsAlive(bbstored_pid)); - TestRemoteProcessMemLeaks("bbstored.memleaks"); + + #ifndef WIN32 + TestRemoteProcessMemLeaks("bbstored.memleaks"); + #endif + return 0; } @@ -1204,6 +1208,10 @@ int test_bbackupd() "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + #ifdef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/untracked-2") + == 0); + #endif TEST_THAT(::rename("testfiles/TestDir1/untracked-1", "testfiles/TestDir1/untracked-2") == 0); TEST_THAT(!TestFileExists("testfiles/TestDir1/untracked-1")); @@ -1243,6 +1251,9 @@ int test_bbackupd() "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + #ifdef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/tracked-2") == 0); + #endif TEST_THAT(::rename("testfiles/TestDir1/tracked-1", "testfiles/TestDir1/tracked-2") == 0); TEST_THAT(!TestFileExists("testfiles/TestDir1/tracked-1")); @@ -1345,6 +1356,7 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); +#ifndef WIN32 // These tests only work as non-root users. if(::getuid() != 0) { @@ -1381,6 +1393,7 @@ int test_bbackupd() ::chmod("testfiles/TestDir1/sub23/read-fail-test-dir", 0770); ::chmod("testfiles/TestDir1/read-fail-test-file", 0770); } +#endif // WIN32 printf("Continuously update file, check isn't uploaded\n"); @@ -1725,11 +1738,14 @@ int test_bbackupd() ::system(BBACKUPQUERY " -q -c testfiles/bbackupd.conf " "-l testfiles/queryLIST.log \"list -rotdh\" quit"); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - - if(::getuid() == 0) - { - ::printf("WARNING: This test was run as root. Some tests have been omitted.\n"); - } + + #ifndef WIN32 + if(::getuid() == 0) + { + ::printf("WARNING: This test was run as root. " + "Some tests have been omitted.\n"); + } + #endif return 0; } -- cgit v1.2.3 From 2a571b61cfd208c7d29c6c4f95c0cf9a47217c3c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 11:16:44 +0000 Subject: Add utility functions for running different types of syncs, set Windows file time (enhanced utimes()), and finding a named entry in a directory on the store. (refs #3) --- test/bbackupd/testbbackupd.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index c2c4a3ec..1390d1df 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -543,6 +543,66 @@ void do_interrupted_restore(const TLSContext &context, int64_t restoredirid) } #endif // !WIN32 +void force_sync() +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "force-sync") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); +} + +void wait_for_sync_start() +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "wait-for-sync") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); +} + +void wait_for_sync_end() +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "wait-for-end") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); +} + +void sync_and_wait() +{ + TEST_THAT(::system(BBACKUPCTL " -q -c testfiles/bbackupd.conf " + "force-sync") == 0); + TestRemoteProcessMemLeaks("bbackupctl.memleaks"); +} + +bool set_file_time(const char* filename, FILETIME creationTime, + FILETIME lastModTime, FILETIME lastAccessTime) +{ + HANDLE handle = openfile(filename, O_RDWR, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + if (handle == INVALID_HANDLE_VALUE) return false; + + BOOL success = SetFileTime(handle, &creationTime, &lastAccessTime, + &lastModTime); + TEST_THAT(success); + + TEST_THAT(CloseHandle(handle)); + return success; +} + +void intercept_setup_delay(const char *filename, unsigned int delay_after, + int delay_ms, int syscall_to_delay); +bool intercept_triggered(); + +int64_t SearchDir(BackupStoreDirectory& rDir, + const std::string& rChildName) +{ + BackupStoreDirectory::Iterator i(rDir); + BackupStoreFilenameClear child(rChildName.c_str()); + BackupStoreDirectory::Entry *en = i.FindMatchingClearName(child); + if (en == 0) return 0; + int64_t id = en->GetObjectID(); + TEST_THAT(id > 0); + TEST_THAT(id != BackupProtocolClientListDirectory::RootDirectory); + return id; +} + int start_internal_daemon() { // ensure that no child processes end up running tests! -- cgit v1.2.3 From 2c0a1804229dacc22eb1aa65c6b18080dbbedfb7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 11:19:06 +0000 Subject: Don't fill in struct dirent.d_ino unless we've detected that it's present on this platform. (refs #3) --- test/bbackupd/testbbackupd.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 1390d1df..17c48d45 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -710,7 +710,11 @@ struct dirent *readdir_test_hook_2(DIR *dir) // fill in the struct dirent appropriately memset(&readdir_test_dirent, 0, sizeof(readdir_test_dirent)); - readdir_test_dirent.d_ino = ++readdir_test_counter; + + #ifdef HAVE_STRUCT_DIRENT_D_INO + readdir_test_dirent.d_ino = ++readdir_test_counter; + #endif + snprintf(readdir_test_dirent.d_name, sizeof(readdir_test_dirent.d_name), "test.%d", readdir_test_counter); -- cgit v1.2.3 From 262688916c54014e03331985ed41fd840dfc8851 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 11:36:57 +0000 Subject: Work around lack of pipe support in Win32 system() command (refs #3) --- test/bbackupd/testbbackupd.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 17c48d45..742a11dd 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -757,8 +757,15 @@ int test_bbackupd() // unpack the files for the initial test TEST_THAT(::system("rm -rf testfiles/TestDir1") == 0); - TEST_THAT(::system("mkdir testfiles/TestDir1") == 0); - TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0); + TEST_THAT(::mkdir("testfiles/TestDir1", 0) == 0); + + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/spacetest1.tgz " + "-C testfiles/TestDir1") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/spacetest1.tgz " + "| ( cd testfiles/TestDir1 && tar xf - )") == 0); + #endif #ifdef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE printf("Skipping intercept-based KeepAlive tests on this platform.\n"); -- cgit v1.2.3 From 8e83d6c0b8eafcad71d006f257a9f54a7565c75a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 11:43:58 +0000 Subject: Enhance test for bbackupd pausing on change of client store marker (refs #3) --- test/bbackupd/testbbackupd.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 742a11dd..fcc2ad47 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1179,9 +1179,30 @@ int test_bbackupd() "testfiles/0_1/backup/01234567/info.rf") == 0); TEST_THAT(::rename("testfiles/0_2/backup/01234567/info.rf.bak", "testfiles/0_2/backup/01234567/info.rf") == 0); - // wait until bbackupd recovers from the exception + + // Check that we DO get errors on compare + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3b.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // Wait until bbackupd recovers from the exception wait_for_backup_operation(100); + // Ensure that the force-upload file gets uploaded, + // meaning that bbackupd recovered + sync_and_wait(); + + // Check that it did get uploaded, and we have no more errors + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3b.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // Bad case: delete a file/symlink, replace it with a directory printf("Replace symlink with directory, add new directory\n"); #ifndef WIN32 -- cgit v1.2.3 From b07526217a86b350296bcbf8cac6388f679efc17 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 11:55:07 +0000 Subject: Compile fix, comment out set_file_time helper function on non-Win32 platforms (refs #3) --- test/bbackupd/testbbackupd.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index fcc2ad47..f7796403 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -571,6 +571,7 @@ void sync_and_wait() TestRemoteProcessMemLeaks("bbackupctl.memleaks"); } +#ifdef WIN32 bool set_file_time(const char* filename, FILETIME creationTime, FILETIME lastModTime, FILETIME lastAccessTime) { @@ -585,6 +586,7 @@ bool set_file_time(const char* filename, FILETIME creationTime, TEST_THAT(CloseHandle(handle)); return success; } +#endif void intercept_setup_delay(const char *filename, unsigned int delay_after, int delay_ms, int syscall_to_delay); -- cgit v1.2.3 From 083cd266c591dd8077f10db8bb53cffc47b8b720 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 18:48:25 +0000 Subject: Test fix: create TestDir1 with a readable mode (refs #3) --- test/bbackupd/testbbackupd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index f7796403..76bec730 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -759,7 +759,7 @@ int test_bbackupd() // unpack the files for the initial test TEST_THAT(::system("rm -rf testfiles/TestDir1") == 0); - TEST_THAT(::mkdir("testfiles/TestDir1", 0) == 0); + TEST_THAT(::mkdir("testfiles/TestDir1", 0777) == 0); #ifdef WIN32 TEST_THAT(::system("tar xzvf testfiles/spacetest1.tgz " -- cgit v1.2.3 From 522a6d30614d2fb87a4b54bdef03bb334fa28c4f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 19:13:35 +0000 Subject: Keep bbackupd pid in a global variable instead of a local one. Stop bbackupd nicely with terminate_bbackupd() instead of killing it, so that we get a memory leak report on Win32. Stop bbackupd and bbstored at end of test if any tests fail. (refs #3) --- test/bbackupd/testbbackupd.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 76bec730..5d2c304c 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -85,6 +85,7 @@ void wait_for_backup_operation(int seconds = TIME_TO_WAIT_FOR_BACKUP_OPERATION) } int bbstored_pid = 0; +int bbackupd_pid = 0; #ifdef HAVE_SYS_XATTR_H bool readxattr_into_map(const char *filename, std::map &rOutput) @@ -1041,14 +1042,15 @@ int test_bbackupd() } #endif // PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE - int pid = LaunchServer(BBACKUPD " testfiles/bbackupd.conf", + bbackupd_pid = LaunchServer(BBACKUPD " testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); - TEST_THAT(pid != -1 && pid != 0); - if(pid > 0) - { - ::sleep(1); - TEST_THAT(ServerIsAlive(pid)); + TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); + + ::sleep(1); + + if(bbackupd_pid > 0) + { // First, check storage space handling -- wait for file to be uploaded wait_for_backup_operation(); @@ -1797,18 +1799,16 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2")); // Kill the daemon - TEST_THAT(KillServer(pid)); - ::sleep(1); - TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("bbackupd.memleaks"); + terminate_bbackupd(bbackupd_pid); // Start it again - pid = LaunchServer(BBACKUPD " testfiles/bbackupd.conf", + bbackupd_pid = LaunchServer(BBACKUPD + " testfiles/bbackupd.conf", "testfiles/bbackupd.pid"); - TEST_THAT(pid != -1 && pid != 0); + TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); - if(pid != -1 && pid != 0) + if(bbackupd_pid != -1 && bbackupd_pid != 0) { // Wait and compare (a little bit longer than usual) wait_for_backup_operation( @@ -1821,10 +1821,7 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Kill it again - TEST_THAT(KillServer(pid)); - ::sleep(1); - TEST_THAT(!ServerIsAlive(pid)); - TestRemoteProcessMemLeaks("bbackupd.memleaks"); + terminate_bbackupd(bbackupd_pid); } } @@ -1871,7 +1868,12 @@ int test(int argc, const char *argv[]) if(r != 0) return r; r = test_bbackupd(); - if(r != 0) return r; + if(r != 0) + { + KillServer(bbackupd_pid); + KillServer(bbstored_pid); + return r; + } test_kill_bbstored(); -- cgit v1.2.3 From 0f5561c0e175e5238c8f3231f06c83d3c7dca451 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Apr 2007 19:18:09 +0000 Subject: Test that filenames containing non-ASCII (8-bit) characters can be backed up and restored, and directories can be changed into and out of, on win32. (refs #3) --- test/bbackupd/testbbackupd.cpp | 300 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 299 insertions(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 5d2c304c..1593e070 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1113,8 +1113,306 @@ int test_bbackupd() "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + +#ifdef WIN32 + printf("\n==== Check that filenames in UTF-8 " + "can be backed up\n"); + + // We have no guarantee that a random Unicode string can be + // represented in the user's character set, so we go the + // other way, taking three random characters from the + // character set and converting them to Unicode. + // + // We hope that these characters are valid in most + // character sets, but they probably are not in multibyte + // character sets such as Shift-JIS, GB2312, etc. This test + // will probably fail if your system locale is set to + // Chinese, Japanese, etc. where one of these character + // sets is used by default. You can check the character + // set for your system in Control Panel -> Regional + // Options -> General -> Language Settings -> Set Default + // (System Locale). Because bbackupquery converts from + // system locale to UTF-8 via the console code page + // (which you can check from the Command Prompt with "chcp") + // they must also be valid in your code page (850 for + // Western Europe). + // + // In ISO-8859-1 (Danish locale) they are three Danish + // accented characters, which are supported in code page + // 850. Depending on your locale, YYMV (your yak may vomit). + + std::string foreignCharsNative("\x91\x9b\x86"); + std::string foreignCharsUnicode; + TEST_THAT(ConvertConsoleToUtf8(foreignCharsNative.c_str(), + foreignCharsUnicode)); + + std::string basedir("testfiles/TestDir1"); + std::string dirname("test" + foreignCharsUnicode + "testdir"); + std::string dirpath(basedir + "/" + dirname); + TEST_THAT(mkdir(dirpath.c_str(), 0) == 0); + + std::string filename("test" + foreignCharsUnicode + "testfile"); + std::string filepath(dirpath + "/" + filename); + + char cwdbuf[1024]; + TEST_THAT(getcwd(cwdbuf, sizeof(cwdbuf)) == cwdbuf); + std::string cwd = cwdbuf; + + // Test that our emulated chdir() works properly + // with relative and absolute paths + TEST_THAT(::chdir(dirpath.c_str()) == 0); + TEST_THAT(::chdir("../../..") == 0); + TEST_THAT(::chdir(cwd.c_str()) == 0); + + // Check that it can be converted to the system encoding + // (which is what is needed on the command line) + std::string systemDirName; + TEST_THAT(ConvertEncoding(dirname.c_str(), CP_UTF8, + systemDirName, CP_ACP)); + + std::string systemFileName; + TEST_THAT(ConvertEncoding(filename.c_str(), CP_UTF8, + systemFileName, CP_ACP)); + + // Check that it can be converted to the console encoding + // (which is what we will see in the output) + std::string consoleDirName; + TEST_THAT(ConvertUtf8ToConsole(dirname.c_str(), + consoleDirName)); + + std::string consoleFileName; + TEST_THAT(ConvertUtf8ToConsole(filename.c_str(), + consoleFileName)); + + // test that bbackupd will let us lcd into the local + // directory using a relative path + std::string command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "\"lcd testfiles/TestDir1/" + systemDirName + "\" " + "quit"; + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + + // and back out again + command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "\"lcd testfiles/TestDir1/" + systemDirName + "\" " + "\"lcd ..\" quit"; + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + + // and using an absolute path + command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "\"lcd " + cwd + "/testfiles/TestDir1/" + + systemDirName + "\" quit"; + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + + // and back out again + command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "\"lcd " + cwd + "/testfiles/TestDir1/" + + systemDirName + "\" " + "\"lcd ..\" quit"; + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + + { + FileStream fs(filepath.c_str(), O_CREAT | O_RDWR); + + std::string data("hello world\n"); + fs.Write(data.c_str(), data.size()); + TEST_THAT(fs.GetPosition() == 12); + fs.Close(); + } + + wait_for_backup_operation(); + // Compare to check that the file was uploaded + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf \"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // Check that we can find it in directory listing + { + SocketStreamTLS conn; + conn.Open(context, Socket::TypeINET, "localhost", + BOX_PORT_BBSTORED); + BackupProtocolClient protocol(conn); + protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); + protocol.QueryLogin(0x01234567, 0); + + int64_t rootDirId = BackupProtocolClientListDirectory + ::RootDirectory; + std::auto_ptr dirreply( + protocol.QueryListDirectory( + rootDirId, false, 0, false)); + std::auto_ptr dirstream( + protocol.ReceiveStream()); + BackupStoreDirectory dir; + dir.ReadFromStream(*dirstream, protocol.GetTimeout()); + + int64_t baseDirId = SearchDir(dir, "Test1"); + TEST_THAT(baseDirId != 0); + dirreply = protocol.QueryListDirectory(baseDirId, + false, 0, false); + dirstream = protocol.ReceiveStream(); + dir.ReadFromStream(*dirstream, protocol.GetTimeout()); + + int64_t testDirId = SearchDir(dir, dirname.c_str()); + TEST_THAT(testDirId != 0); + dirreply = protocol.QueryListDirectory(testDirId, + false, 0, false); + dirstream = protocol.ReceiveStream(); + dir.ReadFromStream(*dirstream, protocol.GetTimeout()); - printf("Delete file and update another, create symlink.\n"); + TEST_THAT(SearchDir(dir, filename.c_str()) != 0); + // Log out + protocol.QueryFinished(); + } + + + // Check that bbackupquery shows the dir in console encoding + command = BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-q \"list Test1\" quit"; + pid_t bbackupquery_pid; + std::auto_ptr queryout; + queryout = LocalProcessStream(command.c_str(), + bbackupquery_pid); + TEST_THAT(queryout.get() != NULL); + TEST_THAT(bbackupquery_pid != -1); + + IOStreamGetLine reader(*queryout); + std::string line; + bool found = false; + while (!reader.IsEOF()) + { + TEST_THAT(reader.GetLine(line)); + if (line.find(consoleDirName) != std::string::npos) + { + found = true; + } + } + TEST_THAT(!(queryout->StreamDataLeft())); + TEST_THAT(reader.IsEOF()); + TEST_THAT(found); + queryout->Close(); + + // Check that bbackupquery can list the dir when given + // on the command line in system encoding, and shows + // the file in console encoding + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"list Test1/" + systemDirName + "\" quit"; + queryout = LocalProcessStream(command.c_str(), + bbackupquery_pid); + TEST_THAT(queryout.get() != NULL); + TEST_THAT(bbackupquery_pid != -1); + + IOStreamGetLine reader2(*queryout); + found = false; + while (!reader2.IsEOF()) + { + TEST_THAT(reader2.GetLine(line)); + if (line.find(consoleFileName) != std::string::npos) + { + found = true; + } + } + TEST_THAT(!(queryout->StreamDataLeft())); + TEST_THAT(reader2.IsEOF()); + TEST_THAT(found); + queryout->Close(); + + // Check that bbackupquery can compare the dir when given + // on the command line in system encoding. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1/" + systemDirName + + " testfiles/TestDir1/" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 1); + + // Check that bbackupquery can restore the dir when given + // on the command line in system encoding. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"restore Test1/" + systemDirName + + " testfiles/restore-" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 0); + + // Compare to make sure it was restored properly. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1/" + systemDirName + + " testfiles/restore-" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 1); + + std::string fileToUnlink = "testfiles/restore-" + + dirname + "/" + filename; + TEST_THAT(::unlink(fileToUnlink.c_str()) == 0); + + // Check that bbackupquery can get the file when given + // on the command line in system encoding. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"get Test1/" + systemDirName + "/" + + systemFileName + " " + "testfiles/restore-" + + systemDirName + "/" + systemFileName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // And after changing directory to a relative path + command = BBACKUPQUERY " -c testfiles/bbackupd.conf -q " + "\"lcd testfiles\" " + "\"cd Test1/" + systemDirName + "\" " + + "\"get " + systemFileName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks"); + + // cannot overwrite a file that exists, so delete it + std::string tmp = "testfiles/" + filename; + TEST_THAT(::unlink(tmp.c_str()) == 0); + + // And after changing directory to an absolute path + command = BBACKUPQUERY " -c testfiles/bbackupd.conf -q " + "\"lcd " + cwd + "/testfiles\" " + "\"cd Test1/" + systemDirName + "\" " + + "\"get " + systemFileName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TEST_RETURN(compareReturnValue, 0); + TestRemoteProcessMemLeaks("testfiles/bbackupquery.memleaks"); + + // Compare to make sure it was restored properly. + // The Get command does not restore attributes, so + // we must compare without them (-A) to succeed. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"compare -cAEQ Test1/" + systemDirName + + " testfiles/restore-" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 1); + + // Compare without attributes. This should fail. + command = BBACKUPQUERY " -c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1/" + systemDirName + + " testfiles/restore-" + systemDirName + "\" quit"; + + compareReturnValue = ::system(command.c_str()); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_RETURN(compareReturnValue, 2); +#endif // WIN32 // Delete a file TEST_THAT(::unlink("testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); -- cgit v1.2.3 From c46531bae61f86f8404d6a161fccfdc0b441f574 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:00:50 +0000 Subject: Detect whether getopt.h is present on system. (refs #3) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4294658c..e52ba99f 100644 --- a/configure.ac +++ b/configure.ac @@ -102,7 +102,7 @@ esac AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([dlfcn.h execinfo.h process.h pwd.h signal.h]) +AC_CHECK_HEADERS([dlfcn.h execinfo.h getopt.h process.h pwd.h signal.h]) AC_CHECK_HEADERS([syslog.h time.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h]) -- cgit v1.2.3 From 20331e780ae21430dd3e9f9edc684cf6a94d481b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:02:08 +0000 Subject: Pass all arguments from test scripts to test executable with proper quoting (refs #3) --- infrastructure/makebuildenv.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index 9d641d78..04bce787 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -445,9 +445,9 @@ __E } writetestfile("$mod/_t", "GLIBCXX_FORCE_NEW=1 ". - './test' . $platform_exe_ext . ' $1 $2 $3 $4 $5', $mod); + './test' . $platform_exe_ext . ' "$@"', $mod); writetestfile("$mod/_t-gdb", "GLIBCXX_FORCE_NEW=1 ". - 'gdb ./test' . $platform_exe_ext . ' $*', $mod); + 'gdb ./test' . $platform_exe_ext . ' "$@"', $mod); } -- cgit v1.2.3 From 5cf9d57447c66eb4b286fea39ebbe0731f0f8084 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:05:55 +0000 Subject: Declare global std::string variables that hold extra arguments for executables run in tests, to be implemented in a follow-up patch. ConvertPaths, LaunchServer and RunCommand all take std::string references instead of char*. Move safe_sleep from test/common to lib/server/Test.h so that all tests can use it. (refs #3) --- lib/common/Test.h | 41 +++++++++++++++++++++++++---------------- test/common/testcommon.cpp | 9 --------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index e6a05220..e485f2ee 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -25,6 +25,7 @@ extern int failures; extern int first_fail_line; extern std::string first_fail_file; +extern std::string bbackupd_args, bbstored_args, bbackupquery_args; #define TEST_FAIL_WITH_MESSAGE(msg) \ { \ @@ -92,34 +93,33 @@ inline int TestGetFileSize(const char *Filename) return -1; } -inline std::string ConvertPaths(const char *pCommandLine) +inline std::string ConvertPaths(const std::string& rOriginal) { #ifdef WIN32 // convert UNIX paths to native - std::string command; - for (int i = 0; pCommandLine[i] != 0; i++) + std::string converted; + for (int i = 0; i < rOriginal.size(); i++) { - if (pCommandLine[i] == '/') + if (rOriginal[i] == '/') { - command += '\\'; + converted += '\\'; } else { - command += pCommandLine[i]; + converted += rOriginal[i]; } } + return converted; #else // !WIN32 - std::string command = pCommandLine; + return rOriginal; #endif - - return command; } -inline int RunCommand(const char *pCommandLine) +inline int RunCommand(const std::string& rCommandLine) { - return ::system(ConvertPaths(pCommandLine).c_str()); + return ::system(ConvertPaths(rCommandLine).c_str()); } #ifdef WIN32 @@ -169,7 +169,7 @@ inline int ReadPidFile(const char *pidFile) return pid; } -inline int LaunchServer(const char *pCommandLine, const char *pidFile) +inline int LaunchServer(const std::string& rCommandLine, const char *pidFile) { #ifdef WIN32 @@ -184,7 +184,7 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) startInfo.cbReserved2 = 0; startInfo.lpReserved2 = NULL; - std::string cmd = ConvertPaths(pCommandLine); + std::string cmd = ConvertPaths(rCommandLine); CHAR* tempCmd = strdup(cmd.c_str()); DWORD result = CreateProcess @@ -215,9 +215,9 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) #else // !WIN32 - if(RunCommand(pCommandLine) != 0) + if(RunCommand(rCommandLine) != 0) { - printf("Server: %s\n", pCommandLine); + printf("Server: %s\n", rCommandLine.c_str()); TEST_FAIL_WITH_MESSAGE("Couldn't start server"); return -1; } @@ -235,7 +235,7 @@ inline int LaunchServer(const char *pCommandLine, const char *pidFile) #endif // time for it to start up - ::fprintf(stdout, "Starting server: %s\n", pCommandLine); + ::fprintf(stdout, "Starting server: %s\n", rCommandLine.c_str()); ::fprintf(stdout, "Waiting for server to start: "); for (int i = 0; i < 15; i++) @@ -398,4 +398,13 @@ inline void wait_for_operation(int seconds) fflush(stdout); } +inline void safe_sleep(int seconds) +{ + struct timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = 0; + while (nanosleep(&ts, &ts) == -1 && errno == EINTR) + { /* sleep again */ } +} + #endif // TEST__H diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 45473425..6c90602a 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -137,15 +137,6 @@ ConfigurationVerify verify = 0 }; -void safe_sleep(int seconds) -{ - struct timespec ts; - ts.tv_sec = seconds; - ts.tv_nsec = 0; - while (nanosleep(&ts, &ts) == -1 && errno == EINTR) - { /* sleep again */ } -} - class TestLogger : public Logger { private: -- cgit v1.2.3 From 2ae391bba728884f076bb4d4eba04b581aa750a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:06:49 +0000 Subject: Use logging framework to log exceptions. (refs #3) --- lib/common/Box.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/common/Box.h b/lib/common/Box.h index 86c34acb..8faa2d58 100644 --- a/lib/common/Box.h +++ b/lib/common/Box.h @@ -27,13 +27,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 @@ -108,11 +109,12 @@ #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_TRACE("Exception thrown: " #type "(" #subtype ") at " \ + __FILE__ "(" << __LINE__ << ")") \ + throw type(type::subtype); \ } // extra macros for converting to network byte order -- cgit v1.2.3 From 463869e7b27285be03d20262f4b877848ba10927 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:07:11 +0000 Subject: Use logging framework to log stack traces from exceptions. (refs #3) --- lib/common/Utils.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/common/Utils.cpp b/lib/common/Utils.cpp index ae06dc70..5dc03124 100644 --- a/lib/common/Utils.cpp +++ b/lib/common/Utils.cpp @@ -20,6 +20,7 @@ #include "Utils.h" #include "CommonException.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -71,11 +72,11 @@ 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]); } #include "MemLeakFindOff.h" -- cgit v1.2.3 From 2e03b1d1953de02562b2b0512329c13f7639e27e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:08:13 +0000 Subject: Log event name instead of numeric code. (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 9789558f..825254d9 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1141,7 +1141,7 @@ int BackupDaemon::UseScriptToSeeIfSyncAllowed() std::string line; if(getLine.GetLine(line, true, 30000)) // 30 seconds should be enough { - // Got a string, intepret + // Got a string, interpret if(line == "now") { // Script says do it now. Obey. @@ -2201,7 +2201,8 @@ void BackupDaemon::NotifySysadmin(int Event) 0 }; - BOX_TRACE("BackupDaemon::NotifySysadmin() called, event = " << Event); + BOX_TRACE("BackupDaemon::NotifySysadmin() called, event = " << + sEventNames[Event]); if(Event < 0 || Event >= NotifyEvent__MAX) { -- cgit v1.2.3 From 6ecbc1c1c5eac92fce40bc931ffb953f1d7a5d1d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:23:24 +0000 Subject: Add options to log timestamps, and a custom tag, with each message to the console, e.g.: 14:53:17 [bbackupd] Finished scan of local files (refs #3) --- lib/common/Logging.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++- lib/common/Logging.h | 8 ++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index 5ecadc72..4078a679 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -9,12 +9,16 @@ #include "Box.h" +#include + #ifdef HAVE_SYSLOG_H #include #endif #include "Logging.h" +#include + bool Logging::sLogToSyslog = false; bool Logging::sLogToConsole = false; bool Logging::sContextSet = false; @@ -172,6 +176,21 @@ Logger::~Logger() Logging::Remove(this); } +bool Console::sShowTime = 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; +} + bool Console::Log(Log::Level level, const std::string& rFile, int line, std::string& rMessage) { @@ -186,8 +205,43 @@ bool Console::Log(Log::Level level, const std::string& rFile, { target = stderr; } + + std::string msg; + + if (sShowTime) + { + struct tm time_now; + time_t time_t_now = time(NULL); + + if (time_t_now == ((time_t)-1)) + { + msg += strerror(errno); + msg += " "; + } + else if (localtime_r(&time_t_now, &time_now) != NULL) + { + std::ostringstream buf; + buf << std::setfill('0') << + std::setw(2) << time_now.tm_hour << ":" << + std::setw(2) << time_now.tm_min << ":" << + std::setw(2) << time_now.tm_sec << " "; + msg += buf.str(); + } + else + { + msg += strerror(errno); + msg += " "; + } + } + + if (sShowTag) + { + msg += "[" + sTag + "] "; + } - fprintf(target, "%s\n", rMessage.c_str()); + msg += rMessage; + + fprintf(target, "%s\n", msg.c_str()); return true; } diff --git a/lib/common/Logging.h b/lib/common/Logging.h index 04aed1cf..65018632 100644 --- a/lib/common/Logging.h +++ b/lib/common/Logging.h @@ -102,11 +102,19 @@ class Logger class Console : public Logger { + private: + static bool sShowTime; + 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); }; // -------------------------------------------------------------------------- -- cgit v1.2.3 From 35e9013d1a108a186908ef1e6ee3f26f9407c5f1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:25:08 +0000 Subject: Add -V option, which sets maximum verbosity in one go. Add -T option, which adds timestamps to console logs. Add -t option, which enabled and sets the tag used on console logs. Add -k option, which keeps console open after forking. (refs #3) --- lib/server/Daemon.cpp | 34 ++++++++++++++++++++++++++++++---- lib/server/Daemon.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 5ee45378..c639309a 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -51,7 +51,8 @@ Daemon *Daemon::spDaemon = 0; Daemon::Daemon() : mpConfiguration(NULL), mReloadConfigWanted(false), - mTerminateWanted(false) + mTerminateWanted(false), + mKeepConsoleOpenAfterFork(false) { if(spDaemon != NULL) { @@ -109,8 +110,9 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) #endif char c; + optind = 0; // just in case anybody used getopt before - while((c = getopt(argc, (char * const *)argv, "c:Dqv")) != -1) + while((c = getopt(argc, (char * const *)argv, "c:DqvVt:Tk")) != -1) { switch(c) { @@ -153,10 +155,34 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) } break; + case 'V': + { + masterLevel = Log::EVERYTHING; + } + break; + + case 't': + { + Console::SetTag(optarg); + } + break; + + case 'T': + { + Console::SetShowTime(true); + } + break; + + case 'k': + { + mKeepConsoleOpenAfterFork = true; + } + break; + case '?': { BOX_FATAL("Unknown option on command line: " - << "'" << optopt << "'"); + << "'" << (char)optopt << "'"); return 2; } break; @@ -377,7 +403,7 @@ int Daemon::Main(const std::string &rConfigFileName, bool singleProcess) } #endif // BOX_MEMORY_LEAK_TESTING - if(asDaemon) + if(asDaemon && !mKeepConsoleOpenAfterFork) { #ifndef WIN32 // Close standard streams diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h index b28d752a..52bab257 100644 --- a/lib/server/Daemon.h +++ b/lib/server/Daemon.h @@ -77,6 +77,7 @@ private: box_time_t mLoadedConfigModifiedTime; bool mReloadConfigWanted; bool mTerminateWanted; + bool mKeepConsoleOpenAfterFork; static Daemon *spDaemon; }; -- cgit v1.2.3 From b5da77c8bcc6e86bc4735308ac88ffde18a0a96f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:32:28 +0000 Subject: Add --bbackupd-args and --bbstored-args options, which may be used to pass additional command-line parameters to bbackupd and bbstored in some tests. Add -t and -T options, which add tags and timestamps to log messages using the logging framework inside the tests themselves. Now you can do things like: ./t -Tt test \ --bbackupd-args="-VTkt bbackupd" \ --bbstored-args="-VTkt bbstored" and you will get output from the test itself, the bbackupd and bbstored daemons, all interleaved, timestamped and tagged on the console. This is very useful for debugging synchronisation problems, where interleaved output from bbackupd and bbstored in the system logs is not enough, because you want to see exactly how they interact with the test, or you don't have access to the system logs. (refs #3) --- infrastructure/buildenv-testmain-template.cpp | 74 +++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index bffd46d1..711257ea 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -28,12 +28,17 @@ #include #include +#ifdef HAVE_GETOPT_H + #include +#endif + #ifdef WIN32 #include "emu.h" #else #include #endif +#include "Logging.h" #include "Test.h" #include "Timer.h" @@ -50,13 +55,14 @@ int test(int argc, const char *argv[]); int failures = 0; int first_fail_line; std::string first_fail_file; +std::string bbackupd_args, bbstored_args, bbackupquery_args; int filedes_open_at_beginning = -1; #ifdef WIN32 // any way to check for open file descriptors on Win32? -inline int count_filedes() { return 0; } +inline int count_filedes() { return 0; } inline bool checkfilesleftopen() { return false; } #else // !WIN32 @@ -96,11 +102,72 @@ bool checkfilesleftopen() #endif -int main(int argc, const char *argv[]) +int main(int argc, char * const * argv) { // Start memory leak testing MEMLEAKFINDER_START +#ifdef HAVE_GETOPT_H + struct option longopts[] = + { + { "bbackupd-args", required_argument, NULL, 'c' }, + { "bbstored-args", required_argument, NULL, 's' }, + { NULL, 0, NULL, 0 } + }; + + int ch; + + while ((ch = getopt_long(argc, argv, "c:s:t:T", longopts, NULL)) + != -1) + { + switch(ch) + { + case 'c': + { + bbackupd_args += " "; + bbackupd_args += optarg; + } + break; + + case 's': + { + bbstored_args += " "; + bbstored_args += optarg; + } + break; + + case 't': + { + Console::SetTag(optarg); + } + break; + + case 'T': + { + Console::SetShowTime(true); + } + break; + + case '?': + { + fprintf(stderr, "Unknown option: %s\n", + optarg); + exit(2); + } + + default: + { + fprintf(stderr, "Unknown option code '%c'\n", + ch); + exit(2); + } + } + } + + argc -= optind - 1; + argv += optind - 1; +#endif // HAVE_GETOPT_H + // If there is more than one argument, then the test is doing something advanced, so leave it alone bool fulltestmode = (argc == 1); @@ -120,6 +187,7 @@ int main(int argc, const char *argv[]) TEST_THAT(WSAStartup(0x0101, &info) != SOCKET_ERROR) #endif } + try { #ifdef BOX_MEMORY_LEAK_TESTING @@ -127,7 +195,7 @@ int main(int argc, const char *argv[]) #endif Timers::Init(); - int returncode = test(argc, argv); + int returncode = test(argc, (const char **)argv); Timers::Cleanup(); // check for memory leaks, if enabled -- cgit v1.2.3 From 8a8e956d8f2baa99d8924f05b3124788c5bb1ebd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:35:32 +0000 Subject: Use additional arguments from command line options when starting bbackupd and bbstored. (refs #3) --- test/bbackupd/testbbackupd.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 1593e070..320a0232 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -419,8 +419,8 @@ int test_setupaccount() int test_run_bbstored() { - bbstored_pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", - "testfiles/bbstored.pid"); + std::string cmd = BBSTORED + bbstored_args + " testfiles/bbstored.conf"; + bbstored_pid = LaunchServer(cmd, "testfiles/bbstored.pid"); TEST_THAT(bbstored_pid != -1 && bbstored_pid != 0); @@ -1042,8 +1042,8 @@ int test_bbackupd() } #endif // PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE - bbackupd_pid = LaunchServer(BBACKUPD " testfiles/bbackupd.conf", - "testfiles/bbackupd.pid"); + std::string cmd = BBACKUPD + bbackupd_args + " testfiles/bbackupd.conf"; + bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid"); TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); @@ -2100,9 +2100,8 @@ int test_bbackupd() terminate_bbackupd(bbackupd_pid); // Start it again - bbackupd_pid = LaunchServer(BBACKUPD - " testfiles/bbackupd.conf", - "testfiles/bbackupd.pid"); + cmd = BBACKUPD + bbackupd_args + " testfiles/bbackupd.conf"; + bbackupd_pid = LaunchServer(cmd, "testfiles/bbackupd.pid"); TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); -- cgit v1.2.3 From 4ce68eed0d932c45ec959a828a05aabbcbc6d33d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:37:10 +0000 Subject: Replace sleep() with safe_sleep() everywhere (refs #3) --- test/bbackupd/testbbackupd.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 320a0232..ac4efee9 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -426,7 +426,7 @@ int test_run_bbstored() if(bbstored_pid > 0) { - ::sleep(1); + ::safe_sleep(1); TEST_THAT(ServerIsAlive(bbstored_pid)); return 0; // success } @@ -437,7 +437,7 @@ int test_run_bbstored() int test_kill_bbstored() { TEST_THAT(KillServer(bbstored_pid)); - ::sleep(1); + ::safe_sleep(1); TEST_THAT(!ServerIsAlive(bbstored_pid)); #ifndef WIN32 @@ -640,7 +640,7 @@ int start_internal_daemon() { printf("."); fflush(stdout); - sleep(1); + safe_sleep(1); pid = ReadPidFile("testfiles/bbackupd.pid"); if (pid > 0) @@ -1047,7 +1047,7 @@ int test_bbackupd() TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); - ::sleep(1); + ::safe_sleep(1); if(bbackupd_pid > 0) { @@ -1588,7 +1588,7 @@ int test_bbackupd() TEST_THAT(fd2 > 0); TEST_THAT(write(fd1, "hello", 5) == 5); TEST_THAT(close(fd1) == 0); - sleep(1); + safe_sleep(1); TEST_THAT(write(fd2, "world", 5) == 5); TEST_THAT(close(fd2) == 0); TEST_THAT(TestFileExists("testfiles/TestDir1/untracked-1")); @@ -1631,7 +1631,7 @@ int test_bbackupd() TEST_THAT(write(fd1, "hello", 5) == 5); TEST_THAT(write(fd1, buffer, sizeof(buffer)) == sizeof(buffer)); TEST_THAT(close(fd1) == 0); - sleep(1); + safe_sleep(1); TEST_THAT(write(fd2, "world", 5) == 5); TEST_THAT(write(fd2, buffer, sizeof(buffer)) == sizeof(buffer)); TEST_THAT(close(fd2) == 0); @@ -1700,7 +1700,7 @@ int test_bbackupd() TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0); TestRemoteProcessMemLeaks("bbackupctl.memleaks"); // Then wait a second, to make sure the scan is complete - ::sleep(1); + ::safe_sleep(1); // Then modify an existing file { chmod("testfiles/TestDir1/sub23/rand.h", 0777); // in the archive, it's read only @@ -1795,7 +1795,7 @@ int test_bbackupd() TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -c testfiles/bbackupd.conf wait-for-sync") == 0); TestRemoteProcessMemLeaks("bbackupctl.memleaks"); // Then wait a second, to make sure the scan is complete - ::sleep(1); + ::safe_sleep(1); { // Open a file, then save something to it every second @@ -1805,7 +1805,7 @@ int test_bbackupd() TEST_THAT(f != 0); fprintf(f, "Loop iteration %d\n", l); fflush(f); - sleep(1); + safe_sleep(1); printf("."); fflush(stdout); ::fclose(f); @@ -1826,7 +1826,7 @@ int test_bbackupd() TEST_THAT(f != 0); fprintf(f, "Loop 2 iteration %d\n", l); fflush(f); - sleep(1); + safe_sleep(1); printf("."); fflush(stdout); ::fclose(f); @@ -1956,7 +1956,7 @@ int test_bbackupd() TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0); TestRemoteProcessMemLeaks("bbackupctl.memleaks"); // Then wait a second, to make sure the scan is complete - ::sleep(1); + ::safe_sleep(1); // Then modify an existing file { FILE *f = fopen("testfiles/TestDir1/sub23/in-the-future", "w"); -- cgit v1.2.3 From 4116e6dfe7ad6b4867fd21a814f61556c419fd13 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:38:11 +0000 Subject: Fix excessively verbose warnings while waiting for daemon to start. (refs #3) --- test/bbackupd/testbbackupd.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index ac4efee9..d60aae86 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -642,7 +642,11 @@ int start_internal_daemon() fflush(stdout); safe_sleep(1); - pid = ReadPidFile("testfiles/bbackupd.pid"); + if (TestFileExists("testfiles/bbackupd.pid")) + { + pid = ReadPidFile("testfiles/bbackupd.pid"); + } + if (pid > 0) { break; -- cgit v1.2.3 From 98b32fc7cc9a651b96d01e80f5ae18ef516e01fa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:39:55 +0000 Subject: Use TARGET_PERL instead of PERL in shebang lines (refs #3) --- test/bbackupd/testfiles/notifyscript.pl.in | 2 +- test/bbackupd/testfiles/syncallowscript.pl.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/bbackupd/testfiles/notifyscript.pl.in b/test/bbackupd/testfiles/notifyscript.pl.in index df0e5a2d..89741e46 100755 --- a/test/bbackupd/testfiles/notifyscript.pl.in +++ b/test/bbackupd/testfiles/notifyscript.pl.in @@ -1,4 +1,4 @@ -#!@PERL@ +#!@TARGET_PERL@ my $f = 'testfiles/notifyran.'.$ARGV[0].'.'; diff --git a/test/bbackupd/testfiles/syncallowscript.pl.in b/test/bbackupd/testfiles/syncallowscript.pl.in index af425e90..f2ef1171 100755 --- a/test/bbackupd/testfiles/syncallowscript.pl.in +++ b/test/bbackupd/testfiles/syncallowscript.pl.in @@ -1,4 +1,4 @@ -#!@PERL@ +#!@TARGET_PERL@ use strict; use warnings; -- cgit v1.2.3 From 231b76c8b767033dcbe43bff159a1afcec02d087 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:40:34 +0000 Subject: Add sync allow script to test config, to allow it to be tested. Use TARGET_PERL to execute the test scripts. (refs #3) --- test/bbackupd/testfiles/bbackupd.conf.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/bbackupd/testfiles/bbackupd.conf.in b/test/bbackupd/testfiles/bbackupd.conf.in index 097cf7b7..ce5d5b7c 100644 --- a/test/bbackupd/testfiles/bbackupd.conf.in +++ b/test/bbackupd/testfiles/bbackupd.conf.in @@ -25,7 +25,8 @@ ExtendedLogFile = testfiles/bbackupd.log CommandSocket = testfiles/bbackupd.sock -NotifyScript = @PERL@ testfiles/notifyscript.pl +NotifyScript = @TARGET_PERL@ testfiles/notifyscript.pl +SyncAllowScript = @TARGET_PERL@ testfiles/syncallowscript.pl Server { -- cgit v1.2.3 From f1b9a0c506ba050bf3a9a2ae9705cc7b2ae7dde0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 14:41:25 +0000 Subject: Test that SyncAllowScript is executed and can pause backup for the correct amount of time. (refs #3) --- test/bbackupd/testbbackupd.cpp | 103 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index d60aae86..70c5e394 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1417,6 +1417,109 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbackupquery.memleaks"); TEST_RETURN(compareReturnValue, 2); #endif // WIN32 + + printf("\n==== Check that SyncAllowScript is executed and can " + "pause backup\n"); + fflush(stdout); + + { + wait_for_sync_end(); + // we now have 3 seconds before bbackupd + // runs the SyncAllowScript again. + + char* sync_control_file = "testfiles" + DIRECTORY_SEPARATOR "syncallowscript.control"; + int fd = open(sync_control_file, + O_CREAT | O_EXCL | O_WRONLY, 0700); + if (fd <= 0) + { + perror(sync_control_file); + } + TEST_THAT(fd > 0); + + char* control_string = "10\n"; + TEST_THAT(write(fd, control_string, + strlen(control_string)) == + (int)strlen(control_string)); + close(fd); + + // this will pause backups, bbackupd will check + // every 10 seconds to see if they are allowed again. + + char* new_test_file = "testfiles" + DIRECTORY_SEPARATOR "TestDir1" + DIRECTORY_SEPARATOR "Added_During_Pause"; + fd = open(new_test_file, + O_CREAT | O_EXCL | O_WRONLY, 0700); + if (fd <= 0) + { + perror(new_test_file); + } + TEST_THAT(fd > 0); + close(fd); + + struct stat st; + + // next poll should happen within the next + // 5 seconds (normally about 3 seconds) + + safe_sleep(1); // 2 seconds before + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.1", &st) != 0); + safe_sleep(4); // 2 seconds after + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.1", &st) == 0); + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.2", &st) != 0); + + // next poll should happen within the next + // 10 seconds (normally about 8 seconds) + + safe_sleep(6); // 2 seconds before + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.2", &st) != 0); + safe_sleep(4); // 2 seconds after + TEST_THAT(stat("testfiles" DIRECTORY_SEPARATOR + "syncallowscript.notifyran.2", &st) == 0); + + // check that no backup has run (compare fails) + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + long start_time = time(NULL); + TEST_THAT(unlink(sync_control_file) == 0); + wait_for_sync_start(); + long end_time = time(NULL); + + long wait_time = end_time - start_time + 2; + // should be about 10 seconds + printf("Waited for %ld seconds, should have been %s", + wait_time, control_string); + TEST_THAT(wait_time >= 8); + TEST_THAT(wait_time <= 12); + + wait_for_sync_end(); + // check that backup has run (compare succeeds) + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query3a.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + if (failures > 0) + { + // stop early to make debugging easier + return 1; + } + } + + printf("\n==== Delete file and update another, " + "create symlink.\n"); // Delete a file TEST_THAT(::unlink("testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); -- cgit v1.2.3 -- cgit v1.2.3 From 1a99df430cd17693e2829ab45b1d46d27b92be0c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 15:16:50 +0000 Subject: Display file and line where memory leak test failed. (refs #3) --- lib/common/Test.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index e485f2ee..89f74563 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -317,7 +317,8 @@ inline void TestRemoteProcessMemLeaksFunc(const char *filename, 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 { @@ -331,12 +332,13 @@ inline void TestRemoteProcessMemLeaksFunc(const char *filename, } ++failures; printf("FAILURE: Memory leaks found in other process " - "(file %s)\n==========\n", filename); + "(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"); -- cgit v1.2.3 From f8d41c2eec776ce3c9920fd01fd3971dc99cf531 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 15:45:05 +0000 Subject: Compile fix for Win32, where no localtime_r is available and localtime is thread safe. (refs #3) --- lib/common/Logging.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index 4078a679..bb728183 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -210,7 +210,7 @@ bool Console::Log(Log::Level level, const std::string& rFile, if (sShowTime) { - struct tm time_now; + struct tm time_now, *tm_ptr = &time_now; time_t time_t_now = time(NULL); if (time_t_now == ((time_t)-1)) @@ -218,13 +218,17 @@ bool Console::Log(Log::Level level, const std::string& rFile, msg += strerror(errno); msg += " "; } - else if (localtime_r(&time_t_now, &time_now) != NULL) + #ifdef WIN32 + else if ((tm_ptr = localtime(&time_t_now)) != NULL) + #else + else if (localtime_r(&time_t_now, &time_now) != NULL) + #endif { std::ostringstream buf; buf << std::setfill('0') << - std::setw(2) << time_now.tm_hour << ":" << - std::setw(2) << time_now.tm_min << ":" << - std::setw(2) << time_now.tm_sec << " "; + std::setw(2) << tm_ptr->tm_hour << ":" << + std::setw(2) << tm_ptr->tm_min << ":" << + std::setw(2) << tm_ptr->tm_sec << " "; msg += buf.str(); } else -- cgit v1.2.3 From fbfc77472d66ce1c3e2bb14f7031e2d8ed75d422 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 15:49:22 +0000 Subject: Merge [1566] from chris/general: Use Sleep() instead of nanosleep again on win32 (lost in merge [1562]). Fix reference to pCommandLine which no longer exists after [1562]. Fix signed/unsigned comparison warning. (refs #3) --- lib/common/Test.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 89f74563..716ff563 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -99,7 +99,7 @@ inline std::string ConvertPaths(const std::string& rOriginal) // convert UNIX paths to native std::string converted; - for (int i = 0; i < rOriginal.size(); i++) + for (size_t i = 0; i < rOriginal.size(); i++) { if (rOriginal[i] == '/') { @@ -206,7 +206,8 @@ inline int LaunchServer(const std::string& rCommandLine, const char *pidFile) if (result == 0) { DWORD err = GetLastError(); - printf("Launch failed: %s: error %d\n", pCommandLine, (int)err); + printf("Launch failed: %s: error %d\n", rCommandLine.c_str(), + (int)err); return -1; } @@ -402,11 +403,15 @@ inline void wait_for_operation(int seconds) inline void safe_sleep(int seconds) { +#ifdef WIN32 + Sleep(seconds * 1000); +#else struct timespec ts; ts.tv_sec = seconds; ts.tv_nsec = 0; while (nanosleep(&ts, &ts) == -1 && errno == EINTR) { /* sleep again */ } +#endif } #endif // TEST__H -- cgit v1.2.3 From 211c489e686c8c43f00decba3f79c7054bea3caf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 19:41:44 +0000 Subject: Fix accidental passing of object to printf() (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 0e4a7cd1..1e7aebe1 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1238,7 +1238,7 @@ void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries: { fprintf(stderr, "Warning: location '%s' path ends " "with '%s', compare may fail!", - rLocation, DIRECTORY_SEPARATOR); + rLocation.c_str(), DIRECTORY_SEPARATOR); } } #endif -- cgit v1.2.3 From a670b7cb878bbb12532d8be0eba2cb2386972e95 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 20:02:40 +0000 Subject: Use LaunchServer to remove the need for some #ifdefs. Use directory separator constant instead of forward slash. Add some blank lines for readability. (refs #3) --- test/basicserver/testbasicserver.cpp | 55 +++++++++++++----------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/test/basicserver/testbasicserver.cpp b/test/basicserver/testbasicserver.cpp index f7ec5e0a..4b33f555 100644 --- a/test/basicserver/testbasicserver.cpp +++ b/test/basicserver/testbasicserver.cpp @@ -436,13 +436,8 @@ int test(int argc, const char *argv[]) // Launch a basic server { - #ifdef WIN32 - int pid = LaunchServer("test srv1 testfiles\\srv1.conf", - "testfiles\\srv1.pid"); - #else - int pid = LaunchServer("./test srv1 testfiles/srv1.conf", - "testfiles/srv1.pid"); - #endif + int pid = LaunchServer("./test srv1 testfiles/srv1.conf", + "testfiles/srv1.pid"); TEST_THAT(pid != -1 && pid != 0); if(pid > 0) @@ -454,9 +449,10 @@ int test(int argc, const char *argv[]) // Move the config file over #ifdef WIN32 - TEST_THAT(::unlink("testfiles/srv1.conf") - != -1); + TEST_THAT(::unlink("testfiles" + DIRECTORY_SEPARATOR "srv1.conf") != -1); #endif + TEST_THAT(::rename( "testfiles" DIRECTORY_SEPARATOR "srv1b.conf", "testfiles" DIRECTORY_SEPARATOR "srv1.conf") @@ -474,6 +470,7 @@ int test(int argc, const char *argv[]) // Kill it off TEST_THAT(KillServer(pid)); + #ifndef WIN32 TestRemoteProcessMemLeaks( "generic-daemon.memleaks"); @@ -483,15 +480,11 @@ int test(int argc, const char *argv[]) // Launch a test forking server { - #ifdef WIN32 - int pid = LaunchServer("test srv2 testfiles\\srv2.conf", - "testfiles\\srv2.pid"); - #else - int pid = LaunchServer("./test srv2 testfiles/srv2.conf", - "testfiles/srv2.pid"); - #endif + int pid = LaunchServer("./test srv2 testfiles/srv2.conf", + "testfiles/srv2.pid"); TEST_THAT(pid != -1 && pid != 0); + if(pid > 0) { // Will it restart? @@ -530,6 +523,7 @@ int test(int argc, const char *argv[]) conns.push_back(&conn2); conns.push_back(&conn3); #endif // !WIN32 + Srv2TestConversations(conns); // Implicit close } @@ -554,15 +548,11 @@ int test(int argc, const char *argv[]) // Launch a test SSL server { - #ifdef WIN32 - int pid = LaunchServer("test srv3 testfiles\\srv3.conf", - "testfiles\\srv3.pid"); - #else - int pid = LaunchServer("./test srv3 testfiles/srv3.conf", - "testfiles/srv3.pid"); - #endif + int pid = LaunchServer("./test srv3 testfiles/srv3.conf", + "testfiles/srv3.pid"); TEST_THAT(pid != -1 && pid != 0); + if(pid > 0) { // Will it restart? @@ -598,9 +588,9 @@ int test(int argc, const char *argv[]) #endif // Quick check that reconnections fail - TEST_CHECK_THROWS(conn1.Open(context, - Socket::TypeUNIX, - "testfiles/srv3.sock"), + TEST_CHECK_THROWS(conn1.Open(context, + Socket::TypeUNIX, + "testfiles/srv3.sock");, ServerException, SocketAlreadyOpen); // Stuff some data around @@ -637,15 +627,11 @@ int test(int argc, const char *argv[]) //protocolserver: // Launch a test protocol handling server { - #ifdef WIN32 - int pid = LaunchServer("test srv4 testfiles\\srv4.conf", - "testfiles\\srv4.pid"); - #else - int pid = LaunchServer("./test srv4 testfiles/srv4.conf", - "testfiles/srv4.pid"); - #endif + int pid = LaunchServer("./test srv4 testfiles/srv4.conf", + "testfiles/srv4.pid"); TEST_THAT(pid != -1 && pid != 0); + if(pid > 0) { ::sleep(1); @@ -656,8 +642,7 @@ int test(int argc, const char *argv[]) #ifdef WIN32 conn.Open(Socket::TypeINET, "localhost", 2003); #else - conn.Open(Socket::TypeUNIX, - "testfiles/srv4.sock"); + conn.Open(Socket::TypeUNIX, "testfiles/srv4.sock"); #endif // Create a protocol -- cgit v1.2.3 From a6a6ca0bb3bae5ba252f3593e418a496377798ed Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 20:46:51 +0000 Subject: Use wait_for_sync_end() rather than calling bbackupquery ourselves (refs #3) --- test/bbackupd/testbbackupd.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 70c5e394..7d703492 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1801,13 +1801,12 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - // Check that modifying files with old timestamps still get added - printf("Modify existing file, but change timestamp to rather old\n"); - // Time critical, so sync - TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0); - TestRemoteProcessMemLeaks("bbackupctl.memleaks"); - // Then wait a second, to make sure the scan is complete - ::safe_sleep(1); + // Check that modifying files with old timestamps + // still get added + printf("\n==== Modify existing file, but change timestamp " + "to rather old\n"); + wait_for_sync_end(); + // Then modify an existing file { chmod("testfiles/TestDir1/sub23/rand.h", 0777); // in the archive, it's read only -- cgit v1.2.3 From e94c3e5e551271ebdb98f444850de873dc4837f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 20:48:18 +0000 Subject: Ignore attempts to listen on a Unix socket on Win32, so that we can share config files for the unit tests (refs #3) --- lib/server/ServerStream.h | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h index d5abccdd..f8578a04 100644 --- a/lib/server/ServerStream.h +++ b/lib/server/ServerStream.h @@ -170,16 +170,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 { @@ -187,8 +193,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(...) { @@ -196,8 +205,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); + } } } -- cgit v1.2.3 From e89ceeb26d5ccb022ad55615266c57298a90e6f4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 20:52:15 +0000 Subject: Use Cygwin chmod command-line tool to make the read-only file writable on Win32, instead of our own chmod() (which does nothing). (refs #3) --- test/bbackupd/testbbackupd.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 7d703492..d869d5d5 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1809,11 +1809,31 @@ int test_bbackupd() // Then modify an existing file { - chmod("testfiles/TestDir1/sub23/rand.h", 0777); // in the archive, it's read only - FILE *f = fopen("testfiles/TestDir1/sub23/rand.h", "w+"); + // in the archive, it's read only + #ifdef WIN32 + TEST_THAT(::system("chmod 0777 testfiles" + "/TestDir1/sub23/rand.h") == 0); + #else + TEST_THAT(chmod("testfiles/TestDir1/sub23" + "/rand.h", 0777) == 0); + #endif + + FILE *f = fopen("testfiles/TestDir1/sub23/rand.h", + "w+"); + + if (f == 0) + { + perror("Failed to open"); + } + TEST_THAT(f != 0); - fprintf(f, "MODIFIED!\n"); - fclose(f); + + if (f != 0) + { + fprintf(f, "MODIFIED!\n"); + fclose(f); + } + // and then move the time backwards! struct timeval times[2]; BoxTimeToTimeval(SecondsToBoxTime((time_t)(365*24*60*60)), times[1]); -- cgit v1.2.3 From 335e891f9d3d365eb9b4534eeeb1f890aea078ed Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 21:17:36 +0000 Subject: Use wait_for_sync_end() to synchronise the test more accurately with bbackupd, hopefully reducing random failures. (refs #3) --- test/bbackupd/testbbackupd.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index d869d5d5..2c7536ea 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1841,7 +1841,9 @@ int test_bbackupd() TEST_THAT(::utimes("testfiles/TestDir1/sub23/rand.h", times) == 0); } // Wait and test - wait_for_backup_operation(); + wait_for_sync_end(); // files too new + wait_for_sync_end(); // should (not) be backed up this time + compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3l.log " @@ -1858,7 +1860,8 @@ int test_bbackupd() #endif // Wait and test - wait_for_backup_operation(); + wait_for_sync_end(); + wait_for_sync_end(); // compare with exclusions, should not find differences compareReturnValue = ::system(BBACKUPQUERY " -q " -- cgit v1.2.3 From 9f0ec2522cb7f7fbe7c56a3564ebd1ab3c8bf6d9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 21:43:59 +0000 Subject: Check that Exclude and AlwaysInclude configurations actually work as they should. (refs #3, merges [711]) --- test/bbackupd/testbbackupd.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 2c7536ea..788a9e46 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1879,6 +1879,93 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + // check that the excluded files did not make it + // into the store, and the included files did + printf("\n==== Check that exclude/alwaysinclude commands " + "actually work\n"); + + { + std::string errs; + std::auto_ptr config( + Configuration::LoadAndVerify( + "testfiles/bbackupd.conf", + &BackupDaemonConfigVerify, errs)); + Configuration& conf(*config); + SSLLib::Initialise(); + TLSContext tlsContext; + std::string certFile(conf.GetKeyValue("CertificateFile")); + std::string keyFile (conf.GetKeyValue("PrivateKeyFile")); + std::string caFile (conf.GetKeyValue("TrustedCAsFile")); + tlsContext.Initialise(false, certFile.c_str(), + keyFile.c_str(), caFile.c_str()); + BackupClientCryptoKeys_Setup( + conf.GetKeyValue("KeysFile").c_str()); + SocketStreamTLS socket; + socket.Open(tlsContext, Socket::TypeINET, + conf.GetKeyValue("StoreHostname").c_str(), + BOX_PORT_BBSTORED); + BackupProtocolClient connection(socket); + connection.Handshake(); + std::auto_ptr + serverVersion(connection.QueryVersion( + BACKUP_STORE_SERVER_VERSION)); + if(serverVersion->GetVersion() != + BACKUP_STORE_SERVER_VERSION) + { + THROW_EXCEPTION(BackupStoreException, + WrongServerVersion); + } + connection.QueryLogin( + conf.GetKeyValueInt("AccountNumber"), + BackupProtocolClientLogin::Flags_ReadOnly); + + int64_t rootDirId = BackupProtocolClientListDirectory + ::RootDirectory; + std::auto_ptr dirreply( + connection.QueryListDirectory( + rootDirId, false, 0, false)); + std::auto_ptr dirstream( + connection.ReceiveStream()); + BackupStoreDirectory dir; + dir.ReadFromStream(*dirstream, connection.GetTimeout()); + + int64_t testDirId = SearchDir(dir, "Test1"); + TEST_THAT(testDirId != 0); + dirreply = connection.QueryListDirectory(testDirId, false, 0, false); + dirstream = connection.ReceiveStream(); + dir.ReadFromStream(*dirstream, connection.GetTimeout()); + + TEST_THAT(!SearchDir(dir, "excluded_1")); + TEST_THAT(!SearchDir(dir, "excluded_2")); + TEST_THAT(!SearchDir(dir, "exclude_dir")); + TEST_THAT(!SearchDir(dir, "exclude_dir_2")); + // xx_not_this_dir_22 should not be excluded by + // ExcludeDirsRegex, because it's a file + TEST_THAT(SearchDir (dir, "xx_not_this_dir_22")); + TEST_THAT(!SearchDir(dir, "zEXCLUDEu")); + TEST_THAT(SearchDir (dir, "dont.excludethis")); + TEST_THAT(SearchDir (dir, "xx_not_this_dir_ALWAYSINCLUDE")); + + int64_t sub23id = SearchDir(dir, "sub23"); + TEST_THAT(sub23id != 0); + dirreply = connection.QueryListDirectory(sub23id, false, 0, false); + dirstream = connection.ReceiveStream(); + dir.ReadFromStream(*dirstream, connection.GetTimeout()); + TEST_THAT(!SearchDir(dir, "xx_not_this_dir_22")); + TEST_THAT(!SearchDir(dir, "somefile.excludethis")); + connection.QueryFinished(); + } + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + #ifndef WIN32 // These tests only work as non-root users. if(::getuid() != 0) -- cgit v1.2.3 From fcc6205a74d413112524f34a7b370fac5cfa2978 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 22:09:20 +0000 Subject: Compare restored files as part of restore test (refs #3, merges part of [623]) --- test/bbackupd/testbbackupd.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 788a9e46..a7e22ea5 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -2115,6 +2115,15 @@ int test_bbackupd() protocol.QueryFinished(); } + // Compare the restored files + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + printf("Add files with current time\n"); // Add some more files and modify others -- cgit v1.2.3 From 21b6abb72797248d6f1799f6d50f7907b3ad188a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 22:15:44 +0000 Subject: Test that file attributes are backed up and compared correctly on Win32 (refs #3, merges part of 694]) --- test/bbackupd/testbbackupd.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index a7e22ea5..da2c4bc8 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -2124,6 +2124,92 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); +#ifdef WIN32 + // make one of the files read-only, expect a compare failure + compareReturnValue = ::system("attrib +r " + "testfiles\\restore-Test1\\f1.dat"); + TEST_RETURN(compareReturnValue, 0); + + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // set it back, expect no failures + compareReturnValue = ::system("attrib -r " + "testfiles\\restore-Test1\\f1.dat"); + TEST_RETURN(compareReturnValue, 0); + + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf -l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // change the timestamp on a file, expect a compare failure + char* testfile = "testfiles\\restore-Test1\\f1.dat"; + HANDLE handle = openfile(testfile, O_RDWR, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + + FILETIME creationTime, lastModTime, lastAccessTime; + TEST_THAT(GetFileTime(handle, &creationTime, &lastAccessTime, + &lastModTime) != 0); + TEST_THAT(CloseHandle(handle)); + + FILETIME dummyTime = lastModTime; + dummyTime.dwHighDateTime -= 100; + + // creation time is backed up, so changing it should cause + // a compare failure + TEST_THAT(set_file_time(testfile, dummyTime, lastModTime, + lastAccessTime)); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // last access time is not backed up, so it cannot be compared + TEST_THAT(set_file_time(testfile, creationTime, lastModTime, + dummyTime)); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // last write time is backed up, so changing it should cause + // a compare failure + TEST_THAT(set_file_time(testfile, creationTime, dummyTime, + lastAccessTime)); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 2); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // set back to original values, check that compare succeeds + TEST_THAT(set_file_time(testfile, creationTime, lastModTime, + lastAccessTime)); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10a.log " + "\"compare -cEQ Test1 testfiles/restore-Test1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); +#endif // WIN32 + printf("Add files with current time\n"); // Add some more files and modify others -- cgit v1.2.3 From 0d5731d7d5848016f51c283fbf87eb2b063df612 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Apr 2007 22:19:15 +0000 Subject: Test that locked files behave as expected on Win32 (refs #3, merges parts of [649], [694], [1461]) --- test/bbackupd/testbbackupd.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index da2c4bc8..bb74f16b 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -2407,6 +2407,76 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2")); TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2")); +#ifdef WIN32 + printf("\n==== Testing locked file behaviour:\n"); + + // Test that locked files cannot be backed up, + // and the appropriate error is reported. + // Wait for the sync to finish, so that we have time to work + wait_for_sync_start(); + // Now we have about three seconds to work + + handle = openfile("testfiles/TestDir1/lockedfile", + O_CREAT | O_EXCL | O_LOCK, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + + if (handle != 0) + { + // first sync will ignore the file, it's too new + wait_for_sync_end(); + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.read-error.1")); + + // this sync should try to back up the file, + // and fail, because it's locked + wait_for_sync_end(); + TEST_THAT(TestFileExists("testfiles/" + "notifyran.read-error.1")); + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.read-error.2")); + + // now close the file and check that it is + // backed up on the next run. + CloseHandle(handle); + wait_for_sync_end(); + TEST_THAT(!TestFileExists("testfiles/" + "notifyran.read-error.2")); + + // compare, and check that it works + // reports the correct error message (and finishes) + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query15a.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // open the file again, compare and check that compare + // reports the correct error message (and finishes) + handle = openfile("testfiles/TestDir1/lockedfile", + O_LOCK, 0); + TEST_THAT(handle != INVALID_HANDLE_VALUE); + + compareReturnValue = ::system(BBACKUPQUERY + " -q -c testfiles/bbackupd.conf " + "-l testfiles/query15.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 3); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // close the file again, check that compare + // works again + CloseHandle(handle); + + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query15a.log " + "\"compare -acQ\" quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + } +#endif + // Kill the daemon terminate_bbackupd(bbackupd_pid); -- cgit v1.2.3 From 278b937f6dffbc6b0e5a4a53e0310358acdf1dd5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:11:36 +0000 Subject: Add a stream which provides a source of zero bytes of arbitrary size, useful for testing support for files over 2GB. (refs #3) --- lib/common/ZeroStream.cpp | 170 ++++++++++++++++++++++++++++++++++++++++++++++ lib/common/ZeroStream.h | 39 +++++++++++ 2 files changed, 209 insertions(+) create mode 100644 lib/common/ZeroStream.cpp create mode 100644 lib/common/ZeroStream.h diff --git a/lib/common/ZeroStream.cpp b/lib/common/ZeroStream.cpp new file mode 100644 index 00000000..9d87d76a --- /dev/null +++ b/lib/common/ZeroStream.cpp @@ -0,0 +1,170 @@ +// -------------------------------------------------------------------------- +// +// 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 + +#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..0119045b --- /dev/null +++ b/lib/common/ZeroStream.h @@ -0,0 +1,39 @@ +// -------------------------------------------------------------------------- +// +// 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 + + -- cgit v1.2.3 From f71cab7197bc0582dcfb3a4320520d8fbe54718b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:13:34 +0000 Subject: Fix inability to handle streams over 2GB properly. (refs #3) --- lib/common/PartialReadStream.cpp | 10 ++++++---- lib/common/PartialReadStream.h | 4 ++-- lib/common/ReadGatherStream.cpp | 9 +++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/common/PartialReadStream.cpp b/lib/common/PartialReadStream.cpp index 0b5c4cf6..76096738 100644 --- a/lib/common/PartialReadStream.cpp +++ b/lib/common/PartialReadStream.cpp @@ -16,13 +16,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 42cb7aeb..1b46b0bd 100644 --- a/lib/common/PartialReadStream.h +++ b/lib/common/PartialReadStream.h @@ -23,7 +23,7 @@ class PartialReadStream : public IOStream { public: - PartialReadStream(IOStream &rSource, int BytesToRead); + PartialReadStream(IOStream &rSource, pos_type BytesToRead); ~PartialReadStream(); private: // no copying allowed @@ -39,7 +39,7 @@ public: private: IOStream &mrSource; - int mBytesLeft; + pos_type mBytesLeft; }; #endif // PARTIALREADSTREAM__H diff --git a/lib/common/ReadGatherStream.cpp b/lib/common/ReadGatherStream.cpp index 9ccc3a54..f50e6664 100644 --- a/lib/common/ReadGatherStream.cpp +++ b/lib/common/ReadGatherStream.cpp @@ -59,8 +59,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 // // -------------------------------------------------------------------------- @@ -145,10 +146,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; -- cgit v1.2.3 From d7f3062292dd3b859c6d2632945b6ef6f102a116 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:14:27 +0000 Subject: Test that PartialReadStream and ReadGatherStream can handle streams over 2GB in size. (refs #3) --- test/common/testcommon.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 6c90602a..19c83d2d 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -31,6 +31,8 @@ #include "Archive.h" #include "Timer.h" #include "Logging.h" +#include "ZeroStream.h" +#include "PartialReadStream.h" #include "MemLeakFindOn.h" @@ -173,6 +175,41 @@ class TestLogger : public Logger int test(int argc, const char *argv[]) { + // Test PartialReadStream and ReadGatherStream handling of files + // over 2GB (refs #2) + { + char buffer[8]; + + ZeroStream zero(0x80000003); + zero.Seek(0x7ffffffe, IOStream::SeekType_Absolute); + TEST_THAT(zero.GetPosition() == 0x7ffffffe); + TEST_THAT(zero.Read(buffer, 8) == 5); + TEST_THAT(zero.GetPosition() == 0x80000003); + TEST_THAT(zero.Read(buffer, 8) == 0); + zero.Seek(0, IOStream::SeekType_Absolute); + TEST_THAT(zero.GetPosition() == 0); + + char* buffer2 = new char [0x1000000]; + TEST_THAT(buffer2 != NULL); + + PartialReadStream part(zero, 0x80000002); + for (int i = 0; i < 0x80; i++) + { + int read = part.Read(buffer2, 0x1000000); + TEST_THAT(read == 0x1000000); + } + TEST_THAT(part.Read(buffer, 8) == 2); + TEST_THAT(part.Read(buffer, 8) == 0); + + delete [] buffer2; + + ReadGatherStream gather(false); + zero.Seek(0, IOStream::SeekType_Absolute); + int component = gather.AddComponent(&zero); + gather.AddBlock(component, 0x80000002); + TEST_THAT(gather.Read(buffer, 8) == 8); + } + // Test self-deleting temporary file streams { std::string tempfile("testfiles/tempfile"); -- cgit v1.2.3 From 9362fdfa7b8f2639a2ec5290b38e2e9c9ea8483b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:15:36 +0000 Subject: Keep a copy of the program name, in case the original goes away, which causes syslog() to write nonsense for the program name. (refs #3) --- lib/common/Logging.cpp | 3 ++- lib/common/Logging.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index bb728183..5f0a2f8f 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -289,6 +289,7 @@ Syslog::~Syslog() void Syslog::SetProgramName(const std::string& rProgramName) { + mName = rProgramName; ::closelog(); - ::openlog(rProgramName.c_str(), LOG_PID, LOG_LOCAL6); + ::openlog(mName.c_str(), LOG_PID, LOG_LOCAL6); } diff --git a/lib/common/Logging.h b/lib/common/Logging.h index 65018632..aea488a5 100644 --- a/lib/common/Logging.h +++ b/lib/common/Logging.h @@ -128,6 +128,9 @@ class Console : public Logger class Syslog : public Logger { + private: + std::string mName; + public: Syslog(); virtual ~Syslog(); -- cgit v1.2.3 From 69c959cea39474dc66a1de128ce89af983882f67 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:30:58 +0000 Subject: Add a stream which logs progress of reading data from another (child) stream, and estimated time of completion, useful for upload progress monitoring. (refs #3) --- lib/common/ReadLoggingStream.cpp | 207 +++++++++++++++++++++++++++++++++++++++ lib/common/ReadLoggingStream.h | 43 ++++++++ 2 files changed, 250 insertions(+) create mode 100644 lib/common/ReadLoggingStream.cpp create mode 100644 lib/common/ReadLoggingStream.h diff --git a/lib/common/ReadLoggingStream.cpp b/lib/common/ReadLoggingStream.cpp new file mode 100644 index 00000000..9023f827 --- /dev/null +++ b/lib/common/ReadLoggingStream.cpp @@ -0,0 +1,207 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: ReadLoggingStream.cpp +// Purpose: Buffering wrapper around IOStreams +// Created: 2007/01/16 +// +// -------------------------------------------------------------------------- + +#include "Box.h" + +#include + +#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..15c3ef48 --- /dev/null +++ b/lib/common/ReadLoggingStream.h @@ -0,0 +1,43 @@ +// -------------------------------------------------------------------------- +// +// 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 + + -- cgit v1.2.3 From 41b16f3b27f87d2f84e59387e78644c05756e307 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:31:38 +0000 Subject: Use ReadLoggingStream to log progress of file uploads. (refs #3) --- lib/backupclient/BackupStoreFileEncodeStream.cpp | 17 ++++++++++++++--- lib/backupclient/BackupStoreFileEncodeStream.h | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/backupclient/BackupStoreFileEncodeStream.cpp b/lib/backupclient/BackupStoreFileEncodeStream.cpp index c692f18e..cda18855 100644 --- a/lib/backupclient/BackupStoreFileEncodeStream.cpp +++ b/lib/backupclient/BackupStoreFileEncodeStream.cpp @@ -38,6 +38,7 @@ using namespace BackupStoreFileCryptVar; BackupStoreFileEncodeStream::BackupStoreFileEncodeStream() : mpRecipe(0), mpFile(0), + mpLogging(0), mStatus(Status_Header), mSendData(true), mTotalBlocks(0), @@ -79,6 +80,13 @@ BackupStoreFileEncodeStream::~BackupStoreFileEncodeStream() mpFile = 0; } + // Clear up logging stream + if(mpLogging) + { + delete mpLogging; + mpLogging = 0; + } + // Free the recipe if(mpRecipe != 0) { @@ -199,6 +207,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); @@ -474,7 +485,7 @@ void BackupStoreFileEncodeStream::SkipPreviousBlocksInInstruction() } // Move forward in the stream - mpFile->Seek(sizeToSkip, IOStream::SeekType_Relative); + mpLogging->Seek(sizeToSkip, IOStream::SeekType_Relative); } @@ -518,14 +529,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 1c748798..fb5d0851 100644 --- a/lib/backupclient/BackupStoreFileEncodeStream.h +++ b/lib/backupclient/BackupStoreFileEncodeStream.h @@ -17,6 +17,7 @@ #include "CollectInBufferStream.h" #include "MD5Digest.h" #include "BackupStoreFile.h" +#include "ReadLoggingStream.h" namespace BackupStoreFileCreation { @@ -100,6 +101,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 -- cgit v1.2.3 From 503d68413c525aa84430c9e6c6b27eee1eaefbe4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:32:24 +0000 Subject: Make Daemon remember whether we're supposed to run in a single process, or not. (refs #3) --- lib/server/Daemon.cpp | 17 +++++++++-------- lib/server/Daemon.h | 5 ++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index c639309a..4cb33c57 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -101,7 +101,6 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // Find filename of config file mConfigFileName = DefaultConfigFile; bool haveConfigFile = false; - bool singleProcess = false; #ifdef NDEBUG int masterLevel = Log::NOTICE; // need an int to do math with @@ -125,7 +124,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) case 'D': { - singleProcess = true; + mSingleProcess = true; } break; @@ -203,7 +202,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if (argc > optind && ::strcmp(argv[optind], "SINGLEPROCESS") == 0) { - singleProcess = true; optind++; + mSingleProcess = true; optind++; } if (argc > optind) @@ -215,19 +214,20 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) Logging::SetGlobalLevel((Log::Level)masterLevel); - return Main(mConfigFileName, singleProcess); + // return Main(mConfigFileName, mSingleProcess); + return Main(mConfigFileName); } // -------------------------------------------------------------------------- // // Function -// Name: Daemon::Main(const std::string& rConfigFileName, -// bool singleProcess) +// 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, bool singleProcess) +// int Daemon::Main(const std::string &rConfigFileName, bool singleProcess) +int Daemon::Main(const std::string &rConfigFileName) { // Banner (optional) { @@ -241,7 +241,8 @@ int Daemon::Main(const std::string &rConfigFileName, bool singleProcess) std::string pidFileName; mConfigFileName = rConfigFileName; - bool asDaemon = !singleProcess; + + bool asDaemon = !mSingleProcess; try { diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h index 52bab257..2ce24cfe 100644 --- a/lib/server/Daemon.h +++ b/lib/server/Daemon.h @@ -41,7 +41,8 @@ private: public: int Main(const char *DefaultConfigFile, int argc, const char *argv[]); - int Main(const std::string &rConfigFile, bool singleProcess); + // int Main(const std::string &rConfigFile, bool singleProcess); + int Main(const std::string &rConfigFile); virtual void Run(); const Configuration &GetConfiguration() const; @@ -66,6 +67,7 @@ public: protected: box_time_t GetLoadedConfigModifiedTime() const; + bool IsSingleProcess() { return mSingleProcess; } private: static void SignalHandler(int sigraised); @@ -77,6 +79,7 @@ private: box_time_t mLoadedConfigModifiedTime; bool mReloadConfigWanted; bool mTerminateWanted; + bool mSingleProcess; bool mKeepConsoleOpenAfterFork; static Daemon *spDaemon; }; -- cgit v1.2.3 From f47682f7d047cb6c963ee7eb078979f25740231d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:33:50 +0000 Subject: Remove comments accidentally left in [1591]. (refs #3) --- lib/server/Daemon.cpp | 2 -- lib/server/Daemon.h | 1 - 2 files changed, 3 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 4cb33c57..e8e0eaa2 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -214,7 +214,6 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) Logging::SetGlobalLevel((Log::Level)masterLevel); - // return Main(mConfigFileName, mSingleProcess); return Main(mConfigFileName); } @@ -226,7 +225,6 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // Created: 2003/07/29 // // -------------------------------------------------------------------------- -// int Daemon::Main(const std::string &rConfigFileName, bool singleProcess) int Daemon::Main(const std::string &rConfigFileName) { // Banner (optional) diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h index 2ce24cfe..c4c7af0d 100644 --- a/lib/server/Daemon.h +++ b/lib/server/Daemon.h @@ -41,7 +41,6 @@ private: public: int Main(const char *DefaultConfigFile, int argc, const char *argv[]); - // int Main(const std::string &rConfigFile, bool singleProcess); int Main(const std::string &rConfigFile); virtual void Run(); -- cgit v1.2.3 From d1642a1b7d5048b3fe182280e84f002f7de65057 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:35:01 +0000 Subject: Don't fork to handle requests when running as a single process (very useful for debugging). (refs #3) --- lib/server/ServerStream.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/server/ServerStream.h b/lib/server/ServerStream.h index f8578a04..7eb99d13 100644 --- a/lib/server/ServerStream.h +++ b/lib/server/ServerStream.h @@ -230,7 +230,7 @@ public: { // Since this is a template parameter, the if() will be optimised out by the compiler #ifndef WIN32 // no fork on Win32 - if(ForkToHandleRequests) + if(ForkToHandleRequests && !IsSingleProcess()) { pid_t pid = ::fork(); switch(pid) @@ -285,7 +285,7 @@ public: #ifndef WIN32 // Clean up child processes (if forking daemon) - if(ForkToHandleRequests) + if(ForkToHandleRequests && !IsSingleProcess()) { int status = 0; int p = 0; @@ -326,7 +326,7 @@ protected: #ifdef WIN32 return false; #else - return ForkToHandleRequests; + return ForkToHandleRequests && !IsSingleProcess(); #endif // WIN32 } -- cgit v1.2.3 From e48ce8770a42e80bc33a655777bed644367c1f16 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:35:34 +0000 Subject: Improve log message for NotifyFileUploading(). (refs #3) --- bin/bbackupd/BackupDaemon.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 8895019d..14782859 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -308,7 +308,7 @@ public: { if (mLogAllFileAccess) { - BOX_INFO("Uploading file: " << rLocalPath); + BOX_INFO("Uploading complete file: " << rLocalPath); } } virtual void NotifyFileUploadingPatch( -- cgit v1.2.3 From 11b2e49ab01b00681c56aa2a8a079ae374b48344 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:36:35 +0000 Subject: Notify about full file uploads. (refs #3) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 22861f76..8cc7e78e 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -31,6 +31,7 @@ #include "Archive.h" #include "PathUtils.h" #include "Logging.h" +#include "ReadLoggingStream.h" #include "MemLeakFindOn.h" @@ -1357,9 +1358,13 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn if(doNormalUpload) { // below threshold or nothing to diff from, so upload whole + rParams.GetProgressNotifier().NotifyFileUploading(this, + rFilename); // Prepare to upload, getting a stream which will encode the file as we go along - std::auto_ptr upload(BackupStoreFile::EncodeFile(rFilename.c_str(), mObjectID, rStoreFilename)); + std::auto_ptr upload( + BackupStoreFile::EncodeFile(rFilename.c_str(), + mObjectID, rStoreFilename)); // Send to store std::auto_ptr stored( -- cgit v1.2.3 From 380e62839d18d6817b0a4aeac8e942bbb1e8a213 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:37:01 +0000 Subject: Fix formatting bugs. (refs #3) --- bin/bbackupd/BackupDaemon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 825254d9..cfe2b7ab 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -300,14 +300,14 @@ void BackupDaemon::RunHelperThread(void) } catch (BoxException &e) { - BOX_ERROR("Failed to open command socket" << + BOX_ERROR("Failed to open command socket: " << e.what()); SetTerminateWanted(); break; // this is fatal to listening thread } catch(std::exception &e) { - BOX_ERROR("Failed to open command socket" << + BOX_ERROR("Failed to open command socket: " << e.what()); SetTerminateWanted(); break; // this is fatal to listening thread -- cgit v1.2.3 From 82bea7ee6395af37ff2b6183e4ed49313dcc3539 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 17:37:37 +0000 Subject: Improve error messages when Getting a file fails with an exception. (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 1e7aebe1..29108786 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -47,6 +47,7 @@ #include "ExcludeList.h" #include "BackupClientMakeExcludeList.h" #include "PathUtils.h" +#include "Logging.h" #include "MemLeakFindOn.h" @@ -1032,10 +1033,22 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) // Done. printf("Object ID %08llx fetched sucessfully.\n", fileId); } + catch (BoxException &e) + { + BOX_ERROR("Failed to fetch file: " << + e.what()); + ::unlink(localName.c_str()); + } + catch(std::exception &e) + { + BOX_ERROR("Failed to fetch file: " << + e.what()); + ::unlink(localName.c_str()); + } catch(...) { + BOX_ERROR("Failed to fetch file: unknown error"); ::unlink(localName.c_str()); - printf("Error occured fetching file.\n"); } } -- cgit v1.2.3 From 4f98aedc41c41afa7ed0388ec838b96829d0577f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 19:57:24 +0000 Subject: Fix getting files with uncertain size (over 2GB) from the store. Failure to drain the stream will leave the EOF byte in it, which breaks further communications with the store over the same connection. (refs #2, refs #3) --- lib/backupclient/BackupStoreFile.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp index 5c621f38..5e800970 100644 --- a/lib/backupclient/BackupStoreFile.cpp +++ b/lib/backupclient/BackupStoreFile.cpp @@ -292,6 +292,14 @@ void BackupStoreFile::DecodeFile(IOStream &rEncodedFile, const char *DecodedFile } 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); + ASSERT(drained == 0); // Write the attributes stream->GetAttributes().WriteAttributes(DecodedFilename); -- cgit v1.2.3 From 5939cfae21c84cc587bec541808ae121a3536737 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 20:42:45 +0000 Subject: Fix bbackupd choosing an invalid (too large) block size for large files (over 2GB) which will cause compare to fail: when rBlockSizeOut == BACKUP_FILE_MAX_BLOCK_SIZE we would have proceeded around the loop one more time and doubled the block size again. (refs #2, refs #3) --- lib/backupclient/BackupStoreFileEncodeStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/backupclient/BackupStoreFileEncodeStream.cpp b/lib/backupclient/BackupStoreFileEncodeStream.cpp index cda18855..423c11a3 100644 --- a/lib/backupclient/BackupStoreFileEncodeStream.cpp +++ b/lib/backupclient/BackupStoreFileEncodeStream.cpp @@ -278,7 +278,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); -- cgit v1.2.3 From a04092e0dfa58849c63b720284cf88437767b890 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 20:43:48 +0000 Subject: Improve error messages when compare throws an exception. (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 29108786..e31df624 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1715,15 +1715,27 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s } catch(BoxException &e) { - printf("ERROR: (%d/%d) during file fetch and comparison for '%s'\n", - e.GetType(), - e.GetSubType(), - storePathDisplay.c_str()); + BOX_ERROR("Failed to fetch and compare " + "'" << + storePathDisplay.c_str() << + "': error " << e.what() << + " (" << e.GetType() << + "/" << e.GetSubType() << ")"); rParams.mUncheckedFiles ++; } + catch(std::exception &e) + { + BOX_ERROR("Failed to fetch and compare " + "'" << + storePathDisplay.c_str() << + "': " << e.what()); + } catch(...) { - printf("ERROR: (unknown) during file fetch and comparison for '%s'\n", storePathDisplay.c_str()); + BOX_ERROR("Failed to fetch and compare " + "'" << + storePathDisplay.c_str() << + "': unknown error"); rParams.mUncheckedFiles ++; } -- cgit v1.2.3 From 53251944e735cbc899283d0b8ac396f9525237e5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 20:44:21 +0000 Subject: Remove newline from end of banner text, since logging framework will add it for us where necessary. (refs #3) --- lib/common/BannerText.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/BannerText.h b/lib/common/BannerText.h index 7e28fa16..23486fef 100644 --- a/lib/common/BannerText.h +++ b/lib/common/BannerText.h @@ -11,7 +11,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-2006" #endif // BANNERTEXT__H -- cgit v1.2.3 From 83682d6cfbe7e9bc65ec573d1150ebbb1d6cb83e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 20:46:35 +0000 Subject: Use logging framework for banner. (refs #3) --- bin/bbackupquery/bbackupquery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index 37025d39..d02c3922 100644 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -186,7 +186,7 @@ int main(int argc, const char *argv[]) if(!quiet) { const char *banner = BANNER_TEXT("Backup Query Tool"); - printf(banner); + BOX_NOTICE(banner); } #ifdef WIN32 -- cgit v1.2.3 From 277fe6e623add50d764215a8952453977df55321 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 21:24:17 +0000 Subject: Return an error code on failure of lcd command. Return an error code if get command fails due to the file already existing. (refs #3, merges [1516]) --- bin/bbackupquery/BackupQueries.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index e31df624..b423f5b7 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -55,10 +55,10 @@ #undef min #undef max -#define COMPARE_RETURN_SAME 1 +#define COMPARE_RETURN_SAME 1 #define COMPARE_RETURN_DIFFERENT 2 #define COMPARE_RETURN_ERROR 3 - +#define COMMAND_RETURN_ERROR 4 // -------------------------------------------------------------------------- // @@ -786,13 +786,19 @@ void BackupQueries::CommandChangeLocalDir(const std::vector &args) if(args.size() != 1 || args[0].size() == 0) { printf("Incorrect usage.\nlcd \n"); + SetReturnCode(COMMAND_RETURN_ERROR); return; } // Try changing directory #ifdef WIN32 std::string dirName; - if(!ConvertConsoleToUtf8(args[0].c_str(), dirName)) return; + if(!ConvertConsoleToUtf8(args[0].c_str(), dirName)) + { + printf("Failed to convert path from console encoding.\n"); + SetReturnCode(COMMAND_RETURN_ERROR); + return; + } int result = ::chdir(dirName.c_str()); #else int result = ::chdir(args[0].c_str()); @@ -801,6 +807,7 @@ void BackupQueries::CommandChangeLocalDir(const std::vector &args) { printf((errno == ENOENT || errno == ENOTDIR)?"Directory '%s' does not exist\n":"Error changing dir to '%s'\n", args[0].c_str()); + SetReturnCode(COMMAND_RETURN_ERROR); return; } @@ -809,11 +816,17 @@ void BackupQueries::CommandChangeLocalDir(const std::vector &args) if(::getcwd(wd, PATH_MAX) == 0) { printf("Error getting current directory\n"); + SetReturnCode(COMMAND_RETURN_ERROR); return; } #ifdef WIN32 - if(!ConvertUtf8ToConsole(wd, dirName)) return; + if(!ConvertUtf8ToConsole(wd, dirName)) + { + printf("Failed to convert new path from console encoding.\n"); + SetReturnCode(COMMAND_RETURN_ERROR); + return; + } printf("Local current directory is now '%s'\n", dirName.c_str()); #else printf("Local current directory is now '%s'\n", wd); @@ -1014,7 +1027,9 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) struct stat st; if(::stat(localName.c_str(), &st) == 0 || errno != ENOENT) { - printf("The local file %s already exists, will not overwrite it.\n", localName.c_str()); + printf("The local file %s already exists, will not " + "overwrite it.\n", localName.c_str()); + SetReturnCode(COMMAND_RETURN_ERROR); return; } -- cgit v1.2.3 From 5f500e07ceaf3e2cb67b6809d266af281e809b99 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 21:26:41 +0000 Subject: Fix rare memory leak. (refs #3, merges part of [1514]) --- lib/win32/emu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 818c6a6b..7f665629 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -1518,6 +1518,7 @@ char* emu_getcwd(char* pBuffer, int BufSize) if (result <= 0 || result >= len) { errno = EACCES; + delete [] pWide; return NULL; } -- cgit v1.2.3 From d8ebd9eef858f350b113f6ecd6ad6b7332b2fde7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 21:28:22 +0000 Subject: Listen on an inet socket as well, to keep tests happy on Windows (refs #3, merges part of [582]) --- test/basicserver/testfiles/srv4.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/basicserver/testfiles/srv4.conf b/test/basicserver/testfiles/srv4.conf index b4c5627c..ebd27268 100644 --- a/test/basicserver/testfiles/srv4.conf +++ b/test/basicserver/testfiles/srv4.conf @@ -1,6 +1,6 @@ Server { - PidFile = testfiles/srv4.pid - ListenAddresses = unix:testfiles/srv4.sock + PidFile = testfiles\srv4.pid + ListenAddresses = unix:testfiles/srv4.sock,inet:localhost } -- cgit v1.2.3 From d725d19a32957b4cf2d29d9310b97ff4860faaca Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 21:28:48 +0000 Subject: Revert to Unix paths (refs #3) --- test/basicserver/testfiles/srv4.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/basicserver/testfiles/srv4.conf b/test/basicserver/testfiles/srv4.conf index ebd27268..f05dff75 100644 --- a/test/basicserver/testfiles/srv4.conf +++ b/test/basicserver/testfiles/srv4.conf @@ -1,6 +1,6 @@ Server { - PidFile = testfiles\srv4.pid + PidFile = testfiles/srv4.pid ListenAddresses = unix:testfiles/srv4.sock,inet:localhost } -- cgit v1.2.3 From 1a6b874bba1880bbeeb1faa08c8d7bcb60acde53 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 22:06:50 +0000 Subject: Test that bbackupd and bbstored are still running at various points during the test, and abort early if not. (refs #3) --- test/bbackupd/testbbackupd.cpp | 152 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index bb74f16b..0113dd2b 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1053,6 +1053,11 @@ int test_bbackupd() ::safe_sleep(1); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + if(bbackupd_pid > 0) { // First, check storage space handling -- wait for file to be uploaded @@ -1118,6 +1123,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + #ifdef WIN32 printf("\n==== Check that filenames in UTF-8 " "can be backed up\n"); @@ -1418,6 +1428,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 2); #endif // WIN32 + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("\n==== Check that SyncAllowScript is executed and can " "pause backup\n"); fflush(stdout); @@ -1518,6 +1533,11 @@ int test_bbackupd() } } + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("\n==== Delete file and update another, " "create symlink.\n"); @@ -1558,6 +1578,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Check that store errors are reported neatly printf("Create store error\n"); TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf", @@ -1597,6 +1622,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Wait until bbackupd recovers from the exception wait_for_backup_operation(100); @@ -1612,6 +1642,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Bad case: delete a file/symlink, replace it with a directory printf("Replace symlink with directory, add new directory\n"); #ifndef WIN32 @@ -1632,6 +1667,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // And the inverse, replace a directory with a file/symlink printf("Replace directory with symlink\n"); #ifndef WIN32 @@ -1649,6 +1689,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // And then, put it back to how it was before. printf("Replace symlink with directory (which was a symlink)\n"); #ifndef WIN32 @@ -1672,6 +1717,11 @@ int test_bbackupd() #ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents2") == 0); #endif + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0); #ifndef WIN32 TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); @@ -1684,6 +1734,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // rename an untracked file over an // existing untracked file printf("Rename over existing untracked file\n"); @@ -1725,6 +1780,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // case which went wrong: rename a tracked file over an // existing tracked file printf("Rename over existing tracked file\n"); @@ -1769,6 +1829,12 @@ int test_bbackupd() // case which went wrong: rename a tracked file over a deleted file printf("Rename an existing file over a deleted file\n"); TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " @@ -1777,6 +1843,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("Add files with old times, update attributes of one to latest time\n"); // Move that file back @@ -1801,6 +1872,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Check that modifying files with old timestamps // still get added printf("\n==== Modify existing file, but change timestamp " @@ -1851,6 +1927,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Add some files and directories which are marked as excluded printf("Add files and dirs for exclusion test\n"); #ifdef WIN32 @@ -2005,6 +2086,11 @@ int test_bbackupd() } #endif // WIN32 + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("Continuously update file, check isn't uploaded\n"); // Make sure everything happens at the same point in the sync cycle: wait until exactly the start of a sync @@ -2055,6 +2141,11 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("Delete directory, change attributes\n"); // Delete a directory @@ -2124,6 +2215,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + #ifdef WIN32 // make one of the files read-only, expect a compare failure compareReturnValue = ::system("attrib +r " @@ -2210,6 +2306,11 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbackupquery.memleaks"); #endif // WIN32 + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("Add files with current time\n"); // Add some more files and modify others @@ -2229,6 +2330,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Rename directory printf("Rename directory\n"); TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", "testfiles/TestDir1/renamed-dir") == 0); @@ -2261,6 +2367,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // Check that modifying files with madly in the future timestamps still get added printf("Create a file with timestamp to way ahead in the future\n"); // Time critical, so sync @@ -2289,6 +2400,11 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("Change client store marker\n"); // Then... connect to the server, and change the client store marker. See what that does! @@ -2324,6 +2440,11 @@ int test_bbackupd() TEST_THAT(done); } + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("Check change of store marker pauses daemon\n"); // Make a change to a file, to detect whether or not @@ -2344,8 +2465,22 @@ int test_bbackupd() "\"compare -ac\" quit"); TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Waiting for bbackupd to recover\n"); + // 100 seconds - (12*3/2) + wait_for_operation(82); + + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; -#ifndef WIN32 +#ifndef WIN32 printf("\n==== Interrupted restore\n"); { do_interrupted_restore(context, restoredirid); @@ -2380,6 +2515,11 @@ int test_bbackupd() } #endif // !WIN32 + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + printf("Check restore deleted files\n"); { SocketStreamTLS conn; @@ -2407,6 +2547,11 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2")); TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2")); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + #ifdef WIN32 printf("\n==== Testing locked file behaviour:\n"); @@ -2486,6 +2631,11 @@ int test_bbackupd() TEST_THAT(bbackupd_pid != -1 && bbackupd_pid != 0); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + if(bbackupd_pid != -1 && bbackupd_pid != 0) { // Wait and compare (a little bit longer than usual) -- cgit v1.2.3 From 4ae598a15cd4981ccbd2fd33c3a6d0e6ea6e76f4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 22:32:24 +0000 Subject: Format messages within test to make them more obvious, and improve readability of test output. (refs #3) --- test/bbackupd/testbbackupd.cpp | 74 +++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 0113dd2b..c60019df 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1584,7 +1584,7 @@ int test_bbackupd() if (!ServerIsAlive(bbstored_pid)) return 1; // Check that store errors are reported neatly - printf("Create store error\n"); + printf("\n==== Create store error\n"); TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf", "testfiles/0_0/backup/01234567/info.rf.bak") == 0); TEST_THAT(::rename("testfiles/0_1/backup/01234567/info.rf", @@ -1648,7 +1648,8 @@ int test_bbackupd() if (!ServerIsAlive(bbstored_pid)) return 1; // Bad case: delete a file/symlink, replace it with a directory - printf("Replace symlink with directory, add new directory\n"); + printf("\n==== Replace symlink with directory, " + "add new directory\n"); #ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir") == 0); #endif @@ -1673,7 +1674,8 @@ int test_bbackupd() if (!ServerIsAlive(bbstored_pid)) return 1; // And the inverse, replace a directory with a file/symlink - printf("Replace directory with symlink\n"); + printf("\n==== Replace directory with symlink\n"); + #ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents") == 0); #endif @@ -1695,7 +1697,9 @@ int test_bbackupd() if (!ServerIsAlive(bbstored_pid)) return 1; // And then, put it back to how it was before. - printf("Replace symlink with directory (which was a symlink)\n"); + printf("\n==== Replace symlink with directory " + "(which was a symlink)\n"); + #ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file") == 0); #endif @@ -1711,9 +1715,12 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - // And finally, put it back to how it was before it was put back to how it was before - // This gets lots of nasty things in the store with directories over other old directories. - printf("Put it all back to how it was\n"); + // And finally, put it back to how it was before + // it was put back to how it was before + // This gets lots of nasty things in the store with + // directories over other old directories. + printf("\n==== Put it all back to how it was\n"); + #ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents2") == 0); #endif @@ -1741,7 +1748,7 @@ int test_bbackupd() // rename an untracked file over an // existing untracked file - printf("Rename over existing untracked file\n"); + printf("\n==== Rename over existing untracked file\n"); int fd1 = open("testfiles/TestDir1/untracked-1", O_CREAT | O_EXCL | O_WRONLY, 0700); int fd2 = open("testfiles/TestDir1/untracked-2", @@ -1787,7 +1794,7 @@ int test_bbackupd() // case which went wrong: rename a tracked file over an // existing tracked file - printf("Rename over existing tracked file\n"); + printf("\n==== Rename over existing tracked file\n"); fd1 = open("testfiles/TestDir1/tracked-1", O_CREAT | O_EXCL | O_WRONLY, 0700); fd2 = open("testfiles/TestDir1/tracked-2", @@ -1826,15 +1833,17 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - // case which went wrong: rename a tracked file over a deleted file - printf("Rename an existing file over a deleted file\n"); - TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); - TEST_THAT(ServerIsAlive(bbackupd_pid)); TEST_THAT(ServerIsAlive(bbstored_pid)); if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; + // case which went wrong: rename a tracked file + // over a deleted file + printf("\n==== Rename an existing file over a deleted file\n"); + TEST_THAT(!TestFileExists("testfiles/TestDir1/x1/dsfdsfs98.fd")); + TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", + "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " @@ -1848,7 +1857,8 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; - printf("Add files with old times, update attributes of one to latest time\n"); + printf("\n==== Add files with old times, update " + "attributes of one to latest time\n"); // Move that file back TEST_THAT(::rename("testfiles/TestDir1/x1/dsfdsfs98.fd", "testfiles/TestDir1/df9834.dsf") == 0); @@ -1933,7 +1943,8 @@ int test_bbackupd() if (!ServerIsAlive(bbstored_pid)) return 1; // Add some files and directories which are marked as excluded - printf("Add files and dirs for exclusion test\n"); + printf("\n==== Add files and dirs for exclusion test\n"); + #ifdef WIN32 TEST_THAT(::system("tar xzvf testfiles/testexclude.tgz -C testfiles") == 0); #else @@ -2052,7 +2063,8 @@ int test_bbackupd() if(::getuid() != 0) { // Check that read errors are reported neatly - printf("Add unreadable files\n"); + printf("\n==== Add unreadable files\n"); + { // Dir and file which can't be read TEST_THAT(::mkdir("testfiles/TestDir1/sub23/read-fail-test-dir", 0000) == 0); @@ -2091,7 +2103,8 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; - printf("Continuously update file, check isn't uploaded\n"); + printf("\n==== Continuously update file, " + "check isn't uploaded\n"); // Make sure everything happens at the same point in the sync cycle: wait until exactly the start of a sync TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -c testfiles/bbackupd.conf wait-for-sync") == 0); @@ -2120,7 +2133,8 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - printf("Keep on continuously updating file, check it is uploaded eventually\n"); + printf("\n==== Keep on continuously updating file, " + "check it is uploaded eventually\n"); for(int l = 0; l < 28; ++l) { @@ -2146,7 +2160,7 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; - printf("Delete directory, change attributes\n"); + printf("\n==== Delete directory, change attributes\n"); // Delete a directory TEST_THAT(::system("rm -rf testfiles/TestDir1/x1") == 0); @@ -2162,7 +2176,7 @@ int test_bbackupd() TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); - printf("Restore files and directories\n"); + printf("\n==== Restore files and directories\n"); int64_t deldirid = 0; int64_t restoredirid = 0; { @@ -2311,7 +2325,7 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; - printf("Add files with current time\n"); + printf("\n==== Add files with current time\n"); // Add some more files and modify others // Use the m flag this time so they have a recent modification time @@ -2336,7 +2350,7 @@ int test_bbackupd() if (!ServerIsAlive(bbstored_pid)) return 1; // Rename directory - printf("Rename directory\n"); + printf("\n==== Rename directory\n"); TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", "testfiles/TestDir1/renamed-dir") == 0); wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " @@ -2355,7 +2369,7 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Rename some files -- one under the threshold, others above - printf("Rename files\n"); + printf("\n==== Rename files\n"); TEST_THAT(rename("testfiles/TestDir1/continousupdate", "testfiles/TestDir1/continousupdate-ren") == 0); TEST_THAT(rename("testfiles/TestDir1/df324", "testfiles/TestDir1/df324-ren") == 0); TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", "testfiles/TestDir1/find2perl-ren") == 0); @@ -2372,8 +2386,10 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; - // Check that modifying files with madly in the future timestamps still get added - printf("Create a file with timestamp to way ahead in the future\n"); + // Check that modifying files with madly in the future + // timestamps still get added + printf("\n==== Create a file with timestamp way ahead " + "in the future\n"); // Time critical, so sync TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0); TestRemoteProcessMemLeaks("bbackupctl.memleaks"); @@ -2405,7 +2421,7 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; - printf("Change client store marker\n"); + printf("\n==== Change client store marker\n"); // Then... connect to the server, and change the client store marker. See what that does! { @@ -2445,7 +2461,7 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; - printf("Check change of store marker pauses daemon\n"); + printf("\n==== Check change of store marker pauses daemon\n"); // Make a change to a file, to detect whether or not // it's hanging around waiting to retry. @@ -2488,7 +2504,7 @@ int test_bbackupd() TEST_THAT(FileExists("testfiles/restore-interrupt.boxbackupresume", &resumesize)); TEST_THAT(resumesize > 16); // make sure it has recorded something to resume - printf("\nResume restore\n"); + printf("\n==== Resume restore\n"); SocketStreamTLS conn; conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); @@ -2520,7 +2536,7 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; - printf("Check restore deleted files\n"); + printf("\n==== Check restore deleted files\n"); { SocketStreamTLS conn; conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); -- cgit v1.2.3 From a0991f8a0dfd9b1c4860213800bf2c8b4b423389 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 22:46:30 +0000 Subject: Use quiet mode in compares, to reduce test output verbosity (refs #3) --- test/bbackupd/testbbackupd.cpp | 67 +++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index c60019df..3fec1fa1 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1088,7 +1088,7 @@ int test_bbackupd() int compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query0a.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1119,7 +1119,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query1.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1566,7 +1566,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query2.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1574,7 +1574,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query2q.log " - "\"compare -acq\" quit"); + "\"compare -acqQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1664,7 +1664,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3c.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1687,7 +1687,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3d.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1711,10 +1711,15 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3e.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + TEST_THAT(ServerIsAlive(bbackupd_pid)); + TEST_THAT(ServerIsAlive(bbstored_pid)); + if (!ServerIsAlive(bbackupd_pid)) return 1; + if (!ServerIsAlive(bbstored_pid)) return 1; + // And finally, put it back to how it was before // it was put back to how it was before // This gets lots of nasty things in the store with @@ -1737,7 +1742,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3f.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1768,7 +1773,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3g.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); #ifdef WIN32 @@ -1783,7 +1788,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3g.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1815,8 +1820,9 @@ int test_bbackupd() // back up both files wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " - "-c testfiles/bbackupd.conf -l testfiles/query3u.log " - "\"compare -ac\" quit"); + "-c testfiles/bbackupd.conf " + "-l testfiles/query3h.log " + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); #ifdef WIN32 @@ -1828,8 +1834,9 @@ int test_bbackupd() TEST_THAT( TestFileExists("testfiles/TestDir1/tracked-2")); wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " - "-c testfiles/bbackupd.conf -l testfiles/query3v.log " - "\"compare -ac\" quit"); + "-c testfiles/bbackupd.conf " + "-l testfiles/query3i.log " + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1848,7 +1855,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3j.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1878,7 +1885,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3k.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1933,7 +1940,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3l.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1959,7 +1966,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3m.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -1967,7 +1974,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3n.log " - "\"compare -acE\" quit"); + "\"compare -acEQ\" quit"); TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2078,7 +2085,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3o.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); // Check that unreadable files were found TEST_RETURN(compareReturnValue, 3); @@ -2172,7 +2179,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query4.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2340,7 +2347,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query5.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2356,7 +2363,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query6.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2364,7 +2371,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query6q.log " - "\"compare -acq\" quit"); + "\"compare -acqQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2377,7 +2384,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query6.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2412,7 +2419,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query3e.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2478,7 +2485,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query6.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 2); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2524,7 +2531,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query14.log " - "\"compare -cE Test1 " + "\"compare -cEQ Test1 " "testfiles/restore-interrupt\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2553,7 +2560,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query11.log " - "\"compare -cE Test1/x1 " + "\"compare -cEQ Test1/x1 " "testfiles/restore-Test1-x1-2\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2660,7 +2667,7 @@ int test_bbackupd() compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " "-l testfiles/query4a.log " - "\"compare -ac\" quit"); + "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); -- cgit v1.2.3 From a2e6ac25f8759d1ce440c08ed8519217c74e349e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 22:51:12 +0000 Subject: Use helper function rather than calling bbackupctl directly. (refs #3) --- test/bbackupd/testbbackupd.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 3fec1fa1..41f7452c 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -2113,9 +2113,10 @@ int test_bbackupd() printf("\n==== Continuously update file, " "check isn't uploaded\n"); - // Make sure everything happens at the same point in the sync cycle: wait until exactly the start of a sync - TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -c testfiles/bbackupd.conf wait-for-sync") == 0); - TestRemoteProcessMemLeaks("bbackupctl.memleaks"); + // Make sure everything happens at the same point in the + // sync cycle: wait until exactly the start of a sync + wait_for_sync_start(); + // Then wait a second, to make sure the scan is complete ::safe_sleep(1); @@ -2398,10 +2399,11 @@ int test_bbackupd() printf("\n==== Create a file with timestamp way ahead " "in the future\n"); // Time critical, so sync - TEST_THAT(::system("../../bin/bbackupctl/bbackupctl -q -c testfiles/bbackupd.conf wait-for-sync") == 0); - TestRemoteProcessMemLeaks("bbackupctl.memleaks"); + wait_for_sync_start(); + // Then wait a second, to make sure the scan is complete ::safe_sleep(1); + // Then modify an existing file { FILE *f = fopen("testfiles/TestDir1/sub23/in-the-future", "w"); -- cgit v1.2.3 From 951f124bb8b17315a0f2af3fd446fb84b90d2a33 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 23:09:43 +0000 Subject: Close updated files during continuous-update test, so that they can be backed up on Win32. (refs #3) --- test/bbackupd/testbbackupd.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 41f7452c..b67488d5 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -2128,16 +2128,18 @@ int test_bbackupd() TEST_THAT(f != 0); fprintf(f, "Loop iteration %d\n", l); fflush(f); - safe_sleep(1); + fclose(f); + printf("."); fflush(stdout); - ::fclose(f); + safe_sleep(1); } printf("\n"); fflush(stdout); // Check there's a difference compareReturnValue = ::system("testfiles/extcheck1.pl"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2146,19 +2148,22 @@ int test_bbackupd() for(int l = 0; l < 28; ++l) { - FILE *f = ::fopen("testfiles/TestDir1/continousupdate", "w+"); + FILE *f = ::fopen("testfiles/TestDir1/" + "continousupdate", "w+"); TEST_THAT(f != 0); fprintf(f, "Loop 2 iteration %d\n", l); fflush(f); - safe_sleep(1); + fclose(f); + printf("."); fflush(stdout); - ::fclose(f); + safe_sleep(1); } printf("\n"); fflush(stdout); compareReturnValue = ::system("testfiles/extcheck2.pl"); + TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); } -- cgit v1.2.3 From 11faa8183f5918065f9355a2bbbb75d848a30edf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 23:13:01 +0000 Subject: Remove misplaced hunk. (refs #3) --- test/bbackupd/testbbackupd.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index b67488d5..cf638a19 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1729,10 +1729,6 @@ int test_bbackupd() #ifndef WIN32 TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents2") == 0); #endif - TEST_THAT(ServerIsAlive(bbackupd_pid)); - TEST_THAT(ServerIsAlive(bbstored_pid)); - if (!ServerIsAlive(bbackupd_pid)) return 1; - if (!ServerIsAlive(bbstored_pid)) return 1; TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0); #ifndef WIN32 -- cgit v1.2.3 From 95dd1eb70287710a8e230d47f7c0075c1da17a01 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 23:14:47 +0000 Subject: Call perl executable to execute external scripts, since shebang doesn't work on win32. (refs #3) --- test/bbackupd/testbbackupd.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index cf638a19..64212f02 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -2134,7 +2134,8 @@ int test_bbackupd() fflush(stdout); // Check there's a difference - compareReturnValue = ::system("testfiles/extcheck1.pl"); + compareReturnValue = ::system("perl testfiles/" + "extcheck1.pl"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); @@ -2158,7 +2159,8 @@ int test_bbackupd() printf("\n"); fflush(stdout); - compareReturnValue = ::system("testfiles/extcheck2.pl"); + compareReturnValue = ::system("perl testfiles/" + "extcheck2.pl"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); -- cgit v1.2.3 From 6ab01622e0dab4d08067472cc42c3ffa9e8fba75 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 28 Apr 2007 23:26:05 +0000 Subject: Gratuitous cosmetic reformatting, to make the test easier to read (refs #3) --- test/bbackupd/testbbackupd.cpp | 335 +++++++++++++++++++++++++++-------------- 1 file changed, 222 insertions(+), 113 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 64212f02..51ed02be 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -752,8 +752,9 @@ int lstat_test_hook(const char *file_name, struct stat *buf) int test_bbackupd() { -// // First, wait for a normal period to make sure the last changes attributes are within a normal backup timeframe. -// wait_for_backup_operation(); + // First, wait for a normal period to make sure the last changes + // attributes are within a normal backup timeframe. + // wait_for_backup_operation(); // Connection gubbins TLSContext context; @@ -1074,11 +1075,14 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); // Unpack some more files -#ifdef WIN32 - TEST_THAT(::system("tar xzvf testfiles/spacetest2.tgz -C testfiles/TestDir1") == 0); -#else - TEST_THAT(::system("gzip -d < testfiles/spacetest2.tgz | ( cd testfiles/TestDir1 && tar xf - )") == 0); -#endif + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/spacetest2.tgz " + "-C testfiles/TestDir1") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/spacetest2.tgz " + "| ( cd testfiles/TestDir1 && tar xf - )") == 0); + #endif + // Delete a file and a directory TEST_THAT(::unlink("testfiles/TestDir1/spacetest/d1/f3") == 0); TEST_THAT(::system("rm -rf testfiles/TestDir1/spacetest/d3/d4") == 0); @@ -1104,11 +1108,13 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/notifyran.store-full.2")); // unpack the initial files again -#ifdef WIN32 - TEST_THAT(::system("tar xzvf testfiles/test_base.tgz -C testfiles") == 0); -#else - TEST_THAT(::system("gzip -d < testfiles/test_base.tgz | ( cd testfiles && tar xf - )") == 0); -#endif + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test_base.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/test_base.tgz " + "| ( cd testfiles && tar xf - )") == 0); + #endif // wait for it to do it's stuff wait_for_backup_operation(); @@ -1543,22 +1549,27 @@ int test_bbackupd() // Delete a file TEST_THAT(::unlink("testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); -#ifndef WIN32 - // New symlink - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/symlink-to-dir") == 0); -#endif + + #ifndef WIN32 + // New symlink + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/symlink-to-dir") == 0); + #endif // Update a file (will be uploaded as a diff) { - // Check that the file is over the diffing threshold in the bbstored.conf file - TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") > 1024); + // Check that the file is over the diffing + // threshold in the bbackupd.conf file + TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") + > 1024); // Add a bit to the end FILE *f = ::fopen("testfiles/TestDir1/f45.df", "a"); TEST_THAT(f != 0); ::fprintf(f, "EXTRA STUFF"); ::fclose(f); - TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") > 1024); + TEST_THAT(TestGetFileSize("testfiles/TestDir1/f45.df") + > 1024); } // wait for backup daemon to do it's stuff, and compare again @@ -1604,7 +1615,7 @@ int test_bbackupd() wait_for_backup_operation(); // Check that it was reported correctly TEST_THAT(TestFileExists("testfiles/notifyran.backup-error.1")); - // Check that the error was only reorted once + // Check that the error was only reported once TEST_THAT(!TestFileExists("testfiles/notifyran.backup-error.2")); // Fix the store TEST_THAT(::rename("testfiles/0_0/backup/01234567/info.rf.bak", @@ -1650,15 +1661,25 @@ int test_bbackupd() // Bad case: delete a file/symlink, replace it with a directory printf("\n==== Replace symlink with directory, " "add new directory\n"); -#ifndef WIN32 - TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir") == 0); -#endif - TEST_THAT(::mkdir("testfiles/TestDir1/symlink-to-dir", 0755) == 0); - TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) == 0); - // NOTE: create a file within the directory to avoid deletion by the housekeeping process later -#ifndef WIN32 - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents") == 0); -#endif + + #ifndef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/symlink-to-dir") + == 0); + #endif + + TEST_THAT(::mkdir("testfiles/TestDir1/symlink-to-dir", 0755) + == 0); + TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) + == 0); + + // NOTE: create a file within the directory to + // avoid deletion by the housekeeping process later + + #ifndef WIN32 + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/x1/dir-to-file/contents") + == 0); + #endif wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " @@ -1676,13 +1697,18 @@ int test_bbackupd() // And the inverse, replace a directory with a file/symlink printf("\n==== Replace directory with symlink\n"); -#ifndef WIN32 - TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents") == 0); -#endif + #ifndef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file" + "/contents") == 0); + #endif + TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0); -#ifndef WIN32 - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); -#endif + + #ifndef WIN32 + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/x1/dir-to-file") == 0); + #endif + wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " @@ -1700,13 +1726,20 @@ int test_bbackupd() printf("\n==== Replace symlink with directory " "(which was a symlink)\n"); -#ifndef WIN32 - TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file") == 0); -#endif - TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", 0755) == 0); -#ifndef WIN32 - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file/contents2") == 0); -#endif + #ifndef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/x1" + "/dir-to-file") == 0); + #endif + + TEST_THAT(::mkdir("testfiles/TestDir1/x1/dir-to-file", + 0755) == 0); + + #ifndef WIN32 + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/x1/dir-to-file/contents2") + == 0); + #endif + wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " @@ -1726,14 +1759,18 @@ int test_bbackupd() // directories over other old directories. printf("\n==== Put it all back to how it was\n"); -#ifndef WIN32 - TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file/contents2") == 0); -#endif + #ifndef WIN32 + TEST_THAT(::unlink("testfiles/TestDir1/x1/dir-to-file" + "/contents2") == 0); + #endif TEST_THAT(::rmdir("testfiles/TestDir1/x1/dir-to-file") == 0); -#ifndef WIN32 - TEST_THAT(::symlink("does-not-exist", "testfiles/TestDir1/x1/dir-to-file") == 0); -#endif + + #ifndef WIN32 + TEST_THAT(::symlink("does-not-exist", + "testfiles/TestDir1/x1/dir-to-file") == 0); + #endif + wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " @@ -1772,10 +1809,12 @@ int test_bbackupd() "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + #ifdef WIN32 - TEST_THAT(::unlink("testfiles/TestDir1/untracked-2") + TEST_THAT(::unlink("testfiles/TestDir1/untracked-2") == 0); #endif + TEST_THAT(::rename("testfiles/TestDir1/untracked-1", "testfiles/TestDir1/untracked-2") == 0); TEST_THAT(!TestFileExists("testfiles/TestDir1/untracked-1")); @@ -1821,9 +1860,12 @@ int test_bbackupd() "\"compare -acQ\" quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + #ifdef WIN32 - TEST_THAT(::unlink("testfiles/TestDir1/tracked-2") == 0); + TEST_THAT(::unlink("testfiles/TestDir1/tracked-2") + == 0); #endif + TEST_THAT(::rename("testfiles/TestDir1/tracked-1", "testfiles/TestDir1/tracked-2") == 0); TEST_THAT(!TestFileExists("testfiles/TestDir1/tracked-1")); @@ -1864,17 +1906,21 @@ int test_bbackupd() "attributes of one to latest time\n"); // Move that file back - TEST_THAT(::rename("testfiles/TestDir1/x1/dsfdsfs98.fd", "testfiles/TestDir1/df9834.dsf") == 0); + TEST_THAT(::rename("testfiles/TestDir1/x1/dsfdsfs98.fd", + "testfiles/TestDir1/df9834.dsf") == 0); // Add some more files - // Because the 'm' option is not used, these files will look very old to the daemon. + // Because the 'm' option is not used, these files will + // look very old to the daemon. // Lucky it'll upload them then! -#ifdef WIN32 - TEST_THAT(::system("tar xzvf testfiles/test2.tgz -C testfiles") == 0); -#else - TEST_THAT(::system("gzip -d < testfiles/test2.tgz | ( cd testfiles && tar xf - )") == 0); - ::chmod("testfiles/TestDir1/sub23/dhsfdss/blf.h", 0415); -#endif + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test2.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/test2.tgz " + "| ( cd testfiles && tar xf - )") == 0); + ::chmod("testfiles/TestDir1/sub23/dhsfdss/blf.h", 0415); + #endif // Wait and test wait_for_backup_operation(); @@ -1925,10 +1971,13 @@ int test_bbackupd() // and then move the time backwards! struct timeval times[2]; - BoxTimeToTimeval(SecondsToBoxTime((time_t)(365*24*60*60)), times[1]); + BoxTimeToTimeval(SecondsToBoxTime( + (time_t)(365*24*60*60)), times[1]); times[0] = times[1]; - TEST_THAT(::utimes("testfiles/TestDir1/sub23/rand.h", times) == 0); + TEST_THAT(::utimes("testfiles/TestDir1/sub23/rand.h", + times) == 0); } + // Wait and test wait_for_sync_end(); // files too new wait_for_sync_end(); // should (not) be backed up this time @@ -1947,12 +1996,14 @@ int test_bbackupd() // Add some files and directories which are marked as excluded printf("\n==== Add files and dirs for exclusion test\n"); - -#ifdef WIN32 - TEST_THAT(::system("tar xzvf testfiles/testexclude.tgz -C testfiles") == 0); -#else - TEST_THAT(::system("gzip -d < testfiles/testexclude.tgz | ( cd testfiles && tar xf - )") == 0); -#endif + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/testexclude.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < " + "testfiles/testexclude.tgz " + "| ( cd testfiles && tar xf - )") == 0); + #endif // Wait and test wait_for_sync_end(); @@ -2070,8 +2121,11 @@ int test_bbackupd() { // Dir and file which can't be read - TEST_THAT(::mkdir("testfiles/TestDir1/sub23/read-fail-test-dir", 0000) == 0); - int fd = ::open("testfiles/TestDir1/read-fail-test-file", O_CREAT | O_WRONLY, 0000); + TEST_THAT(::mkdir("testfiles/TestDir1/sub23" + "/read-fail-test-dir", 0000) == 0); + int fd = ::open("testfiles/TestDir1" + "/read-fail-test-file", + O_CREAT | O_WRONLY, 0000); TEST_THAT(fd != -1); ::close(fd); } @@ -2083,23 +2137,24 @@ int test_bbackupd() "-l testfiles/query3o.log " "\"compare -acQ\" quit"); - // Check that unreadable files were found - TEST_RETURN(compareReturnValue, 3); - - // Check for memory leaks during compare + // should find differences + TEST_RETURN(compareReturnValue, 3); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Check that it was reported correctly TEST_THAT(TestFileExists("testfiles/notifyran.read-error.1")); - // Check that the error was only reorted once + // Check that the error was only reported once TEST_THAT(!TestFileExists("testfiles/notifyran.read-error.2")); - // Set permissions on file and dir to stop errors in the future - ::chmod("testfiles/TestDir1/sub23/read-fail-test-dir", 0770); - ::chmod("testfiles/TestDir1/read-fail-test-file", 0770); + // Set permissions on file and dir to stop + // errors in the future + TEST_THAT(::chmod("testfiles/TestDir1/sub23" + "/read-fail-test-dir", 0770) == 0); + TEST_THAT(::chmod("testfiles/TestDir1" + "/read-fail-test-file", 0770) == 0); } -#endif // WIN32 +#endif TEST_THAT(ServerIsAlive(bbackupd_pid)); TEST_THAT(ServerIsAlive(bbstored_pid)); @@ -2193,17 +2248,24 @@ int test_bbackupd() { // connect and log in SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, "localhost", + BOX_PORT_BBSTORED); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); - std::auto_ptr loginConf(protocol.QueryLogin(0x01234567, BackupProtocolClientLogin::Flags_ReadOnly)); + std::auto_ptr + loginConf(protocol.QueryLogin(0x01234567, + BackupProtocolClientLogin::Flags_ReadOnly)); // Find the ID of the Test1 directory - restoredirid = GetDirID(protocol, "Test1", BackupProtocolClientListDirectory::RootDirectory); + restoredirid = GetDirID(protocol, "Test1", + BackupProtocolClientListDirectory::RootDirectory); TEST_THAT(restoredirid != 0); // Test the restoration - TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-Test1", true /* print progress dots */) == Restore_Complete); + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/restore-Test1", + true /* print progress dots */) + == Restore_Complete); // Compare it compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query10.log \"compare -cE Test1 testfiles/restore-Test1\" quit"); @@ -2211,7 +2273,10 @@ int test_bbackupd() TestRemoteProcessMemLeaks("bbackupquery.memleaks"); // Make sure you can't restore a restored directory - TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-Test1", true /* print progress dots */) == Restore_TargetExists); + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/restore-Test1", + true /* print progress dots */) + == Restore_TargetExists); // Make sure you can't restore to a nonexistant path printf("Try to restore to a path that doesn't exist\n"); @@ -2224,8 +2289,13 @@ int test_bbackupd() deldirid = GetDirID(protocol, "x1", restoredirid); TEST_THAT(deldirid != 0); - // Just check it doesn't bomb out -- will check this properly later (when bbackupd is stopped) - TEST_THAT(BackupClientRestore(protocol, deldirid, "testfiles/restore-Test1-x1", true /* print progress dots */, true /* deleted files */) == Restore_Complete); + // Just check it doesn't bomb out -- will check this + // properly later (when bbackupd is stopped) + TEST_THAT(BackupClientRestore(protocol, deldirid, + "testfiles/restore-Test1-x1", + true /* print progress dots */, + true /* deleted files */) + == Restore_Complete); // Log out protocol.QueryFinished(); @@ -2340,11 +2410,13 @@ int test_bbackupd() // Add some more files and modify others // Use the m flag this time so they have a recent modification time -#ifdef WIN32 - TEST_THAT(::system("tar xzvmf testfiles/test3.tgz -C testfiles") == 0); -#else - TEST_THAT(::system("gzip -d < testfiles/test3.tgz | ( cd testfiles && tar xmf - )") == 0); -#endif + #ifdef WIN32 + TEST_THAT(::system("tar xzvmf testfiles/test3.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/test3.tgz " + "| ( cd testfiles && tar xmf - )") == 0); + #endif // Wait and test wait_for_backup_operation(); @@ -2362,7 +2434,8 @@ int test_bbackupd() // Rename directory printf("\n==== Rename directory\n"); - TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", "testfiles/TestDir1/renamed-dir") == 0); + TEST_THAT(rename("testfiles/TestDir1/sub23/dhsfdss", + "testfiles/TestDir1/renamed-dir") == 0); wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " @@ -2381,9 +2454,12 @@ int test_bbackupd() // Rename some files -- one under the threshold, others above printf("\n==== Rename files\n"); - TEST_THAT(rename("testfiles/TestDir1/continousupdate", "testfiles/TestDir1/continousupdate-ren") == 0); - TEST_THAT(rename("testfiles/TestDir1/df324", "testfiles/TestDir1/df324-ren") == 0); - TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", "testfiles/TestDir1/find2perl-ren") == 0); + TEST_THAT(rename("testfiles/TestDir1/continousupdate", + "testfiles/TestDir1/continousupdate-ren") == 0); + TEST_THAT(rename("testfiles/TestDir1/df324", + "testfiles/TestDir1/df324-ren") == 0); + TEST_THAT(rename("testfiles/TestDir1/sub23/find2perl", + "testfiles/TestDir1/find2perl-ren") == 0); wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " @@ -2409,16 +2485,21 @@ int test_bbackupd() // Then modify an existing file { - FILE *f = fopen("testfiles/TestDir1/sub23/in-the-future", "w"); + FILE *f = fopen("testfiles/TestDir1/sub23/" + "in-the-future", "w"); TEST_THAT(f != 0); fprintf(f, "Back to the future!\n"); fclose(f); // and then move the time forwards! struct timeval times[2]; - BoxTimeToTimeval(GetCurrentBoxTime() + SecondsToBoxTime((time_t)(365*24*60*60)), times[1]); + BoxTimeToTimeval(GetCurrentBoxTime() + + SecondsToBoxTime((time_t)(365*24*60*60)), + times[1]); times[0] = times[1]; - TEST_THAT(::utimes("testfiles/TestDir1/sub23/in-the-future", times) == 0); + TEST_THAT(::utimes("testfiles/TestDir1/sub23/" + "in-the-future", times) == 0); } + // Wait and test wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " @@ -2435,7 +2516,8 @@ int test_bbackupd() printf("\n==== Change client store marker\n"); - // Then... connect to the server, and change the client store marker. See what that does! + // Then... connect to the server, and change the + // client store marker. See what that does! { bool done = false; int tries = 4; @@ -2444,7 +2526,8 @@ int test_bbackupd() try { SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, + "localhost", BOX_PORT_BBSTORED); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); std::auto_ptr loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write @@ -2513,22 +2596,38 @@ int test_bbackupd() { do_interrupted_restore(context, restoredirid); int64_t resumesize = 0; - TEST_THAT(FileExists("testfiles/restore-interrupt.boxbackupresume", &resumesize)); - TEST_THAT(resumesize > 16); // make sure it has recorded something to resume + TEST_THAT(FileExists("testfiles/" + "restore-interrupt.boxbackupresume", + &resumesize)); + // make sure it has recorded something to resume + TEST_THAT(resumesize > 16); printf("\n==== Resume restore\n"); SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, "localhost", + BOX_PORT_BBSTORED); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); - std::auto_ptr loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write + std::auto_ptr + loginConf(protocol.QueryLogin(0x01234567, + 0 /* read-write */)); - // Check that the restore fn returns resume possible, rather than doing anything - TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-interrupt", true /* print progress dots */) == Restore_ResumePossible); + // Check that the restore fn returns resume possible, + // rather than doing anything + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/restore-interrupt", + true /* print progress dots */) + == Restore_ResumePossible); // Then resume it - TEST_THAT(BackupClientRestore(protocol, restoredirid, "testfiles/restore-interrupt", true /* print progress dots */, false /* deleted files */, false /* undelete server */, true /* resume */) == Restore_Complete); + TEST_THAT(BackupClientRestore(protocol, restoredirid, + "testfiles/restore-interrupt", + true /* print progress dots */, + false /* deleted files */, + false /* undelete server */, + true /* resume */) + == Restore_Complete); protocol.QueryFinished(); @@ -2551,13 +2650,21 @@ int test_bbackupd() printf("\n==== Check restore deleted files\n"); { SocketStreamTLS conn; - conn.Open(context, Socket::TypeINET, "localhost", BOX_PORT_BBSTORED); + conn.Open(context, Socket::TypeINET, "localhost", + BOX_PORT_BBSTORED); BackupProtocolClient protocol(conn); protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION); - std::auto_ptr loginConf(protocol.QueryLogin(0x01234567, 0)); // read-write + std::auto_ptr + loginConf(protocol.QueryLogin(0x01234567, + 0 /* read-write */)); // Do restore and undelete - TEST_THAT(BackupClientRestore(protocol, deldirid, "testfiles/restore-Test1-x1-2", true /* print progress dots */, true /* deleted files */, true /* undelete on server */) == Restore_Complete); + TEST_THAT(BackupClientRestore(protocol, deldirid, + "testfiles/restore-Test1-x1-2", + true /* print progress dots */, + true /* deleted files */, + true /* undelete on server */) + == Restore_Complete); protocol.QueryFinished(); @@ -2706,11 +2813,13 @@ int test(int argc, const char *argv[]) BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys"); // Initial files -#ifdef WIN32 - TEST_THAT(::system("tar xzvf testfiles/test_base.tgz -C testfiles") == 0); -#else - TEST_THAT(::system("gzip -d < testfiles/test_base.tgz | ( cd testfiles && tar xf - )") == 0); -#endif + #ifdef WIN32 + TEST_THAT(::system("tar xzvf testfiles/test_base.tgz " + "-C testfiles") == 0); + #else + TEST_THAT(::system("gzip -d < testfiles/test_base.tgz " + "| ( cd testfiles && tar xf - )") == 0); + #endif // Do the tests -- cgit v1.2.3 From 5042e10cbb84843948a06fe3f7f45175e836a21f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 29 Apr 2007 13:44:46 +0000 Subject: Initialise mSingleProcess flag to false (oops!) (refs #3) --- lib/server/Daemon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index e8e0eaa2..f2728459 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -52,6 +52,7 @@ Daemon::Daemon() : mpConfiguration(NULL), mReloadConfigWanted(false), mTerminateWanted(false), + mSingleProcess(false), mKeepConsoleOpenAfterFork(false) { if(spDaemon != NULL) -- cgit v1.2.3 From 9ddebaa7d9534fae58cc9cca6f8fdd5139bccf69 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 29 Apr 2007 13:46:22 +0000 Subject: Make directories user-writable while restoring them, so that restoring read-only directories as a non-root user doesn't crash. Restore the correct permissions after restoring the directory's contents. (refs #3) --- lib/backupclient/BackupClientFileAttributes.cpp | 10 ++++++++-- lib/backupclient/BackupClientFileAttributes.h | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp index ba65d57a..9918c0d6 100644 --- a/lib/backupclient/BackupClientFileAttributes.cpp +++ b/lib/backupclient/BackupClientFileAttributes.cpp @@ -578,7 +578,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) @@ -704,7 +705,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 62ba2184..fa56ff65 100644 --- a/lib/backupclient/BackupClientFileAttributes.h +++ b/lib/backupclient/BackupClientFileAttributes.h @@ -45,7 +45,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; -- cgit v1.2.3 From 649214baa3166aec940f17a8f93dd234111f2044 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 29 Apr 2007 13:47:03 +0000 Subject: Make directories user-writable while restoring them, so that restoring read-only directories as a non-root user doesn't crash. Restore the correct permissions after restoring the directory's contents. (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index ec4ca681..0b2b6d84 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -412,7 +412,7 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir try { - dirAttr.WriteAttributes(rLocalDirectoryName.c_str()); + dirAttr.WriteAttributes(rLocalDirectoryName.c_str(), true); } catch (BoxException &e) { @@ -591,6 +591,7 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir } } + // Make sure the restore info has been saved if(bytesWrittenSinceLastRestoreInfoSave != 0) { @@ -663,6 +664,30 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir } } + // now remove the user writable flag, if we added it earlier + try + { + dirAttr.WriteAttributes(rLocalDirectoryName.c_str(), false); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Failed to restore attributes for %s: %s", + rLocalDirectoryName.c_str(), e.what()); + return Restore_UnknownError; + } + catch(std::exception &e) + { + ::syslog(LOG_ERR, "Failed to restore attributes for %s: %s", + rLocalDirectoryName.c_str(), e.what()); + return Restore_UnknownError; + } + catch(...) + { + ::syslog(LOG_ERR, "Failed to restore attributes for %s: " + "unknown error", rLocalDirectoryName.c_str()); + return Restore_UnknownError; + } + return Restore_Complete; } -- cgit v1.2.3 From 1e0c90956567752044545f3ef4876415da9e9700 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 29 Apr 2007 13:47:48 +0000 Subject: Remove unwanted blank line. (refs #3) --- lib/backupclient/BackupClientRestore.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 0b2b6d84..834bfb9a 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -591,7 +591,6 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir } } - // Make sure the restore info has been saved if(bytesWrittenSinceLastRestoreInfoSave != 0) { -- cgit v1.2.3 From 6d029275a46a9408a797b197c6f31d48c470b065 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 29 Apr 2007 13:48:55 +0000 Subject: Remove assertion that we are at the end of the stream when decoding finishes. This is not true when decoding raw files on disk. (refs #3) --- lib/backupclient/BackupStoreFile.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp index 5e800970..75095fa4 100644 --- a/lib/backupclient/BackupStoreFile.cpp +++ b/lib/backupclient/BackupStoreFile.cpp @@ -299,7 +299,13 @@ void BackupStoreFile::DecodeFile(IOStream &rEncodedFile, const char *DecodedFile // out of our connection stream. char buffer[1]; int drained = rEncodedFile.Read(buffer, 1); - ASSERT(drained == 0); + + // 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); -- cgit v1.2.3 From 08f4df17d8139952c5023f42859b7e06c0738d29 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 29 Apr 2007 13:56:53 +0000 Subject: Report Restore_UnknownError properly during restore. Report unknown result codes. (refs #3) --- bin/bbackupquery/BackupQueries.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index b423f5b7..fd83780a 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -2036,8 +2036,12 @@ void BackupQueries::CommandRestore(const std::vector &args, const b break; #endif + case Restore_UnknownError: + printf("Unknown error during restore.\n"); + break; + default: - printf("ERROR: Unknown restore result.\n"); + printf("ERROR: Unknown restore result %d.\n", result); break; } } -- cgit v1.2.3 From 88208fa390db67217cbe5433d88fc7ee99b4944b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 29 Apr 2007 21:31:14 +0000 Subject: Read any remaining data from the encoded stream (such as EOF marker) before discarding it, to ensure that we don't break the protocol. (refs #2, refs #3) --- bin/bbackupquery/BackupQueries.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index fd83780a..7f511b74 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -1695,7 +1695,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s equal = false; } - // Must always read the entire decoded string, if it's not a symlink + // Must always read the entire decoded stream, if it's not a symlink if(fileOnServerStream->StreamDataLeft()) { // Absorb all the data remaining @@ -1705,6 +1705,17 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s fileOnServerStream->Read(buffer, sizeof(buffer), mrConnection.GetTimeout()); } } + + // Must always read the entire encoded stream + if(objectStream->StreamDataLeft()) + { + // Absorb all the data remaining + char buffer[2048]; + while(objectStream->StreamDataLeft()) + { + objectStream->Read(buffer, sizeof(buffer), mrConnection.GetTimeout()); + } + } } } -- cgit v1.2.3 From 55ce748d246a63f0f57b2b132ef9c8f4ee748309 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 2 May 2007 10:24:45 +0000 Subject: Compile fix, thanks to Matt Brown (refs #3) --- lib/common/Test.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/common/Test.h b/lib/common/Test.h index 716ff563..f6704db4 100644 --- a/lib/common/Test.h +++ b/lib/common/Test.h @@ -10,16 +10,18 @@ #ifndef TEST__H #define TEST__H -#include -#include -#include +#include #include +#include +#include + +#include +#include #ifdef HAVE_UNISTD_H #include #endif -#include #include extern int failures; -- cgit v1.2.3 From d5b75f603a0c4df8fcdd78b6930b744bd95c9ba6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 2 May 2007 12:15:40 +0000 Subject: Fix running common tests in release mode, by not doing things that crash in release mode, but assert in debug mode. (refs #3) --- test/common/testcommon.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 19c83d2d..0477509a 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -296,25 +296,37 @@ int test(int argc, const char *argv[]) Timers::Cleanup(); // Check that using timer methods without initialisation - // throws an exception - TEST_CHECK_THROWS(Timers::Add(*(Timer*)NULL), - CommonException, AssertFailed); - TEST_CHECK_THROWS(Timers::Remove(*(Timer*)NULL), - CommonException, AssertFailed); + // throws an assertion failure. Can only do this in debug mode + #ifndef NDEBUG + TEST_CHECK_THROWS(Timers::Add(*(Timer*)NULL), + CommonException, AssertFailed); + TEST_CHECK_THROWS(Timers::Remove(*(Timer*)NULL), + CommonException, AssertFailed); + #endif + // TEST_CHECK_THROWS(Timers::Signal(), CommonException, AssertFailed); - TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, AssertFailed); + #ifndef NDEBUG + TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, + AssertFailed); + #endif // Check that we can initialise the timers Timers::Init(); // Check that double initialisation throws an exception - TEST_CHECK_THROWS(Timers::Init(), CommonException, AssertFailed); + #ifndef NDEBUG + TEST_CHECK_THROWS(Timers::Init(), CommonException, + AssertFailed); + #endif // Check that we can clean up the timers Timers::Cleanup(); // Check that double cleanup throws an exception - TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, AssertFailed); + #ifndef NDEBUG + TEST_CHECK_THROWS(Timers::Cleanup(), CommonException, + AssertFailed); + #endif Timers::Init(); -- cgit v1.2.3 From 728d8e963e8b4ec5853855f700877393b1846616 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 2 May 2007 17:16:16 +0000 Subject: Add missing #include , thanks to Matt Brown (refs #3) --- lib/common/Logging.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index 5f0a2f8f..eee05ba3 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -9,6 +9,7 @@ #include "Box.h" +#include #include #ifdef HAVE_SYSLOG_H -- cgit v1.2.3 From 4aae957662f2bc0fa616a1f581372763ac8416e5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 3 May 2007 11:17:12 +0000 Subject: Read-only restore test fix (refs #3) --- test/bbackupd/testbbackupd.cpp | 56 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 51ed02be..6c5e2e82 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1134,6 +1134,56 @@ int test_bbackupd() if (!ServerIsAlive(bbackupd_pid)) return 1; if (!ServerIsAlive(bbstored_pid)) return 1; + + printf("\n==== Check that read-only directories and " + "their contents can be restored.\n"); + + { + #ifdef WIN32 + TEST_THAT(::system("chmod 0555 testfiles/" + "TestDir1/x1") == 0); + #else + TEST_THAT(chmod("testfiles/TestDir1/x1", + 0555) == 0); + #endif + + wait_for_sync_end(); // too new + wait_for_sync_end(); // should be backed up now + + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1 testfiles/TestDir1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // check that we can restore it + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-q \"restore Test1 testfiles/restore1\" " + "quit"); + TEST_RETURN(compareReturnValue, 0); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // check that it restored properly + compareReturnValue = ::system(BBACKUPQUERY " " + "-c testfiles/bbackupd.conf " + "-q \"compare -cEQ Test1 testfiles/restore1\" " + "quit"); + TEST_RETURN(compareReturnValue, 1); + TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + + // put the permissions back to sensible values + #ifdef WIN32 + TEST_THAT(::system("chmod 0755 testfiles/" + "TestDir1/x1") == 0); + #else + TEST_THAT(chmod("testfiles/TestDir1/x1", + 0755) == 0); + #endif + + } + #ifdef WIN32 printf("\n==== Check that filenames in UTF-8 " "can be backed up\n"); @@ -2268,7 +2318,11 @@ int test_bbackupd() == Restore_Complete); // Compare it - compareReturnValue = ::system("../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query10.log \"compare -cE Test1 testfiles/restore-Test1\" quit"); + compareReturnValue = ::system(BBACKUPQUERY " -q " + "-c testfiles/bbackupd.conf " + "-l testfiles/query10.log " + "\"compare -cE Test1 testfiles/restore-Test1\" " + "quit"); TEST_RETURN(compareReturnValue, 1); TestRemoteProcessMemLeaks("bbackupquery.memleaks"); -- cgit v1.2.3 From 3b5150c9d27cf3cb619ea3680d3f8d7845b9ff06 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 3 May 2007 11:37:05 +0000 Subject: Make testfiles writable before trying to delete them, otherwise read-only tests might not work (refs #3) --- infrastructure/makebuildenv.pl.in | 1 + 1 file changed, 1 insertion(+) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index 04bce787..7069b09d 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -414,6 +414,7 @@ test -r testfiles/bbackupd.pid && kill `cat testfiles/bbackupd.pid` test -r testfiles/bbstored.pid && kill `cat testfiles/bbstored.pid` echo Removing old test files... +chmod -R a+rwx testfiles rm -rf testfiles echo Copying new test files... -- cgit v1.2.3 From 76396f594e6e3050bbde6a324e8f79be9cf4d4a3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 3 May 2007 11:37:47 +0000 Subject: Slightly more progress information during tests (refs #3) --- test/bbackupd/testbbackupd.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 6c5e2e82..ef37c5dd 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -776,8 +776,11 @@ int test_bbackupd() #endif #ifdef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE - printf("Skipping intercept-based KeepAlive tests on this platform.\n"); + printf("\n==== Skipping intercept-based KeepAlive tests " + "on this platform.\n"); #else + printf("\n==== Testing SSL KeepAlive messages\n"); + { #ifdef WIN32 #error TODO: implement threads on Win32, or this test \ @@ -1061,7 +1064,9 @@ int test_bbackupd() if(bbackupd_pid > 0) { - // First, check storage space handling -- wait for file to be uploaded + printf("\n==== Testing that backup pauses when store is full\n"); + + // wait for files to be uploaded wait_for_backup_operation(); // Set limit to something very small -- cgit v1.2.3 From 8da5d31e2f3a22a52b6228a289efe9c7b1d9f6c7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 May 2007 10:49:50 +0000 Subject: Fix emulated chdir to work with relative paths and with bbackupquery's "sh" command (which doesn't like UNC paths). Fix error messages by removing surplus newline kindly added by Windows. (refs #3, merges [1514] and [1569]) --- lib/win32/emu.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 7f665629..0077166f 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -503,6 +503,10 @@ std::string GetErrorMessage(DWORD errorCode) 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); @@ -1474,6 +1478,7 @@ void syslog(int loglevel, const char *frmt, ...) int emu_chdir(const char* pDirName) { + /* std::string AbsPathWithUnicode = ConvertPathToAbsoluteUnicode(pDirName); @@ -1484,11 +1489,19 @@ int emu_chdir(const char* pDirName) } 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; } -- cgit v1.2.3 From 530e03da8716461f64eabd526ba514d489aae1f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 May 2007 10:52:32 +0000 Subject: Gratuitous additional spaces (refs #3) --- test/bbackupd/testbbackupd.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index ef37c5dd..9a4c9919 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1944,6 +1944,7 @@ int test_bbackupd() TEST_THAT(!TestFileExists("testfiles/TestDir1/x1/dsfdsfs98.fd")); TEST_THAT(::rename("testfiles/TestDir1/df9834.dsf", "testfiles/TestDir1/x1/dsfdsfs98.fd") == 0); + wait_for_backup_operation(); compareReturnValue = ::system(BBACKUPQUERY " -q " "-c testfiles/bbackupd.conf " @@ -2536,6 +2537,7 @@ int test_bbackupd() // timestamps still get added printf("\n==== Create a file with timestamp way ahead " "in the future\n"); + // Time critical, so sync wait_for_sync_start(); @@ -2707,6 +2709,7 @@ int test_bbackupd() if (!ServerIsAlive(bbstored_pid)) return 1; printf("\n==== Check restore deleted files\n"); + { SocketStreamTLS conn; conn.Open(context, Socket::TypeINET, "localhost", -- cgit v1.2.3 From 1086a5fea7adf15f4a9602b691832a0e0a2a705b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 May 2007 10:58:28 +0000 Subject: Remove old support for Cygwin. Remove lib/win32 dependency on lib/server (circular). Remove all dependencies on lib/win32. Enable all modules and tests on Win32. (refs #3) --- modules.txt | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/modules.txt b/modules.txt index 0cb67add..a66b63ba 100644 --- a/modules.txt +++ b/modules.txt @@ -9,56 +9,37 @@ # Generic support code and modules -OMIT:mingw32 -OMIT:mingw32msvc -OMIT:CYGWIN lib/raidfile -END-OMIT - lib/crypto lib/server -lib/win32 lib/server lib/compress lib/intercept -test/common lib/win32 -test/crypto lib/crypto lib/win32 -test/compress lib/compress lib/win32 -OMIT:mingw32 -OMIT:mingw32msvc -test/basicserver lib/server lib/win32 -OMIT:CYGWIN +test/common +test/crypto lib/crypto +test/compress lib/compress test/raidfile lib/raidfile lib/intercept -END-OMIT +test/basicserver lib/server # IF_DISTRIBUTION(boxbackup) # Backup system lib/backupclient lib/server lib/crypto lib/compress - -OMIT:mingw32 -OMIT:mingw32msvc -OMIT:CYGWIN lib/backupstore lib/server lib/raidfile lib/backupclient -bin/bbstored lib/raidfile lib/server lib/backupstore lib/backupclient lib/win32 -bin/bbstoreaccounts lib/raidfile lib/backupstore lib/win32 -bin/bbackupobjdump lib/backupclient lib/backupstore lib/win32 -END-OMIT -bin/bbackupd lib/server lib/backupclient lib/win32 -bin/bbackupquery lib/server lib/backupclient lib/win32 -bin/bbackupctl lib/server lib/backupclient lib/win32 +bin/bbackupobjdump lib/backupclient lib/backupstore +bin/bbstored lib/raidfile lib/server lib/backupstore lib/backupclient +bin/bbstoreaccounts lib/raidfile lib/backupstore +bin/bbackupd lib/server lib/backupclient +bin/bbackupquery lib/server lib/backupclient +bin/bbackupctl lib/server lib/backupclient -OMIT:mingw32 -OMIT:mingw32msvc -OMIT:CYGWIN test/backupstore bin/bbstored bin/bbstoreaccounts lib/server lib/backupstore lib/backupclient lib/raidfile test/backupstorefix bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile bin/bbackupquery bin/bbackupd test/backupstorepatch bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile test/backupdiff lib/backupclient test/bbackupd bin/bbackupd bin/bbstored bin/bbstoreaccounts bin/bbackupquery bin/bbackupctl lib/server lib/backupstore lib/backupclient lib/intercept -END-OMIT # END_IF_DISTRIBUTION -- cgit v1.2.3 From 8a62484a39528b2921d0f3e39e263e3c26c85e13 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 10 May 2007 21:47:48 +0000 Subject: Fix the license in the docs to reflect the actual license. (refs #3, merges [1652]) --- documentation/boxbackup/adminguide.xml | 45 ++++++++++++++++++++------------- documentation/boxbackup/instguide.xml | 46 +++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 35 deletions(-) diff --git a/documentation/boxbackup/adminguide.xml b/documentation/boxbackup/adminguide.xml index c33e49d0..43bc6103 100644 --- a/documentation/boxbackup/adminguide.xml +++ b/documentation/boxbackup/adminguide.xml @@ -9,8 +9,8 @@ License - Copyright © 2003 - 2006, Ben Summers and contributors. All rights - reserved. + Copyright © 2003 - 2007, Ben Summers and contributors. + All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -30,23 +30,34 @@ - Neither the name of the authors nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission + All use of this software and associated advertising materials + must display the following acknowledgement: This product includes + software developed by Ben Summers. + + + + The names of the Authors may not be used to endorse or promote + products derived from this software without specific prior written + permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + [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. @@ -1229,4 +1240,4 @@ make testing, and should not be relied on in a production environment. - \ No newline at end of file + diff --git a/documentation/boxbackup/instguide.xml b/documentation/boxbackup/instguide.xml index 2a5bc3e3..b66b7169 100644 --- a/documentation/boxbackup/instguide.xml +++ b/documentation/boxbackup/instguide.xml @@ -7,9 +7,8 @@ License - Copyright (c) <YEAR>, <OWNER> - - All rights reserved. + Copyright © 2003 - 2007, Ben Summers and contributors. + All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -29,23 +28,34 @@ - Neither the name of the <ORGANIZATION> nor the names of - its contributors may be used to endorse or promote products derived - from this software without specific prior written permission + All use of this software and associated advertising materials + must display the following acknowledgement: This product includes + software developed by Ben Summers. + + + + The names of the Authors may not be used to endorse or promote + products derived from this software without specific prior written + permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + + [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. @@ -747,4 +757,4 @@ bbackupd.exe -i If you wish to customise the package you can find the spec file in the contrib/rpm directory. - \ No newline at end of file + -- cgit v1.2.3 From 1ab89d2bcda71194a5d3465d5078e9d01bcd520f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 3 Jun 2007 14:37:48 +0000 Subject: Add missing #include , thanks Tobias. --- lib/common/EventWatchFilesystemObject.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/common/EventWatchFilesystemObject.cpp b/lib/common/EventWatchFilesystemObject.cpp index 4282f1e3..84781113 100644 --- a/lib/common/EventWatchFilesystemObject.cpp +++ b/lib/common/EventWatchFilesystemObject.cpp @@ -9,6 +9,7 @@ #include "Box.h" +#include #include #ifdef HAVE_UNISTD_H -- cgit v1.2.3 From 7a24bc6f9816214ea2e56dd427699d763f36599c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Jun 2007 21:13:34 +0000 Subject: Hopefully reset getopt in a way that's compatible with BSD and GLIBC, thanks to Tobias Balle-Petersen for pointing out this bug. --- lib/server/Daemon.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index f2728459..9ff270a9 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -110,7 +110,16 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) #endif char c; - optind = 0; // just in case anybody used getopt before + + // 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 + #ifdef __GLIBC__ + optind = 1; + #else + optind = 0; + optreset = 1; + #endif while((c = getopt(argc, (char * const *)argv, "c:DqvVt:Tk")) != -1) { -- cgit v1.2.3 From fd397879c425ff9ef02de10dee8ab25b76e5211b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 Jun 2007 21:17:08 +0000 Subject: Get it right this time. --- lib/server/Daemon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 9ff270a9..8b1a1786 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -115,9 +115,9 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // unfortunately glibc and BSD differ on this point! // http://www.ussg.iu.edu/hypermail/linux/kernel/0305.3/0262.html #ifdef __GLIBC__ - optind = 1; - #else optind = 0; + #else + optind = 1; optreset = 1; #endif -- cgit v1.2.3 From 00ed2553cf50ecc56631ca9133a926d2b488ed04 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 20 Jun 2007 21:29:55 +0000 Subject: Include to avoid compile failures on BSD, thanks James O'Gorman. (refs #3, merges [1698]) --- infrastructure/buildenv-testmain-template.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/infrastructure/buildenv-testmain-template.cpp b/infrastructure/buildenv-testmain-template.cpp index 711257ea..4de30e2e 100644 --- a/infrastructure/buildenv-testmain-template.cpp +++ b/infrastructure/buildenv-testmain-template.cpp @@ -38,6 +38,8 @@ #include #endif +#include + #include "Logging.h" #include "Test.h" #include "Timer.h" -- cgit v1.2.3 From a2f458359da4b9078a495952544390e03c132164 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Jun 2007 19:16:56 +0000 Subject: Handle USE_SVN_VERSION in distribution VERSION files. --- infrastructure/makedistribution.pl.in | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/infrastructure/makedistribution.pl.in b/infrastructure/makedistribution.pl.in index 52e1c2e4..d2c29660 100755 --- a/infrastructure/makedistribution.pl.in +++ b/infrastructure/makedistribution.pl.in @@ -1,3 +1,4 @@ +#!/usr/bin/perl #!@PERL@ use strict; use Symbol; @@ -36,6 +37,29 @@ close VERSION; die "Archive name '$archive_name' is not equal to the distribution name '$distribution'" unless $archive_name eq $distribution; +my $svnversion = `svnversion .`; +chomp $svnversion; +$svnversion =~ tr/0-9A-Za-z/_/c; + +if($version =~ /USE_SVN_VERSION/) +{ + # for developers, use SVN version + open INFO,'svn info . |'; + my $svnurl; + while() + { + if(m/^URL: (.+?)[\n\r]+/) + { + $svnurl = $1; + } + } + close INFO; + $svnurl =~ m'box/(.+)$'; + my $svndir = $1; + $svndir =~ tr/0-9A-Za-z/_/c; + $version =~ s/USE_SVN_VERSION/$svndir.'_'.$svnversion/e; +} + # make initial directory my $base_name = "$archive_name-$version"; system "rm -rf $base_name"; @@ -47,8 +71,6 @@ open LICENSE,"$dist_root/LICENSE.txt" or die "Can't open $dist_root/LICENSE.txt" my $license_f; read LICENSE,$license_f,100000; close LICENSE; -my $svnversion = `svnversion .`; -chomp $svnversion; my @license = ('distribution '.$base_name.' (svn version: '.$svnversion.')',split(/\n/,$license_f)); # copy files, make a note of all the modules included -- cgit v1.2.3 From e7a44dd27bb02fde83dd6bee24d18521bbe57f16 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Jun 2007 19:17:30 +0000 Subject: Use SVN version in distributions built from this branch. --- distribution/boxbackup/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/boxbackup/VERSION.txt b/distribution/boxbackup/VERSION.txt index 891c9b59..d46ff63a 100644 --- a/distribution/boxbackup/VERSION.txt +++ b/distribution/boxbackup/VERSION.txt @@ -1,2 +1,2 @@ -0.09_plus3 +0.10_plus_USE_SVN_VERSION boxbackup -- cgit v1.2.3 From 38d1e9596510560674dd80b6ed6b6e2c3ba5d1f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Jun 2007 19:17:57 +0000 Subject: Add lib/intercept to distribution manifest, to ensure that it gets distributed. --- distribution/boxbackup/DISTRIBUTION-MANIFEST.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/distribution/boxbackup/DISTRIBUTION-MANIFEST.txt b/distribution/boxbackup/DISTRIBUTION-MANIFEST.txt index 96908264..b24a5527 100644 --- a/distribution/boxbackup/DISTRIBUTION-MANIFEST.txt +++ b/distribution/boxbackup/DISTRIBUTION-MANIFEST.txt @@ -1,3 +1,4 @@ +lib/intercept lib/raidfile test/raidfile test/raidfile/testfiles @@ -37,4 +38,4 @@ infrastructure/msvc NO-LICENSE-IN-DIR infrastructure/msvc/2003 infrastructure/msvc/2003 NO-LICENSE-IN-DIR infrastructure/msvc/2005 -infrastructure/msvc/2005 \ No newline at end of file +infrastructure/msvc/2005 -- cgit v1.2.3 From 2de49a8682edac16c95faa8bcbc9f16a306cc762 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Jun 2007 19:54:54 +0000 Subject: Handle USE_SVN_VERSION in the middle of a version string. --- infrastructure/BoxPlatform.pm.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in index 828516e2..b034eed1 100644 --- a/infrastructure/BoxPlatform.pm.in +++ b/infrastructure/BoxPlatform.pm.in @@ -51,7 +51,7 @@ BEGIN $product_name = ; chomp $product_name; close VERSION; - if($product_version eq 'USE_SVN_VERSION') + if($product_version =~ /USE_SVN_VERSION/) { # for developers, use SVN version my $svnversion = `svnversion .`; @@ -70,7 +70,7 @@ BEGIN $svnurl =~ m!box/(.+)$!; my $svndir = $1; $svndir =~ tr/0-9A-Za-z/_/c; - $product_version = $svndir.'_'.$svnversion; + $product_version =~ s/USE_SVN_VERSION/$svndir.'_'.$svnversion/e; } # where to put the files -- cgit v1.2.3 From e130a12a74d33d86fa61e8edaf3e3720f4f09f90 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 27 Jun 2007 20:18:43 +0000 Subject: Replace version in VERSION.txt, if it contains USE_SVN_VERSION. --- infrastructure/makedistribution.pl.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/infrastructure/makedistribution.pl.in b/infrastructure/makedistribution.pl.in index d2c29660..314259f6 100755 --- a/infrastructure/makedistribution.pl.in +++ b/infrastructure/makedistribution.pl.in @@ -136,6 +136,7 @@ copy_from_list("$dist_root/DISTRIBUTION-MANIFEST.txt"); or die "Copy of root extra files failed"; unlink "$base_name/DISTRIBUTION-MANIFEST.txt" or die "Delete of DISTRIBUTION-MANIFEST.txt file failed"; +replace_version_in("VERSION.txt"); # produce a new modules file my $modules = gensym; @@ -338,6 +339,7 @@ sub replace_version_in while() { s/###DISTRIBUTION-VERSION-NUMBER###/$version/g; + s/.*USE_SVN_VERSION.*/$version/g; print OUT } -- cgit v1.2.3 From 592d1e26597202ce0eed301d61981823cd7084f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Jun 2007 19:54:45 +0000 Subject: Add a new -F option for daemons, which runs in the foreground but still accepts multiple connections, unlike -D or SINGLEPROCESS. --- lib/server/Daemon.cpp | 11 +++++++++-- lib/server/Daemon.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 8b1a1786..37698101 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -53,6 +53,7 @@ Daemon::Daemon() mReloadConfigWanted(false), mTerminateWanted(false), mSingleProcess(false), + mRunInForeground(false), mKeepConsoleOpenAfterFork(false) { if(spDaemon != NULL) @@ -121,7 +122,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) optreset = 1; #endif - while((c = getopt(argc, (char * const *)argv, "c:DqvVt:Tk")) != -1) + while((c = getopt(argc, (char * const *)argv, "c:DFqvVt:Tk")) != -1) { switch(c) { @@ -138,6 +139,12 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) } break; + case 'F': + { + mRunInForeground = true; + } + break; + case 'q': { if(masterLevel == Log::NOTHING) @@ -250,7 +257,7 @@ int Daemon::Main(const std::string &rConfigFileName) mConfigFileName = rConfigFileName; - bool asDaemon = !mSingleProcess; + bool asDaemon = !mSingleProcess && !mRunInForeground; try { diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h index c4c7af0d..bce6c3c1 100644 --- a/lib/server/Daemon.h +++ b/lib/server/Daemon.h @@ -79,6 +79,7 @@ private: bool mReloadConfigWanted; bool mTerminateWanted; bool mSingleProcess; + bool mRunInForeground; bool mKeepConsoleOpenAfterFork; static Daemon *spDaemon; }; -- cgit v1.2.3 From 7c581bcb685e99e37b64752b1e85330765e3be0f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 28 Jun 2007 20:54:28 +0000 Subject: Log reasons for failure to connect to a socket. --- lib/server/SocketStream.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp index 61d3846f..ebc57041 100644 --- a/lib/server/SocketStream.cpp +++ b/lib/server/SocketStream.cpp @@ -15,6 +15,7 @@ #include #include +#include #ifndef WIN32 #include @@ -164,6 +165,10 @@ void SocketStream::Open(int Type, const char *Name, int Port) #else ::close(mSocketHandle); #endif + BOX_ERROR("Failed to connect to socket (type " << Type << + ", name " << Name << ", port " << Port << "): " << + "error " << errno << " (" << strerror(errno) << + ")"); mSocketHandle = INVALID_SOCKET_VALUE; THROW_EXCEPTION(ConnectionException, Conn_SocketConnectError) } -- cgit v1.2.3 From a03d260fe420c4fc82375f7dd6eb1db6a86a065a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 30 Jun 2007 11:22:08 +0000 Subject: Improved build targets, thanks to James O'Gorman (fixes #30) --- infrastructure/makeparcels.pl.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/infrastructure/makeparcels.pl.in b/infrastructure/makeparcels.pl.in index a8eceb8a..880246d7 100755 --- a/infrastructure/makeparcels.pl.in +++ b/infrastructure/makeparcels.pl.in @@ -78,7 +78,7 @@ MAKE = $make_command __E -print MAKE "all:\t",join(' ',map {parcel_target($_)} @parcels),"\n\n"; +print MAKE "all:\t",join(' ',map {"build-".$_} @parcels),"\n\n"; print MAKE "clean:\n"; for my $parcel (@parcels) @@ -95,6 +95,7 @@ my $release_flag = BoxPlatform::make_flag('RELEASE'); for my $parcel (@parcels) { my $target = parcel_target($parcel); + print MAKE "build-$parcel:\t$target\n\n"; print MAKE $target,":\n"; my $dir = parcel_dir($parcel); -- cgit v1.2.3 From 30879db08edddc827d9dae05aec39061bc64437e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 30 Jun 2007 11:53:15 +0000 Subject: Add extra debugging to help find out why getopt is behaving weirdly on debian etch (http://lists.warhead.org.uk/pipermail/boxbackup/2007-June/003603.html) --- lib/server/Daemon.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 37698101..66b317d5 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -124,6 +124,12 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) while((c = getopt(argc, (char * const *)argv, "c:DFqvVt:Tk")) != -1) { + BOX_TRACE("getopt: returned '" << c << "'"); + BOX_TRACE("getopt: optind = " << optind); + BOX_TRACE("getopt: optopt = " << optopt); + BOX_TRACE("getopt: optarg = " << optarg); + BOX_TRACE("getopt: argv[optind] = " << argv[optind]); + switch(c) { case 'c': @@ -212,6 +218,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) } } + BOX_TRACE("getopt: returned " << (int)c << ", finished."); + if (argc > optind && !haveConfigFile) { mConfigFileName = argv[optind]; optind++; -- cgit v1.2.3 From d3fa5137921158e027c5e0d55c1c456723bdd1e7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 30 Jun 2007 14:17:17 +0000 Subject: Make test/bbackupd intercept timer tests a little less strict, because object IDs can vary depending on the order that readdir() returns files in. (refs #3) --- test/bbackupd/testbbackupd.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 9a4c9919..2b8225cc 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -841,7 +841,8 @@ int test_bbackupd() { std::string line; TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receive Success(0xe)"); + std::string comp = "Receive Success(0x"; + TEST_THAT(line.substr(0, comp.size()) == comp); TEST_THAT(reader.GetLine(line)); TEST_THAT(line == "Receiving stream, size 124"); TEST_THAT(reader.GetLine(line)); @@ -850,9 +851,9 @@ int test_bbackupd() TEST_THAT(line == "Receive IsAlive()"); TEST_THAT(reader.GetLine(line)); - std::string comp = "Send StoreFile(0x3,"; + comp = "Send StoreFile(0x3,"; TEST_THAT(line.substr(0, comp.size()) == comp); - comp = ",0xe,\"f1\")"; + comp = ",\"f1\")"; TEST_THAT(line.substr(line.size() - comp.size()) == comp); } @@ -892,7 +893,8 @@ int test_bbackupd() { std::string line; TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receive Success(0xf)"); + std::string comp = "Receive Success(0x"; + TEST_THAT(line.substr(0, comp.size()) == comp); TEST_THAT(reader.GetLine(line)); TEST_THAT(line == "Receiving stream, size 124"); @@ -902,7 +904,7 @@ int test_bbackupd() // so there will be no keepalives. TEST_THAT(reader.GetLine(line)); - std::string comp = "Send StoreFile(0x3,"; + comp = "Send StoreFile(0x3,"; TEST_THAT(line.substr(0, comp.size()) == comp); comp = ",0x0,\"f1\")"; TEST_THAT(line.substr(line.size() - comp.size()) @@ -944,7 +946,8 @@ int test_bbackupd() { std::string line; TEST_THAT(reader.GetLine(line)); - TEST_THAT(line == "Receive Success(0x10)"); + std::string comp = "Receive Success(0x"; + TEST_THAT(line.substr(0, comp.size()) == comp); TEST_THAT(reader.GetLine(line)); TEST_THAT(line == "Receiving stream, size 124"); @@ -964,7 +967,7 @@ int test_bbackupd() TEST_THAT(line == "Receive IsAlive()"); TEST_THAT(reader.GetLine(line)); - std::string comp = "Send StoreFile(0x3,"; + comp = "Send StoreFile(0x3,"; TEST_THAT(line.substr(0, comp.size()) == comp); comp = ",0x0,\"f1\")"; TEST_THAT(line.substr(line.size() - comp.size()) -- cgit v1.2.3 From 8c5759d7b2556de04e088ed6dfc0d2a5b0ed2769 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 1 Jul 2007 15:29:53 +0000 Subject: Add --with-bdb-headers and --with-bdb-lib flags to configure to fix Berkeley DB detection issues on FreeBSD. The original --with-bdb-dir flag is still present for systems that install BDB in a "standard" location. (merges [1714] from trunk by James O'Gorman, refs #3) --- infrastructure/m4/ax_path_bdb.m4 | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/infrastructure/m4/ax_path_bdb.m4 b/infrastructure/m4/ax_path_bdb.m4 index 08d71053..bec4a5d4 100644 --- a/infrastructure/m4/ax_path_bdb.m4 +++ b/infrastructure/m4/ax_path_bdb.m4 @@ -13,7 +13,9 @@ dnl values to add to LIBS, CPPFLAGS, and LDFLAGS, as well as setting dnl BDB_VERSION to the version found. HAVE_DB_H is defined also. dnl dnl The option --with-bdb-dir=DIR can be used to specify a specific -dnl Berkeley DB installation to use. +dnl Berkeley DB installation to use, or --with-bdb-headers=DIR and +dnl --with-bdb-lib=DIR can be used to specify individual include and +dnl library locations. dnl dnl An example of it's use is: dnl @@ -57,6 +59,8 @@ dnl Changes: dnl dnl 1/5/05 applied patch from Rafa Rzepecki to eliminate compiler dnl warning about unused variable, argv +dnl 1/7/07 Add --with-bdb-headers and --with-bdb-lib options +dnl (James O'Gorman, james@netinertia.co.uk) dnl dnl @category InstalledPackages dnl @author Tim Toolan @@ -73,16 +77,35 @@ AC_DEFUN([AX_PATH_BDB], [ [AC_HELP_STRING([--with-bdb-dir=DIR], [Berkeley DB installation directory])]) + # Add --with-bdb-headers and --with-bdb-lib options + AC_ARG_WITH([bdb-headers], + [AC_HELP_STRING([--with-bdb-headers=DIR], + [Berkeley DB include files location])]) + + AC_ARG_WITH([bdb-lib], + [AC_HELP_STRING([--with-bdb-lib=DIR], + [Berkeley DB library location])]) + # Check if --with-bdb-dir was specified. - if test "x$with_bdb_dir" = "x" ; then + if test "x$with_bdb_dir" = "x" -a \ + "x$with_bdb_headers" = "x" -a "x$with_bdb_lib" = "x"; then # No option specified, so just search the system. AX_PATH_BDB_NO_OPTIONS([$1], [HIGHEST], [ ax_path_bdb_ok=yes ]) else - # Set --with-bdb-dir option. - ax_path_bdb_INC="$with_bdb_dir/include" - ax_path_bdb_LIB="$with_bdb_dir/lib" + # Check if the --with-bdb-headers and --with-bdb-lib flags were defined + # Use them if so, otherwise use --with-bdb-dir + if test "x$with_bdb_headers" = "x"; then + ax_path_bdb_INC="$with_bdb_dir/include" + else + ax_path_bdb_INC="$with_bdb_headers" + fi + if test "x$with_bdb_lib" = "x"; then + ax_path_bdb_LIB="$with_bdb_dir/lib" + else + ax_path_bdb_LIB="$with_bdb_lib" + fi dnl # Save previous environment, and modify with new stuff. ax_path_bdb_save_CPPFLAGS="$CPPFLAGS" -- cgit v1.2.3 From 9abeb07ffc1ef91bc351f11f3d2d078e62ce2ae6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 1 Jul 2007 22:55:51 +0000 Subject: Remove --with-bdb-dir option, to avoid confusion and be consistent with the SSL flags. (merges [1717] by James O'Gorman, refs #3) --- infrastructure/m4/ax_path_bdb.m4 | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/infrastructure/m4/ax_path_bdb.m4 b/infrastructure/m4/ax_path_bdb.m4 index bec4a5d4..1a771048 100644 --- a/infrastructure/m4/ax_path_bdb.m4 +++ b/infrastructure/m4/ax_path_bdb.m4 @@ -12,12 +12,10 @@ dnl sets BDB_LIBS, BDB_CPPFLAGS, and BDB_LDFLAGS to the necessary dnl values to add to LIBS, CPPFLAGS, and LDFLAGS, as well as setting dnl BDB_VERSION to the version found. HAVE_DB_H is defined also. dnl -dnl The option --with-bdb-dir=DIR can be used to specify a specific -dnl Berkeley DB installation to use, or --with-bdb-headers=DIR and -dnl --with-bdb-lib=DIR can be used to specify individual include and -dnl library locations. +dnl The options --with-bdb-headers=DIR and --with-bdb-lib=DIR can be +dnl used to specify a specific Berkeley DB installation to use. dnl -dnl An example of it's use is: +dnl An example of its use is: dnl dnl AX_PATH_BDB([3],[ dnl LIBS="$BDB_LIBS $LIBS" @@ -72,11 +70,6 @@ AC_DEFUN([AX_PATH_BDB], [ dnl # Used to indicate success or failure of this function. ax_path_bdb_ok=no - # Add --with-bdb-dir option to configure. - AC_ARG_WITH([bdb-dir], - [AC_HELP_STRING([--with-bdb-dir=DIR], - [Berkeley DB installation directory])]) - # Add --with-bdb-headers and --with-bdb-lib options AC_ARG_WITH([bdb-headers], [AC_HELP_STRING([--with-bdb-headers=DIR], @@ -87,25 +80,14 @@ AC_DEFUN([AX_PATH_BDB], [ [Berkeley DB library location])]) # Check if --with-bdb-dir was specified. - if test "x$with_bdb_dir" = "x" -a \ - "x$with_bdb_headers" = "x" -a "x$with_bdb_lib" = "x"; then + if test "x$with_bdb_headers" = "x" -a "x$with_bdb_lib" = "x"; then # No option specified, so just search the system. AX_PATH_BDB_NO_OPTIONS([$1], [HIGHEST], [ ax_path_bdb_ok=yes ]) else - # Check if the --with-bdb-headers and --with-bdb-lib flags were defined - # Use them if so, otherwise use --with-bdb-dir - if test "x$with_bdb_headers" = "x"; then - ax_path_bdb_INC="$with_bdb_dir/include" - else - ax_path_bdb_INC="$with_bdb_headers" - fi - if test "x$with_bdb_lib" = "x"; then - ax_path_bdb_LIB="$with_bdb_dir/lib" - else - ax_path_bdb_LIB="$with_bdb_lib" - fi + ax_path_bdb_INC="$with_bdb_headers" + ax_path_bdb_LIB="$with_bdb_lib" dnl # Save previous environment, and modify with new stuff. ax_path_bdb_save_CPPFLAGS="$CPPFLAGS" -- cgit v1.2.3 From ea9109761619772853bac35fa538ab5af0877377 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 3 Jul 2007 21:13:56 +0000 Subject: Hopefully work around buggy getopt implementation noted by TBP in http://lists.warhead.org.uk/pipermail/boxbackup/2007-July/003614.html (refs #3) --- lib/server/Daemon.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 66b317d5..bc591f3b 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -124,12 +124,21 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) while((c = getopt(argc, (char * const *)argv, "c:DFqvVt:Tk")) != -1) { - BOX_TRACE("getopt: returned '" << c << "'"); + BOX_TRACE("getopt: returned '" << c << "' (" << (int)c << ")"); BOX_TRACE("getopt: optind = " << optind); BOX_TRACE("getopt: optopt = " << optopt); BOX_TRACE("getopt: optarg = " << optarg); BOX_TRACE("getopt: argv[optind] = " << argv[optind]); + // Workaround for weird behaviour noted by TBP in + // http://lists.warhead.org.uk/pipermail/boxbackup/2007-July/003614.html + if (c == '?' && optopt == 0) + { + // this apparently means "end of options" in some + // buggy libc? + break; + } + switch(c) { case 'c': -- cgit v1.2.3 From d31881f5df1677baef7235d82ffc04cbd79b6e68 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 3 Jul 2007 21:18:03 +0000 Subject: More debugging. --- lib/server/Daemon.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index bc591f3b..6817585b 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -122,6 +122,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) optreset = 1; #endif + BOX_TRACE("'?' == " << (int)'?'); + while((c = getopt(argc, (char * const *)argv, "c:DFqvVt:Tk")) != -1) { BOX_TRACE("getopt: returned '" << c << "' (" << (int)c << ")"); -- cgit v1.2.3 From c79d76b9c317b6469ad48eb296d807e6da261190 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Jul 2007 18:23:24 +0000 Subject: Make char signed to fix getopt usage on ARM and PowerPC, thanks to TBP and Reinhard Tartler (refs #3, see http://lists.warhead.org.uk/pipermail/boxbackup/2007-July/003614.html) --- lib/server/Daemon.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 6817585b..34ac0440 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -110,7 +110,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) int masterLevel = Log::INFO; // need an int to do math with #endif - char c; + signed char c; // reset getopt, just in case anybody used it before. // unfortunately glibc and BSD differ on this point! @@ -132,15 +132,6 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) BOX_TRACE("getopt: optarg = " << optarg); BOX_TRACE("getopt: argv[optind] = " << argv[optind]); - // Workaround for weird behaviour noted by TBP in - // http://lists.warhead.org.uk/pipermail/boxbackup/2007-July/003614.html - if (c == '?' && optopt == 0) - { - // this apparently means "end of options" in some - // buggy libc? - break; - } - switch(c) { case 'c': -- cgit v1.2.3 From 35fce7de6b3ff302dab90f8013d9ebd434f90b03 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 5 Jul 2007 19:28:31 +0000 Subject: Use a signed int instead of char for getopt, thanks Martin. (refs #3) --- lib/server/Daemon.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 34ac0440..147eeb24 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -110,7 +110,7 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) int masterLevel = Log::INFO; // need an int to do math with #endif - signed char c; + signed int c; // reset getopt, just in case anybody used it before. // unfortunately glibc and BSD differ on this point! @@ -122,16 +122,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) optreset = 1; #endif - BOX_TRACE("'?' == " << (int)'?'); - while((c = getopt(argc, (char * const *)argv, "c:DFqvVt:Tk")) != -1) { - BOX_TRACE("getopt: returned '" << c << "' (" << (int)c << ")"); - BOX_TRACE("getopt: optind = " << optind); - BOX_TRACE("getopt: optopt = " << optopt); - BOX_TRACE("getopt: optarg = " << optarg); - BOX_TRACE("getopt: argv[optind] = " << argv[optind]); - switch(c) { case 'c': @@ -220,8 +212,6 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) } } - BOX_TRACE("getopt: returned " << (int)c << ", finished."); - if (argc > optind && !haveConfigFile) { mConfigFileName = argv[optind]; optind++; -- cgit v1.2.3 From 2cee87c2df1aa7809c07907cfc3a61f39796c2ad Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Jul 2007 21:58:59 +0000 Subject: Hopefully fix a bug reported by Tobias Balle-Petersen, where unused locations on the store would never be deleted because the timer would be reset on every backup pass (refs #3). --- bin/bbackupd/BackupDaemon.cpp | 47 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index cfe2b7ab..d690e299 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1812,10 +1812,27 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con // Any entries in the root directory which need deleting? if(dir.GetNumberOfEntries() > 0) { + box_time_t now = GetCurrentBoxTime(); + + // This should reset the timer if the list of unused + // locations changes, but it will not if the number of + // unused locations does not change, but the locations + // do change, e.g. one mysteriously appears and another + // mysteriously appears. (FIXME) + if (dir.GetNumberOfEntries() != mUnusedRootDirEntries.size() || + mDeleteUnusedRootDirEntriesAfter == 0) + { + mDeleteUnusedRootDirEntriesAfter = now + + SecondsToBoxTime( + BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER); + } + + int secs = BoxTimeToSeconds(mDeleteUnusedRootDirEntriesAfter + - now); + BOX_NOTICE(dir.GetNumberOfEntries() << " redundant locations " "in root directory found, will delete from store " - "after " << BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER - << " seconds."); + "after " << secs << " seconds."); // Store directories in list of things to delete mUnusedRootDirEntries.clear(); @@ -1826,14 +1843,13 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con // Add name to list BackupStoreFilenameClear clear(en->GetName()); const std::string &name(clear.GetClearFilename()); - mUnusedRootDirEntries.push_back(std::pair(en->GetObjectID(), name)); + mUnusedRootDirEntries.push_back( + std::pair + (en->GetObjectID(), name)); // Log this BOX_INFO("Unused location in root: " << name); } ASSERT(mUnusedRootDirEntries.size() > 0); - // Time to delete them - mDeleteUnusedRootDirEntriesAfter = - GetCurrentBoxTime() + SecondsToBoxTime(BACKUP_DELETE_UNUSED_ROOT_ENTRIES_AFTER); } } @@ -2256,16 +2272,27 @@ void BackupDaemon::NotifySysadmin(int Event) // -------------------------------------------------------------------------- void BackupDaemon::DeleteUnusedRootDirEntries(BackupClientContext &rContext) { - if(mUnusedRootDirEntries.empty() || mDeleteUnusedRootDirEntriesAfter == 0) + if(mUnusedRootDirEntries.empty()) { - // Nothing to do. + BOX_INFO("Not deleting unused entries - none in list"); return; } + if(mDeleteUnusedRootDirEntriesAfter == 0) + { + BOX_INFO("Not deleting unused entries - " + "zero delete time (bad)"); + return; + } + // Check time - if(GetCurrentBoxTime() < mDeleteUnusedRootDirEntriesAfter) + box_time_t now = GetCurrentBoxTime(); + if(now < mDeleteUnusedRootDirEntriesAfter) { - // Too early to delete files + int secs = BoxTimeToSeconds(mDeleteUnusedRootDirEntriesAfter + - now); + BOX_INFO("Not deleting unused entries - too early (" + << secs << " seconds remaining)"); return; } -- cgit v1.2.3 From 1893383ff18bf5af2443c467b3811c8544653f1e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 19:35:13 +0000 Subject: Warn if an exception is thrown, with line number, as this shouldn't be happening on production systems anyway. --- lib/common/Box.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/Box.h b/lib/common/Box.h index 8faa2d58..9c0141d7 100644 --- a/lib/common/Box.h +++ b/lib/common/Box.h @@ -112,7 +112,7 @@ #define THROW_EXCEPTION(type, subtype) \ { \ OPTIONAL_DO_BACKTRACE \ - BOX_TRACE("Exception thrown: " #type "(" #subtype ") at " \ + BOX_WARN("Exception thrown: " #type "(" #subtype ") at " \ __FILE__ "(" << __LINE__ << ")") \ throw type(type::subtype); \ } -- cgit v1.2.3 From ee62a6ec511a7699e276aae63927a3fa1ce6df2e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 20:50:46 +0000 Subject: Add more debugging checks and messages for location setup error reported by Pete Jalajas (http://lists.warhead.org.uk/pipermail/boxbackup/2007-July/003668.html) --- bin/bbackupd/BackupDaemon.cpp | 40 ++++++++++++++++++++++++++++++++-------- lib/win32/emu.cpp | 5 +++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index d690e299..4a72f762 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1696,7 +1696,11 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con if(::statfs(ploc->mPath.c_str(), &s) != 0) #endif // HAVE_STRUCT_STATVFS_F_MNTONNAME { - THROW_EXCEPTION(CommonException, OSFileError) + BOX_WARNING("Failed to stat location: " + << ploc->mPath + << ": " << strerror(errno)); + THROW_EXCEPTION(CommonException, + OSFileError) } // Where the filesystem is mounted @@ -1781,13 +1785,24 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con } // Execute create directory command - MemBlockStream attrStream(attr); - std::auto_ptr dirCreate(connection.QueryCreateDirectory( - BackupProtocolClientListDirectory::RootDirectory, - attrModTime, dirname, attrStream)); - - // Object ID for later creation - oid = dirCreate->GetObjectID(); + try + { + MemBlockStream attrStream(attr); + std::auto_ptr dirCreate(connection.QueryCreateDirectory( + BackupProtocolClientListDirectory::RootDirectory, + attrModTime, dirname, attrStream)); + + // Object ID for later creation + oid = dirCreate->GetObjectID(); + } + catch (BoxException &e) + { + BOX_ERROR("Failed to create remote " + "directory '/" << dirname << + "', skipping location."); + continue; + } + } // Create and store the directory object for the root of this location @@ -1798,6 +1813,15 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con // Push it back on the vector of locations mLocations.push_back(ploc); } + catch (std::exception &e) + { + delete ploc; + ploc = 0; + BOX_ERROR("Failed to setup location '" + << ploc->mName << "' path '" + << ploc->mPath << "': " << e.what()); + throw; + } catch(...) { delete ploc; diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 0077166f..d69d8197 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -390,6 +390,10 @@ bool ConvertEncoding(const std::string& rSource, int sourceCodePage, 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; } @@ -398,6 +402,7 @@ bool ConvertEncoding(const std::string& rSource, int sourceCodePage, if (!pConsole) { + // Error should have been logged by ConvertFromWideString return false; } -- cgit v1.2.3 From 7ea889902db918ac63c22a06a0ed0a1673ff1b61 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 20:56:03 +0000 Subject: More helpful error messages when location setup failed. --- bin/bbackupd/BackupDaemon.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 4a72f762..4e5621a4 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1817,18 +1817,20 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con { delete ploc; ploc = 0; - BOX_ERROR("Failed to setup location '" + BOX_ERROR("Failed to configure location '" << ploc->mName << "' path '" - << ploc->mPath << "': " << e.what()); + << ploc->mPath << "': " << e.what() << + ": please check for previous errors"); throw; } catch(...) { delete ploc; ploc = 0; - BOX_ERROR("Failed to setup location '" + BOX_ERROR("Failed to configure location '" << ploc->mName << "' path '" - << ploc->mPath << "'"); + << ploc->mPath << "': please check for " + "previous errors"); throw; } } -- cgit v1.2.3 From 3fb02f866aab7fb0fae89df384b807bffe2a686c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 20:56:20 +0000 Subject: Typo compile fix. --- lib/common/Box.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/Box.h b/lib/common/Box.h index 9c0141d7..080b56b2 100644 --- a/lib/common/Box.h +++ b/lib/common/Box.h @@ -112,7 +112,7 @@ #define THROW_EXCEPTION(type, subtype) \ { \ OPTIONAL_DO_BACKTRACE \ - BOX_WARN("Exception thrown: " #type "(" #subtype ") at " \ + BOX_WARNING("Exception thrown: " #type "(" #subtype ") at " \ __FILE__ "(" << __LINE__ << ")") \ throw type(type::subtype); \ } -- cgit v1.2.3 From b74916f3604913634ebcb026218f6127bb196b15 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:45:05 +0000 Subject: Create logger object in the right place to avoid accidental triggering. --- test/common/testcommon.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 0477509a..0f0f1f9a 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -739,8 +739,6 @@ int test(int argc, const char *argv[]) // Test ExcludeList { - TestLogger logger(Log::WARNING); - ExcludeList elist; // Check assumption TEST_THAT(Configuration::MultiValueSeparator == '\x01'); @@ -799,6 +797,7 @@ int test(int argc, const char *argv[]) #undef CASE_SENSITIVE + TestLogger logger(Log::WARNING); TEST_THAT(!logger.IsTriggered()); elist.AddDefiniteEntries(std::string("/foo")); TEST_THAT(!logger.IsTriggered()); -- cgit v1.2.3 From 3d5eed381090199735be57193602129f7b62b083 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:51:40 +0000 Subject: License update. (refs #3, merges [1654]) --- LICENSE.txt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index fc3f9f3e..d08aa509 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,18 +1,24 @@ - -Copyright (c) 2003, 2005 - Ben Summers. All rights reserved. +Box Backup, http://www.fluffy.co.uk/boxbackup + +Copyright (c) 2003-2007 Ben Summers and contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + 3. All use of this software and associated advertising materials must display the following acknowledgement: - This product includes software developed by Ben Summers. + + This product includes software developed by Ben Summers and + contributors. + 4. The names of the Authors may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -32,6 +38,3 @@ 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. - - - \ No newline at end of file -- cgit v1.2.3 From bb6e7aa2084c0de6f613cec8ca101c8cfdd49c1e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:52:35 +0000 Subject: Include LICENSE.txt in client parcels. Don't include Nick's old ReadMe.txt. (refs #3, merges [1655]) --- parcels.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parcels.txt b/parcels.txt index f9669900..742cb61e 100644 --- a/parcels.txt +++ b/parcels.txt @@ -8,10 +8,10 @@ backup-client bin bbackupquery bin bbackupctl script bin/bbackupd/bbackupd-config + script LICENSE.txt ONLY:mingw32,mingw32msvc script bin/bbackupd/win32/installer.iss - script bin/bbackupd/win32/ReadMe.txt script bin/bbackupd/win32/bbackupd.conf END-ONLY -- cgit v1.2.3 From 7e3dfe1ec0045833552f880769ba2538f1cdce48 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:53:01 +0000 Subject: Delete Nick's old outdated ReadMe.txt. (refs #3, merges [1656]) --- bin/bbackupd/win32/ReadMe.txt | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 bin/bbackupd/win32/ReadMe.txt diff --git a/bin/bbackupd/win32/ReadMe.txt b/bin/bbackupd/win32/ReadMe.txt deleted file mode 100644 index 3d260750..00000000 --- a/bin/bbackupd/win32/ReadMe.txt +++ /dev/null @@ -1,24 +0,0 @@ -Upgrade instructions - -Version 0.09g to 0.09h - -This version included patches to the server as well. The server for this -upgrade can be found at http://home.earthlink.net/~gniemcew/ but hopefully -will be merged into the core in the next release. - -New values in the bbackupd.conf can now be added: - -StoreObjectInfoFile = C:\Program Files\Box Backup\bbackupd\bbackupd.dat - -This stores the state when a backup daemon is shutdown. - -KeepAliveTime = 250 - -This is imperative if MaximumDiffingTime is larger than 300, this stops the ssl -layer timing out when a diff is performed. It is wise to set MaximumDiffingTime -long enough for the largest file you may have. If you do not wish to upgrade your -server then make KeepAliveTime greater than MaximumDiffingTime. - -Have fun - -Nick -- cgit v1.2.3 From b39d9117ec9fbbf83b63bbd2eb5b4cb34feb123a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:53:28 +0000 Subject: Fix license (acknowledgement must include the contributors). Document RAID options better, and mention that they are deprecated. Improve clock time warning (use a DocBook ). Change some invalid s to . Document setting up log rotation with logrotate, and how to restart syslogd. Replace some itemised lists with glossaries. Use and in a few places where it should be used. Make "Adding and removing backed up locations" into a separate section, as I think it should be. Document the main configuration options (not yet the backup locations). Recommend that users compare their backups regularly and automatically with cron. (refs #3, merges [1657]) --- documentation/boxbackup/adminguide.xml | 985 ++++++++++++++++++++++++++++----- 1 file changed, 858 insertions(+), 127 deletions(-) diff --git a/documentation/boxbackup/adminguide.xml b/documentation/boxbackup/adminguide.xml index 43bc6103..6ea4c7b5 100644 --- a/documentation/boxbackup/adminguide.xml +++ b/documentation/boxbackup/adminguide.xml @@ -9,8 +9,8 @@ License - Copyright © 2003 - 2007, Ben Summers and contributors. - All rights reserved. + Copyright © 2003 - 2007, Ben Summers and contributors. All rights + reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -32,7 +32,7 @@ All use of this software and associated advertising materials must display the following acknowledgement: This product includes - software developed by Ben Summers. + software developed by Ben Summers and contributors. @@ -42,22 +42,20 @@ - [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. + 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. @@ -87,9 +85,13 @@ cd boxbackup-0.10-server-darwin8.5.0 useradd _bbstored - BoxBackup supports Raid for the backup store. There are some - configuration options. Use the following command if you want to create - a simple server WITHOUT Raid protection: + Box Backup has a built-in software RAID facility (redundant + array of inexpensive disks) for the backup store. This allows you to + spread the store data over three disks, and recover from the loss of + any one disk without losing data. However, this is now deprecated, and + you are recommended to use the software or hardware RAID facilities of + your operating system instead. Use the following command if you want + to create a simple server without Box Backup RAID: mkdir /tmp/boxbackupRepository # Create the directory chown _bbstored /tmp/boxbackupRepository/ # Change the owner to the new boxbackup daemon user @@ -106,7 +108,8 @@ chown _bbstored /tmp/boxbackupRepository/ # Change the owner to the Since you might be using NAT, might move the server around or the domain name might change, choose a name that describes the server. When the network address of the server changes, you need to update the - ListenAddresses directive in the /etc/box/bbstored.conf file. + ListenAddresses directive in the + /etc/box/bbstored.conf file. /usr/local/bin/bbstored-config /etc/box hostname _bbstored @@ -116,7 +119,7 @@ chown _bbstored /tmp/boxbackupRepository/ # Change the owner to the TODO: Expand on this. Explain the 5 steps in detail. - If you want to run the system as a non-root user, look If you want to run the server as a non-root user, look here. @@ -131,47 +134,52 @@ chown _bbstored /tmp/boxbackupRepository/ # Change the owner to the not trivial. However, a script to does most of the work in a way which should be good enough for most deployments. - Important Note: The certificate - authority directory is intended to be stored on another server. It - should not be kept on the backup server to limit the impact of a - server compromise. The instructions and the script assume that it will - be kept elsewhere, so will ask you to copy files to and from the - CA. - - Clock time warning: SSL - certificates contain validity dates, including a "valid from" time. If - the clock on the machine which signs the certificates is not - syncronised to the clocks of the machines using these certificates, - you will probably get strange errors until the start time is reached - on all machines. If you get strange errors when attempting to use new - certificates, check the clocks! You will probably just need to wait a - while until the certificates become valid, rather than having to - regenerate them. + + The certificate authority directory is intended to be stored + on another server. It should not be kept on the backup server, in + order to limit the impact of a server compromise. The instructions + and the script assume that it will be kept elsewhere, so will ask + you to copy files to and from the CA. + + + + SSL certificates contain validity dates, including a "valid + from" time. If the clock on the machine which signs the certificates + is not syncronised to the clocks of the machines using these + certificates, you will probably get strange errors until the start + time is reached on all machines. If you get strange errors when + attempting to use new certificates, check the clocks on all machines + (client, store and CA). You will probably just need to wait a while + until the certificates become valid, rather than having to + regenerate them. +
- Set up a CA + Set up a Certificate Authority - It's best to do this on a machine other than your server, - probably without direct network access. The contents of this - directory control who can access your backup store server. + It is recommended that you keep your Certificate Authority on + a separate machine than either the client or the server, preferably + without direct network access. The contents of this directory + control who can access your backup store server. To setup the basic key structure, do the following: /usr/local/bin/bbstored-certs ca init - (See OpenSSL notes if you + (See OpenSSL notes if you get an OpenSSL error) - This creates the directory 'ca' in the current directory, and - initialises it with basic keys. + This creates the directory called ca in + the current directory, and initialises it with basic keys.
Sign a server certificate - When you use the bbstored-config script to set up a config - file for a server, it will generate a certificate request (CSR) for - you. Transfer it to the machine with your CA, then do: + When you use the bbstored-config script to + set up a config file for a server, it will generate a certificate + request (CSR) for you. Transfer it to the machine with your CA, then + do: /usr/local/bin/bbstored-certs ca sign-server hostname-csr.pem @@ -281,12 +289,28 @@ local5.info /var/log/raidfile touch /var/log/box touch /var/log/raidfile - Set up log rotation, by adding in /etc/newsyslog.conf: + Set up log rotation for these new log files. For example, if you + have /etc/newsyslog.conf, add the following lines + to it: /var/log/box 644 7 2000 * Z /var/log/raidfile 644 7 2000 * Z - Then restart syslogd. + If you have /etc/logrotate.d, create a new + file in there (for example + /etc/logrotate.d/boxbackup) containing the + following: + + /var/log/box /var/log/raidfile { + weekly + create + compress + rotate 52 +} + + Then restart syslogd, for example: + + /etc/init.d/syslogd restart
@@ -309,22 +333,24 @@ touch /var/log/raidfile The backup client has to be run as root, because it needs to read all your files to back them up, although it is possible to back up a single user's files by running it as that user. (Tip: specify a - directory other than /etc/box, and then give the alternate config file - as the first argument to bbackupd). However, it will fall over if you - don't give yourself read access to one of your files. + directory other than /etc/box, and then give the + alternate config file as the first argument to + bbackupd). However, it will fall over if you don't + give yourself read access to one of your files.
Basic configuration - Run the bbackupd-config script to generate the configuration - files and generate a private key and certificate request. + Run the bbackupd-config script to generate + the configuration files and generate a private key and certificate + request. /usr/local/bin/bbackupd-config /etc/box lazy 999 hostname /var/bbackupd /home - (See OpenSSL notes if - you get an OpenSSL error) + (See OpenSSL notes if you + get an OpenSSL error) The items in bold need to be changed. In order, they are the account number, the hostname of the server you're using, and @@ -337,27 +363,34 @@ touch /var/log/raidfile catch bad configuration of this nature! You may also want to consider changing the mode from lazy to - snapshot, depending on what your system is used for. - - - - lazy. This mode regularly - scans the files, with only a rough schedule. It uploads files as - and when they are changed, if the latest version is more than a - set age. This is good for backing up user's documents stored on - a server, and spreads the load out over the day. - - - - snapshot. This mode - emulates the traditional backup behaviour of taking a snapshot - of the filesystem. The backup daemon does absolutely nothing - until it is instructed to make a backup using the bbackupctl - utility (probably as a cron job), at which point it uploads all - files which have been changed since the last time it - uploaded. - - + snapshot, depending on what your system is used for: + + + + Lazy Mode + + + This mode regularly scans the files, with only a rough + schedule. It uploads files as and when they are changed, if + the latest version is more than a set age. This is good for + backing up user's documents stored on a server, and spreads + the load out over the day. + + + + + Snapshot Mode + + + This mode emulates the traditional backup behaviour of + taking a snapshot of the filesystem. The backup daemon does + absolutely nothing until it is instructed to make a backup + using the bbackupctl utility (probably as a cron job), at + which point it uploads all files which have been changed since + the last time it uploaded. + + + When you run the config script, it will tell you what you need to do next. Don't forget to read all the output. An example is shown @@ -373,11 +406,12 @@ touch /var/log/raidfile install them where instructed by the bbackupd-config script during basic bbackupd configuration. - You can then run the daemon (as root) by typing - /usr/local/bin/bbackupd, and of course, adding it to your system's - startup scripts. The first time it's run it will upload everything. - Interrupting it and restarting it will only upload files which were - not uploaded before - it's very tolerant. + You can then run the daemon (as root) by running + /usr/local/bin/bbackupd, and of course, adding it + to your system's startup scripts. The first time it's run it will + upload everything. Interrupting it and restarting it will only + upload files which were not uploaded before - it's very + tolerant. If you run in snapshot mode, you will need to add a cron job to schedule backups. The config script will tell you the exact @@ -395,11 +429,14 @@ touch /var/log/raidfile If you want to see what it's doing in more detail (probably a good idea), follow the instructions in the server setup to create - new log files with syslog. Adding and removing backed up - locations. + new log files with syslog. +
+ +
+ Adding and removing backed up locations By editing the /etc/box/bbackupd.conf file, you can add and - remove directories to back up -- see comments in this file for help. + remove directories to back up - see comments in this file for help. Send bbackupd a HUP signal after you modify it. When you remove a location, it will not be marked as deleted @@ -475,9 +512,10 @@ touch /var/log/raidfile This is an example of output from the bbstored-config script. - Important: Follow the - instructions output by your script, not the ones here -- they may be - different for your system. + + Follow the instructions output by your script, not the ones + here -- they may be different for your system. + /usr/local/bin/bbackupd-config /etc/box lazy 51 server.example.com /var/bbackupd /home /etc/samba @@ -549,8 +587,690 @@ What you need to do now... Remember to make a secure, offsite backup of your backup keys, as described in Basic - configuration above. If you do not,, and that key is lost, - you have no backups. + configuration above. If you do not, and that key is lost, you + have no backups. +
+
+ +
+ Configuration Options + + Box Backup has many options in its configuration file. We will + try to list them all here. + + First of all, here is an example configuration file, for + reference: + + + Example Configuration File + + StoreHostname = localhost +AccountNumber = 0x2 + +KeysFile = /etc/box/2-FileEncKeys.raw +CertificateFile = /etc/box/2-cert.pem +PrivateKeyFile = /etc/box/2-key.pem +TrustedCAsFile = /etc/box/serverCA.pem +DataDirectory = /var/run/boxbackup +NotifyScript = /etc/box/NotifySysadmin.sh +CommandSocket = /var/run/box/bbackupd.sock + +UpdateStoreInterval = 86400 +MinimumFileAge = 3600 +MaxUploadWait = 7200 +FileTrackingSizeThreshold = 65536 +DiffingUploadSizeThreshold = 65536 +MaximumDiffingTime = 20 +ExtendedLogging = no +LogAllFileAccess = yes + +Server +{ + PidFile = /var/run/bbackupd.pid +} +BackupLocations +{ + etc + { + Path = /etc + } + home + { + Path = /home + ExcludeDir = /home/shared + ExcludeDir = /home/chris/.ccache + ExcludeDir = /home/chris/.mozilla/firefox/vvvkq3vp.default/Cache + } +} + + + As you can see from the example above, the configuration file + has a number of subsections, enclosed in curly braces {}. Some options + appear outside of any subsection, and we will refer to these as root options. The available options in + each section are described below. + + Every option has the form name = value. Names are + not case-sensitive, but values are. Depending on the option, the value + may be: + + + + a path (to a file or directory); + + + + a number (usually in seconds or bytes); + + + + a boolean (the word Yes or No); + + + + a hostname (or IP address). + + + + Paths are specified in native format, i.e. a full Windows path + with drive letter on Windows clients, or a full Unix path on Unix + clients. + + + Example: + + StoreObjectInfoFile = + /var/state/boxbackup/bbackupd.dat + + StoreObjectInfoFile = C:\Program Files\Box + Backup\data\bbackupd.dat + The use of relative paths (which do not start with a + forward slash on Unix, or a drive specification on Windows) is + possible but not recommended, since they are interpreted relative to + the current working directory when bbackupd was started, which is + liable to change unexpectedly over time. + + Numbers which start with "0x" are interpreted as hexadecimal. + Numbers which do not start with "0x" are interpreted as + decimal. + +
+ Root Options + + These options appear outside of any subsection. By convention + they are at the beginning of the configuration file. + + Some options are required, and some are optional. + + + + StoreHostname (required) + + + The Internet host name (DNS name) or IP address of the + server. This is only used to connect to the server. + + + + + AccountNumber (required) + + + The number of the client's account on the server. This + must be provided by the server operator, and must match the + account number in the client's certificate, otherwise the + client will not be able to log into the server. + + The account number may be specified in hexadecimal + (starting with 0x, as in the example above) or in decimal, but + since the server operator works in hexadecimal, that format is + highly recommended and is the default. + + + + + KeysFile (required) + + + The path to the file containing the encryption key used + for data encryption of client file data and filenames. This is + the most important file to keep safe, since without it your + backups cannot be decrypted and are useless. Likewise, if an + attacker gets access to this key and to your encrypted + backups, he can decrypt them and read all your data. + + Do not change the encryption key without deleting all + files from the account on the server first. None of your old + files on the store will be readable if you do so, and if you + change it back, none of the files uploaded with the new key + will be readable. + + + + + CertificateFile (required) + + + The path to the OpenSSL client certificate in PEM + format. This is supplied by the server operator in response to + the certificate request which you send to them. Together with + the PrivateKeyFile, this provides access to the store server + and the encrypted data stored there. + + It is not critical to protect this file or to back it up + safely, since it can be regenerated by creating a new + certificate request, and asking the server operator to sign + it. You may wish to back it up, together with the + PrivateKeyFile, to avoid this inconvenience if you lose all + your data and need quick access to your backups. + + If you do back them up, you should keep them in a + separate location to the KeysFile, since any person holding + the KeysFile and the PrivateKeyFile can gain access to your + encrypted data and decrypt it. + + + + + PrivateKeyFile (required) + + + The path to the OpenSSL private key in PEM format. This + is generated at the same time as the certificate request, but + there is no need to send it to the server operator, and you + should not do so, in case the communication is intercepted by + an attacker. Together with the CertificateFile, this provides + access to the store server and the encrypted data stored + there. + + See the notes under CertificateFile for information + about backing up this file. + + + + + TrustedCAsFile (required) + + + The path to the OpenSSL certificate of the Client + Certificate Authority (CCA), in PEM format. This is supplied + by the server operator along with your account details, or + along with your signed client certificate. This is used to + verify that the server which you are connecting to is + authorised by the person who signed your certificate. It + protects you against DNS and ARP poisoning and IP spoofing + attacks. + + + + + DataDirectory (required) + + + The path to a directory where bbackupd will keep local + state information. This consists of timestamp files which + identify the last backup start and end times, used by + bbackupquery to determine whether files + have changed, and optionally a database of inode numbers, + which are used to check for files being renamed. The database + is only saved if Box Backup is built with Berkeley Database + (BDB) support. + + + + + NotifyScript (optional) + + + The path to the script or command to run when the Box + Backup client detects an error during the backup process. This + is normally used to notify the client system administrator by + e-mail when a backup fails for any reason. + + The script or command is called with one of the + following additional arguments to identify the cause of the + problem: + + + + store-full + + + The backup store is full. No new files are being + uploaded. If some files are marked as deleted, they + should be removed in due course by the server's + housekeeping process. Otherwise, you need to remove some + files from your backup set, or ask the store operator + for more space. + + + + + read-error + + + One or more files which were supposed to be backed + up could not be read. This could be due to: + + running the server as a non-root user; + + + + backing up a mounted filesystem such as + NFS; + + + + access control lists being applied to some + files; + + + + SELinux being enabled; + + + + trying to back up open files under + Windows; + + + + strange directory permissions such as 0000 or + 0400. + + Check the client logs, e.g. + /var/log/bbackupd on Unix, or the Windows Event Viewer + in Control Panel > Administrative Tools, for more + information about which files are not being backed up + and why. + + + + + backup-error + + + There was a communications error with the server, + or an unexpected exception was encountered during a + backup run. Check the client logs, e.g. + /var/log/box on Unix, or the + Windows Event Viewer in Control Panel > + Administrative Tools, for more information about the + problem. + + You may wish to check your Internet access to the + server, check that the server is running, and ask your + server operator to check your account on the + server. + + + + + + + + CommandSocket (optional) + + + The path to the Unix socket which + bbackupd creates when running, and which + bbackupctl uses to communicate with it, for + example to force a sync or a configuration reload. If this + option is omitted, no socket will be created, and + bbackupctl will not function. + + Unix sockets appear within the filesystem on Unix, as a + special type of file, and must be created in a directory which + exists and to which bbackupd has write access, and bbackupctl + has read access. + + On Windows, the path is ignored, and a named + pipe is created instead. This does not currently + have any security attached, so it can be accessed by any user. + Unlike a Unix socket it can also be accessed remotely. Please + use this option with extreme caution on Windows, and only on + fully trusted networks. + + + + + AutomaticBackup (optional) + + + Enable or disable the client from connecting + automatically to the store every + UpdateStoreInterval seconds. When + enabled (set to Yes), the client is in + Lazy Mode. When disabled (set to + No), it is in Snapshot + Mode. This setting is optional, and the default + value is Yes. + + + + + UpdateStoreInterval (required) + + + The approximate time between successive connections to + the server, in seconds, when the client is in Lazy + Mode. The actual time is randomised slightly to + prevent "rush hour" traffic jams on the server, where many + clients try to connect at the same time. + + This value is ignored if the client is in + Snapshot Mode. However, it is still + required. It can be set to zero in this case. + + You will probably need to experiment with the value of + this option. A good value to start with is probably 86400 + seconds, which is one day. + + + + + MinimumFileAge (required) + + + The number of seconds since a file was last modified + before it will be backed up. The reason for this is to avoid + repeatedly backing up files which are repeatedly changing. A + good value is about 3600 seconds (one hour). If set to zero, + files which have changed will always be backed up on the next + backup run. + + The MaxUploadWait option + overrides this option in some circumstances. + + + + + MaxUploadWait (required) + + + The number of seconds since a file was last uploaded + before it will be uploaded again, even if it keeps changing. + The reason for this is to ensure that files which are + continuously modified are eventually uploaded anyway. This + should be no less than the value of + MinimumFileAge. A good value is about + 14400 seconds (4 hours). + + + + + MaxFileTimeInFuture (optional) + + + The maximum time that a file's timestamp can be in the + future, before it will be backed up anyway. Due to clock + synchronisation problems, it is inevitable that you will + occasionally see files timestamped in the future. Normally, + for files which are dated only slightly in the future, you + will want to wait until after the file's date before backing + it up. However, for files whose dates are very wrong (more + than a few hours) you will normally prefer to back them up + immediately. + + A good value is about 7200 seconds (2 hours) to cope + with potential problems when moving in and out of daylight + saving time, if applicable in your timezone. The default + value, if this setting is not provided, is 172800 seconds (2 + days). + + + + + FileTrackingSizeThreshold (required) + + + The minimum size of files which will be tracked by inode + number to detect renames. It is not worth detecting renames of + small files, since they are quick to upload again in full, and + keeping their inode numbers in memory increases the client's + memory usage and slows down searches. Larger files should be + tracked to avoid wasting space on the store and long + uploads. + + A good value is about 65536 bytes (64 kilobytes). + + + + + DiffingUploadSizeThreshold (required) + + + The minimum size of files which will be compared to the + old file on the server, and for which only changes will be + uploaded. It is not worth comparing small files, since they + are quick to upload again in full, and sending the entire file + reduces the risk of data loss if the store is accidentally + corrupted. Larger files should have only their differences + uploaded to avoid wasting space on the store and long + uploads. + + A good value is about 65536 bytes (64 kilobytes). + + + + + MaximumDiffingTime (optional) + + + The maximum time for which the client will attempt to + find differences between the current version and the old + version in the store, before giving up and uploading the + entire file again. Very large files (several gigabytes) may + take a very long time to scan for changes, but would also take + a very long time to upload again and use a lot of space on the + store, so it is normally worth omitting this value. + + Use this option only if, for some bizarre reason, you + prefer to upload really large files in full rather than spend + a long time scanning them for changes. + + + + + KeepAliveTime (optional) + + + The interval (in seconds) between sending Keep-Alive + messages to the server while performing long operations such + as finding differences in large files, or scanning large + directories. + + These messages ensure that the SSL connection is not + closed by the server, or an intervening firewall, due to lack + of activity. + + The server will normally wait up to 15 minutes (900 + seconds) before disconnecting the client, so the value should + be given and should be less than 900. Some firewalls may time + out inactive connections after 10 or 5 minutes. + + A good value is 300 seconds (5 minutes). You may need to + reduce this if you frequently see TLSReadFailed or + TLSWriteFailed errors on the client. + + + + + StoreObjectInfoFile (optional) + + + Enables the use of a state file, which stores the + client's internal state when the client is not running. This + is useful on clients machines which are frequently shut down, + for example desktop and laptop computers, because it removes + the need for the client to recontact the store and rescan all + directories on the first backup run, which may take some time. + This feature is somewhat experimental and not well tested. + + + This is option is disabled by default, in which case the + state is stored in memory only. The value is the path to the + state file. + + + + + ExtendedLogging (optional) + + + Enables the connection debugging mode of the client, + which writes all commands sent to or received from the server + to the system logs. This generates a lot + of output, so it should only be used when instructed, or when + you suspect a connection problem or client-server protocol + error (and you know how to interpret the output). + + This is a boolean value, which may be set to + Yes or No. The default is of + course No. + + + + + ExtendedLogFile (optional, new in 0.11) + + + Enables the same debugging output as + ExtendedLogging, but written to a file + instead of the system logs. This is useful if you need + extended logging, but do not have access to the system logs, + for example if you are not the administrator of the + computer. + + The value is the path to the file where these logs will + be written. If omitted, extended logs will not be written to a + file. This is entirely independent of the + ExtendedLogging option. It does not + make much sense to use both at the same time. + + + + + LogAllFileAccess (optional, new in 0.11) + + + Enables logging of all local file and directory access, + file uploads (full and differential), and excluded files. This + may be useful if the client is failing to upload a particular + file, or crashing while trying to upload it. The logs will be + sent to the system log or Windows Event Viewer. + + This is a boolean value, which may be set to + Yes or No. The default is of + course No. + + + + + SyncAllowScript (optional) + + + The path to the script or command to run when the client + is about to start an automatic backup run, and wishes to know + whether it is safe to do so. This is useful for clients which + do not always have access to the server, for example laptops + and computers on dial-up Internet connections. + + The script should either output the word + now if the backup should proceed, or else a + number, in seconds, which indicates how long the client should + wait before trying to connect again. Any other output will + result in an error on the client, and the backup will not + run. + + This value is optional, and by default no such script is + used. + + + +
+ +
+ Server Section + + These options appear within the Server subsection, which is at + the root level. + + + + PidFile + + + This option enables the client to write its processs + identifier (PID) to the specified file after starting. The + file will be deleted when the client daemon exits for any + reason. This is disabled by default, but is recommended + whenever you run the client daemon as a daemon (in the + background), which is usually the case. This file can be used + by scripts to determine whether the daemon is still running, + and to send it messages to reload its configuration or to + terminate. + + + Example Server Section + + Server +{ + PidFile = /var/state/boxbackup/bbackupd.pid +} + + + + +
+ +
+ Backup Locations Section + + This section serves only as a container for all defined backup + locations. + + + Example Backup Locations Section + + BackupLocations +{ + etc + { + Path = /etc + } + home + { + Path = /home + ExcludeDir = /home/shared + ExcludeDir = /home/chris/.ccache + ExcludeDir = /home/chris/.mozilla/firefox/vvvkq3vp.default/Cache + } +} + + + Each subsection is a backup location. The name of the + subsection is the name that will be used on the server. The root + directory of the account on the server contains one subdirectory per + location. The name should be simple, not containing any spaces or + special characters. + + If you do not define any locations, the client will not back + up any files! + + It is currently not recommended to back up the root directory + of the filesystem on Unix. Box Backup is designed to back up + important data and configuration files, not full systems. + Nevertheless, nothing prevents you from doing so if you + desire. + + On Windows, it is currently not possible to back up files + which are open (currently in use), such as open documents in + Microsoft Office, and system files such as the registry and the + paging file. You will get an error for each open file which the + client attempts to back up. Once the file has been closed, it will + be backed up normally. System files will always be open, and should + be excluded from your backups.
@@ -681,8 +1401,8 @@ What you need to do now... up the data it needs from /etc/box/bbackupd.conf. You should run it as root so it can find everything it needs. - Full documentation can be found in the bbackupquery man page. It follows + Full documentation can be found in the bbackupquery manual page. It follows the model of a command line sftp client quite closely. TODO: Link to bbackupquery man-page here. @@ -804,33 +1524,44 @@ query >
Verify backups - Since this system is not yet 100% production-ready, you'll be - keen to verify that your backups are correct. This is easy: + As with any backup system, you should frequently check that + your backups are working properly by comparing them. Box Backup + makes this very easy and completely automatic. All you have to do is + schedule the bbackupquery compare command to run + regularly, and check its output. You can run the command manually as + follows: /usr/local/bin/bbackupquery "compare -a" quit - It will report all the differences between the store and the - files on disc. It will download everything, so may take a while. You - should expect to see some differences on a typical compare, because - files which have recently changed are unlikely to have been uploaded - yet. Consider checking the timestamps on the files, or keeping a - record of these messages and comparing them with a future - verification. + This command will report all the differences found between the + store and the files on disc. It will download everything, so may + take a while. You should expect to see some differences on a typical + compare, because files which have recently changed are unlikely to + have been uploaded yet. It will also tell you how many files have + been modified since the last backup run, since these will normally + have changed, and such failures are expected. + + You are strongly recommended to add this command as a + cron job, at least once a month, and to check the + output for anything suspicious, particularly a large number of + compare failures, failures on files that have not been modified, or + any error (anything except a compare mismatch) that occurs during + the compare operation. + + Consider keeping a record of these messages and comparing them + with a future verification. If you would like to do a "quick" check which just downloads - file checksums and compares against that, then do: + file checksums and compares against that, then run: /usr/local/bin/bbackupquery "compare -aq" quit However, this does not check that the file attributes are correct, and since the checksums are generated on the client they may not reflect the data on the server if there is a problem -- the - server cannot check the encrypted contents. View this as a good + server cannot check the encrypted contents. View this as a quick indication, rather than a definite check that your backup verifies correctly. - - You may wish to run either one as a cron job while testing - this system.
@@ -947,8 +1678,8 @@ Object ID 0000437e fetched successfully. Fixing corruptions of store data This section gives help on what to do if your server has suffered - corruption, for example, after an unclean shutdown or other OS or - hardware problem. + corruption, for example, after an unclean shutdown or other operating + system or hardware problem. In general, as updates to the store are made in an atomic manner, the most likely result is wasted disc space. However, if really bad @@ -970,34 +1701,34 @@ Object ID 0000437e fetched successfully. lost+found directories as deleted. Finally, those directories will be removed by the housekeeping process on the server. - These instructions assume you're working on account 1234, - subsitute this for whatever account you're actually working on. These - will need to be repeated for all affected accounts. + These instructions assume you're working on account 1234. Replace + this with the account number that you actually want to check (the one + that is experiencing errors). These steps will need to be repeated for + all affected accounts.
Stop bbackupd First, make sure that bbackupd is not running on the client - machine for the account you are going to recover. Use kill to - terminate it. This step is not strictly necessary, but is recommended. - During any checks on the account, bbackupd will be unable to log in, - and after they are complete, the account is marked as changed on the - server so bbackupd will perform a complete scan. + machine for the account you are going to recover. Use + bbackupctl terminate to stop it. This step is not + strictly necessary, but is recommended. During any checks on the + account, bbackupd will be unable to log in, and after they are + complete, the account is marked as changed on the server so bbackupd + will perform a complete scan.
Are you using RAID on the server? - At the moment, the raidfile recovery tools have not been - written. However, when two out of three files are available, the - server will run succesfully, even if it complains a lot in the logs. - So, your best bet here is to fix the accounts, if necessary, and - retrieve any files you need. Then move the old store directories aside - (in case you need them) and start afresh with new accounts, and let - the clients upload all their data again. These utilities will be - written shortly! - - TODO: Is this true anymore??? + The raidfile recovery tools have not been written, and probably + will not be, since Box Backup RAID is deprecated. However, when two + out of three files are available, the server will successfully allow + access to your data, even if it complains a lot in the logs. The best + thing to do is to fix the accounts, if necessary, and retrieve any + files you need. Then move the old store directories aside (in case you + need them) and start afresh with new accounts, and let the clients + upload all their data again.
@@ -1049,7 +1780,7 @@ Object ID 0000437e fetched successfully.
- Troubleshooting + Troubleshooting If you are trying to fix a store after your disc has been corrupted, see Fixing corruptions of @@ -1240,4 +1971,4 @@ make testing, and should not be relied on in a production environment.
- + \ No newline at end of file -- cgit v1.2.3 From 211d24938fdfadae7e8c9b152bdf936dc4b82249 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:54:04 +0000 Subject: Apply Gary's patch to save the list of unused root directory entries in the store object info file, so that they will persist across restarts. (refs #18, refs #3, merges [1658]) --- bin/bbackupd/BackupDaemon.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 4e5621a4..edb1246a 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -2611,7 +2611,7 @@ BackupDaemon::CommandSocketInfo::~CommandSocketInfo() static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F; static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE"; -static const int STOREOBJECTINFO_VERSION = 1; +static const int STOREOBJECTINFO_VERSION = 2; bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const { @@ -2671,8 +2671,9 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time // // aFile.Close(); - BOX_INFO("Saved store object info file: " - << StoreObjectInfoFile); + BOX_INFO("Saved store object info file: " << + StoreObjectInfoFile << ", version " << + STOREOBJECTINFO_VERSION); } catch(std::exception &e) { @@ -2827,6 +2828,26 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ mIDMapMounts.push_back(strItem); } + // + // + // + iCount = 0; + anArchive.Read(iCount); + + for(int v = 0; v < iCount; v++) + { + int64_t anId; + anArchive.Read(anId); + + std::string aName; + anArchive.Read(aName); + + mUnusedRootDirEntries.push_back(std::pair(anId, aName)); + } + + if (iCount > 0) + anArchive.Read(mDeleteUnusedRootDirEntriesAfter); + // // // -- cgit v1.2.3 From 26d8ac70f566a4a43579929cd96174618b3b9949 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:54:32 +0000 Subject: Apply Gary's patch from ticket #19 to respect the server's hard limit rather than the soft limit. This allows setting the soft limit to zero, so that housekeeping will remove all old versions of all files. (refs #19, refs #3, merges [1659]) --- bin/bbackupd/BackupClientContext.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index c18bcfd6..18859393 100644 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -197,16 +197,12 @@ BackupProtocolClient &BackupClientContext::GetConnection() ::syslog(LOG_INFO, "Connection made, login successful"); // Check to see if there is any space available on the server - int64_t softLimit = loginConf->GetBlocksSoftLimit(); - int64_t hardLimit = loginConf->GetBlocksHardLimit(); - // Threshold for uploading new stuff - int64_t stopUploadThreshold = softLimit + ((hardLimit - softLimit) / 3); - if(loginConf->GetBlocksUsed() > stopUploadThreshold) + if(loginConf->GetBlocksUsed() >= loginConf->GetBlocksHardLimit()) { // no -- flag so only things like deletions happen mStorageLimitExceeded = true; // Log - ::syslog(LOG_WARNING, "Exceeded storage limits on server -- not uploading changes to files"); + ::syslog(LOG_WARNING, "Exceeded storage hard-limit on server -- not uploading changes to files"); } } catch(...) -- cgit v1.2.3 From 18b71f8cbbdf85907a9e204b9e9f2d056ac43419 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:56:06 +0000 Subject: Experimental fix for restore problem reported by Mikael Syska: query > restore Admin "c:\admin\" Failed to read file information: The parameter is incorrect. (87) Failed to get file information for 'c:' Failed to check existence for c:: Common OSFileError (Error accessing a file. Check permissions.) ERROR: Unknown restore result. (refs #3, merges [1659]) --- lib/backupclient/BackupClientRestore.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 834bfb9a..028c1659 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -304,6 +304,15 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir // 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 += '\\'; + } + #endif + int parentExists; try -- cgit v1.2.3 From a436702cdf84264e1176548a4dd0f78f8eeb123a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:58:40 +0000 Subject: Fix restoring to top-level directories (e.g. c:\test) (refs #3, merges [1661]) --- lib/backupclient/BackupClientRestore.cpp | 4 ++++ lib/win32/emu.cpp | 31 ++++++++++++++++++------------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 028c1659..9b3a3edc 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -311,6 +311,10 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { parentDirectoryName += '\\'; } + else if (lastSlash == 0) + { + parentDirectoryName += '\\'; + } #endif int parentExists; diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index d69d8197..4224d62e 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -460,23 +460,28 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName) // Is the path relative or absolute? // Absolute paths on Windows are always a drive letter // followed by ':' + + 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[1] != ':') + 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()] != '\\') { -- cgit v1.2.3 From d79aefa67d3a9dcf9c76b670468851ae3709807b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:59:09 +0000 Subject: Fix unit tests now that bbackupd honours the hard limit and not the soft limit. (refs #3, merges [1662]) --- test/bbackupd/testbbackupd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 2b8225cc..696bd1a6 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -1078,7 +1078,7 @@ int test_bbackupd() // soft limit + 1/3 of (hard - soft). Set small values // for limits accordingly. TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS " -c " - "testfiles/bbstored.conf setlimit 01234567 10B 40B") + "testfiles/bbstored.conf setlimit 01234567 9B 10B") == 0); TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks"); -- cgit v1.2.3 From 1072b4054a8e01cd848fd0025d766292f174a609 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 21:59:36 +0000 Subject: Don't #include sys/time.h unless our platform has it, thanks Gary. (refs #3, merges [1664]) --- lib/common/Timer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/common/Timer.h b/lib/common/Timer.h index 8e229a0a..ba6d71f4 100644 --- a/lib/common/Timer.h +++ b/lib/common/Timer.h @@ -11,7 +11,9 @@ #ifndef TIMER__H #define TIMER__H -#include +#ifdef HAVE_SYS_TIME_H + #include +#endif #include -- cgit v1.2.3 From 243823b91f9bf4eb5f60dbce575904cd20a237ef Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:00:00 +0000 Subject: We now have pcreposix.h instead of regex.h, at least if you follow the MSVC build instructions. (refs #3, merges [1665]) --- lib/common/BoxConfig-MSVC.h | 3 ++- lib/common/ExcludeList.cpp | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/common/BoxConfig-MSVC.h b/lib/common/BoxConfig-MSVC.h index 01fc9c63..0f84f964 100644 --- a/lib/common/BoxConfig-MSVC.h +++ b/lib/common/BoxConfig-MSVC.h @@ -176,7 +176,8 @@ /* #undef HAVE_READLINE_READLINE_H */ /* Define to 1 if you have the header file. */ -#define HAVE_REGEX_H 1 +/* #undef HAVE_REGEX_H */ +#define HAVE_PCREPOSIX_H 1 /* Define to 1 if you have the `setproctitle' function. */ /* #undef HAVE_SETPROCTITLE */ diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp index e24246c8..a8d07dcc 100644 --- a/lib/common/ExcludeList.cpp +++ b/lib/common/ExcludeList.cpp @@ -9,7 +9,10 @@ #include "Box.h" -#ifdef HAVE_REGEX_H +#ifdef HAVE_PCREPOSIX_H + #include + #define EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED +#elif defined HAVE_REGEX_H #include #define EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED #endif -- cgit v1.2.3 From 5c3881a66cb2932f66972a17b28cee3c3564b707 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:00:22 +0000 Subject: MSVC compile fix, thanks Gary. (refs #3, merges [1666]) --- bin/bbackupd/BackupDaemon.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 14782859..7df62c95 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -229,13 +229,15 @@ public: const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath) { - BOX_WARNING("Ignored directory: " << rLocalPath << ": " #ifdef WIN32 - "is an NTFS junction/reparse point; " + BOX_WARNING("Ignored directory: " << rLocalPath << + ": is an NTFS junction/reparse point; create " + "a new location if you want to back it up"); #else - "is a mount point; " + BOX_WARNING("Ignored directory: " << rLocalPath << + ": is a mount point; create a new location " + "if you want to back it up"); #endif - "create a new location if you want to back it up"); } virtual void NotifyFileExcluded( const BackupClientDirectoryRecord* pDirRecord, -- cgit v1.2.3 From 05eb0d9aef01161294de5622f421531970efd464 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:00:41 +0000 Subject: Make autogen_ClientException, thanks Gary. (refs #3, merges [1667]) --- win32.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32.bat b/win32.bat index 86fcf943..6430df8f 100644 --- a/win32.bat +++ b/win32.bat @@ -14,7 +14,7 @@ cd ..\..\ cd .\lib\compress & perl ./../../lib/common/makeexception.pl.in CompressException.txt cd ..\..\ -cd .\lib\common & perl ./../../lib/common/makeexception.pl.in CommonException.txt & perl ./../../lib/common/makeexception.pl.in ConversionException.txt +cd .\lib\common & perl ./../../lib/common/makeexception.pl.in CommonException.txt & perl ./../../lib/common/makeexception.pl.in ConversionException.txt & perl ./../../lib/common/makeexception.pl.in ClientException.txt cd ..\..\ -- cgit v1.2.3 From 3e8085ecd57ecf4d7f2c4d7a05dba71e70c9a525 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:01:04 +0000 Subject: Define DEBUG_NEW in the same file whether or not BOX_MEMORY_LEAK_TESTING is defined, thanks Gary. (refs #3, merges [1668]) --- lib/common/Box.h | 1 + lib/common/MemLeakFinder.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/common/Box.h b/lib/common/Box.h index 080b56b2..abaad9f2 100644 --- a/lib/common/Box.h +++ b/lib/common/Box.h @@ -95,6 +95,7 @@ #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(); diff --git a/lib/common/MemLeakFinder.h b/lib/common/MemLeakFinder.h index 6bfdc3d0..450d42f8 100644 --- a/lib/common/MemLeakFinder.h +++ b/lib/common/MemLeakFinder.h @@ -10,8 +10,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 -- cgit v1.2.3 From 3fdbfc61a49360884c80318426a8e6719330c2c9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:01:40 +0000 Subject: Apply remaining parts of Gary's patch, missing from [1658], thanks Gary (refs #3, merges [1669]) --- bin/bbackupd/BackupDaemon.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index edb1246a..a772d8de 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -2845,6 +2845,26 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ mUnusedRootDirEntries.push_back(std::pair(anId, aName)); } + if (iCount > 0) + anArchive.Read(mDeleteUnusedRootDirEntriesAfter); + + // + // + // + iCount = 0; + anArchive.Read(iCount); + + for(int v = 0; v < iCount; v++) + { + int64_t anId; + anArchive.Read(anId); + + std::string aName; + anArchive.Read(aName); + + mUnusedRootDirEntries.push_back(std::pair(anId, aName)); + } + if (iCount > 0) anArchive.Read(mDeleteUnusedRootDirEntriesAfter); -- cgit v1.2.3 From 1e57cefbd35bb58f221fcd291b4038b22e95e186 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:02:26 +0000 Subject: Update copyright to 2007. (refs #3, merges [1670]) --- lib/common/BannerText.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/BannerText.h b/lib/common/BannerText.h index 23486fef..c9d85d5c 100644 --- a/lib/common/BannerText.h +++ b/lib/common/BannerText.h @@ -11,7 +11,7 @@ #define BANNERTEXT__H #define BANNER_TEXT(UtilityName) \ - "Box " UtilityName " v" BOX_VERSION ", (c) Ben Summers and contributors 2003-2006" + "Box " UtilityName " v" BOX_VERSION ", (c) Ben Summers and contributors 2003-2007" #endif // BANNERTEXT__H -- cgit v1.2.3 From 8894c945eb3c5acebd64bb1e71514484246dc596 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:02:54 +0000 Subject: Undo bad merge of [1658] and [1669] (refs #3, merges [1671]) --- bin/bbackupd/BackupDaemon.cpp | 47 +++---------------------------------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index a772d8de..4e5621a4 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -2611,7 +2611,7 @@ BackupDaemon::CommandSocketInfo::~CommandSocketInfo() static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F; static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE"; -static const int STOREOBJECTINFO_VERSION = 2; +static const int STOREOBJECTINFO_VERSION = 1; bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const { @@ -2671,9 +2671,8 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time // // aFile.Close(); - BOX_INFO("Saved store object info file: " << - StoreObjectInfoFile << ", version " << - STOREOBJECTINFO_VERSION); + BOX_INFO("Saved store object info file: " + << StoreObjectInfoFile); } catch(std::exception &e) { @@ -2828,46 +2827,6 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ mIDMapMounts.push_back(strItem); } - // - // - // - iCount = 0; - anArchive.Read(iCount); - - for(int v = 0; v < iCount; v++) - { - int64_t anId; - anArchive.Read(anId); - - std::string aName; - anArchive.Read(aName); - - mUnusedRootDirEntries.push_back(std::pair(anId, aName)); - } - - if (iCount > 0) - anArchive.Read(mDeleteUnusedRootDirEntriesAfter); - - // - // - // - iCount = 0; - anArchive.Read(iCount); - - for(int v = 0; v < iCount; v++) - { - int64_t anId; - anArchive.Read(anId); - - std::string aName; - anArchive.Read(aName); - - mUnusedRootDirEntries.push_back(std::pair(anId, aName)); - } - - if (iCount > 0) - anArchive.Read(mDeleteUnusedRootDirEntriesAfter); - // // // -- cgit v1.2.3 From 964e6eb5a08030d06629a4d71bf1b383ad6f3b79 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:03:18 +0000 Subject: Fixed object store read/write, fixes #18 properly, thanks Gary! (refs #3, merges [1672]) --- bin/bbackupd/BackupDaemon.cpp | 46 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 4e5621a4..41003280 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -2611,7 +2611,7 @@ BackupDaemon::CommandSocketInfo::~CommandSocketInfo() static const int STOREOBJECTINFO_MAGIC_ID_VALUE = 0x7777525F; static const std::string STOREOBJECTINFO_MAGIC_ID_STRING = "BBACKUPD-STATE"; -static const int STOREOBJECTINFO_VERSION = 1; +static const int STOREOBJECTINFO_VERSION = 2; bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const { @@ -2667,12 +2667,30 @@ bool BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time for(int v = 0; v < iCount; v++) anArchive.Write(mIDMapMounts[v]); + // + // + // + iCount = mUnusedRootDirEntries.size(); + anArchive.Write(iCount); + + for(int v = 0; v < iCount; v++) + { + anArchive.Write(mUnusedRootDirEntries[v].first); + anArchive.Write(mUnusedRootDirEntries[v].second); + } + + if (iCount > 0) + { + anArchive.Write(mDeleteUnusedRootDirEntriesAfter); + } + // // // aFile.Close(); - BOX_INFO("Saved store object info file: " - << StoreObjectInfoFile); + BOX_INFO("Saved store object info file version " << + STOREOBJECTINFO_VERSION << " (" << + StoreObjectInfoFile << ")"); } catch(std::exception &e) { @@ -2827,12 +2845,32 @@ bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_ mIDMapMounts.push_back(strItem); } + // + // + // + iCount = 0; + anArchive.Read(iCount); + + for(int v = 0; v < iCount; v++) + { + int64_t anId; + anArchive.Read(anId); + + std::string aName; + anArchive.Read(aName); + + mUnusedRootDirEntries.push_back(std::pair(anId, aName)); + } + + if (iCount > 0) + anArchive.Read(mDeleteUnusedRootDirEntriesAfter); + // // // aFile.Close(); BOX_INFO("Loaded store object info file version " << iVersion - << "(" << StoreObjectInfoFile << ")"); + << " (" << StoreObjectInfoFile << ")"); return true; } -- cgit v1.2.3 From e2816b665349a6855c464fe72cb9225d38ba38c4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:03:38 +0000 Subject: Fixed object use after delete, thanks Gary! (refs #3, merges [1673]) --- bin/bbackupd/BackupDaemon.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 41003280..4d5b6fa4 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1825,12 +1825,14 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con } catch(...) { - delete ploc; - ploc = 0; BOX_ERROR("Failed to configure location '" << ploc->mName << "' path '" << ploc->mPath << "': please check for " "previous errors"); + + delete ploc; + ploc = NULL; + throw; } } -- cgit v1.2.3 From 31d71a6d64427ee42fe7bbab6623027c99ed4dee Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:04:05 +0000 Subject: Update Visual Studio project files to match new files added, thanks Gary! (refs #3, merges [1674]) --- infrastructure/msvc/2003/bbackupd.vcproj | 6 ++++++ infrastructure/msvc/2003/common.vcproj | 18 ++++++++++++++++++ infrastructure/msvc/2005/bbackupd.vcproj | 8 ++++++++ infrastructure/msvc/2005/common.vcproj | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/infrastructure/msvc/2003/bbackupd.vcproj b/infrastructure/msvc/2003/bbackupd.vcproj index 8e680956..182c10a2 100644 --- a/infrastructure/msvc/2003/bbackupd.vcproj +++ b/infrastructure/msvc/2003/bbackupd.vcproj @@ -129,6 +129,9 @@ + + @@ -169,6 +172,9 @@ + + diff --git a/infrastructure/msvc/2003/common.vcproj b/infrastructure/msvc/2003/common.vcproj index ab73a8fb..bdae0bb8 100644 --- a/infrastructure/msvc/2003/common.vcproj +++ b/infrastructure/msvc/2003/common.vcproj @@ -170,15 +170,24 @@ + + + + + + @@ -441,6 +450,9 @@ + + @@ -462,6 +474,9 @@ + + @@ -474,6 +489,9 @@ + + diff --git a/infrastructure/msvc/2005/bbackupd.vcproj b/infrastructure/msvc/2005/bbackupd.vcproj index ac6147d2..abed0f4c 100644 --- a/infrastructure/msvc/2005/bbackupd.vcproj +++ b/infrastructure/msvc/2005/bbackupd.vcproj @@ -194,6 +194,10 @@ + + @@ -240,6 +244,10 @@ + + diff --git a/infrastructure/msvc/2005/common.vcproj b/infrastructure/msvc/2005/common.vcproj index e7afd8c6..5a715be4 100644 --- a/infrastructure/msvc/2005/common.vcproj +++ b/infrastructure/msvc/2005/common.vcproj @@ -243,6 +243,10 @@ RelativePath="..\..\..\lib\common\IOStreamGetLine.cpp" > + + @@ -251,14 +255,26 @@ RelativePath="..\..\..\lib\common\PartialReadStream.cpp" > + + + + + + @@ -597,6 +613,10 @@ RelativePath="..\..\..\lib\server\LocalProcessStream.h" > + + @@ -625,10 +645,18 @@ RelativePath="..\..\..\lib\common\PartialReadStream.h" > + + + + @@ -641,6 +669,10 @@ RelativePath="..\..\..\lib\common\Test.h" > + + -- cgit v1.2.3 From 2e128f8778af9763eb4cd919ea80264baa2b3a6d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:04:29 +0000 Subject: Make ClientException autogen files in the correct directory, thanks Gary! (refs #3, merges [1675]) --- win32.bat | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/win32.bat b/win32.bat index 6430df8f..744c31b3 100644 --- a/win32.bat +++ b/win32.bat @@ -14,7 +14,11 @@ cd ..\..\ cd .\lib\compress & perl ./../../lib/common/makeexception.pl.in CompressException.txt cd ..\..\ -cd .\lib\common & perl ./../../lib/common/makeexception.pl.in CommonException.txt & perl ./../../lib/common/makeexception.pl.in ConversionException.txt & perl ./../../lib/common/makeexception.pl.in ClientException.txt +cd .\lib\common & perl ./../../lib/common/makeexception.pl.in CommonException.txt & perl ./../../lib/common/makeexception.pl.in ConversionException.txt + +cd ..\..\ + +cd .\bin\bbackupd & perl ./../../lib/common/makeexception.pl.in ClientException.txt cd ..\..\ -- cgit v1.2.3 From 4a3627d5b883c0f66c9f2b770a427c18df51203f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:04:53 +0000 Subject: Disable some warnings under MSVC to reduce build noise, thanks Gary! (refs #3, merges [1676]) --- lib/win32/emu.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/win32/emu.h b/lib/win32/emu.h index ec6c0918..1f078c14 100644 --- a/lib/win32/emu.h +++ b/lib/win32/emu.h @@ -385,4 +385,16 @@ std::string GetErrorMessage(DWORD errorCode); // 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 -- cgit v1.2.3 From 8bc9c724d51312906be6e965b45a7bc071cfb931 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:05:56 +0000 Subject: Work around the fact that we may have regex support without having regex.h (e.g. from pcreposix.h/libpcreposix) and disabuse HAVE_REGEX_H, define and use HAVE_REGEX_SUPPORT instead, thanks Gary! (refs #3, merges [1677] [1678] [1679]) --- configure.ac | 20 +++++++++++++++-- docs/backup/win32_build_on_cygwin_using_mingw.txt | 14 +++--------- lib/common/BoxConfig-MSVC.h | 1 + lib/common/ExcludeList.cpp | 27 ++++++++++++----------- lib/common/ExcludeList.h | 4 ++-- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/configure.ac b/configure.ac index e52ba99f..cab2ee97 100644 --- a/configure.ac +++ b/configure.ac @@ -112,7 +112,23 @@ AC_CHECK_HEADER([regex.h], [have_regex_h=yes]) if test "$have_regex_h" = "yes"; then AC_DEFINE([HAVE_REGEX_H], [1], [Define to 1 if regex.h is available]) - AC_SEARCH_LIBS([regcomp], ["pcreposix -lpcre"]) +else + AC_CHECK_HEADER([pcreposix.h], [have_pcreposix_h=yes]) +fi + +if test "$have_pcreposix_h" = "yes"; then + AC_SEARCH_LIBS([regcomp], ["pcreposix -lpcre"],,[have_pcreposix_h=no_regcomp]) +fi + +if test "$have_pcreposix_h" = "yes"; then + AC_DEFINE([HAVE_PCREPOSIX_H], [1], [Define to 1 if pcreposix.h is available]) +fi + +if test "$have_regex_h" = "yes" -o "$have_pcreposix_h" = "yes"; then + have_regex_support=yes + AC_DEFINE([HAVE_REGEX_SUPPORT], [1], [Define to 1 if regular expressions are supported]) +else + have_regex_support=no fi AC_SEARCH_LIBS([dlsym], ["dl"]) @@ -274,7 +290,7 @@ A summary of the build configuration is below. Box Backup will function without these features, but will work better where they are present. Refer to the documentation for more information on each feature. -Regular expressions: $have_regex_h +Regular expressions: $have_regex_support Large files: $have_large_file_support Berkeley DB: $ax_path_bdb_ok Readline: $have_libreadline diff --git a/docs/backup/win32_build_on_cygwin_using_mingw.txt b/docs/backup/win32_build_on_cygwin_using_mingw.txt index c35764bb..d93c2bce 100644 --- a/docs/backup/win32_build_on_cygwin_using_mingw.txt +++ b/docs/backup/win32_build_on_cygwin_using_mingw.txt @@ -35,20 +35,12 @@ Configure PCRE for MinGW compilation, and build and install it: export CFLAGS="-mno-cygwin" ./configure make winshared - cp .libs/pcreposix.dll /bin - cp .libs/pcreposix.dll.a /usr/i686-pc-mingw32/lib - cp pcreposix.h /usr/i686-pc-mingw32/include/regex.h + cp .libs/libpcre.a .libs/libpcreposix.a /usr/lib/mingw + cp pcreposix.h /usr/include/mingw Now unpack the Box Backup sources, enter the source directory, and configure like this: - export CXX="g++ -mno-cygwin" - export LD="g++ -mno-cygwin" - export CFLAGS="-mno-cygwin -mthreads" - export CXXFLAGS="-mno-cygwin -mthreads" - export LDFLAGS="-mno-cygwin -mthreads" - export LIBS="-lcrypto -lws2_32 -lgdi32" - (if you don't have a "configure" file, run "./bootstrap") - ./configure --target=i686-pc-mingw32 + ./infrastructure/mingw/configure.sh make diff --git a/lib/common/BoxConfig-MSVC.h b/lib/common/BoxConfig-MSVC.h index 0f84f964..6ce496f5 100644 --- a/lib/common/BoxConfig-MSVC.h +++ b/lib/common/BoxConfig-MSVC.h @@ -178,6 +178,7 @@ /* Define to 1 if you have the header file. */ /* #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 */ diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp index a8d07dcc..b9f41634 100644 --- a/lib/common/ExcludeList.cpp +++ b/lib/common/ExcludeList.cpp @@ -9,11 +9,12 @@ #include "Box.h" -#ifdef HAVE_PCREPOSIX_H - #include - #define EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED -#elif defined HAVE_REGEX_H - #include +#ifdef HAVE_REGEX_SUPPORT + #ifdef HAVE_PCREPOSIX_H + #include + #else + #include + #endif #define EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED #endif @@ -49,7 +50,7 @@ ExcludeList::ExcludeList() // -------------------------------------------------------------------------- ExcludeList::~ExcludeList() { -#ifdef HAVE_REGEX_H +#ifdef HAVE_REGEX_SUPPORT // free regex memory while(mRegex.size() > 0) { @@ -167,7 +168,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 ens; @@ -252,7 +253,7 @@ bool ExcludeList::IsExcluded(const std::string &rTest) const } // Check against regular expressions -#ifdef HAVE_REGEX_H +#ifdef HAVE_REGEX_SUPPORT for(std::vector::const_iterator i(mRegex.begin()); i != mRegex.end(); ++i) { // Test against this expression @@ -308,7 +309,7 @@ void ExcludeList::Deserialize(Archive & rArchive) // mDefinite.clear(); -#ifdef HAVE_REGEX_H +#ifdef HAVE_REGEX_SUPPORT // free regex memory while(mRegex.size() > 0) { @@ -349,7 +350,7 @@ void ExcludeList::Deserialize(Archive & rArchive) // // // -#ifdef HAVE_REGEX_H +#ifdef HAVE_REGEX_SUPPORT rArchive.Read(iCount); if (iCount > 0) @@ -386,7 +387,7 @@ void ExcludeList::Deserialize(Archive & rArchive) } } } -#endif // HAVE_REGEX_H +#endif // HAVE_REGEX_SUPPORT // // @@ -441,7 +442,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()); @@ -454,7 +455,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 522ee370..3c41bd11 100644 --- a/lib/common/ExcludeList.h +++ b/lib/common/ExcludeList.h @@ -50,7 +50,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;} @@ -58,7 +58,7 @@ public: private: std::set mDefinite; -#ifdef HAVE_REGEX_H +#ifdef HAVE_REGEX_SUPPORT std::vector mRegex; std::vector mRegexStr; // save original regular expression string-based source for Serialize #endif -- cgit v1.2.3 From 7b5cdbc15c0a4971e3cf2d142b54dccb41d527d5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:06:27 +0000 Subject: More updates to docs. (refs #3, merges [1680]) --- docs/backup/win32_build_on_cygwin_using_mingw.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/backup/win32_build_on_cygwin_using_mingw.txt b/docs/backup/win32_build_on_cygwin_using_mingw.txt index d93c2bce..e71b5764 100644 --- a/docs/backup/win32_build_on_cygwin_using_mingw.txt +++ b/docs/backup/win32_build_on_cygwin_using_mingw.txt @@ -1,13 +1,20 @@ How to build Box Backup on Win32 using Cygwin and MinGW -By Chris Wilson, 2005-12-07 +By Chris Wilson, 2007-05-26 + +(To read this document online with better formatting, browse to: +http://bbdev.fluffy.co.uk/trac/wiki/CompileWithMinGW) + +Start by installing Cygwin on your Windows machine [http://www.cygwin.org]. +Make sure to select the following packages during installation: -Install Cygwin on your Windows box [http://www.cygwin.org] -Make sure to include the following packages: * Devel/gcc-mingw * Devel/gcc-mingw-core * Devel/gcc-mingw-g++ * Mingw/mingw-zlib +If you already have Cygwin installed, please re-run the installer and +ensure that those packages are installed. + Download OpenSSL from [http://www.openssl.org/source/openssl-0.9.7i.tar.gz] -- cgit v1.2.3 From bf880c2b40637c9026e1fb8040220b705338e640 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:06:52 +0000 Subject: Fix to match static lib installation instructions. (refs #3, merges [1681]) --- infrastructure/mingw/configure.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/infrastructure/mingw/configure.sh b/infrastructure/mingw/configure.sh index 1dd1b014..f1ad353f 100755 --- a/infrastructure/mingw/configure.sh +++ b/infrastructure/mingw/configure.sh @@ -2,15 +2,15 @@ if [ ! -r "/usr/i686-pc-mingw32/lib/libssl.a" ]; then echo "Error: install OpenSSL as instructed by" \ - "docs/backup/mingw_build.txt" >&2 + "docs/backup/win32_build_on_cygwin_using_mingw.txt" >&2 exit 2 fi -if [ ! -r "/usr/i686-pc-mingw32/lib/libpcreposix.a" \ - -o ! -r "/usr/i686-pc-mingw32/lib/libpcre.a" \ - -o ! -r "/usr/i686-pc-mingw32/include/regex.h" ]; then +if [ ! -r "/usr/lib/mingw/libpcreposix.a" \ + -o ! -r "/usr/lib/mingw/libpcre.a" \ + -o ! -r "/usr/include/mingw/pcreposix.h" ]; then echo "Error: install PCRE as instructed by" \ - "docs/backup/mingw_build.txt" >&2 + "docs/backup/win32_build_on_cygwin_using_mingw.txt" >&2 exit 2 fi -- cgit v1.2.3 From e915f55a45b63e558d2abeb72726d80555039fea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:07:24 +0000 Subject: Fix regex tests for HAVE_REGEX_SUPPORT. (refs #3, merges [1682]) --- test/common/testcommon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/common/testcommon.cpp b/test/common/testcommon.cpp index 0f0f1f9a..eb057228 100644 --- a/test/common/testcommon.cpp +++ b/test/common/testcommon.cpp @@ -750,7 +750,7 @@ int test(int argc, const char *argv[]) TEST_THAT(elist.SizeOfDefiniteList() == 4); // Add regex entries - #ifdef HAVE_REGEX_H + #ifdef HAVE_REGEX_SUPPORT elist.AddRegexEntries(std::string("[a-d]+\\.reg$" "\x01" "EXCLUDE" "\x01" "^exclude$")); elist.AddRegexEntries(std::string("")); TEST_CHECK_THROWS(elist.AddRegexEntries(std::string("[:not_valid")), CommonException, BadRegularExpression); @@ -782,7 +782,7 @@ int test(int argc, const char *argv[]) TEST_THAT(elist.IsExcluded("thingdefthree") == !CASE_SENSITIVE); - #ifdef HAVE_REGEX_H + #ifdef HAVE_REGEX_SUPPORT TEST_THAT(elist.IsExcluded(std::string("b.reg")) == true); TEST_THAT(elist.IsExcluded(std::string("B.reg")) == !CASE_SENSITIVE); TEST_THAT(elist.IsExcluded(std::string("b.Reg")) == !CASE_SENSITIVE); -- cgit v1.2.3 From 273e5baec103e402d81004190413b3efd131716b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:07:59 +0000 Subject: Make RaidFileController::Initialise take a std::string instead of a char array, in C++ style. (refs #3, merges [1683]) --- lib/raidfile/RaidFileController.cpp | 10 ++++++---- lib/raidfile/RaidFileController.h | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/raidfile/RaidFileController.cpp b/lib/raidfile/RaidFileController.cpp index 14469c68..81307103 100644 --- a/lib/raidfile/RaidFileController.cpp +++ b/lib/raidfile/RaidFileController.cpp @@ -59,12 +59,12 @@ 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; @@ -97,11 +97,13 @@ void RaidFileController::Initialise(const char *ConfigFilename) // Load the configuration std::string err; - std::auto_ptr pconfig = Configuration::LoadAndVerify(ConfigFilename, &verify, err); + std::auto_ptr pconfig = Configuration::LoadAndVerify( + rConfigFilename, &verify, err); if(pconfig.get() == 0 || !err.empty()) { - fprintf(stderr, "RaidFile configuation file errors:\n%s", err.c_str()); + fprintf(stderr, "RaidFile configuation file errors:\n%s", + err.c_str()); THROW_EXCEPTION(RaidFileException, BadConfigFile) } diff --git a/lib/raidfile/RaidFileController.h b/lib/raidfile/RaidFileController.h index 4962d236..783cb055 100644 --- a/lib/raidfile/RaidFileController.h +++ b/lib/raidfile/RaidFileController.h @@ -81,7 +81,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();} // -------------------------------------------------------------------------- -- cgit v1.2.3 From 88edb51fc08aa8dfe1fed4c614343d1f2405dac9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:08:21 +0000 Subject: Make Configuration take a std::string filename instead of a char array, in C++ style. (refs #3, merges [1684]) --- lib/common/Configuration.cpp | 13 +++++-------- lib/common/Configuration.h | 11 +++++++++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/common/Configuration.cpp b/lib/common/Configuration.cpp index def93571..5f9376c5 100644 --- a/lib/common/Configuration.cpp +++ b/lib/common/Configuration.cpp @@ -83,19 +83,16 @@ Configuration::~Configuration() // Created: 2003/07/23 // // -------------------------------------------------------------------------- -std::auto_ptr Configuration::LoadAndVerify(const char *Filename, const ConfigurationVerify *pVerify, std::string &rErrorMsg) +std::auto_ptr 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 file(Filename); + FileHandleGuard file(rFilename); // GetLine object FdGetLine getline(file); diff --git a/lib/common/Configuration.h b/lib/common/Configuration.h index 4c455b0f..64e7568e 100644 --- a/lib/common/Configuration.h +++ b/lib/common/Configuration.h @@ -69,8 +69,15 @@ public: MultiValueSeparator = '\x01' }; - static std::auto_ptr LoadAndVerify(const char *Filename, const ConfigurationVerify *pVerify, std::string &rErrorMsg); - static std::auto_ptr Load(const char *Filename, std::string &rErrorMsg) { return LoadAndVerify(Filename, 0, rErrorMsg); } + static std::auto_ptr LoadAndVerify( + const std::string& rFilename, + const ConfigurationVerify *pVerify, + std::string &rErrorMsg); + + static std::auto_ptr 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; -- cgit v1.2.3 From 498e58eb188d98c6ec78e57cdc5f0c211f1f4dcf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:11:03 +0000 Subject: Make Configuration take a std::string filename instead of a char array, in C++ style. Add a function to get default config file paths at runtime, dependent on the location of the executable being run. Pass the config file name directly to Daemon::Main, instead of faking argv. No default raid file path at compile time on Windows, depends on executable location when run. Determine RaidFile path at runtime if not supplied in config file on Windows. Don't define default locations for config files at compile time on Windows, provide macros to determine them at runtime instead. Make FileHandleGuard take a std::string instead of a char array, C++ style. Determine config file location at runtime instead of hard-coding on Windows. Thanks to Paul MacKenzie, Per Thomsen, Pete Jalajas, Stuart Sanders, Dave Bamford and Gary for pushing me to do this. (fixes #12) Determine config file path at runtime. Call Daemon::Main with config file name instead of building fake argv. (refs #3, merges [1684] [1685] [1686] [1687] [1688] [1689] [1690] [1691] [1692]) --- bin/bbackupctl/bbackupctl.cpp | 17 +++++-- bin/bbackupd/Win32BackupService.cpp | 26 ++++------- bin/bbackupd/bbackupd.cpp | 2 +- bin/bbackupquery/bbackupquery.cpp | 22 ++++++--- bin/bbstoreaccounts/bbstoreaccounts.cpp | 18 ++++++-- bin/bbstored/BackupStoreDaemon.cpp | 18 +++++++- bin/bbstored/bbstored.cpp | 9 +++- lib/backupstore/BackupStoreConfigVerify.cpp | 8 +++- lib/common/BoxPortsAndFiles.h | 23 ++++++---- lib/common/Guards.h | 6 +-- lib/win32/emu.cpp | 70 ++++++++++++++++++++++------- lib/win32/emu.h | 4 ++ test/bbackupd/testbbackupd.cpp | 5 +-- 13 files changed, 164 insertions(+), 64 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index 9fb8f259..f0a966c4 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -66,7 +66,13 @@ int main(int argc, const char *argv[]) #endif // Filename for configuration file? - const char *configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG; + std::string configFilename; + + #ifdef WIN32 + configFilename = BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE; + #else + configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG; + #endif // Quiet? bool quiet = false; @@ -103,9 +109,14 @@ int main(int argc, const char *argv[]) } // Read in the configuration file - if(!quiet) printf("Using configuration file %s\n", configFilename); + if(!quiet) printf("Using configuration file %s\n", + configFilename.c_str()); + std::string errs; - std::auto_ptr config(Configuration::LoadAndVerify(configFilename, &BackupDaemonConfigVerify, errs)); + std::auto_ptr config( + Configuration::LoadAndVerify + (configFilename, &BackupDaemonConfigVerify, errs)); + if(config.get() == 0 || !errs.empty()) { printf("Invalid configuration file:\n%s", errs.c_str()); diff --git a/bin/bbackupd/Win32BackupService.cpp b/bin/bbackupd/Win32BackupService.cpp index 7cbf4828..1470b42d 100644 --- a/bin/bbackupd/Win32BackupService.cpp +++ b/bin/bbackupd/Win32BackupService.cpp @@ -29,31 +29,23 @@ void TerminateService(void) DWORD Win32BackupService::WinService(const char* pConfigFileName) { - char exepath[MAX_PATH]; - GetModuleFileName(NULL, exepath, sizeof(exepath)); + DWORD ret; + + // keep MAINHELPER_START happy + int argc = 0; + char* argv[] = {NULL}; + + MAINHELPER_START - std::string configfile; - if (pConfigFileName != NULL) { - configfile = pConfigFileName; + ret = this->Main(pConfigFileName); } else { - // make the default config file name, - // based on the program path - configfile = exepath; - configfile = configfile.substr(0, - configfile.rfind(DIRECTORY_SEPARATOR_ASCHAR)); - configfile += DIRECTORY_SEPARATOR "bbackupd.conf"; + ret = this->Main(BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE); } - const char *argv[] = {exepath, "-c", configfile.c_str()}; - int argc = sizeof(argv) / sizeof(*argv); - DWORD ret; - - MAINHELPER_START - ret = this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); MAINHELPER_END return ret; diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index f7091140..b8c8f61a 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -89,7 +89,7 @@ int main(int argc, const char *argv[]) else { ExitCode = gpDaemonService->Main( - BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); + BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE, argc, argv); } delete gpDaemonService; diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index d02c3922..9cc3eb1a 100644 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -66,7 +66,8 @@ int main(int argc, const char *argv[]) { int returnCode = 0; - MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupquery.memleaks", "bbackupquery") + MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupquery.memleaks", + "bbackupquery") MAINHELPER_START #ifdef WIN32 @@ -77,7 +78,7 @@ int main(int argc, const char *argv[]) if (WSAStartup(0x0101, &info) == SOCKET_ERROR) { - // throw error? perhaps give it its own id in the furture + // throw error? perhaps give it its own id in the future THROW_EXCEPTION(BackupStoreException, Internal) } #endif @@ -90,7 +91,13 @@ int main(int argc, const char *argv[]) FILE *logFile = 0; // Filename for configuration file? - const char *configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG; + std::string configFilename; + + #ifdef WIN32 + configFilename = BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE; + #else + configFilename = BOX_FILE_BBACKUPD_DEFAULT_CONFIG; + #endif // Flags bool quiet = false; @@ -215,9 +222,14 @@ int main(int argc, const char *argv[]) #endif // WIN32 // Read in the configuration file - if(!quiet) printf("Using configuration file %s\n", configFilename); + if(!quiet) printf("Using configuration file %s\n", + configFilename.c_str()); + std::string errs; - std::auto_ptr config(Configuration::LoadAndVerify(configFilename, &BackupDaemonConfigVerify, errs)); + std::auto_ptr config( + Configuration::LoadAndVerify + (configFilename, &BackupDaemonConfigVerify, errs)); + if(config.get() == 0 || !errs.empty()) { printf("Invalid configuration file:\n%s", errs.c_str()); diff --git a/bin/bbstoreaccounts/bbstoreaccounts.cpp b/bin/bbstoreaccounts/bbstoreaccounts.cpp index dd42458b..567c5bbc 100644 --- a/bin/bbstoreaccounts/bbstoreaccounts.cpp +++ b/bin/bbstoreaccounts/bbstoreaccounts.cpp @@ -402,12 +402,19 @@ void PrintUsageAndExit() int main(int argc, const char *argv[]) { - MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbstoreaccounts.memleaks", "bbstoreaccounts") + MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbstoreaccounts.memleaks", + "bbstoreaccounts") MAINHELPER_START - // Filename for configuraiton file? - const char *configFilename = BOX_FILE_BBSTORED_DEFAULT_CONFIG; + // Filename for configuration file? + std::string configFilename; + + #ifdef WIN32 + configFilename = BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE; + #else + configFilename = BOX_FILE_BBSTORED_DEFAULT_CONFIG; + #endif // See if there's another entry on the command line int c; @@ -431,7 +438,10 @@ int main(int argc, const char *argv[]) // Read in the configuration file std::string errs; - std::auto_ptr config(Configuration::LoadAndVerify(configFilename, &BackupConfigFileVerify, errs)); + std::auto_ptr config( + Configuration::LoadAndVerify + (configFilename, &BackupConfigFileVerify, errs)); + if(config.get() == 0 || !errs.empty()) { printf("Invalid configuration file:\n%s", errs.c_str()); diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index c9601575..049c0ae4 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -132,7 +132,23 @@ void BackupStoreDaemon::SetupInInitialProcess() // Initialise the raid files controller RaidFileController &rcontroller = RaidFileController::GetController(); - rcontroller.Initialise(config.GetKeyValue("RaidFileConf").c_str()); + + std::string raidFileConfig; + + #ifdef WIN32 + if (!config.KeyExists("RaidFileConf")) + { + raidFileConfig = BOX_GET_DEFAULT_RAIDFILE_CONFIG_FILE; + } + else + { + raidFileConfig = config.GetKeyValue("RaidFileConf"); + } + #else + raidFileConfig = config.GetKeyValue("RaidFileConf"); + #endif + + rcontroller.Initialise(raidFileConfig); // Load the account database std::auto_ptr pdb(BackupStoreAccountDatabase::Read(config.GetKeyValue("AccountDatabase").c_str())); diff --git a/bin/bbstored/bbstored.cpp b/bin/bbstored/bbstored.cpp index c0ea1199..54858dd4 100644 --- a/bin/bbstored/bbstored.cpp +++ b/bin/bbstored/bbstored.cpp @@ -23,7 +23,14 @@ int main(int argc, const char *argv[]) Logging::ToSyslog (true); BackupStoreDaemon daemon; - return daemon.Main(BOX_FILE_BBSTORED_DEFAULT_CONFIG, argc, argv); + + #ifdef WIN32 + return daemon.Main(BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE, + argc, argv); + #else + return daemon.Main(BOX_FILE_BBSTORED_DEFAULT_CONFIG, + argc, argv); + #endif MAINHELPER_END } diff --git a/lib/backupstore/BackupStoreConfigVerify.cpp b/lib/backupstore/BackupStoreConfigVerify.cpp index 6fa05d06..784adfb8 100644 --- a/lib/backupstore/BackupStoreConfigVerify.cpp +++ b/lib/backupstore/BackupStoreConfigVerify.cpp @@ -35,7 +35,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/common/BoxPortsAndFiles.h b/lib/common/BoxPortsAndFiles.h index 562c6724..a6ca9f6d 100644 --- a/lib/common/BoxPortsAndFiles.h +++ b/lib/common/BoxPortsAndFiles.h @@ -14,20 +14,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" +#define BOX_FILE_BBSTORED_DEFAULT_CONFIG "/etc/box/bbstored.conf" +#endif // Default name of the named pipe #define BOX_NAMED_PIPE_NAME L"\\\\.\\pipe\\boxbackup" diff --git a/lib/common/Guards.h b/lib/common/Guards.h index fbcfedaf..d2fb84e0 100644 --- a/lib/common/Guards.h +++ b/lib/common/Guards.h @@ -32,13 +32,13 @@ template Date: Thu, 26 Jul 2007 22:12:34 +0000 Subject: Build server parcel on Windows too, since some people want it. (refs #3, merges [1701]) --- parcels.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/parcels.txt b/parcels.txt index 742cb61e..5a4ad8f9 100644 --- a/parcels.txt +++ b/parcels.txt @@ -21,15 +21,9 @@ ONLY:mingw32 optional script /bin/pcreposix.dll END-ONLY -OMIT:mingw32 -OMIT:mingw32msvc -OMIT:CYGWIN - backup-server bin bbstored bin bbstoreaccounts script bin/bbstored/bbstored-certs script bin/bbstored/bbstored-config script lib/raidfile/raidfile-config - -END-OMIT -- cgit v1.2.3 From 9e9690313bb35a6e4434291cb19a4dd6500db855 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:19:04 +0000 Subject: Reinsert dependency of test/backupstorefix on bin/bbackupctl (refs #3, merges [1650]) --- modules.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.txt b/modules.txt index a66b63ba..d0d0b76b 100644 --- a/modules.txt +++ b/modules.txt @@ -36,7 +36,7 @@ bin/bbackupquery lib/server lib/backupclient bin/bbackupctl lib/server lib/backupclient test/backupstore bin/bbstored bin/bbstoreaccounts lib/server lib/backupstore lib/backupclient lib/raidfile -test/backupstorefix bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile bin/bbackupquery bin/bbackupd +test/backupstorefix bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile bin/bbackupquery bin/bbackupd bin/bbackupctl test/backupstorepatch bin/bbstored bin/bbstoreaccounts lib/backupstore lib/raidfile test/backupdiff lib/backupclient test/bbackupd bin/bbackupd bin/bbstored bin/bbstoreaccounts bin/bbackupquery bin/bbackupctl lib/server lib/backupstore lib/backupclient lib/intercept -- cgit v1.2.3 From 05db569d4efc62eaa10597142b8eac4937421e14 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2007 22:23:22 +0000 Subject: Remove compare again. (refs #3, merges [1651]) --- test/bbackupd/testbbackupd.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/bbackupd/testbbackupd.cpp b/test/bbackupd/testbbackupd.cpp index 3942ea7c..49b7f48a 100644 --- a/test/bbackupd/testbbackupd.cpp +++ b/test/bbackupd/testbbackupd.cpp @@ -2323,14 +2323,8 @@ int test_bbackupd() true /* print progress dots */) == Restore_Complete); - // Compare it - compareReturnValue = ::system(BBACKUPQUERY " -q " - "-c testfiles/bbackupd.conf " - "-l testfiles/query10.log " - "\"compare -cE Test1 testfiles/restore-Test1\" " - "quit"); - TEST_RETURN(compareReturnValue, 1); - TestRemoteProcessMemLeaks("bbackupquery.memleaks"); + // On Win32 we can't open another connection + // to the server, so we'll compare later. // Make sure you can't restore a restored directory TEST_THAT(BackupClientRestore(protocol, restoredirid, -- cgit v1.2.3 From 0b2fd98dd63c533e00c0d61ce022f37ee75857cc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 31 Jul 2007 23:18:05 +0000 Subject: Replace almost all calls to syslog() with logging framework. (refs #3) --- bin/bbackupctl/bbackupctl.cpp | 33 ++--- bin/bbackupd/BackupClientContext.cpp | 16 +-- bin/bbackupd/Win32ServiceFunctions.cpp | 53 +++---- bin/bbackupquery/BackupQueries.cpp | 9 +- bin/bbstored/BBStoreDHousekeeping.cpp | 33 +++-- bin/bbstored/BackupCommands.cpp | 65 ++++++--- bin/bbstored/BackupStoreDaemon.cpp | 28 ++-- bin/bbstored/HousekeepStoreAccount.cpp | 59 ++++++-- lib/backupclient/BackupClientFileAttributes.cpp | 13 +- lib/backupclient/BackupClientRestore.cpp | 184 +++++++++--------------- lib/backupclient/BackupStoreFile.cpp | 7 +- lib/common/BoxTime.cpp | 9 +- lib/common/DebugPrintf.cpp | 6 - lib/common/Logging.h | 14 ++ lib/raidfile/RaidFileRead.cpp | 41 +++--- lib/server/Daemon.cpp | 7 +- lib/server/LocalProcessStream.cpp | 8 +- lib/server/SSLLib.cpp | 13 +- lib/server/ServerStream.h | 16 ++- lib/server/Socket.cpp | 9 +- lib/server/WinNamedPipeStream.cpp | 89 ++++++------ 21 files changed, 349 insertions(+), 363 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index f0a966c4..a5dc4c10 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -162,7 +162,7 @@ int main(int argc, const char *argv[]) ); #if defined WIN32 && ! defined NDEBUG - syslog(LOG_ERR,"Failed to connect to the command socket"); + BOX_ERROR("Failed to connect to the command socket"); #endif return 1; @@ -175,29 +175,16 @@ int main(int argc, const char *argv[]) std::string configSummary; if(!getLine.GetLine(configSummary)) { -#if defined WIN32 && ! defined NDEBUG - syslog(LOG_ERR, "Failed to receive configuration summary " + BOX_ERROR("Failed to receive configuration summary " "from daemon"); -#else - printf("Failed to receive configuration summary from daemon\n"); -#endif - return 1; } // Was the connection rejected by the server? if(getLine.IsEOF()) { -#if defined WIN32 && ! defined NDEBUG - syslog(LOG_ERR, "Server rejected the connection. " - "Are you running bbackupctl as the same user " - "as the daemon?"); -#else - printf("Server rejected the connection. " - "Are you running bbackupctl as the same user " - "as the daemon?\n"); -#endif - + BOX_ERROR("Server rejected the connection. Are you running " + "bbackupctl as the same user as the daemon?"); return 1; } @@ -224,11 +211,7 @@ int main(int argc, const char *argv[]) std::string stateLine; if(!getLine.GetLine(stateLine) || getLine.IsEOF()) { -#if defined WIN32 && ! defined NDEBUG - syslog(LOG_ERR, "Failed to receive state line from daemon"); -#else - printf("Failed to receive state line from daemon\n"); -#endif + BOX_ERROR("Failed to receive state line from daemon"); return 1; } @@ -236,7 +219,7 @@ int main(int argc, const char *argv[]) int currentState; if(::sscanf(stateLine.c_str(), "state %d", ¤tState) != 1) { - printf("State line didn't decode\n"); + BOX_ERROR("Received invalid state line from daemon"); return 1; } @@ -266,8 +249,8 @@ int main(int argc, const char *argv[]) if(!autoBackup) { - printf("ERROR: Daemon is not in automatic mode -- " - "sync will never start!\n"); + BOX_ERROR("Daemon is not in automatic mode, " + "sync will never start!"); return 1; } diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index 18859393..4b4efd90 100644 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -9,12 +9,10 @@ #include "Box.h" -#ifdef HAVE_SYSLOG_H - #include -#endif #ifdef HAVE_SIGNAL_H #include #endif + #ifdef HAVE_SYS_TIME_H #include #endif @@ -127,7 +125,8 @@ BackupProtocolClient &BackupClientContext::GetConnection() } // Log intention - ::syslog(LOG_INFO, "Opening connection to server %s...", mHostname.c_str()); + BOX_INFO("Opening connection to server '" << + mHostname << "'..."); // Connect! mpSocket->Open(mrTLSContext, Socket::TypeINET, mHostname.c_str(), BOX_PORT_BBSTORED); @@ -147,8 +146,8 @@ BackupProtocolClient &BackupClientContext::GetConnection() if (!mpExtendedLogFileHandle) { - ::syslog(LOG_ERR, "Failed to open extended " - "log file: %s", strerror(errno)); + BOX_ERROR("Failed to open extended log " + "file: " << strerror(errno)); } else { @@ -194,7 +193,7 @@ BackupProtocolClient &BackupClientContext::GetConnection() } // Log success - ::syslog(LOG_INFO, "Connection made, login successful"); + BOX_INFO("Connection made, login successful"); // Check to see if there is any space available on the server if(loginConf->GetBlocksUsed() >= loginConf->GetBlocksHardLimit()) @@ -202,7 +201,8 @@ BackupProtocolClient &BackupClientContext::GetConnection() // no -- flag so only things like deletions happen mStorageLimitExceeded = true; // Log - ::syslog(LOG_WARNING, "Exceeded storage hard-limit on server -- not uploading changes to files"); + BOX_WARNING("Exceeded storage hard-limit on server, " + "not uploading changes to files"); } } catch(...) diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index 3010cf3f..f4c8894b 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -44,7 +44,7 @@ void ErrorHandler(char *s, DWORD err) char buf[256]; memset(buf, 0, sizeof(buf)); _snprintf(buf, sizeof(buf)-1, "%s (%d)", s, err); - ::syslog(LOG_ERR, "%s", buf); + BOX_ERROR(buf); MessageBox(0, buf, "Error", MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY); ExitProcess(err); @@ -191,16 +191,16 @@ int InstallService(const char* pConfigFileName) if (emu_stat(pConfigFileName, &st) != 0) { - syslog(LOG_ERR, "Failed to open configuration file: " - "%s: %s", pConfigFileName, strerror(errno)); + BOX_ERROR("Failed to open configuration file '" << + pConfigFileName << "': " << strerror(errno)); return 1; } if (!(st.st_mode & S_IFREG)) { - syslog(LOG_ERR, "Failed to open configuration file: " - "%s: not a file", pConfigFileName); + BOX_ERROR("Failed to open configuration file '" << + pConfigFileName << "': not a file"); return 1; } } @@ -209,8 +209,8 @@ int InstallService(const char* pConfigFileName) if (!scm) { - syslog(LOG_ERR, "Failed to open service control manager: " - "error %d", GetLastError()); + BOX_ERROR("Failed to open service control manager: " << + GetErrorMessage(GetLastError())); return 1; } @@ -248,21 +248,21 @@ int InstallService(const char* pConfigFileName) { case ERROR_SERVICE_EXISTS: { - ::syslog(LOG_ERR, "Failed to create Box Backup " + BOX_ERROR("Failed to create Box Backup " "service: it already exists"); } break; case ERROR_SERVICE_MARKED_FOR_DELETE: { - ::syslog(LOG_ERR, "Failed to create Box Backup " + BOX_ERROR("Failed to create Box Backup " "service: it is waiting to be deleted"); } break; case ERROR_DUPLICATE_SERVICE_NAME: { - ::syslog(LOG_ERR, "Failed to create Box Backup " + BOX_ERROR("Failed to create Box Backup " "service: a service with this name " "already exists"); } @@ -270,15 +270,16 @@ int InstallService(const char* pConfigFileName) default: { - ::syslog(LOG_ERR, "Failed to create Box Backup " - "service: error %d", err); + BOX_ERROR("Failed to create Box Backup " + "service: error " << + GetErrorMessage(GetLastError())); } } return 1; } - ::syslog(LOG_INFO, "Created Box Backup service"); + BOX_INFO("Created Box Backup service"); SERVICE_DESCRIPTION desc; desc.lpDescription = "Backs up your data files over the Internet"; @@ -286,8 +287,8 @@ int InstallService(const char* pConfigFileName) if (!ChangeServiceConfig2(newService, SERVICE_CONFIG_DESCRIPTION, &desc)) { - ::syslog(LOG_WARNING, "Failed to set description for " - "Box Backup service: error %d", GetLastError()); + BOX_WARNING("Failed to set description for Box Backup " + "service: " << GetErrorMessage(GetLastError())); } CloseServiceHandle(newService); @@ -301,8 +302,8 @@ int RemoveService(void) if (!scm) { - syslog(LOG_ERR, "Failed to open service control manager: " - "error %d", GetLastError()); + BOX_ERROR("Failed to open service control manager: " << + GetErrorMessage(GetLastError())); return 1; } @@ -317,13 +318,13 @@ int RemoveService(void) err == ERROR_IO_PENDING) // hello microsoft? anyone home? { - syslog(LOG_ERR, "Failed to open Box Backup service: " + BOX_ERROR("Failed to open Box Backup service: " "not installed or not found"); } else { - syslog(LOG_ERR, "Failed to open Box Backup service: " - "error %d", err); + BOX_ERROR("Failed to open Box Backup service: " << + GetErrorMessage(err)); } return 1; } @@ -334,8 +335,8 @@ int RemoveService(void) err = GetLastError(); if (err != ERROR_SERVICE_NOT_ACTIVE) { - syslog(LOG_WARNING, "Failed to stop Box Backup " - "service: error %d", err); + BOX_WARNING("Failed to stop Box Backup service: " << + GetErrorMessage(err)); } } @@ -345,18 +346,18 @@ int RemoveService(void) if (deleted) { - syslog(LOG_INFO, "Box Backup service deleted"); + BOX_INFO("Box Backup service deleted"); return 0; } else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) { - syslog(LOG_ERR, "Failed to remove Box Backup service: " + BOX_ERROR("Failed to remove Box Backup service: " "it is already being deleted"); } else { - syslog(LOG_ERR, "Failed to remove Box Backup service: " - "error %d", err); + BOX_ERROR("Failed to remove Box Backup service: " << + GetErrorMessage(err)); } return 1; diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 7f511b74..0c5f9c15 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -2009,19 +2009,14 @@ void BackupQueries::CommandRestore(const std::vector &args, const b false /* don't undelete after restore! */, opts['r'] /* resume? */); } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to restore: %s", e.what()); - return; - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to restore: %s", e.what()); + BOX_ERROR("Failed to restore: " << e.what()); return; } catch(...) { - ::syslog(LOG_ERR, "Failed to restore: unknown error"); + BOX_ERROR("Failed to restore: unknown exception"); return; } diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp index a4b26a93..16a1432a 100644 --- a/bin/bbstored/BBStoreDHousekeeping.cpp +++ b/bin/bbstored/BBStoreDHousekeeping.cpp @@ -11,10 +11,6 @@ #include -#ifdef HAVE_SYSLOG_H - #include -#endif - #include "BackupStoreDaemon.h" #include "BackupStoreAccountDatabase.h" #include "BackupStoreAccounts.h" @@ -82,7 +78,7 @@ void BackupStoreDaemon::RunHousekeepingIfNeeded() // Store the time mLastHousekeepingRun = timeNow; - ::syslog(LOG_INFO, "Starting housekeeping"); + BOX_INFO("Starting housekeeping"); // Get the list of accounts std::vector accounts; @@ -112,18 +108,25 @@ void BackupStoreDaemon::RunHousekeepingIfNeeded() } catch(BoxException &e) { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s (%d/%d) -- aborting housekeeping run for this account", - *i, e.what(), e.GetType(), e.GetSubType()); + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(*i) << " threw exception, " + "aborting run for this account: " << + e.what() << " (" << + e.GetType() << "/" << e.GetSubType() << ")"); } catch(std::exception &e) { - ::syslog(LOG_ERR, "while housekeeping account %08X, exception %s -- aborting housekeeping run for this account", - *i, e.what()); + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(*i) << " threw exception, " + "aborting run for this account: " << + e.what()); } catch(...) { - ::syslog(LOG_ERR, "while housekeeping account %08X, unknown exception -- aborting housekeeping run for this account", - *i); + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(*i) << " threw exception, " + "aborting run for this account: " + "unknown exception"); } int64_t timeNow = GetCurrentBoxTime(); @@ -144,7 +147,7 @@ void BackupStoreDaemon::RunHousekeepingIfNeeded() } } - ::syslog(LOG_INFO, "Finished housekeeping"); + BOX_INFO("Finished housekeeping"); // Placed here for accuracy, if StopRun() is true, for example. SetProcessTitle("housekeeping, idle"); @@ -190,7 +193,7 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT std::string line; if(mInterProcessComms.GetLine(line, false /* no pre-processing */, MaximumWaitTime)) { - TRACE1("housekeeping received command '%s' over interprocess comms\n", line.c_str()); + TRACE1("Housekeeping received command '%s' over interprocess comms\n", line.c_str()); int account = 0; @@ -212,7 +215,9 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT if(account == AccountNum) { // Yes! -- need to stop now so when it retries to get the lock, it will succeed - ::syslog(LOG_INFO, "Housekeeping giving way to connection for account 0x%08x", AccountNum); + BOX_INFO("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(AccountNum) << + "giving way to client connection"); return true; } } diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index fd19713d..bca52c04 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -9,10 +9,6 @@ #include "Box.h" -#ifdef HAVE_SYSLOG_H -#include -#endif - #include #include @@ -88,11 +84,26 @@ std::auto_ptr BackupProtocolServerLogin::DoCommand(BackupProtoco // Check given client ID against the ID in the certificate certificate // and that the client actually has an account on this machine - if(mClientID != rContext.GetClientID() || !rContext.GetClientHasAccount()) + if(mClientID != rContext.GetClientID()) { - ::syslog(LOG_INFO, "Failed login: Client ID presented was %08X", mClientID); - return std::auto_ptr(new BackupProtocolServerError( - BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_BadLogin)); + BOX_WARNING("Failed login from client ID " << + BOX_FORMAT_ACCOUNT(mClientID) << + ": wrong certificate for this account"); + return std::auto_ptr( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_BadLogin)); + } + + if(!rContext.GetClientHasAccount()) + { + BOX_WARNING("Failed login from client ID " << + BOX_FORMAT_ACCOUNT(mClientID) << + ": no such account on this server"); + return std::auto_ptr( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_BadLogin)); } // If we need to write, check that nothing else has got a write lock @@ -101,9 +112,12 @@ std::auto_ptr BackupProtocolServerLogin::DoCommand(BackupProtoco // See if the context will get the lock if(!rContext.AttemptToGetWriteLock()) { - ::syslog(LOG_INFO, "Failed to get write lock (for Client ID %08X)", mClientID); - return std::auto_ptr(new BackupProtocolServerError( - BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_CannotLockStoreForWriting)); + BOX_WARNING("Failed to get write lock for Client ID " << + BOX_FORMAT_ACCOUNT(mClientID)); + return std::auto_ptr( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_CannotLockStoreForWriting)); } // Debug: check we got the lock @@ -120,7 +134,11 @@ std::auto_ptr BackupProtocolServerLogin::DoCommand(BackupProtoco rContext.SetPhase(BackupContext::Phase_Commands); // Log login - ::syslog(LOG_INFO, "Login: Client ID %08X, %s", mClientID, ((mFlags & Flags_ReadOnly) != Flags_ReadOnly)?"Read/Write":"Read-only"); + BOX_NOTICE("Login from Client ID " << + BOX_FORMAT_ACCOUNT(mClientID) << + " " << + (((mFlags & Flags_ReadOnly) != Flags_ReadOnly) + ?"Read/Write":"Read-only")); // Get the usage info for reporting to the client int64_t blocksUsed = 0, blocksSoftLimit = 0, blocksHardLimit = 0; @@ -140,7 +158,8 @@ std::auto_ptr BackupProtocolServerLogin::DoCommand(BackupProtoco // -------------------------------------------------------------------------- std::auto_ptr BackupProtocolServerFinished::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) { - ::syslog(LOG_INFO, "Session finished"); + BOX_NOTICE("Session finished for Client ID " << + BOX_FORMAT_ACCOUNT(rContext.GetClientID())); // Let the context know about it rContext.ReceivedFinishCommand(); @@ -311,13 +330,23 @@ std::auto_ptr BackupProtocolServerGetFile::DoCommand(BackupProto en = rdir.FindEntryByID(id); if(en == 0) { - ::syslog(LOG_ERR, "Object %llx in dir %llx for account %x references object %llx which does not exist in dir", - mObjectID, mInDirectory, rContext.GetClientID(), id); - return std::auto_ptr(new BackupProtocolServerError( - BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_PatchConsistencyError)); + BOX_ERROR("Object " << + BOX_FORMAT_OBJECTID(mObjectID) << + " in dir " << + BOX_FORMAT_OBJECTID(mInDirectory) << + " for account " << + BOX_FORMAT_ACCOUNT(rContext.GetClientID()) << + " references object " << + BOX_FORMAT_OBJECTID(id) << + " which does not exist in dir"); + return std::auto_ptr( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_PatchConsistencyError)); } id = en->GetDependsNewer(); - } while(en != 0 && id != 0); + } + while(en != 0 && id != 0); // OK! The last entry in the chain is the full file, the others are patches back from it. // Open the last one, which is the current from file diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 049c0ae4..c5d5fe40 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -208,7 +208,7 @@ void BackupStoreDaemon::Run() // Change the log name ::openlog("bbstored/hk", LOG_PID, LOG_LOCAL6); // Log that housekeeping started - ::syslog(LOG_INFO, "Housekeeping process started"); + BOX_INFO("Housekeeping process started"); // Ignore term and hup // Parent will handle these and alert the child via the socket, don't want to randomly die ::signal(SIGHUP, SIG_IGN); @@ -281,19 +281,19 @@ void BackupStoreDaemon::Connection(SocketStreamTLS &rStream) } catch(BoxException &e) { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "exception %s (%d/%d)", DaemonName(), - e.what(), e.GetType(), e.GetSubType()); + BOX_ERROR("Error in child process, terminating connection: " << + e.what() << " (" << e.GetType() << "/" << + e.GetSubType() << ")"); } catch(std::exception &e) { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "exception %s", DaemonName(), e.what()); + BOX_ERROR("Error in child process, terminating connection: " << + e.what()); } catch(...) { - ::syslog(LOG_ERR, "%s: disconnecting due to " - "unknown exception", DaemonName()); + BOX_ERROR("Error in child process, terminating connection: " << + "unknown exception"); } } @@ -311,7 +311,7 @@ void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream) std::string clientCommonName(rStream.GetPeerCommonName()); // Log the name - ::syslog(LOG_INFO, "Certificate CN: %s", clientCommonName.c_str()); + BOX_INFO("Client certificate CN: " << clientCommonName); // Check it int32_t id; @@ -357,10 +357,8 @@ void BackupStoreDaemon::LogConnectionStats(const char *commonName, const SocketStreamTLS &s) { // Log the amount of data transferred - ::syslog(LOG_INFO, "Connection statistics for %s: " - "IN=%lld OUT=%lld TOTAL=%lld", commonName, - (long long)s.GetBytesRead(), - (long long)s.GetBytesWritten(), - (long long)s.GetBytesRead() + - (long long)s.GetBytesWritten()); + BOX_INFO("Connection statistics for " << commonName << ":" + " IN=" << s.GetBytesRead() << + " OUT=" << s.GetBytesWritten() << + " TOTAL=" << (s.GetBytesRead() + s.GetBytesWritten())); } diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp index 8d2d9e4c..9f4239e7 100644 --- a/bin/bbstored/HousekeepStoreAccount.cpp +++ b/bin/bbstored/HousekeepStoreAccount.cpp @@ -9,9 +9,10 @@ #include "Box.h" -#include #include +#include + #include "HousekeepStoreAccount.h" #include "BackupStoreDaemon.h" #include "StoreStructure.h" @@ -137,11 +138,18 @@ void HousekeepStoreAccount::DoHousekeeping() || (usedDeleted + mBlocksInDeletedFilesDelta) != mBlocksInDeletedFiles || usedDirectories != mBlocksInDirectories) { // Log this - ::syslog(LOG_ERR, "On housekeeping, sizes in store do not match calculated sizes, correcting"); - ::syslog(LOG_ERR, "different (store,calc): acc 0x%08x, used (%lld,%lld), old (%lld,%lld), deleted (%lld,%lld), dirs (%lld,%lld)", - mAccountID, - (used + mBlocksUsedDelta), mBlocksUsed, (usedOld + mBlocksInOldFilesDelta), mBlocksInOldFiles, - (usedDeleted + mBlocksInDeletedFilesDelta), mBlocksInDeletedFiles, usedDirectories, mBlocksInDirectories); + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(mAccountID) << " found " + "and fixed wrong block counts: " + "used (" << + (used + mBlocksUsedDelta) << "," << + mBlocksUsed << "), old (" << + (usedOld + mBlocksInOldFilesDelta) << "," << + mBlocksInOldFiles << "), deleted (" << + (usedDeleted + mBlocksInDeletedFilesDelta) << + "," << mBlocksInDeletedFiles << "), dirs (" << + usedDirectories << "," << mBlocksInDirectories + << ")"); } // If the current values don't match, store them @@ -173,17 +181,33 @@ void HousekeepStoreAccount::DoHousekeeping() // Log deletion if anything was deleted if(mFilesDeleted > 0 || mEmptyDirectoriesDeleted > 0) { - ::syslog(LOG_INFO, "Account 0x%08x, removed %lld blocks (%lld files, %lld dirs)%s", mAccountID, 0 - (mBlocksUsedDelta + removeASAPBlocksUsedDelta), - mFilesDeleted, mEmptyDirectoriesDeleted, - deleteInterrupted?" was interrupted":""); + BOX_INFO("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(mAccountID) << " " + "removed " << + (0 - (mBlocksUsedDelta + removeASAPBlocksUsedDelta)) << + " blocks (" << mFilesDeleted << " files, " << + mEmptyDirectoriesDeleted << " dirs)" << + (deleteInterrupted?" and was interrupted":"")); } // Make sure the delta's won't cause problems if the counts are really wrong, and // it wasn't fixed because the store was updated during the scan. - if(mBlocksUsedDelta < (0 - info->GetBlocksUsed())) mBlocksUsedDelta = (0 - info->GetBlocksUsed()); - if(mBlocksInOldFilesDelta < (0 - info->GetBlocksInOldFiles())) mBlocksInOldFilesDelta = (0 - info->GetBlocksInOldFiles()); - if(mBlocksInDeletedFilesDelta < (0 - info->GetBlocksInDeletedFiles())) mBlocksInDeletedFilesDelta =(0 - info->GetBlocksInDeletedFiles()); - if(mBlocksInDirectoriesDelta < (0 - info->GetBlocksInDirectories())) mBlocksInDirectoriesDelta = (0 - info->GetBlocksInDirectories()); + if(mBlocksUsedDelta < (0 - info->GetBlocksUsed())) + { + mBlocksUsedDelta = (0 - info->GetBlocksUsed()); + } + if(mBlocksInOldFilesDelta < (0 - info->GetBlocksInOldFiles())) + { + mBlocksInOldFilesDelta = (0 - info->GetBlocksInOldFiles()); + } + if(mBlocksInDeletedFilesDelta < (0 - info->GetBlocksInDeletedFiles())) + { + mBlocksInDeletedFilesDelta = (0 - info->GetBlocksInDeletedFiles()); + } + if(mBlocksInDirectoriesDelta < (0 - info->GetBlocksInDirectories())) + { + mBlocksInDirectoriesDelta = (0 - info->GetBlocksInDirectories()); + } // Update the usage counts in the store info->ChangeBlocksUsed(mBlocksUsedDelta); @@ -554,7 +578,14 @@ void HousekeepStoreAccount::DeleteFile(int64_t InDirectory, int64_t ObjectID, Ba BackupStoreDirectory::Entry *pentry = rDirectory.FindEntryByID(ObjectID); if(pentry == 0) { - ::syslog(LOG_ERR, "acc 0x%08x, object %lld not found in dir %lld, logic error/corruption? Run bbstoreaccounts check fix", mAccountID, ObjectID, InDirectory); + BOX_ERROR("Housekeeping on account " << + BOX_FORMAT_ACCOUNT(mAccountID) << " " + "found error: object " << + BOX_FORMAT_OBJECTID(ObjectID) << " " + "not found in dir " << + BOX_FORMAT_OBJECTID(InDirectory) << ", " + "indicates logic error/corruption? Run " + "bbstoreaccounts check fix"); return; } diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp index 9918c0d6..925d1620 100644 --- a/lib/backupclient/BackupClientFileAttributes.cpp +++ b/lib/backupclient/BackupClientFileAttributes.cpp @@ -344,8 +344,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; } @@ -355,8 +355,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 @@ -627,9 +627,8 @@ void BackupClientFileAttributes::WriteAttributes(const char *Filename, } #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); diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 9b3a3edc..92853624 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -235,20 +235,20 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir } catch (BoxException &e) { - ::syslog(LOG_ERR, "Failed to check existence for %s: %s", - rLocalDirectoryName.c_str(), e.what()); + BOX_ERROR("Failed to check existence for " << + rLocalDirectoryName << ": " << e.what()); return Restore_UnknownError; } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to check existence for %s: %s", - rLocalDirectoryName.c_str(), e.what()); + BOX_ERROR("Failed to check existence for " << + rLocalDirectoryName << ": " << e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to check existence for %s: " - "unknown error", rLocalDirectoryName.c_str()); + BOX_ERROR("Failed to check existence for " << + rLocalDirectoryName << ": unknown error"); return Restore_UnknownError; } @@ -263,13 +263,14 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir ::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()); if(::unlink(rLocalDirectoryName.c_str()) != 0) { - ::syslog(LOG_ERR, "Failed to delete " - "file %s: %s", - rLocalDirectoryName.c_str(), + 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); } break; case ObjectExists_NoObject: @@ -325,20 +326,20 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir } catch (BoxException &e) { - ::syslog(LOG_ERR, "Failed to check existence for %s: " - "%s", parentDirectoryName.c_str(), e.what()); + BOX_ERROR("Failed to check existence for " << + parentDirectoryName << ": " << e.what()); return Restore_UnknownError; } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to check existence for %s: " - "%s", parentDirectoryName.c_str(), e.what()); + BOX_ERROR("Failed to check existence for " << + parentDirectoryName << ": " << e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to check existence for %s: " - "unknown error", parentDirectoryName.c_str()); + BOX_ERROR("Failed to check existence for " << + parentDirectoryName << ": unknown error"); return Restore_UnknownError; } @@ -349,24 +350,22 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir break; case ObjectExists_File: - fprintf(stderr, "Failed to restore: '%s' " + BOX_ERROR("Failed to restore: '" << + parentDirectoryName << "' " "is a file, but should be a " - "directory.\n", - parentDirectoryName.c_str()); + "directory."); return Restore_TargetPathNotFound; case ObjectExists_NoObject: - fprintf(stderr, "Failed to restore: " - "parent '%s' of target directory " - "does not exist.\n", - parentDirectoryName.c_str()); + BOX_ERROR("Failed to restore: parent '" << + parentDirectoryName << "' of target " + "directory does not exist."); return Restore_TargetPathNotFound; default: - fprintf(stderr, "Failed to restore: " - "unknown result from " - "ObjectExists('%s').\n", - parentDirectoryName.c_str()); + BOX_ERROR("Failed to restore: unknown " + "result from ObjectExists('" << + parentDirectoryName << "')"); return Restore_UnknownError; } } @@ -375,8 +374,8 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir exists == ObjectExists_File) && ::mkdir(rLocalDirectoryName.c_str(), S_IRWXU) != 0) { - ::syslog(LOG_ERR, "Failed to create directory %s: %s", - rLocalDirectoryName.c_str(), + BOX_ERROR("Failed to create directory '" << + rLocalDirectoryName << "': " << strerror(errno)); return Restore_UnknownError; } @@ -386,23 +385,18 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename); } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to save resume info file %s: %s", - Params.mRestoreResumeInfoFilename.c_str(), e.what()); - return Restore_UnknownError; - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to save resume info file %s: %s", - Params.mRestoreResumeInfoFilename.c_str(), e.what()); + BOX_ERROR("Failed to save resume info file '" << + Params.mRestoreResumeInfoFilename << "': " << + e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to save resume info file %s: " - "unknown error", - Params.mRestoreResumeInfoFilename.c_str()); + BOX_ERROR("Failed to save resume info file '" << + Params.mRestoreResumeInfoFilename << + "': unknown error"); return Restore_UnknownError; } @@ -427,22 +421,16 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { dirAttr.WriteAttributes(rLocalDirectoryName.c_str(), true); } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to restore attributes for %s: %s", - rLocalDirectoryName.c_str(), e.what()); - return Restore_UnknownError; - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to restore attributes for %s: %s", - rLocalDirectoryName.c_str(), e.what()); + BOX_ERROR("Failed to restore attributes for '" << + rLocalDirectoryName << "': " << e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to restore attributes for %s: " - "unknown error", rLocalDirectoryName.c_str()); + BOX_ERROR("Failed to restore attributes for '" << + rLocalDirectoryName << "': unknown error"); return Restore_UnknownError; } @@ -464,9 +452,8 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir // Unlink anything which already exists -- for resuming restores, we can't overwrite files already there. if(::unlink(localFilename.c_str()) == 0) { - ::syslog(LOG_ERR, "Failed to delete " - "file %s: %s", - localFilename.c_str(), + BOX_ERROR("Failed to delete file '" << + localFilename << "': " << strerror(errno)); return Restore_UnknownError; } @@ -494,27 +481,18 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir BackupStoreFile::DecodeFile(*objectStream, localFilename.c_str(), rConnection.GetTimeout()); } } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to restore " - "file %s: %s", - localFilename.c_str(), - e.what()); - return Restore_UnknownError; - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to restore " - "file %s: %s", - localFilename.c_str(), + BOX_ERROR("Failed to restore file '" << + localFilename << "': " << e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to restore " - "file %s: unknown error", - localFilename.c_str()); + BOX_ERROR("Failed to restore file '" << + localFilename << + "': unknown error"); return Restore_UnknownError; } @@ -540,28 +518,20 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir true /* treat links as not existing */); } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to determine " - "whether file exists: %s: %s", - localFilename.c_str(), - e.what()); - return Restore_UnknownError; - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to determine " - "whether file exists: %s: %s", - localFilename.c_str(), + BOX_ERROR("Failed to determine " + "whether file exists: '" << + localFilename << "': " << e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to determine " - "whether file exists: %s: " - "unknown error", - localFilename.c_str()); + BOX_ERROR("Failed to determine " + "whether file exists: '" << + localFilename << "': " + "unknown error"); return Restore_UnknownError; } @@ -577,23 +547,18 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { Params.mResumeInfo.Save(Params.mRestoreResumeInfoFilename); } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to save resume info file %s: %s", - Params.mRestoreResumeInfoFilename.c_str(), e.what()); - return Restore_UnknownError; - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to save resume info file %s: %s", - Params.mRestoreResumeInfoFilename.c_str(), e.what()); + BOX_ERROR("Failed to save resume info file '" << + Params.mRestoreResumeInfoFilename << + "': " << e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to save resume info file %s: " - "unknown error", - Params.mRestoreResumeInfoFilename.c_str()); + BOX_ERROR("Failed to save resume info file '" << + Params.mRestoreResumeInfoFilename << + "': unknown error"); return Restore_UnknownError; } @@ -613,27 +578,18 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir Params.mResumeInfo.Save( Params.mRestoreResumeInfoFilename); } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to save resume info file " - "%s: %s", - Params.mRestoreResumeInfoFilename.c_str(), - e.what()); - return Restore_UnknownError; - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to save resume info file " - "%s: %s", - Params.mRestoreResumeInfoFilename.c_str(), + BOX_ERROR("Failed to save resume info file '" << + Params.mRestoreResumeInfoFilename << "': " << e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to save resume info file " - "%s: unknown error", - Params.mRestoreResumeInfoFilename.c_str()); + BOX_ERROR("Failed to save resume info file '" << + Params.mRestoreResumeInfoFilename << + "': unknown error"); return Restore_UnknownError; } @@ -681,22 +637,16 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir { dirAttr.WriteAttributes(rLocalDirectoryName.c_str(), false); } - catch (BoxException &e) - { - ::syslog(LOG_ERR, "Failed to restore attributes for %s: %s", - rLocalDirectoryName.c_str(), e.what()); - return Restore_UnknownError; - } catch(std::exception &e) { - ::syslog(LOG_ERR, "Failed to restore attributes for %s: %s", - rLocalDirectoryName.c_str(), e.what()); + BOX_ERROR("Failed to restore attributes for '" << + rLocalDirectoryName << "': " << e.what()); return Restore_UnknownError; } catch(...) { - ::syslog(LOG_ERR, "Failed to restore attributes for %s: " - "unknown error", rLocalDirectoryName.c_str()); + BOX_ERROR("Failed to restore attributes for '" << + rLocalDirectoryName << "': unknown error"); return Restore_UnknownError; } diff --git a/lib/backupclient/BackupStoreFile.cpp b/lib/backupclient/BackupStoreFile.cpp index 75095fa4..7e93d59d 100644 --- a/lib/backupclient/BackupStoreFile.cpp +++ b/lib/backupclient/BackupStoreFile.cpp @@ -17,10 +17,8 @@ #include #include #include + #ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE - #ifndef WIN32 - #include - #endif #include #endif @@ -758,8 +756,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; } } diff --git a/lib/common/BoxTime.cpp b/lib/common/BoxTime.cpp index eafb244f..1ddcffd4 100644 --- a/lib/common/BoxTime.cpp +++ b/lib/common/BoxTime.cpp @@ -12,12 +12,11 @@ #ifdef HAVE_SYS_TIME_H #include #endif + #ifdef HAVE_TIME_H #include #endif -#ifdef HAVE_SYSLOG_H - #include -#endif + #include #include @@ -40,8 +39,8 @@ box_time_t GetCurrentBoxTime() struct timeval tv; if (gettimeofday(&tv, NULL) != 0) { - ::syslog(LOG_ERR, "gettimeofday() failed (%s), " - "dropping precision", strerror(errno)); + BOX_ERROR("Failed to gettimeofday(), dropping " + "precision: " << strerror(errno)); } else { diff --git a/lib/common/DebugPrintf.cpp b/lib/common/DebugPrintf.cpp index 8d75f458..14cd3534 100644 --- a/lib/common/DebugPrintf.cpp +++ b/lib/common/DebugPrintf.cpp @@ -14,12 +14,6 @@ #include #include -#ifdef WIN32 - #include "emu.h" -#else - #include -#endif - #include "MemLeakFindOn.h" // Use this apparently superflous printf function to avoid having to diff --git a/lib/common/Logging.h b/lib/common/Logging.h index aea488a5..e87d1d4f 100644 --- a/lib/common/Logging.h +++ b/lib/common/Logging.h @@ -10,6 +10,7 @@ #ifndef LOGGING__H #define LOGGING__H +#include #include #include @@ -42,6 +43,19 @@ #define BOX_TRACE(stuff) BOX_LOG(Log::TRACE, stuff) #endif +#define BOX_FORMAT_ACCOUNT(accno) \ + std::hex << \ + std::showbase << \ + std::internal << \ + std::setw(8) << \ + std::setfill('0') << \ + (accno) + +#define BOX_FORMAT_OBJECTID(objectid) \ + std::hex << \ + std::showbase << \ + (objectid) + #undef ERROR namespace Log diff --git a/lib/raidfile/RaidFileRead.cpp b/lib/raidfile/RaidFileRead.cpp index 58aecfb1..187270f9 100644 --- a/lib/raidfile/RaidFileRead.cpp +++ b/lib/raidfile/RaidFileRead.cpp @@ -21,10 +21,6 @@ #include #endif -#ifdef HAVE_SYSLOG_H - #include -#endif - #ifdef HAVE_DIRENT_H #include #endif @@ -548,8 +544,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) @@ -861,8 +857,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); @@ -879,8 +877,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); @@ -1054,8 +1054,9 @@ std::auto_ptr 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 } @@ -1130,8 +1131,9 @@ std::auto_ptr 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; @@ -1146,8 +1148,9 @@ std::auto_ptr 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; @@ -1169,8 +1172,10 @@ std::auto_ptr 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)); diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index 147eeb24..a9eb5bf5 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -19,10 +19,6 @@ #include #include -#ifdef HAVE_SYSLOG_H - #include -#endif - #ifdef WIN32 #include #endif @@ -353,7 +349,8 @@ int Daemon::Main(const std::string &rConfigFileName) // Set new session if(::setsid() == -1) { - ::syslog(LOG_ERR, "can't setsid"); + BOX_ERROR("Failed to setsid(): " << + strerror(errno)); THROW_EXCEPTION(ServerException, DaemoniseFailed) } diff --git a/lib/server/LocalProcessStream.cpp b/lib/server/LocalProcessStream.cpp index fef7166b..9750aca1 100644 --- a/lib/server/LocalProcessStream.cpp +++ b/lib/server/LocalProcessStream.cpp @@ -120,8 +120,8 @@ std::auto_ptr LocalProcessStream(const char *CommandLine, pid_t &rPidO HANDLE writeInChild, readFromChild; if(!CreatePipe(&readFromChild, &writeInChild, &secAttr, 0)) { - ::syslog(LOG_ERR, "Failed to CreatePipe for child process: " - "error %d", GetLastError()); + BOX_ERROR("Failed to CreatePipe for child process: " + GetErrorMessage(GetLastError())); THROW_EXCEPTION(ServerException, SocketPairFailed) } SetHandleInformation(readFromChild, HANDLE_FLAG_INHERIT, 0); @@ -155,8 +155,8 @@ std::auto_ptr LocalProcessStream(const char *CommandLine, pid_t &rPidO if(!result) { - ::syslog(LOG_ERR, "Failed to CreateProcess: '%s': " - "error %d", CommandLine, GetLastError()); + BOX_ERROR("Failed to CreateProcess: '" << CommandLine << + "': " << GetErrorMessage(GetLastError())); CloseHandle(writeInChild); CloseHandle(readFromChild); THROW_EXCEPTION(ServerException, ServerForkError) diff --git a/lib/server/SSLLib.cpp b/lib/server/SSLLib.cpp index 2a5bdbde..6082a9f4 100644 --- a/lib/server/SSLLib.cpp +++ b/lib/server/SSLLib.cpp @@ -14,10 +14,6 @@ #include #include -#ifndef WIN32 -#include -#endif - #include "SSLLib.h" #include "ServerException.h" @@ -73,13 +69,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/ServerStream.h b/lib/server/ServerStream.h index 7eb99d13..5f615336 100644 --- a/lib/server/ServerStream.h +++ b/lib/server/ServerStream.h @@ -14,7 +14,6 @@ #include #ifndef WIN32 - #include #include #endif @@ -73,7 +72,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; @@ -82,7 +84,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; @@ -91,7 +95,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; @@ -266,7 +272,7 @@ public: } // Log it - ::syslog(LOG_INFO, "%s (handling in child %d)", logMessage.c_str(), pid); + BOX_WARNING("Error message from child process " << pid << ": " << logMessage); } else { diff --git a/lib/server/Socket.cpp b/lib/server/Socket.cpp index afed4888..28dae69f 100644 --- a/lib/server/Socket.cpp +++ b/lib/server/Socket.cpp @@ -17,7 +17,6 @@ #ifndef WIN32 #include #include -#include #include #include #endif @@ -124,18 +123,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/WinNamedPipeStream.cpp b/lib/server/WinNamedPipeStream.cpp index 32ae42f2..d7e90793 100644 --- a/lib/server/WinNamedPipeStream.cpp +++ b/lib/server/WinNamedPipeStream.cpp @@ -63,8 +63,8 @@ WinNamedPipeStream::~WinNamedPipeStream() } catch (std::exception &e) { - ::syslog(LOG_ERR, "Caught exception while destroying " - "named pipe, ignored."); + BOX_ERROR("Caught exception while destroying " + "named pipe, ignored: " << e.what()); } } } @@ -100,8 +100,8 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) if (mSocketHandle == INVALID_HANDLE_VALUE) { - ::syslog(LOG_ERR, "CreateNamedPipeW failed: %s", - GetErrorMessage(GetLastError()).c_str()); + BOX_ERROR("Failed to CreateNamedPipeW(" << pName << "): " << + GetErrorMessage(GetLastError())); THROW_EXCEPTION(ServerException, SocketOpenError) } @@ -109,8 +109,8 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) if (!connected) { - ::syslog(LOG_ERR, "ConnectNamedPipe failed: %s", - GetErrorMessage(GetLastError()).c_str()); + BOX_ERROR("Failed to ConnectNamedPipe(" << pName << "): " << + GetErrorMessage(GetLastError())); Close(); THROW_EXCEPTION(ServerException, SocketOpenError) } @@ -126,8 +126,8 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) if (mReadableEvent == INVALID_HANDLE_VALUE) { - ::syslog(LOG_ERR, "Failed to create the Readable event: %s", - GetErrorMessage(GetLastError()).c_str()); + BOX_ERROR("Failed to create the Readable event: " << + GetErrorMessage(GetLastError())); Close(); THROW_EXCEPTION(CommonException, Internal) } @@ -144,8 +144,8 @@ void WinNamedPipeStream::Accept(const wchar_t* pName) if (err != ERROR_IO_PENDING) { - ::syslog(LOG_ERR, "Failed to start overlapped read: " - "%s", GetErrorMessage(err).c_str()); + BOX_ERROR("Failed to start overlapped read: " << + GetErrorMessage(err)); Close(); THROW_EXCEPTION(ConnectionException, Conn_SocketReadError) @@ -183,13 +183,13 @@ void WinNamedPipeStream::Connect(const wchar_t* pName) DWORD err = GetLastError(); if (err == ERROR_PIPE_BUSY) { - ::syslog(LOG_ERR, "Failed to connect to backup " - "daemon: it is busy with another connection"); + BOX_ERROR("Failed to connect to backup daemon: " + "it is busy with another connection"); } else { - ::syslog(LOG_ERR, "Failed to connect to backup " - "daemon: %s", GetErrorMessage(err).c_str()); + BOX_ERROR("Failed to connect to backup daemon: " << + GetErrorMessage(err)); } THROW_EXCEPTION(ServerException, SocketOpenError) } @@ -261,16 +261,14 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) { if (err == ERROR_BROKEN_PIPE) { - ::syslog(LOG_ERR, "Control " - "client disconnected"); + BOX_ERROR("Control client " + "disconnected"); } else { - ::syslog(LOG_ERR, - "Failed to wait for " + BOX_ERROR("Failed to wait for " "ReadFile to complete: " - "%s", - GetErrorMessage(err).c_str()); + << GetErrorMessage(err)); } Close(); @@ -326,15 +324,13 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) } else if (err == ERROR_BROKEN_PIPE) { - ::syslog(LOG_ERR, - "Control client disconnected"); + BOX_ERROR("Control client disconnected"); mReadClosed = true; } else { - ::syslog(LOG_ERR, "Failed to start " - "overlapped read: %s", - GetErrorMessage(err).c_str()); + BOX_ERROR("Failed to start overlapped read: " + << GetErrorMessage(err)); Close(); THROW_EXCEPTION(ConnectionException, Conn_SocketReadError) @@ -387,9 +383,8 @@ int WinNamedPipeStream::Read(void *pBuffer, int NBytes, int Timeout) } else { - ::syslog(LOG_ERR, "Failed to read from " - "control socket: %s", - GetErrorMessage(err).c_str()); + BOX_ERROR("Failed to read from control socket: " + << GetErrorMessage(err)); THROW_EXCEPTION(ConnectionException, Conn_SocketReadError) } @@ -440,8 +435,8 @@ void WinNamedPipeStream::Write(const void *pBuffer, int NBytes) if (!Success) { DWORD err = GetLastError(); - ::syslog(LOG_ERR, "Failed to write to control socket: " - "%s", GetErrorMessage(err).c_str()); + BOX_ERROR("Failed to write to control socket: " << + GetErrorMessage(err)); Close(); // ERROR_NO_DATA is a strange name for @@ -474,8 +469,7 @@ void WinNamedPipeStream::Close() { if (mSocketHandle == INVALID_HANDLE_VALUE && mIsConnected) { - fprintf(stderr, "Inconsistent connected state\n"); - ::syslog(LOG_ERR, "Inconsistent connected state"); + BOX_ERROR("Named pipe: inconsistent connected state"); mIsConnected = false; } @@ -488,29 +482,27 @@ void WinNamedPipeStream::Close() { if (!CancelIo(mSocketHandle)) { - ::syslog(LOG_ERR, "Failed to cancel outstanding " - "I/O: %s", - GetErrorMessage(GetLastError()).c_str()); + BOX_ERROR("Failed to cancel outstanding I/O: " << + GetErrorMessage(GetLastError())); } if (mReadableEvent == INVALID_HANDLE_VALUE) { - ::syslog(LOG_ERR, "Failed to destroy Readable " - "event: invalid handle"); + BOX_ERROR("Failed to destroy Readable event: " + "invalid handle"); } else if (!CloseHandle(mReadableEvent)) { - ::syslog(LOG_ERR, "Failed to destroy Readable " - "event: %s", - GetErrorMessage(GetLastError()).c_str()); + BOX_ERROR("Failed to destroy Readable event: " << + GetErrorMessage(GetLastError())); } mReadableEvent = INVALID_HANDLE_VALUE; if (!FlushFileBuffers(mSocketHandle)) { - ::syslog(LOG_INFO, "FlushFileBuffers failed: %s", - GetErrorMessage(GetLastError()).c_str()); + BOX_ERROR("Failed to FlushFileBuffers: " << + GetErrorMessage(GetLastError())); } if (!DisconnectNamedPipe(mSocketHandle)) @@ -518,9 +510,8 @@ void WinNamedPipeStream::Close() DWORD err = GetLastError(); if (err != ERROR_PIPE_NOT_CONNECTED) { - ::syslog(LOG_ERR, "DisconnectNamedPipe " - "failed: %s", - GetErrorMessage(err).c_str()); + BOX_ERROR("Failed to DisconnectNamedPipe: " << + GetErrorMessage(err)); } } @@ -536,8 +527,8 @@ void WinNamedPipeStream::Close() if (!result) { - ::syslog(LOG_ERR, "CloseHandle failed: %s", - GetErrorMessage(GetLastError()).c_str()); + BOX_ERROR("Failed to CloseHandle: " << + GetErrorMessage(GetLastError())); THROW_EXCEPTION(ServerException, SocketCloseError) } } @@ -585,8 +576,8 @@ void WinNamedPipeStream::WriteAllBuffered() if (!FlushFileBuffers(mSocketHandle)) { - ::syslog(LOG_WARNING, "FlushFileBuffers failed: %s", - GetErrorMessage(GetLastError()).c_str()); + BOX_ERROR("Failed to FlushFileBuffers: " << + GetErrorMessage(GetLastError())); } } -- cgit v1.2.3 From 4e8ef2a6239d3416b67438e4ab0c5ba9b92aa596 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 31 Jul 2007 23:52:26 +0000 Subject: Quiet make by default (make V=1 to override) (refs #3) --- infrastructure/makebuildenv.pl.in | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index 7069b09d..c990c900 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -544,6 +544,13 @@ DEPENDMAKEFLAGS = VARIENT = DEBUG .endif +HIDE = \$(if \$(V),,@) +_CXX = \$(if \$(V),\$(CXX), @ echo "[CXX] \$<" && \$(CXX)) +_LINK = \$(if \$(V),\$(CXX), @ echo "[LINK] \$@" && \$(CXX)) +_WINDRES = \$(if \$(V),\$(WINDRES), @ echo "[WINDRES] \$<" && \$(WINDRES)) +_AR = \$(if \$(V),\$(AR), @ echo "[AR] \$@" && \$(AR)) +_RANLIB = \$(if \$(V),\$(RANLIB), @ echo "[RANLIB] \$@" && \$(RANLIB)) + __E # read directory @@ -646,12 +653,12 @@ __E if ($is_cpp) { - $make .= "\t\$(CXX) \$(CXXFLAGS) $compile_line_extra ". + $make .= "\t\$(_CXX) \$(CXXFLAGS) $compile_line_extra ". "-c $file -o $out_name\n\n"; } elsif ($is_rc) { - $make .= "\t\$(WINDRES) $file $out_name\n\n"; + $make .= "\t\$(_WINDRES) $file $out_name\n\n"; my $res_list = $module_resources_win32{$mod}; $res_list ||= []; push @$res_list, $base.'.o'; @@ -690,7 +697,7 @@ __E # run make for things we require for my $dep (@all_deps_for_module) { - $deps_makeinfo .= "\t\t(cd ../../$dep; \$(MAKE)$sub_make_options \$(DEPENDMAKEFLAGS) -D NODEPS)\n"; + $deps_makeinfo .= "\t\t\$(HIDE) (cd ../../$dep; \$(MAKE)$sub_make_options \$(DEPENDMAKEFLAGS) -D NODEPS)\n"; } $deps_makeinfo .= ".\tendif\n.endif\n\n"; } @@ -734,9 +741,9 @@ __E if($target_is_library) { # make a library archive... - print MAKE "\t(echo -n > $end_target; rm $end_target)\n"; - print MAKE "\t\$(AR) -q $end_target $o_file_list\n"; - print MAKE "\t\$(RANLIB) $end_target\n"; + print MAKE "\t\$(HIDE) (echo -n > $end_target; rm $end_target)\n"; + print MAKE "\t\$(_AR) -q $end_target $o_file_list\n"; + print MAKE "\t\$(_RANLIB) $end_target\n"; } else { @@ -760,7 +767,7 @@ __E } # link line... - print MAKE "\t\$(CXX) $link_line_extra -o $end_target $o_file_list $lib_files$lo $platform_lib_files\n"; + print MAKE "\t\$(_LINK) $link_line_extra -o $end_target $o_file_list $lib_files$lo $platform_lib_files\n"; } # tests need to copy the test file over if($type eq 'test') @@ -781,7 +788,7 @@ __E print MAKE "clean:\n\t-rm -rf \$(OUTDIR)/*\n.\tifndef SUBCLEAN\n"; for my $dep (@all_deps_for_module) { - print MAKE "\t(cd ../../$dep; \$(MAKE) \$(DEPENDMAKEFLAGS) -D SUBCLEAN clean)\n"; + print MAKE "\t\$(HIDE) (cd ../../$dep; \$(MAKE) \$(DEPENDMAKEFLAGS) -D SUBCLEAN clean)\n"; } print MAKE ".\tendif\n"; -- cgit v1.2.3 From c0f0b74c04054ddab5610cba9d2268c04c6a7e9f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 2 Aug 2007 22:24:34 +0000 Subject: Undo removal of syslog() header, still needed in this file. --- lib/common/DebugPrintf.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/common/DebugPrintf.cpp b/lib/common/DebugPrintf.cpp index 14cd3534..8d75f458 100644 --- a/lib/common/DebugPrintf.cpp +++ b/lib/common/DebugPrintf.cpp @@ -14,6 +14,12 @@ #include #include +#ifdef WIN32 + #include "emu.h" +#else + #include +#endif + #include "MemLeakFindOn.h" // Use this apparently superflous printf function to avoid having to -- cgit v1.2.3 From 747589f03a1ba61273d21ed6446ad47841a1f46a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 2 Aug 2007 23:28:17 +0000 Subject: Convert most printf() and fprintf() calls to use logging framework instead. (refs #3) --- bin/bbackupctl/bbackupctl.cpp | 47 +++--- bin/bbackupquery/BackupQueries.cpp | 280 ++++++++++++++++--------------- bin/bbackupquery/bbackupquery.cpp | 34 ++-- bin/bbstoreaccounts/bbstoreaccounts.cpp | 66 +++++--- lib/backupclient/BackupClientRestore.cpp | 6 +- lib/backupstore/BackupStoreCheck.cpp | 92 ++++++---- lib/backupstore/BackupStoreCheck2.cpp | 24 +-- lib/common/DebugMemLeakFinder.cpp | 3 +- lib/common/Logging.cpp | 42 ++++- lib/crypto/Random.cpp | 3 +- lib/raidfile/RaidFileController.cpp | 3 +- lib/server/SSLLib.cpp | 3 +- test/bbackupd/testfiles/extcheck1.pl.in | 2 +- test/bbackupd/testfiles/extcheck2.pl.in | 2 +- 14 files changed, 358 insertions(+), 249 deletions(-) diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index a5dc4c10..edbc252f 100644 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -109,8 +109,7 @@ int main(int argc, const char *argv[]) } // Read in the configuration file - if(!quiet) printf("Using configuration file %s\n", - configFilename.c_str()); + if(!quiet) BOX_NOTICE("Using configuration file " << configFilename); std::string errs; std::auto_ptr config( @@ -119,7 +118,7 @@ int main(int argc, const char *argv[]) if(config.get() == 0 || !errs.empty()) { - printf("Invalid configuration file:\n%s", errs.c_str()); + BOX_ERROR("Invalid configuration file: " << errs); return 1; } // Easier coding @@ -128,10 +127,10 @@ int main(int argc, const char *argv[]) // Check there's a socket defined in the config file if(!conf.KeyExists("CommandSocket")) { - printf("Daemon isn't using a control socket, " + BOX_ERROR("Daemon isn't using a control socket, " "could not execute command.\n" "Add a CommandSocket declaration to the " - "bbackupd.conf file.\n"); + "bbackupd.conf file."); return 1; } @@ -153,18 +152,14 @@ int main(int argc, const char *argv[]) } catch(...) { - printf("Failed to connect to daemon control socket.\n" + BOX_ERROR("Failed to connect to daemon control socket.\n" "Possible causes:\n" " * Daemon not running\n" " * Daemon busy syncing with store server\n" " * Another bbackupctl process is communicating with the daemon\n" - " * Daemon is waiting to recover from an error\n" + " * Daemon is waiting to recover from an error" ); -#if defined WIN32 && ! defined NDEBUG - BOX_ERROR("Failed to connect to the command socket"); -#endif - return 1; } @@ -193,19 +188,19 @@ int main(int argc, const char *argv[]) if(::sscanf(configSummary.c_str(), "bbackupd: %d %d %d %d", &autoBackup, &updateStoreInterval, &minimumFileAge, &maxUploadWait) != 4) { - printf("Config summary didn't decode\n"); + BOX_ERROR("Config summary didn't decode."); return 1; } // Print summary? if(!quiet) { - printf("Daemon configuration summary:\n" - " AutomaticBackup = %s\n" - " UpdateStoreInterval = %d seconds\n" - " MinimumFileAge = %d seconds\n" - " MaxUploadWait = %d seconds\n", - autoBackup?"true":"false", updateStoreInterval, - minimumFileAge, maxUploadWait); + BOX_INFO("Daemon configuration summary:\n" + " AutomaticBackup = " << + (autoBackup?"true":"false") << "\n" + " UpdateStoreInterval = " << updateStoreInterval << + " seconds\n" + " MinimumFileAge = " << minimumFileAge << " seconds\n" + " MaxUploadWait = " << maxUploadWait << " seconds\n"); } std::string stateLine; @@ -266,8 +261,8 @@ int main(int argc, const char *argv[]) if (currentState != 0) { - printf("Waiting for current sync/error state " - "to finish...\n"); + BOX_INFO("Waiting for current sync/error state " + "to finish..."); } } break; @@ -310,14 +305,14 @@ int main(int argc, const char *argv[]) { if(line == "start-sync") { - if (!quiet) printf("Sync started...\n"); + if (!quiet) BOX_INFO("Sync started..."); syncIsRunning = true; } else if(line == "finish-sync") { if (syncIsRunning) { - if (!quiet) printf("Sync finished.\n"); + if (!quiet) BOX_INFO("Sync finished.\n"); // Send a quit command to finish nicely connection.Write("quit\n", 5); @@ -326,7 +321,7 @@ int main(int argc, const char *argv[]) } else { - if (!quiet) printf("Previous sync finished.\n"); + if (!quiet) BOX_INFO("Previous sync finished."); } // daemon must still be busy } @@ -340,13 +335,13 @@ int main(int argc, const char *argv[]) { if(!quiet) { - printf("Succeeded.\n"); + BOX_INFO("Succeeded.\n"); } finished = true; } else if(line == "error") { - printf("ERROR. (Check command spelling)\n"); + BOX_ERROR("Check command spelling"); returnCode = 1; finished = true; } diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 0c5f9c15..09003d4d 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -181,7 +181,7 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) if (!ConvertEncoding(*i, CP_ACP, converted, GetConsoleCP())) { - printf("Failed to convert encoding"); + BOX_ERROR("Failed to convert encoding"); return; } *i = converted; @@ -255,7 +255,7 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) // No such command if(alias[a] == 0) { - printf("Unrecognised command: %s\n", Command); + BOX_ERROR("Unrecognised command: " << Command); return; } } @@ -275,8 +275,8 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) // Valid option? if(::strchr(commands[cmd].opts, *c) == NULL) { - printf("Invalid option '%c' for command %s\n", - *c, commands[cmd].name); + BOX_ERROR("Invalid option '" << *c << "' for " + "command " << commands[cmd].name); return; } opts[(int)*c] = true; @@ -305,9 +305,8 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) case COMMAND_pwd: { // Simple implementation, so do it here - printf("%s (%08llx)\n", - GetCurrentDirectoryName().c_str(), - (long long)GetCurrentDirectoryID()); + BOX_INFO(GetCurrentDirectoryName() << " (" << + BOX_FORMAT_OBJECTID(GetCurrentDirectoryID())); } break; @@ -320,7 +319,7 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) break; case COMMAND_sh: - printf("The command to run must be specified as an argument.\n"); + BOX_ERROR("The command to run must be specified as an argument."); break; case COMMAND_GetObject: @@ -401,8 +400,8 @@ void BackupQueries::CommandList(const std::vector &args, const bool if(rootDir == 0) { - printf("Directory '%s' not found on store\n", - args[0].c_str()); + BOX_ERROR("Directory '" << args[0] << "' not found " + "on store."); return; } } @@ -747,7 +746,7 @@ void BackupQueries::CommandChangeDir(const std::vector &args, const { if(args.size() != 1 || args[0].size() == 0) { - printf("Incorrect usage.\ncd [-o] [-d] \n"); + BOX_ERROR("Incorrect usage. cd [-o] [-d] "); return; } @@ -764,7 +763,7 @@ void BackupQueries::CommandChangeDir(const std::vector &args, const if(id == 0) { - printf("Directory '%s' not found\n", args[0].c_str()); + BOX_ERROR("Directory '" << args[0] << "' not found."); return; } @@ -785,7 +784,7 @@ void BackupQueries::CommandChangeLocalDir(const std::vector &args) { if(args.size() != 1 || args[0].size() == 0) { - printf("Incorrect usage.\nlcd \n"); + BOX_ERROR("Incorrect usage. lcd "); SetReturnCode(COMMAND_RETURN_ERROR); return; } @@ -795,7 +794,7 @@ void BackupQueries::CommandChangeLocalDir(const std::vector &args) std::string dirName; if(!ConvertConsoleToUtf8(args[0].c_str(), dirName)) { - printf("Failed to convert path from console encoding.\n"); + BOX_ERROR("Failed to convert path from console encoding."); SetReturnCode(COMMAND_RETURN_ERROR); return; } @@ -805,8 +804,16 @@ void BackupQueries::CommandChangeLocalDir(const std::vector &args) #endif if(result != 0) { - printf((errno == ENOENT || errno == ENOTDIR)?"Directory '%s' does not exist\n":"Error changing dir to '%s'\n", - args[0].c_str()); + if(errno == ENOENT || errno == ENOTDIR) + { + BOX_ERROR("Directory '" << args[0] << "' does not exist."); + } + else + { + BOX_ERROR("Error changing to directory '" << + args[0] << ": " << strerror(errno)); + } + SetReturnCode(COMMAND_RETURN_ERROR); return; } @@ -815,7 +822,8 @@ void BackupQueries::CommandChangeLocalDir(const std::vector &args) char wd[PATH_MAX]; if(::getcwd(wd, PATH_MAX) == 0) { - printf("Error getting current directory\n"); + BOX_ERROR("Error getting current directory: " << + strerror(errno)); SetReturnCode(COMMAND_RETURN_ERROR); return; } @@ -823,13 +831,13 @@ void BackupQueries::CommandChangeLocalDir(const std::vector &args) #ifdef WIN32 if(!ConvertUtf8ToConsole(wd, dirName)) { - printf("Failed to convert new path from console encoding.\n"); + BOX_ERROR("Failed to convert new path from console encoding."); SetReturnCode(COMMAND_RETURN_ERROR); return; } - printf("Local current directory is now '%s'\n", dirName.c_str()); + BOX_INFO("Local current directory is now '" << dirName << "'."); #else - printf("Local current directory is now '%s'\n", wd); + BOX_INFO("Local current directory is now '" << wd << "'."); #endif } @@ -847,14 +855,15 @@ void BackupQueries::CommandGetObject(const std::vector &args, const // Check args if(args.size() != 2) { - printf("Incorrect usage.\ngetobject \n"); + BOX_ERROR("Incorrect usage. getobject " + ""); return; } int64_t id = ::strtoll(args[0].c_str(), 0, 16); if(id == std::numeric_limits::min() || id == std::numeric_limits::max() || id == 0) { - printf("Not a valid object ID (specified in hex)\n"); + BOX_ERROR("Not a valid object ID (specified in hex)."); return; } @@ -862,7 +871,7 @@ void BackupQueries::CommandGetObject(const std::vector &args, const struct stat st; if(::stat(args[1].c_str(), &st) == 0 || errno != ENOENT) { - printf("The local file %s already exists\n", args[1].c_str()); + BOX_ERROR("The local file '" << args[1] << " already exists."); return; } @@ -880,18 +889,20 @@ void BackupQueries::CommandGetObject(const std::vector &args, const std::auto_ptr objectStream(mrConnection.ReceiveStream()); objectStream->CopyStreamTo(out); - printf("Object ID %08llx fetched successfully.\n", id); + BOX_INFO("Object ID " << BOX_FORMAT_OBJECTID(id) << + " fetched successfully."); } else { - printf("Object does not exist on store.\n"); + BOX_ERROR("Object ID " << BOX_FORMAT_OBJECTID(id) << + " does not exist on store."); ::unlink(args[1].c_str()); } } catch(...) { ::unlink(args[1].c_str()); - printf("Error occured fetching object.\n"); + BOX_ERROR("Error occured fetching object."); } } @@ -911,9 +922,9 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) // Check args if(args.size() < 1 || (opts['i'] && args.size() != 2) || args.size() > 2) { - printf("Incorrect usage.\n" + BOX_ERROR("Incorrect usage.\n" "get [] or\n" - "get -i \n"); + "get -i "); return; } @@ -931,7 +942,7 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) std::string out; if(!ConvertConsoleToUtf8(i->c_str(), out)) { - fprintf(stderr, "failed to convert encoding\n"); + BOX_ERROR("Failed to convert encoding."); return; } *i = out; @@ -952,8 +963,8 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) dirId = FindDirectoryObjectID(dirName); if(dirId == 0) { - printf("Directory '%s' not found\n", - dirName.c_str()); + BOX_ERROR("Directory '" << dirName << + "' not found."); return; } } @@ -981,18 +992,19 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) fileId == std::numeric_limits::max() || fileId == 0) { - printf("Not a valid object ID (specified in hex)\n"); + BOX_ERROR("Not a valid object ID (specified in hex)."); return; } // Check that the item is actually in the directory if(dir.FindEntryByID(fileId) == 0) { - printf("ID '%08llx' not found in current " + BOX_ERROR("File ID " << + BOX_FORMAT_OBJECTID(fileId) << + " not found in current " "directory on store.\n" - "(You can only download objects by ID " - "from the current directory.)\n", - fileId); + "(You can only download files by ID " + "from the current directory.)"); return; } @@ -1007,10 +1019,11 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) if(en == 0) { - printf("Filename '%s' not found in current " + BOX_ERROR("Filename '" << args[0] << "' " + "not found in current " "directory on store.\n" "(Subdirectories in path not " - "searched.)\n", args[0].c_str()); + "searched.)"); return; } @@ -1027,8 +1040,8 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) struct stat st; if(::stat(localName.c_str(), &st) == 0 || errno != ENOENT) { - printf("The local file %s already exists, will not " - "overwrite it.\n", localName.c_str()); + BOX_ERROR("The local file " << localName << " already exists, " + "will not overwrite it."); SetReturnCode(COMMAND_RETURN_ERROR); return; } @@ -1046,7 +1059,8 @@ void BackupQueries::CommandGet(std::vector args, const bool *opts) BackupStoreFile::DecodeFile(*objectStream, localName.c_str(), mrConnection.GetTimeout()); // Done. - printf("Object ID %08llx fetched sucessfully.\n", fileId); + BOX_INFO("Object ID " << BOX_FORMAT_OBJECTID(fileId) << + " fetched successfully."); } catch (BoxException &e) { @@ -1160,14 +1174,16 @@ void BackupQueries::CommandCompare(const std::vector &args, const b } else { - printf("Warning: couldn't determine the time of the last synchronisation -- checks not performed.\n"); + BOX_WARNING("Failed to determine the time of the last " + "synchronisation -- checks not performed."); } } // Quick compare? if(params.mQuickCompare) { - printf("WARNING: Quick compare used -- file attributes are not checked.\n"); + BOX_WARNING("Quick compare used -- file attributes are not " + "checked."); } if(!opts['l'] && opts['a'] && args.size() == 0) @@ -1192,7 +1208,7 @@ void BackupQueries::CommandCompare(const std::vector &args, const b // Can't be bothered to do all the hard work to work out which location it's on, and hence which exclude list if(!params.mIgnoreExcludes) { - printf("Cannot use excludes on directory to directory comparison -- use -E flag to specify ignored excludes\n"); + BOX_ERROR("Cannot use excludes on directory to directory comparison -- use -E flag to specify ignored excludes."); return; } else @@ -1203,22 +1219,22 @@ void BackupQueries::CommandCompare(const std::vector &args, const b } else { - printf("Incorrect usage.\ncompare -a\n or compare -l \n or compare \n"); + BOX_ERROR("Incorrect usage.\ncompare -a\n or compare -l \n or compare "); return; } if (!params.mQuietCompare) { - printf("\n[ %d (of %d) differences probably due to file " - "modifications after the last upload ]\n", - params.mDifferencesExplainedByModTime, - params.mDifferences); + BOX_INFO("[ " << + params.mDifferencesExplainedByModTime << " (of " << + params.mDifferences << ") differences probably " + "due to file modifications after the last upload ]"); } - printf("Differences: %d (%d dirs excluded, %d files excluded, " - "%d files not checked)\n", - params.mDifferences, params.mExcludedDirs, - params.mExcludedFiles, params.mUncheckedFiles); + BOX_INFO("Differences: " << params.mDifferences << " (" << + params.mExcludedDirs << " dirs excluded, " << + params.mExcludedFiles << " files excluded, " << + params.mUncheckedFiles << " files not checked)"); // Set return code? if(opts['c']) @@ -1253,7 +1269,7 @@ void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries: const Configuration &locations(mrConfiguration.GetSubConfiguration("BackupLocations")); if(!locations.SubConfigurationExists(rLocation.c_str())) { - printf("Location %s does not exist.\n", rLocation.c_str()); + BOX_ERROR("Location " << rLocation << " does not exist."); return; } const Configuration &loc(locations.GetSubConfiguration(rLocation.c_str())); @@ -1264,9 +1280,9 @@ void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries: if (path.size() > 0 && path[path.size()-1] == DIRECTORY_SEPARATOR_ASCHAR) { - fprintf(stderr, "Warning: location '%s' path ends " - "with '%s', compare may fail!", - rLocation.c_str(), DIRECTORY_SEPARATOR); + BOX_WARNING("Location '" << rLocation << "' path ends " + "with '" DIRECTORY_SEPARATOR "', " + "compare may fail!"); } } #endif @@ -1319,9 +1335,9 @@ void BackupQueries::Compare(const std::string &rStoreDir, const std::string &rLo // Found? if(dirID == 0) { - printf("Local directory '%s' exists, but " - "server directory '%s' does not exist\n", - rLocalDir.c_str(), rStoreDir.c_str()); + BOX_WARNING("Local directory '" << rLocalDir << "' exists, " + "but server directory '" << rStoreDir << "' does not " + "exist."); rParams.mDifferences ++; return; } @@ -1369,24 +1385,23 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s // What kind of error? if(errno == ENOTDIR) { - printf("Local object '%s' is a file, " - "server object '%s' is a directory\n", - localDirDisplay.c_str(), - storeDirDisplay.c_str()); + BOX_WARNING("Local object '" << localDirDisplay << "' " + "is a file, server object '" << + storeDirDisplay << "' is a directory."); rParams.mDifferences ++; } else if(errno == ENOENT) { - printf("Local directory '%s' does not exist " - "(compared to server directory '%s')\n", - localDirDisplay.c_str(), - storeDirDisplay.c_str()); + BOX_WARNING("Local directory '" << localDirDisplay << + "' does not exist (compared to server " + "directory '" << storeDirDisplay << "')."); rParams.mDifferences ++; } else { - printf("ERROR: stat on local dir '%s'\n", - localDirDisplay.c_str()); + BOX_WARNING("Failed to access local directory '" << + localDirDisplay << ": " << strerror(errno) << + "'."); rParams.mUncheckedFiles ++; } return; @@ -1407,8 +1422,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s // Test out the attributes if(!dir.HasAttributes()) { - printf("Store directory '%s' doesn't have attributes.\n", - storeDirDisplay.c_str()); + BOX_WARNING("Store directory '" << storeDirDisplay << "' " + "doesn't have attributes."); } else { @@ -1423,10 +1438,9 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s if(!(attr.Compare(localAttr, true, true /* ignore modification times */))) { - printf("Local directory '%s' has different attributes " - "to store directory '%s'.\n", - localDirDisplay.c_str(), - storeDirDisplay.c_str()); + BOX_WARNING("Local directory '" << localDirDisplay << + "' has different attributes to store " + "directory '" << storeDirDisplay << "'."); rParams.mDifferences ++; } } @@ -1435,8 +1449,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s DIR *dirhandle = ::opendir(rLocalDir.c_str()); if(dirhandle == 0) { - printf("ERROR: opendir on local dir '%s'\n", - localDirDisplay.c_str()); + BOX_WARNING("Failed to open local directory '" << + localDirDisplay << "': " << strerror(errno)); rParams.mUncheckedFiles ++; return; } @@ -1457,9 +1471,9 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s #ifdef HAVE_VALID_DIRENT_D_TYPE if (localDirEn->d_type != DT_DIR) { - fprintf(stderr, "ERROR: d_type does " - "not really work on your " - "platform. Reconfigure Box!\n"); + BOX_ERROR("d_type does not really " + "work on your platform. " + "Reconfigure Box!"); return; } #endif @@ -1504,8 +1518,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s // Close directory if(::closedir(dirhandle) != 0) { - printf("ERROR: closedir on local dir '%s'\n", - localDirDisplay.c_str()); + BOX_ERROR("Failed to close local directory '" << + localDirDisplay << "': " << strerror(errno)); } dirhandle = 0; @@ -1565,10 +1579,10 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s if(local == localFiles.end()) { // Not found -- report - printf("Local file '%s' does not exist, " - "but store file '%s' does.\n", - localPathDisplay.c_str(), - storePathDisplay.c_str()); + BOX_WARNING("Local file '" << + localDirDisplay << "' does not exist, " + "but store file '" << + storePathDisplay << "' does."); rParams.mDifferences ++; } else @@ -1643,20 +1657,21 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s ignoreAttrModTime, fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */)) { - printf("Local file '%s' " - "has different attributes " - "to store file '%s'.\n", - localPathDisplay.c_str(), - storePathDisplay.c_str()); + BOX_WARNING("Local file '" << + localPathDisplay << + "' has different attributes " + "to store file '" << + storePathDisplay << + "'."); rParams.mDifferences ++; if(modifiedAfterLastSync) { rParams.mDifferencesExplainedByModTime ++; - printf("(the file above was modified after the last sync time -- might be reason for difference)\n"); + BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)"); } else if(i->second->HasAttributes()) { - printf("(the file above has had new attributes applied)\n"); + BOX_INFO("(the file above has had new attributes applied)\n"); } } @@ -1722,20 +1737,21 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s // Report if not equal. if(!equal) { - printf("Local file '%s' " + BOX_WARNING("Local file '" << + localPathDisplay << "' " "has different contents " - "to store file '%s'.\n", - localPathDisplay.c_str(), - storePathDisplay.c_str()); + "to store file '" << + storePathDisplay << + "'."); rParams.mDifferences ++; if(modifiedAfterLastSync) { rParams.mDifferencesExplainedByModTime ++; - printf("(the file above was modified after the last sync time -- might be reason for difference)\n"); + BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)"); } else if(i->second->HasAttributes()) { - printf("(the file above has had new attributes applied)\n"); + BOX_INFO("(the file above has had new attributes applied)\n"); } } } @@ -1794,11 +1810,11 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s if(rParams.mpExcludeFiles == 0 || !(rParams.mpExcludeFiles->IsExcluded(localPath))) { - printf("Local file '%s' exists, " - "but store file '%s' " - "does not exist.\n", - localPathDisplay.c_str(), - storePathDisplay.c_str()); + BOX_WARNING("Local file '" << + localPathDisplay << + "' exists, but store file '" << + storePathDisplay << + "' does not."); rParams.mDifferences ++; // Check the file modification time @@ -1809,7 +1825,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s if(FileModificationTime(st) > rParams.mLatestFileUploadTime) { rParams.mDifferencesExplainedByModTime ++; - printf("(the file above was modified after the last sync time -- might be reason for difference)\n"); + BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)"); } } } @@ -1852,19 +1868,19 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s rParams.mpExcludeDirs->IsExcluded(localPath)) { // Not found -- report - printf("Local directory '%s' is excluded, but " - "store directory '%s' still exists.\n", - localPathDisplay.c_str(), - storePathDisplay.c_str()); + BOX_WARNING("Local directory '" << + localPathDisplay << "' is excluded, " + "but store directory '" << + storePathDisplay << "' still exists."); rParams.mDifferences ++; } else if(local == localDirs.end()) { // Not found -- report - printf("Local directory '%s' does not exist, " - "but store directory '%s' does.\n", - localPathDisplay.c_str(), - storePathDisplay.c_str()); + BOX_WARNING("Local directory '" << + localPathDisplay << "' does not exist, " + "but store directory '" << + storePathDisplay << "' does."); rParams.mDifferences ++; } else if(rParams.mpExcludeDirs != NULL && @@ -1908,10 +1924,10 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s // Should this be ignored (ie is excluded)? if(rParams.mpExcludeDirs == 0 || !(rParams.mpExcludeDirs->IsExcluded(localPath))) { - printf("Local directory '%s' exists, but " - "store directory '%s' does not exist.\n", - localPathDisplay.c_str(), - storePathDisplay.c_str()); + BOX_WARNING("Local directory '" << + localPathDisplay << "' exists, but " + "store directory '" << + storePathDisplay << "' does not."); rParams.mDifferences ++; } else @@ -1944,7 +1960,7 @@ void BackupQueries::CommandRestore(const std::vector &args, const b // Check arguments if(args.size() != 2) { - printf("Incorrect usage.\nrestore [-d] [-r] [-i] \n"); + BOX_ERROR("Incorrect usage. restore [-d] [-r] [-i] "); return; } @@ -1959,7 +1975,7 @@ void BackupQueries::CommandRestore(const std::vector &args, const b dirID = ::strtoll(args[0].c_str(), 0, 16); if(dirID == std::numeric_limits::min() || dirID == std::numeric_limits::max() || dirID == 0) { - printf("Not a valid object ID (specified in hex)\n"); + BOX_ERROR("Not a valid object ID (specified in hex)"); return; } } @@ -1982,12 +1998,12 @@ void BackupQueries::CommandRestore(const std::vector &args, const b // Allowable? if(dirID == 0) { - printf("Directory '%s' not found on server\n", args[0].c_str()); + BOX_ERROR("Directory '" << args[0] << "' not found on server"); return; } if(dirID == BackupProtocolClientListDirectory::RootDirectory) { - printf("Cannot restore the root directory -- restore locations individually.\n"); + BOX_ERROR("Cannot restore the root directory -- restore locations individually."); return; } @@ -2023,31 +2039,31 @@ void BackupQueries::CommandRestore(const std::vector &args, const b switch(result) { case Restore_Complete: - printf("Restore complete\n"); + BOX_INFO("Restore complete."); break; case Restore_ResumePossible: - printf("Resume possible -- repeat command with -r flag to resume\n"); + BOX_ERROR("Resume possible -- repeat command with -r flag to resume"); break; case Restore_TargetExists: - printf("The target directory exists. You cannot restore over an existing directory.\n"); + BOX_ERROR("The target directory exists. You cannot restore over an existing directory."); break; #ifdef WIN32 case Restore_TargetPathNotFound: - printf("The target directory path does not exist.\n" + BOX_ERROR("The target directory path does not exist.\n" "To restore to a directory whose parent " - "does not exist, create the parent first.\n"); + "does not exist, create the parent first."); break; #endif case Restore_UnknownError: - printf("Unknown error during restore.\n"); + BOX_ERROR("Unknown error during restore."); break; default: - printf("ERROR: Unknown restore result %d.\n", result); + BOX_ERROR("Unknown restore result " << result << "."); break; } } @@ -2167,7 +2183,7 @@ void BackupQueries::CommandUndelete(const std::vector &args, const // Check arguments if(args.size() != 1) { - printf("Incorrect usage.\nundelete \n"); + BOX_ERROR("Incorrect usage. undelete "); return; } @@ -2185,12 +2201,12 @@ void BackupQueries::CommandUndelete(const std::vector &args, const // Allowable? if(dirID == 0) { - printf("Directory '%s' not found on server\n", args[0].c_str()); + BOX_ERROR("Directory '" << args[0] << "' not found on server."); return; } if(dirID == BackupProtocolClientListDirectory::RootDirectory) { - printf("Cannot undelete the root directory.\n"); + BOX_ERROR("Cannot undelete the root directory."); return; } diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index 9cc3eb1a..98726843 100644 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -12,8 +12,14 @@ #ifdef HAVE_UNISTD_H #include #endif + +#include #include -#include + +#ifdef HAVE_SYS_TYPES_H + #include +#endif + #ifdef HAVE_LIBREADLINE #ifdef HAVE_READLINE_READLINE_H #include @@ -168,7 +174,8 @@ int main(int argc, const char *argv[]) logFile = ::fopen(optarg, "w"); if(logFile == 0) { - printf("Can't open log file '%s'\n", optarg); + BOX_ERROR("Failed to open log file '" << + optarg << "': " << strerror(errno)); } break; @@ -201,14 +208,14 @@ int main(int argc, const char *argv[]) { if (!SetConsoleCP(CP_UTF8)) { - fprintf(stderr, "Failed to set input codepage: " - "error %d\n", GetLastError()); + BOX_ERROR("Failed to set input codepage: " << + GetErrorMessage(GetLastError())); } if (!SetConsoleOutputCP(CP_UTF8)) { - fprintf(stderr, "Failed to set output codepage: " - "error %d\n", GetLastError()); + BOX_ERROR("Failed to set output codepage: " << + GetErrorMessage(GetLastError())); } // enable input of Unicode characters @@ -222,8 +229,7 @@ int main(int argc, const char *argv[]) #endif // WIN32 // Read in the configuration file - if(!quiet) printf("Using configuration file %s\n", - configFilename.c_str()); + if(!quiet) BOX_INFO("Using configuration file " << configFilename); std::string errs; std::auto_ptr config( @@ -232,7 +238,7 @@ int main(int argc, const char *argv[]) if(config.get() == 0 || !errs.empty()) { - printf("Invalid configuration file:\n%s", errs.c_str()); + BOX_FATAL("Invalid configuration file: " << errs); return 1; } // Easier coding @@ -252,12 +258,12 @@ int main(int argc, const char *argv[]) BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile").c_str()); // 2. Connect to server - if(!quiet) printf("Connecting to store...\n"); + if(!quiet) BOX_INFO("Connecting to store..."); SocketStreamTLS socket; socket.Open(tlsContext, Socket::TypeINET, conf.GetKeyValue("StoreHostname").c_str(), BOX_PORT_BBSTORED); // 3. Make a protocol, and handshake - if(!quiet) printf("Handshake with store...\n"); + if(!quiet) BOX_INFO("Handshake with store..."); BackupProtocolClient connection(socket); connection.Handshake(); @@ -268,7 +274,7 @@ int main(int argc, const char *argv[]) } // 4. Log in to server - if(!quiet) printf("Login to store...\n"); + if(!quiet) BOX_INFO("Login to store..."); // Check the version of the server { std::auto_ptr serverVersion(connection.QueryVersion(BACKUP_STORE_SERVER_VERSION)); @@ -345,9 +351,9 @@ int main(int argc, const char *argv[]) #endif // Done... stop nicely - if(!quiet) printf("Logging off...\n"); + if(!quiet) BOX_INFO("Logging off..."); connection.QueryFinished(); - if(!quiet) printf("Session finished.\n"); + if(!quiet) BOX_INFO("Session finished."); // Return code returnCode = context.GetReturnCode(); diff --git a/bin/bbstoreaccounts/bbstoreaccounts.cpp b/bin/bbstoreaccounts/bbstoreaccounts.cpp index 567c5bbc..8a00e3b9 100644 --- a/bin/bbstoreaccounts/bbstoreaccounts.cpp +++ b/bin/bbstoreaccounts/bbstoreaccounts.cpp @@ -37,12 +37,13 @@ void CheckSoftHardLimits(int64_t SoftLimit, int64_t HardLimit) { if(SoftLimit >= HardLimit) { - printf("ERROR: Soft limit must be less than the hard limit.\n"); + BOX_FATAL("Soft limit must be less than the hard limit."); exit(1); } if(SoftLimit > ((HardLimit * MAX_SOFT_LIMIT_SIZE) / 100)) { - printf("ERROR: Soft limit must be no more than %d%% of the hard limit.\n", MAX_SOFT_LIMIT_SIZE); + BOX_FATAL("Soft limit must be no more than " << + MAX_SOFT_LIMIT_SIZE << "% of the hard limit."); exit(1); } } @@ -53,7 +54,7 @@ int BlockSizeOfDiscSet(int DiscSet) RaidFileController &controller(RaidFileController::GetController()); if(DiscSet < 0 || DiscSet >= controller.GetNumDiscSets()) { - printf("Disc set %d does not exist\n", DiscSet); + BOX_FATAL("Disc set " << DiscSet << " does not exist."); exit(1); } @@ -89,7 +90,7 @@ int64_t SizeStringToBlocks(const char *string, int DiscSet) int64_t number = strtol(string, &endptr, 0); if(endptr == string || number == LONG_MIN || number == LONG_MAX) { - printf("%s is an invalid number\n", string); + BOX_FATAL("'" << string << "' is not a valid number."); exit(1); } @@ -116,7 +117,8 @@ int64_t SizeStringToBlocks(const char *string, int DiscSet) break; default: - printf("%s has an invalid units specifier\nUse B for blocks, M for Mb, G for Gb, eg 2Gb\n", string); + BOX_FATAL(string << " has an invalid units specifier " + "(use B for blocks, M for Mb, G for Gb, eg 2Gb)"); exit(1); break; } @@ -143,7 +145,8 @@ bool GetWriteLockOnAccount(NamedLock &rLock, const std::string rRootDir, int Dis if(!gotLock) { // Couldn't lock the account -- just stop now - printf("Couldn't lock the account -- did not change the limits\nTry again later.\n"); + BOX_ERROR("Failed to lock the account, did not change limits. " + "Try again later."); return 1; } @@ -168,7 +171,8 @@ int SetLimit(Configuration &rConfig, const std::string &rUsername, int32_t ID, c // Already exists? if(!db->EntryExists(ID)) { - printf("Account %x does not exist\n", ID); + BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << + " does not exist."); return 1; } @@ -198,7 +202,9 @@ int SetLimit(Configuration &rConfig, const std::string &rUsername, int32_t ID, c // Save info->Save(); - printf("Limits on account 0x%08x changed to %lld soft, %lld hard\n", ID, softlimit, hardlimit); + BOX_NOTICE("Limits on account " << BOX_FORMAT_ACCOUNT(ID) << + " changed to " << softlimit << " soft, " << + hardlimit << " hard."); return 0; } @@ -211,7 +217,8 @@ int AccountInfo(Configuration &rConfig, int32_t ID) // Exists? if(!db->EntryExists(ID)) { - printf("Account %x does not exist\n", ID); + BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << + " does not exist."); return 1; } @@ -241,11 +248,12 @@ int DeleteAccount(Configuration &rConfig, const std::string &rUsername, int32_t // Check user really wants to do this if(AskForConfirmation) { - ::printf("Really delete account %08x?\n(type 'yes' to confirm)\n", ID); + BOX_WARNING("Really delete account " << + BOX_FORMAT_ACCOUNT(ID) << "? (type 'yes' to confirm)"); char response[256]; if(::fgets(response, sizeof(response), stdin) == 0 || ::strcmp(response, "yes\n") != 0) { - printf("Deletion cancelled\n"); + BOX_NOTICE("Deletion cancelled."); return 0; } } @@ -256,7 +264,8 @@ int DeleteAccount(Configuration &rConfig, const std::string &rUsername, int32_t // Exists? if(!db->EntryExists(ID)) { - printf("Account %x does not exist\n", ID); + BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << + " does not exist."); return 1; } @@ -318,24 +327,27 @@ int DeleteAccount(Configuration &rConfig, const std::string &rUsername, int32_t toDelete.push_back((*i) + DIRECTORY_SEPARATOR + rootDir); } } - + + int retcode = 0; + // Thirdly, delete the directories... for(std::vector::const_iterator d(toDelete.begin()); d != toDelete.end(); ++d) { - ::printf("Deleting store directory %s...\n", (*d).c_str()); + BOX_NOTICE("Deleting store directory " << (*d) << "..."); // Just use the rm command to delete the files std::string cmd("rm -rf "); cmd += *d; // Run command if(::system(cmd.c_str()) != 0) { - ::printf("ERROR: Deletion of %s failed.\n(when cleaning up, remember to delete all raid directories)\n", (*d).c_str()); - return 1; + BOX_ERROR("Failed to delete files in " << (*d) << + ", delete them manually."); + retcode = 1; } } // Success! - return 0; + return retcode; } int CheckAccount(Configuration &rConfig, const std::string &rUsername, int32_t ID, bool FixErrors, bool Quiet) @@ -346,7 +358,8 @@ int CheckAccount(Configuration &rConfig, const std::string &rUsername, int32_t I // Exists? if(!db->EntryExists(ID)) { - printf("Account %x does not exist\n", ID); + BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << + " does not exist."); return 1; } @@ -381,7 +394,8 @@ int CreateAccount(Configuration &rConfig, const std::string &rUsername, int32_t // Already exists? if(db->EntryExists(ID)) { - printf("Account %x already exists\n", ID); + BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << + " already exists."); return 1; } @@ -389,7 +403,7 @@ int CreateAccount(Configuration &rConfig, const std::string &rUsername, int32_t BackupStoreAccounts acc(*db); acc.Create(ID, DiscNumber, SoftLimit, HardLimit, rUsername); - printf("Account %x created\n", ID); + BOX_NOTICE("Account " << BOX_FORMAT_ACCOUNT(ID) << " created."); return 0; } @@ -444,7 +458,8 @@ int main(int argc, const char *argv[]) if(config.get() == 0 || !errs.empty()) { - printf("Invalid configuration file:\n%s", errs.c_str()); + BOX_ERROR("Invalid configuration file " << configFilename << + ":" << errs); } // Get the user under which the daemon runs @@ -484,7 +499,8 @@ int main(int argc, const char *argv[]) if(argc < 5 || ::sscanf(argv[2], "%d", &discnum) != 1) { - printf("create requires raid file disc number, soft and hard limits\n"); + BOX_ERROR("create requires raid file disc number, " + "soft and hard limits."); return 1; } @@ -506,7 +522,7 @@ int main(int argc, const char *argv[]) // Change the limits on this account if(argc < 4) { - printf("setlimit requires soft and hard limits\n"); + BOX_ERROR("setlimit requires soft and hard limits."); return 1; } @@ -540,7 +556,7 @@ int main(int argc, const char *argv[]) } else { - ::printf("Unknown option %s.\n", argv[o]); + BOX_ERROR("Unknown option " << argv[o] << "."); return 2; } } @@ -550,7 +566,7 @@ int main(int argc, const char *argv[]) } else { - printf("Unknown command '%s'\n", argv[0]); + BOX_ERROR("Unknown command '" << argv[0] << "'."); return 1; } diff --git a/lib/backupclient/BackupClientRestore.cpp b/lib/backupclient/BackupClientRestore.cpp index 92853624..3c03c87c 100644 --- a/lib/backupclient/BackupClientRestore.cpp +++ b/lib/backupclient/BackupClientRestore.cpp @@ -260,7 +260,11 @@ static int BackupClientRestoreDir(BackupProtocolClient &rConnection, int64_t Dir 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) { BOX_ERROR("Failed to delete file " << diff --git a/lib/backupstore/BackupStoreCheck.cpp b/lib/backupstore/BackupStoreCheck.cpp index 16eeecf9..176ece8f 100644 --- a/lib/backupstore/BackupStoreCheck.cpp +++ b/lib/backupstore/BackupStoreCheck.cpp @@ -102,7 +102,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) } @@ -110,41 +110,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(); @@ -152,7 +154,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(); @@ -160,29 +162,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"); } } @@ -304,7 +317,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; } } @@ -336,7 +352,7 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID) // 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; } @@ -378,9 +394,9 @@ void BackupStoreCheck::CheckObjectsDir(int64_t StartID) if(!fileOK) { // Unexpected or bad file, delete it - ::printf("Spurious file %s" DIRECTORY_SEPARATOR "%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) { @@ -401,7 +417,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) { @@ -509,7 +527,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; } @@ -596,7 +614,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; } @@ -622,7 +642,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 @@ -630,8 +654,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 { @@ -645,13 +673,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 @@ -670,7 +698,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())); } } } @@ -686,7 +714,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."); } } @@ -729,7 +757,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/BackupStoreCheck2.cpp b/lib/backupstore/BackupStoreCheck2.cpp index 7bc9a109..9c6f2452 100644 --- a/lib/backupstore/BackupStoreCheck2.cpp +++ b/lib/backupstore/BackupStoreCheck2.cpp @@ -47,7 +47,7 @@ void BackupStoreCheck::CheckRoot() } else { - ::printf("Root directory doesn't exist\n"); + BOX_WARNING("Root directory doesn't exist"); ++mNumberErrorsFound; @@ -118,7 +118,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? @@ -147,7 +147,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) @@ -229,11 +229,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 */); @@ -300,7 +304,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; } } @@ -524,7 +528,7 @@ void BackupStoreCheck::WriteNewStoreInfo() } catch(...) { - ::printf("Load of existing store info failed, regenerating.\n"); + BOX_WARNING("Load of existing store info failed, regenerating."); ++mNumberErrorsFound; } @@ -551,7 +555,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) { @@ -559,7 +563,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 @@ -586,7 +590,7 @@ void BackupStoreCheck::WriteNewStoreInfo() if(mFixErrors) { info->Save(); - ::printf("New store info file written successfully.\n"); + BOX_NOTICE("New store info file written successfully."); } } diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp index a99b2072..e9b0e681 100644 --- a/lib/common/DebugMemLeakFinder.cpp +++ b/lib/common/DebugMemLeakFinder.cpp @@ -374,7 +374,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"); } } diff --git a/lib/common/Logging.cpp b/lib/common/Logging.cpp index eee05ba3..d22db238 100644 --- a/lib/common/Logging.cpp +++ b/lib/common/Logging.cpp @@ -243,6 +243,23 @@ bool Console::Log(Log::Level level, const std::string& rFile, { 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; @@ -272,8 +289,29 @@ bool Syslog::Log(Log::Level level, const std::string& rFile, case Log::TRACE: /* fall through */ case Log::EVERYTHING: syslogLevel = LOG_DEBUG; break; } - - syslog(syslogLevel, "%s", rMessage.c_str()); + + 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; } diff --git a/lib/crypto/Random.cpp b/lib/crypto/Random.cpp index 30049ff7..1d6a07f0 100644 --- a/lib/crypto/Random.cpp +++ b/lib/crypto/Random.cpp @@ -34,7 +34,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/raidfile/RaidFileController.cpp b/lib/raidfile/RaidFileController.cpp index 81307103..0cc2ede7 100644 --- a/lib/raidfile/RaidFileController.cpp +++ b/lib/raidfile/RaidFileController.cpp @@ -102,8 +102,7 @@ void RaidFileController::Initialise(const std::string& rConfigFilename) 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/server/SSLLib.cpp b/lib/server/SSLLib.cpp index 6082a9f4..e9c990b9 100644 --- a/lib/server/SSLLib.cpp +++ b/lib/server/SSLLib.cpp @@ -49,7 +49,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 } diff --git a/test/bbackupd/testfiles/extcheck1.pl.in b/test/bbackupd/testfiles/extcheck1.pl.in index 955515b9..2a7c0e9a 100755 --- a/test/bbackupd/testfiles/extcheck1.pl.in +++ b/test/bbackupd/testfiles/extcheck1.pl.in @@ -3,7 +3,7 @@ use strict; my $flags = $ARGV[0] or ""; -unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit|") +unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit 2>&1 |") { print "Couldn't open compare utility\n"; exit 2; diff --git a/test/bbackupd/testfiles/extcheck2.pl.in b/test/bbackupd/testfiles/extcheck2.pl.in index bfa6f253..c79bf414 100755 --- a/test/bbackupd/testfiles/extcheck2.pl.in +++ b/test/bbackupd/testfiles/extcheck2.pl.in @@ -3,7 +3,7 @@ use strict; my $flags = $ARGV[0] or ""; -unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit|") +unless(open IN,"../../bin/bbackupquery/bbackupquery -q -c testfiles/bbackupd.conf -l testfiles/query4.log \"compare -ac$flags\" quit 2>&1 |") { print "Couldn't open compare utility\n"; exit 2; -- cgit v1.2.3 From 8738a529ddeb5fc2d2ec56a9b722c1ef56dc684c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Aug 2007 19:39:42 +0000 Subject: Fix documentation comments on ExcludeDir/AlwaysInclude. Fix warning about mounted filesystems to reflect current reality. --- bin/bbackupd/bbackupd-config.in | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/bin/bbackupd/bbackupd-config.in b/bin/bbackupd/bbackupd-config.in index c06b818d..86a094d5 100755 --- a/bin/bbackupd/bbackupd-config.in +++ b/bin/bbackupd/bbackupd-config.in @@ -123,9 +123,9 @@ __E print ' ',$_,"\n" for(@tobackup); print <<__E; -Note: If other file systems are mounted inside these directories, then problems may occur -with files on the store server being renamed incorrectly. This will cause efficiency -problems, but not affect the integrity of the backups. +Note: If other file systems are mounted inside these directories, then +they will NOT be backed up. You will have to create separate locations for +any mounted filesystems inside your backup locations. WARNING: Directories not checked against mountpoints. Check mounted filesystems manually. @@ -425,7 +425,24 @@ Server # files, except one MP3 file in particular. # # In general, Exclude excludes a file or directory, unless the directory is -# explicitly mentioned in a AlwaysInclude directive. +# explicitly mentioned in a AlwaysInclude directive. However, Box Backup +# does NOT scan inside excluded directories and will never back up an +# AlwaysIncluded file or directory inside an excluded directory or any +# subdirectory thereof. +# +# To back up a directory inside an excluded directory, use a configuration +# like this, to ensure that each directory in the path to the important +# files is included, but none of their contents will be backed up except +# the directories futher down that path to the important one. +# +# ExcludeDirsRegex = /home/user/bigfiles/.* +# ExcludeFilesRegex = /home/user/bigfiles/.* +# AlwaysIncludeDir = /home/user/bigfiles/path +# AlwaysIncludeDir = /home/user/bigfiles/path/to +# AlwaysIncludeDir = /home/user/bigfiles/path/important +# AlwaysIncludeDir = /home/user/bigfiles/path/important/files +# AlwaysIncludeDirsRegex = /home/user/bigfiles/path/important/files/.* +# AlwaysIncludeFilesRegex = /home/user/bigfiles/path/important/files/.* # # If a directive ends in Regex, then it is a regular expression rather than a # explicit full pathname. See -- cgit v1.2.3 From b75e036cf14bb6caceb6f76bbda06659619f1f41 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Aug 2007 21:33:28 +0000 Subject: Fix quiet-build makefiles to work on BSDs --- infrastructure/makebuildenv.pl.in | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/infrastructure/makebuildenv.pl.in b/infrastructure/makebuildenv.pl.in index c990c900..b5d462d9 100755 --- a/infrastructure/makebuildenv.pl.in +++ b/infrastructure/makebuildenv.pl.in @@ -544,6 +544,32 @@ DEPENDMAKEFLAGS = VARIENT = DEBUG .endif +__E + + if ($bsd_make) + { + print MAKE <<__E; +.ifdef V +HIDE = +_CXX = \$(CXX) +_LINK = \$(CXX) +_WINDRES = \$(WINDRES) +_AR = \$(AR) +_RANLIB = \$(RANLIB) +.else +HIDE = @ +_CXX = @ echo "[CXX] " \$(*F) && \$(CXX) +_LINK = @ echo "[LINK] " \$(*F) && \$(CXX) +_WINDRES = @ echo "[WINDRES]" \$(*F) && \$(WINDRES) +_AR = @ echo "[AR] " \$(*F) && \$(AR) +_RANLIB = @ echo "[RANLIB] " \$(*F) && \$(RANLIB) +.endif + +__E + } + else + { + print MAKE <<__E; HIDE = \$(if \$(V),,@) _CXX = \$(if \$(V),\$(CXX), @ echo "[CXX] \$<" && \$(CXX)) _LINK = \$(if \$(V),\$(CXX), @ echo "[LINK] \$@" && \$(CXX)) @@ -552,6 +578,7 @@ _AR = \$(if \$(V),\$(AR), @ echo "[AR] \$@" && \$(AR)) _RANLIB = \$(if \$(V),\$(RANLIB), @ echo "[RANLIB] \$@" && \$(RANLIB)) __E + } # read directory opendir DIR,$mod; -- cgit v1.2.3 From a1ce6b9d022e30bf0974906fefc9d1d2ffe2e067 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 30 Aug 2007 18:48:14 +0000 Subject: Fix $bsd_make to not be defined on GNU/kFreeBSD, which uses GNU Make. --- infrastructure/BoxPlatform.pm.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in index b034eed1..8c084090 100644 --- a/infrastructure/BoxPlatform.pm.in +++ b/infrastructure/BoxPlatform.pm.in @@ -27,7 +27,9 @@ BEGIN $build_os = 'CYGWIN' if $build_os =~ m/CYGWIN/; $make_command = ($build_os eq 'Darwin') ? 'bsdmake' : ($build_os eq 'SunOS') ? 'gmake' : 'make'; - $bsd_make = ($build_os ne 'Linux' && $build_os ne 'CYGWIN' && $build_os ne "SunOS"); + + $bsd_make = ($build_os ne 'Linux' && $build_os ne 'CYGWIN' && + $build_os ne "SunOS" && $build_os ne 'GNU/kFreeBSD'); # blank extra flags by default $platform_compile_line_extra = '@CPPFLAGS@ @CXXFLAGS@ @CXXFLAGS_STRICT@'; -- cgit v1.2.3 From bc121daa5ce85a575ba0158a923077b068d5dd24 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 31 Aug 2007 18:43:59 +0000 Subject: Update the comments in the generated configuration file to better describe the available options and their units. --- bin/bbackupd/bbackupd-config.in | 58 +++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/bin/bbackupd/bbackupd-config.in b/bin/bbackupd/bbackupd-config.in index 86a094d5..cc8cc293 100755 --- a/bin/bbackupd/bbackupd-config.in +++ b/bin/bbackupd/bbackupd-config.in @@ -302,21 +302,24 @@ if($backup_mode eq 'lazy') # lazy mode configuration print CONFIG <<__E; -# A scan of the local discs will be made once an hour (approximately). -# To avoid cycles of load on the server, this time is randomly adjusted by a small -# percentage as the daemon runs. +# The number of seconds between backup runs under normal conditions. A scan To +# avoid cycles of load on the server, this time is randomly adjusted by a +# small percentage as the daemon runs. UpdateStoreInterval = 3600 -# A file must have been modified at least 6 hours ago before it will be uploaded. +# The minimum age of a file, in seconds, that will be uploaded. Avoids +# repeated uploads of a file which is constantly being modified. MinimumFileAge = 21600 -# If a file is modified repeated, it won't be uploaded immediately in case it's modified again. -# However, it should be uploaded eventually. This is how long we should wait after first noticing -# a change. (1 day) +# If a file is modified repeated, it won't be uploaded immediately in case +# it's modified again, due to the MinimumFileAge specified above. However, it +# should be uploaded eventually even if it is being modified repeatedly. This +# is how long we should wait, in seconds, after first noticing a change. +# (86400 seconds = 1 day) MaxUploadWait = 86400 @@ -352,13 +355,17 @@ FileTrackingSizeThreshold = 65535 DiffingUploadSizeThreshold = 8192 -# The limit on how much time is spent diffing files. Most files shouldn't take very long, -# but if you have really big files you can use this to limit the time spent diffing them. +# The limit on how much time is spent diffing files, in seconds. Most files +# shouldn't take very long, but if you have really big files you can use this +# to limit the time spent diffing them. +# # * Reduce if you are having problems with processor usage. -# * Increase if you have large files, and think the upload of changes is too large and want -# to spend more time searching for unchanged blocks. +# +# * Increase if you have large files, and think the upload of changes is too +# large and you want bbackupd to spend more time searching for unchanged +# blocks. -MaximumDiffingTime = 20 +MaximumDiffingTime = 120 # Uncomment this line to see exactly what the daemon is going when it's connected to the server. @@ -366,14 +373,20 @@ MaximumDiffingTime = 20 # ExtendedLogging = yes -# Use this to temporarily stop bbackupd from syncronising or connecting to the store. -# This specifies a program or script script which is run just before each sync, and ideally -# the full path to the interpreter. It will be run as the same user bbackupd is running as, -# usually root. -# The script prints either "now" or a number to STDOUT (and a terminating newline, no quotes). -# If the result was "now", then the sync will happen. If it's a number, then the script will -# be asked again in that number of seconds. -# For example, you could use this on a laptop to only backup when on a specific network. +# This specifies a program or script script which is run just before each +# sync, and ideally the full path to the interpreter. It will be run as the +# same user bbackupd is running as, usually root. +# +# The script must output (print) either "now" or a number to STDOUT (and a +# terminating newline, no quotes). +# +# If the result was "now", then the sync will happen. If it's a number, then +# no backup will happen for that number of seconds (bbackupd will pause) and +# then the script will be run again. +# +# Use this to temporarily stop bbackupd from syncronising or connecting to the +# store. For example, you could use this on a laptop to only backup when on a +# specific network, or when it has a working Internet connection. # SyncAllowScript = /path/to/intepreter/or/exe script-name parameters etc @@ -396,7 +409,7 @@ Server PidFile = /var/run/bbackupd.pid } -# + # BackupLocations specifies which locations on disc should be backed up. Each # directory is in the format # @@ -444,13 +457,12 @@ Server # AlwaysIncludeDirsRegex = /home/user/bigfiles/path/important/files/.* # AlwaysIncludeFilesRegex = /home/user/bigfiles/path/important/files/.* # -# If a directive ends in Regex, then it is a regular expression rather than a +# If a directive ends in Regex, then it is a regular expression rather than a # explicit full pathname. See # # man 7 re_format # # for the regex syntax on your platform. -# BackupLocations { -- cgit v1.2.3 From 0199687f46d3c51df525feb4fe82bcf42eb4f8d3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 1 Sep 2007 13:26:31 +0000 Subject: Log more detailed errors when the server returns an error while uploading a file. (merges [1781]) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 19 ++++---- bin/bbackupd/BackupClientDirectoryRecord.h | 4 ++ bin/bbackupd/BackupDaemon.h | 65 ++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 8cc7e78e..df62c59c 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -887,9 +887,7 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP { // Connection errors should just be passed on to the main handler, retries // would probably just cause more problems. - rParams.GetProgressNotifier() - .NotifyFileUploadException( - this, filename, e); + // Already logged by UploadFile throw; } catch(BoxException &e) @@ -1386,12 +1384,17 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn { // Check and see what error the protocol has -- as it might be an error... int type, subtype; - if(connection.GetLastError(type, subtype) - && type == BackupProtocolClientError::ErrorType - && subtype == BackupProtocolClientError::Err_StorageLimitExceeded) + if(connection.GetLastError(type, subtype)) { - // The hard limit was exceeded on the server, notify! - rParams.mrDaemon.NotifySysadmin(BackupDaemon::NotifyEvent_StoreFull); + if(type == BackupProtocolClientError::ErrorType + && subtype == BackupProtocolClientError::Err_StorageLimitExceeded) + { + // The hard limit was exceeded on the server, notify! + rParams.mrDaemon.NotifySysadmin(BackupDaemon::NotifyEvent_StoreFull); + } + rParams.GetProgressNotifier() + .NotifyFileUploadServerError( + this, rFilename, type, subtype); } } diff --git a/bin/bbackupd/BackupClientDirectoryRecord.h b/bin/bbackupd/BackupClientDirectoryRecord.h index 39797466..9e4dda7a 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.h +++ b/bin/bbackupd/BackupClientDirectoryRecord.h @@ -78,6 +78,10 @@ class ProgressNotifier const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath, const BoxException& rException) = 0; + virtual void NotifyFileUploadServerError( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + int type, int subtype) = 0; virtual void NotifyFileUploading( const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath) = 0; diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 7df62c95..47ae1d55 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -21,6 +21,7 @@ #include "SocketListen.h" #include "SocketStream.h" #include "Logging.h" +#include "autogen_BackupProtocolClient.h" #ifdef WIN32 #include "WinNamedPipeStream.h" @@ -304,6 +305,70 @@ public: << "/" << rException.GetSubType() << ")"); } } + virtual void NotifyFileUploadServerError( + const BackupClientDirectoryRecord* pDirRecord, + const std::string& rLocalPath, + int type, int subtype) + { + std::ostringstream msgs; + if (type != BackupProtocolClientError::ErrorType) + { + msgs << "unknown error type " << type; + } + else + { + switch(subtype) + { + case BackupProtocolClientError::Err_WrongVersion: + msgs << "WrongVersion"; + break; + case BackupProtocolClientError::Err_NotInRightProtocolPhase: + msgs << "NotInRightProtocolPhase"; + break; + case BackupProtocolClientError::Err_BadLogin: + msgs << "BadLogin"; + break; + case BackupProtocolClientError::Err_CannotLockStoreForWriting: + msgs << "CannotLockStoreForWriting"; + break; + case BackupProtocolClientError::Err_SessionReadOnly: + msgs << "SessionReadOnly"; + break; + case BackupProtocolClientError::Err_FileDoesNotVerify: + msgs << "FileDoesNotVerify"; + break; + case BackupProtocolClientError::Err_DoesNotExist: + msgs << "DoesNotExist"; + break; + case BackupProtocolClientError::Err_DirectoryAlreadyExists: + msgs << "DirectoryAlreadyExists"; + break; + case BackupProtocolClientError::Err_CannotDeleteRoot: + msgs << "CannotDeleteRoot"; + break; + case BackupProtocolClientError::Err_TargetNameExists: + msgs << "TargetNameExists"; + break; + case BackupProtocolClientError::Err_StorageLimitExceeded: + msgs << "StorageLimitExceeded"; + break; + case BackupProtocolClientError::Err_DiffFromFileDoesNotExist: + msgs << "DiffFromFileDoesNotExist"; + break; + case BackupProtocolClientError::Err_DoesNotExistInDirectory: + msgs << "DoesNotExistInDirectory"; + break; + case BackupProtocolClientError::Err_PatchConsistencyError: + msgs << "PatchConsistencyError"; + break; + default: + msgs << "unknown error subtype " << subtype; + } + } + + BOX_ERROR("Failed to upload file: " << rLocalPath + << ": server error: " << msgs.str()); + } virtual void NotifyFileUploading( const BackupClientDirectoryRecord* pDirRecord, const std::string& rLocalPath) -- cgit v1.2.3 From f43a65d77ecccdc5e49d4dbfdbb498a7e0799afa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 1 Sep 2007 15:11:30 +0000 Subject: Use ProgressNotifier to report upload exceptions (merges last part of [1342]) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index df62c59c..f97ff315 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -887,7 +887,9 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP { // Connection errors should just be passed on to the main handler, retries // would probably just cause more problems. - // Already logged by UploadFile + rParams.GetProgressNotifier() + .NotifyFileUploadException( + this, filename, e); throw; } catch(BoxException &e) -- cgit v1.2.3 From 86deff6eb3b2308ea88d78b2c4eba1208d9abfb4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 1 Sep 2007 16:58:15 +0000 Subject: Use sigset() instead of signal() to ensure that SysV systems (like Solaris) will not clear our signal handler after firing it. --- lib/common/Timer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/common/Timer.cpp b/lib/common/Timer.cpp index fe565c21..a032f330 100644 --- a/lib/common/Timer.cpp +++ b/lib/common/Timer.cpp @@ -39,7 +39,7 @@ void Timers::Init() InitTimer(); SetTimerHandler(Timers::SignalHandler); #else - sighandler_t oldHandler = ::signal(SIGALRM, + sighandler_t oldHandler = ::sigset(SIGALRM, Timers::SignalHandler); ASSERT(oldHandler == 0); #endif // WIN32 && !PLATFORM_CYGWIN @@ -70,7 +70,7 @@ void Timers::Cleanup() int result = ::setitimer(ITIMER_REAL, &timeout, NULL); ASSERT(result == 0); - sighandler_t oldHandler = ::signal(SIGALRM, NULL); + sighandler_t oldHandler = ::sigset(SIGALRM, NULL); ASSERT(oldHandler == Timers::SignalHandler); #endif // WIN32 && !PLATFORM_CYGWIN @@ -146,8 +146,11 @@ void Timers::Reschedule() } #ifndef WIN32 - if (::signal(SIGALRM, Timers::SignalHandler) != Timers::SignalHandler) + void (*oldhandler)(int) = ::sigset(SIGALRM, Timers::SignalHandler); + if (oldhandler != Timers::SignalHandler) { + printf("Signal handler was %p, expected %p\n", + oldhandler, Timers::SignalHandler); THROW_EXCEPTION(CommonException, Internal) } #endif -- cgit v1.2.3 From d2d2c47f0a4261fe53c1b3e5faba45f436b32e9e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 1 Sep 2007 20:56:26 +0000 Subject: Call the notify script whenever backup starts or finishes, but the default script does nothing in this case. Requested by scott . --- bin/bbackupd/BackupDaemon.cpp | 35 ++++++++++++++++++++++++++++------ bin/bbackupd/BackupDaemon.h | 2 ++ bin/bbackupd/bbackupd-config.in | 42 +++++++++++++++++++++++++++++------------ 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 4d5b6fa4..46a76304 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -903,6 +903,9 @@ void BackupDaemon::Run2() // Delete any unused directories? DeleteUnusedRootDirEntries(clientContext); + // Notify administrator + NotifySysadmin(NotifyEvent_BackupStart); + // Go through the records, syncing them for(std::vector::const_iterator i(mLocations.begin()); @@ -986,6 +989,9 @@ void BackupDaemon::Run2() // Log BOX_NOTICE("Finished scan of local files"); + // Notify administrator + NotifySysadmin(NotifyEvent_BackupFinish); + // -------------------------------------------------------------------------------------------- // We had a successful backup, save the store @@ -2231,7 +2237,8 @@ void BackupDaemon::TouchFileInWorkingDir(const char *Filename) // // Function // Name: BackupDaemon::NotifySysadmin(int) -// Purpose: Run the script to tell the sysadmin about events which need attention. +// Purpose: Run the script to tell the sysadmin about events +// which need attention. // Created: 25/2/04 // // -------------------------------------------------------------------------- @@ -2242,26 +2249,40 @@ void BackupDaemon::NotifySysadmin(int Event) "store-full", "read-error", "backup-error", + "backup-start", + "backup-finish", 0 }; + BOX_TRACE("sizeof(sEventNames) == " << sizeof(sEventNames)); + BOX_TRACE("sizeof(*sEventNames) == " << sizeof(*sEventNames)); + BOX_TRACE("NotifyEvent__MAX == " << NotifyEvent__MAX); + ASSERT((sizeof(sEventNames)/sizeof(*sEventNames)) == NotifyEvent__MAX + 1); + BOX_TRACE("BackupDaemon::NotifySysadmin() called, event = " << sEventNames[Event]); if(Event < 0 || Event >= NotifyEvent__MAX) { - THROW_EXCEPTION(BackupStoreException, BadNotifySysadminEventCode); + THROW_EXCEPTION(BackupStoreException, + BadNotifySysadminEventCode); } // Don't send lots of repeated messages - if(mNotificationsSent[Event]) + if(mNotificationsSent[Event] && + Event != NotifyEvent_BackupStart && + Event != NotifyEvent_BackupFinish) { + BOX_WARNING("Suppressing duplicate notification about " << + sEventNames[Event]); return; } // Is there a notifation script? const Configuration &conf(GetConfiguration()); - if(!conf.KeyExists("NotifyScript")) + if(!conf.KeyExists("NotifyScript") && + Event != NotifyEvent_BackupStart && + Event != NotifyEvent_BackupFinish) { // Log, and then return BOX_ERROR("Not notifying administrator about event " @@ -2271,7 +2292,8 @@ void BackupDaemon::NotifySysadmin(int Event) } // Script to run - std::string script(conf.GetKeyValue("NotifyScript") + ' ' + sEventNames[Event]); + std::string script(conf.GetKeyValue("NotifyScript") + ' ' + + sEventNames[Event]); // Log what we're about to do BOX_NOTICE("About to notify administrator about event " @@ -2285,7 +2307,8 @@ void BackupDaemon::NotifySysadmin(int Event) << script << "')"); } - // Flag that this is done so the administrator isn't constantly bombarded with lots of errors + // Flag that this is done so the administrator isn't constantly + // bombarded with lots of errors mNotificationsSent[Event] = true; } diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index 47ae1d55..ab64bbfa 100644 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -85,6 +85,8 @@ public: NotifyEvent_StoreFull = 0, NotifyEvent_ReadError, NotifyEvent_BackupError, + NotifyEvent_BackupStart, + NotifyEvent_BackupFinish, NotifyEvent__MAX // When adding notifications, remember to add strings to NotifySysadmin() }; diff --git a/bin/bbackupd/bbackupd-config.in b/bin/bbackupd/bbackupd-config.in index cc8cc293..5dbd2dd9 100755 --- a/bin/bbackupd/bbackupd-config.in +++ b/bin/bbackupd/bbackupd-config.in @@ -211,12 +211,24 @@ $sendmail = 'sendmail' if $sendmail !~ m/\S/; print NOTIFY <<__EOS; #!/bin/sh +# This script is run whenever bbackupd changes state or encounters a +# problem which requires the system administrator to assist: +# +# 1) The store is full, and no more data can be uploaded. +# 2) Some files or directories were not readable. +# 3) A backup run starts or finishes. +# +# The default script emails the system administrator, except for backups +# starting and stopping, where it does nothing. + SUBJECT="BACKUP PROBLEM on host $hostname" SENDTO="$current_username" -if [ \$1 = store-full ] -then -$sendmail \$SENDTO <" >&2 + exit 2 +elif [ "\$1" = store-full ]; then + $sendmail \$SENDTO < Date: Sat, 1 Sep 2007 23:01:43 +0000 Subject: Fix error message when failing to create remote directory for location. --- bin/bbackupd/BackupDaemon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index 46a76304..cfeb320e 100644 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -1804,7 +1804,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con catch (BoxException &e) { BOX_ERROR("Failed to create remote " - "directory '/" << dirname << + "directory '/" << ploc->mName << "', skipping location."); continue; } -- cgit v1.2.3 From f3e20f4376f6659f2db503a7861550a3ba7b814e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 1 Sep 2007 23:03:58 +0000 Subject: Format account number properly (8 hex digits). --- lib/common/Logging.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/Logging.h b/lib/common/Logging.h index e87d1d4f..9601a495 100644 --- a/lib/common/Logging.h +++ b/lib/common/Logging.h @@ -47,7 +47,7 @@ std::hex << \ std::showbase << \ std::internal << \ - std::setw(8) << \ + std::setw(10) << \ std::setfill('0') << \ (accno) -- cgit v1.2.3 From 85e0afebafedb7852876571dfa3a8d1abad7de00 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Sep 2007 20:07:42 +0000 Subject: Document and enable KeepAliveTime option by default. --- bin/bbackupd/bbackupd-config.in | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/bin/bbackupd/bbackupd-config.in b/bin/bbackupd/bbackupd-config.in index 5dbd2dd9..b5dc8be8 100755 --- a/bin/bbackupd/bbackupd-config.in +++ b/bin/bbackupd/bbackupd-config.in @@ -341,6 +341,25 @@ MinimumFileAge = 21600 MaxUploadWait = 86400 +# If the connection is idle for some time (e.g. over 10 minutes or 600 +# seconds, not sure exactly how long) then the server will give up and +# disconnect the client, resulting in Connection Protocol_Timeout errors +# on the server and TLSReadFailed or TLSWriteFailed errors on the client. +# Also, some firewalls and NAT gateways will kill idle connections after +# similar lengths of time. +# +# This can happen for example when most files are backed up already and +# don't need to be sent to the store again, while scanning a large +# directory, or while calculating diffs of a large file. To avoid this, +# KeepAliveTime specifies that special keep-alive messages should be sent +# when the connection is otherwise idle for a certain length of time, +# specified here in seconds. +# +# The default is that these messages are never sent, equivalent to setting +# this option to zero, but we recommend that all users enable this. + +KeepAliveTime = 120 + __E } else -- cgit v1.2.3 From 0e6d5549ef6ffd700c1797a33d29193ee44b2ebe Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Sep 2007 21:08:30 +0000 Subject: Win32 compile fix (logging framework abuse). (merges [1810]) --- lib/server/LocalProcessStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/server/LocalProcessStream.cpp b/lib/server/LocalProcessStream.cpp index 9750aca1..af24de1b 100644 --- a/lib/server/LocalProcessStream.cpp +++ b/lib/server/LocalProcessStream.cpp @@ -120,7 +120,7 @@ std::auto_ptr LocalProcessStream(const char *CommandLine, pid_t &rPidO HANDLE writeInChild, readFromChild; if(!CreatePipe(&readFromChild, &writeInChild, &secAttr, 0)) { - BOX_ERROR("Failed to CreatePipe for child process: " + BOX_ERROR("Failed to CreatePipe for child process: " << GetErrorMessage(GetLastError())); THROW_EXCEPTION(ServerException, SocketPairFailed) } -- cgit v1.2.3 From e2efafa787ffa1b45063551b6832a9590141dceb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Sep 2007 21:54:33 +0000 Subject: Fix comments. (merges [1812]) --- bin/bbackupd/BackupClientDirectoryRecord.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index f97ff315..e5a57bc1 100644 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -1384,7 +1384,8 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn if(e.GetType() == ConnectionException::ExceptionType && e.GetSubType() == ConnectionException::Protocol_UnexpectedReply) { - // Check and see what error the protocol has -- as it might be an error... + // Check and see what error the protocol has, + // this is more useful to users than the exception. int type, subtype; if(connection.GetLastError(type, subtype)) { -- cgit v1.2.3 From 783e3baacc9e101c540fd2cb39e94c02d32f8e72 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Sep 2007 21:55:07 +0000 Subject: Don't initialise MemLeakFinder twice when running as a service. Return a non-zero exit code if running as a service fails. (merges [1813]) --- bin/bbackupd/Win32BackupService.cpp | 8 -------- bin/bbackupd/Win32ServiceFunctions.cpp | 5 ++++- bin/bbackupd/Win32ServiceFunctions.h | 6 +++--- bin/bbackupd/bbackupd.cpp | 12 ++++++------ 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/bin/bbackupd/Win32BackupService.cpp b/bin/bbackupd/Win32BackupService.cpp index 1470b42d..9f0ac867 100644 --- a/bin/bbackupd/Win32BackupService.cpp +++ b/bin/bbackupd/Win32BackupService.cpp @@ -31,12 +31,6 @@ DWORD Win32BackupService::WinService(const char* pConfigFileName) { DWORD ret; - // keep MAINHELPER_START happy - int argc = 0; - char* argv[] = {NULL}; - - MAINHELPER_START - if (pConfigFileName != NULL) { ret = this->Main(pConfigFileName); @@ -46,8 +40,6 @@ DWORD Win32BackupService::WinService(const char* pConfigFileName) ret = this->Main(BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE); } - MAINHELPER_END - return ret; } diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp index f4c8894b..5acf5f67 100644 --- a/bin/bbackupd/Win32ServiceFunctions.cpp +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -161,7 +161,7 @@ VOID ServiceMain(DWORD argc, LPTSTR *argv) } } -void OurService(char* pConfigFileName) +int OurService(char* pConfigFileName) { spConfigFileName = pConfigFileName; @@ -180,7 +180,10 @@ void OurService(char* pConfigFileName) ErrorHandler("Failed to start service. Did you start " "Box Backup from the Service Control Manager? " "(StartServiceCtrlDispatcher)", GetLastError()); + return 1; } + + return 0; } int InstallService(const char* pConfigFileName) diff --git a/bin/bbackupd/Win32ServiceFunctions.h b/bin/bbackupd/Win32ServiceFunctions.h index 70e1f085..cecd5c7b 100644 --- a/bin/bbackupd/Win32ServiceFunctions.h +++ b/bin/bbackupd/Win32ServiceFunctions.h @@ -12,8 +12,8 @@ #ifndef WIN32SERVICEFUNCTIONS_H #define WIN32SERVICEFUNCTIONS_H -int RemoveService (void); -int InstallService (const char* pConfigFilePath); -void OurService (char* pConfigFileName); +int RemoveService (void); +int InstallService (const char* pConfigFilePath); +int OurService (char* pConfigFileName); #endif diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index b8c8f61a..e094d499 100644 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -25,6 +25,8 @@ int main(int argc, const char *argv[]) { + int ExitCode = 0; + MAINHELPER_START Logging::SetProgramName("Box Backup (bbackupd)"); @@ -65,8 +67,6 @@ int main(int argc, const char *argv[]) EnableBackupRights(); - int ExitCode = 0; - if (runAsWin32Service) { BOX_INFO("Box Backup service starting"); @@ -77,7 +77,7 @@ int main(int argc, const char *argv[]) config = strdup(argv[2]); } - OurService(config); + ExitCode = OurService(config); if (config) { @@ -94,14 +94,14 @@ int main(int argc, const char *argv[]) delete gpDaemonService; - return ExitCode; - #else // !WIN32 BackupDaemon daemon; - return daemon.Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); + ExitCode = daemon.Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); #endif // WIN32 MAINHELPER_END + + return ExitCode; } -- cgit v1.2.3 From 6ecbbd73e47eb14d144925421294702eff8370ff Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Sep 2007 21:55:53 +0000 Subject: No need to print syslog() messages any more, now that we have a logging framework. (merges [1814]) --- lib/win32/emu.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/win32/emu.cpp b/lib/win32/emu.cpp index 1a6b0e79..071dc788 100644 --- a/lib/win32/emu.cpp +++ b/lib/win32/emu.cpp @@ -509,8 +509,16 @@ std::string ConvertPathToAbsoluteUnicode(const char *pFileName) tmpStr = ""; return tmpStr; } - - if (filename.length() >= 1 && filename[0] == '\\') + + if (filename.length() > 2 && filename[0] == '\\' && + filename[1] == '\\') + { + tmpStr += "UNC\\"; + filename.replace(0, 2, ""); + // \\?\UNC\\ + // see http://msdn2.microsoft.com/en-us/library/aa365247.aspx + } + else if (filename.length() >= 1 && filename[0] == '\\') { // root directory of current drive. tmpStr = wd; @@ -1520,8 +1528,8 @@ void syslog(int loglevel, const char *frmt, ...) sHaveWarnedEventLogFull = false; } - printf("%s\r\n", buffer); - fflush(stdout); + // printf("%s\r\n", buffer); + // fflush(stdout); } int emu_chdir(const char* pDirName) -- cgit v1.2.3 From e38e470008f360f788f2d32bd4182c09d4ed7418 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Sep 2007 21:57:38 +0000 Subject: Fix compiler warning. (merges [1820], [1821]) --- lib/common/ConversionString.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/ConversionString.cpp b/lib/common/ConversionString.cpp index b86bad4f..2d0a8d58 100644 --- a/lib/common/ConversionString.cpp +++ b/lib/common/ConversionString.cpp @@ -123,7 +123,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; } -- cgit v1.2.3 From 2ff87143551e6882c90ceaba940a34779b922882 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Sep 2007 20:52:00 +0000 Subject: Don't include the install-backup-client script in Windows builds, as it's pretty useless without Cygwin, and of marginal use with it (refs #24). --- infrastructure/makeparcels.pl.in | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/infrastructure/makeparcels.pl.in b/infrastructure/makeparcels.pl.in index 880246d7..0846ef46 100755 --- a/infrastructure/makeparcels.pl.in +++ b/infrastructure/makeparcels.pl.in @@ -101,8 +101,12 @@ for my $parcel (@parcels) my $dir = parcel_dir($parcel); print MAKE "\ttest -d $dir || mkdir $dir\n"; - open SCRIPT,">parcels/scripts/install-$parcel" or die "Can't open installer script for $parcel for writing"; - print SCRIPT "#!/bin/sh\n\n"; + unless ($target_windows) + { + open SCRIPT,">parcels/scripts/install-$parcel" or die + "Can't open installer script for $parcel for writing"; + print SCRIPT "#!/bin/sh\n\n"; + } for(@{$parcel_contents{$parcel}}) { @@ -136,21 +140,34 @@ for my $parcel (@parcels) $name = $1; } - print SCRIPT "install $name $install_into_dir\n"; + unless ($target_windows) + { + print SCRIPT "install $name $install_into_dir\n"; + } + } + + unless ($target_windows) + { + close SCRIPT; + chmod 0755,"parcels/scripts/install-$parcel"; } - close SCRIPT; - - chmod 0755,"parcels/scripts/install-$parcel"; - my $root = parcel_root($parcel); - print MAKE "\tcp parcels/scripts/install-$parcel $dir\n"; + + unless ($target_windows) + { + print MAKE "\tcp parcels/scripts/install-$parcel $dir\n"; + } + print MAKE "\t(cd parcels; tar cf - $root | gzip -9 - > $root.tgz )\n"; print MAKE "\n"; - - print MAKE "install-$parcel:\n"; - print MAKE "\t(cd $dir; ./install-$parcel)\n\n"; + + unless ($target_windows) + { + print MAKE "install-$parcel:\n"; + print MAKE "\t(cd $dir; ./install-$parcel)\n\n"; + } } print MAKE <<__E; -- cgit v1.2.3