From 3bedf8846f4d7a5cb38276b274662d62a36dcd52 Mon Sep 17 00:00:00 2001 From: Martin Ebourne Date: Mon, 12 Dec 2005 20:50:00 +0000 Subject: Marged chris/win32/merge/07-win32-fixes at r210 to trunk --- bin/bbackupctl/bbackupctl.cpp | 60 +++++- bin/bbackupd/BackupClientContext.cpp | 2 + bin/bbackupd/BackupClientDirectoryRecord.cpp | 30 ++- bin/bbackupd/BackupClientInodeToIDMap.cpp | 51 ++++- bin/bbackupd/BackupClientInodeToIDMap.h | 12 +- bin/bbackupd/BackupDaemon.cpp | 291 ++++++++++++++++++++++++--- bin/bbackupd/BackupDaemon.h | 14 +- bin/bbackupd/Win32BackupService.cpp | 51 +++++ bin/bbackupd/Win32BackupService.h | 21 ++ bin/bbackupd/Win32ServiceFunctions.cpp | 236 ++++++++++++++++++++++ bin/bbackupd/Win32ServiceFunctions.h | 19 ++ bin/bbackupd/bbackupd.cpp | 72 ++++++- bin/bbackupd/win32/ReadMe.txt | 24 +++ bin/bbackupd/win32/bbackupd.conf | 143 +++++++++++++ bin/bbackupd/win32/installer.iss | 51 +++++ bin/bbackupquery/BackupQueries.cpp | 18 +- bin/bbackupquery/bbackupquery.cpp | 19 +- bin/bbstoreaccounts/bbstoreaccounts.cpp | 4 + 18 files changed, 1064 insertions(+), 54 deletions(-) create mode 100644 bin/bbackupd/Win32BackupService.cpp create mode 100644 bin/bbackupd/Win32BackupService.h create mode 100644 bin/bbackupd/Win32ServiceFunctions.cpp create mode 100644 bin/bbackupd/Win32ServiceFunctions.h create mode 100644 bin/bbackupd/win32/ReadMe.txt create mode 100644 bin/bbackupd/win32/bbackupd.conf create mode 100644 bin/bbackupd/win32/installer.iss (limited to 'bin') diff --git a/bin/bbackupctl/bbackupctl.cpp b/bin/bbackupctl/bbackupctl.cpp index 0dc4f98d..d39092e8 100755 --- a/bin/bbackupctl/bbackupctl.cpp +++ b/bin/bbackupctl/bbackupctl.cpp @@ -19,6 +19,10 @@ #include "SocketStream.h" #include "IOStreamGetLine.h" +#ifdef WIN32 + #include "WinNamedPipeStream.h" +#endif + #include "MemLeakFindOn.h" void PrintUsageAndExit() @@ -26,7 +30,8 @@ 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, even if SyncAllowScript says no\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" @@ -38,7 +43,12 @@ int main(int argc, const char *argv[]) { int returnCode = 0; - MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupctl.memleaks", "bbackupctl") +#if defined WIN32 && ! defined NDEBUG + ::openlog("Box Backup (bbackupctl)", 0, 0); +#endif + + MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupctl.memleaks", + "bbackupctl") MAINHELPER_START @@ -99,20 +109,35 @@ int main(int argc, const char *argv[]) } // Connect to socket + +#ifndef WIN32 SocketStream connection; +#else /* WIN32 */ + WinNamedPipeStream connection; +#endif /* ! WIN32 */ + try { +#ifdef WIN32 + connection.Connect(BOX_NAMED_PIPE_NAME); +#else connection.Open(Socket::TypeUNIX, conf.GetKeyValue("CommandSocket").c_str()); +#endif } catch(...) { - printf("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" \ + printf("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" ); + +#if defined WIN32 && ! defined NDEBUG + syslog(LOG_ERR,"Failed to connect to the command socket"); +#endif + return 1; } @@ -123,14 +148,29 @@ 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 " + "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()) { - printf("Server rejected the connection. Are you running bbackupctl as the same user as the daemon?\n"); +#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 + return 1; } @@ -212,6 +252,10 @@ int main(int argc, const char *argv[]) } MAINHELPER_END + +#if defined WIN32 && ! defined NDEBUG + closelog(); +#endif return returnCode; } diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp index 08a203c1..50f2cd08 100755 --- a/bin/bbackupd/BackupClientContext.cpp +++ b/bin/bbackupd/BackupClientContext.cpp @@ -9,7 +9,9 @@ #include "Box.h" +#ifndef WIN32 #include +#endif #include "BoxPortsAndFiles.h" #include "BoxTime.h" diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp index 307c72c4..1a124333 100755 --- a/bin/bbackupd/BackupClientDirectoryRecord.cpp +++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp @@ -133,7 +133,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()); + TRACE1("Stat failed for '%s' (directory)\n", + rLocalPath.c_str()); return; } // Store inode number in map so directories are tracked in case they're renamed @@ -202,11 +203,18 @@ void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::Syn } // Stat file to get info - filename = rLocalPath + DIRECTORY_SEPARATOR + en->d_name; + filename = rLocalPath + DIRECTORY_SEPARATOR + + en->d_name; + if(::lstat(filename.c_str(), &st) != 0) { - TRACE1("Stat failed for '%s' (contents)\n", filename.c_str()); - THROW_EXCEPTION(CommonException, OSFileError) + // Report the error (logs and + // eventual email to administrator) + SetErrorWhenReadingFilesystemObject( + rParams, filename.c_str()); + + // Ignore this entry for now. + continue; } int type = st.st_mode & S_IFMT; @@ -506,7 +514,7 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP box_time_t modTime = 0; uint64_t attributesHash = 0; int64_t fileSize = 0; - ino_t inodeNum = 0; + InodeRefType inodeNum = 0; bool hasMultipleHardLinks = true; // BLOCK { @@ -865,7 +873,7 @@ bool BackupClientDirectoryRecord::UpdateItems(BackupClientDirectoryRecord::SyncP // Get attributes box_time_t attrModTime = 0; - ino_t inodeNum = 0; + InodeRefType inodeNum = 0; BackupClientFileAttributes attr; attr.ReadAttributes(dirname.c_str(), true /* directories have zero mod times */, 0 /* not interested in mod time */, &attrModTime, 0 /* not file size */, @@ -1109,8 +1117,12 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn std::auto_ptr upload(BackupStoreFile::EncodeFile(rFilename.c_str(), mObjectID, rStoreFilename)); // Send to store - std::auto_ptr stored(connection.QueryStoreFile(mObjectID, ModificationTime, - AttributesHash, 0 /* no diff from file ID */, rStoreFilename, *upload)); + std::auto_ptr stored( + connection.QueryStoreFile( + mObjectID, ModificationTime, + AttributesHash, + 0 /* no diff from file ID */, + rStoreFilename, *upload)); // Get object ID from the result objID = stored->GetObjectID(); @@ -1130,7 +1142,7 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn rParams.mrDaemon.NotifySysadmin(BackupDaemon::NotifyEvent_StoreFull); } } - + // Send the error on it's way throw; } diff --git a/bin/bbackupd/BackupClientInodeToIDMap.cpp b/bin/bbackupd/BackupClientInodeToIDMap.cpp index 7141d5f4..c3f20df0 100755 --- a/bin/bbackupd/BackupClientInodeToIDMap.cpp +++ b/bin/bbackupd/BackupClientInodeToIDMap.cpp @@ -65,7 +65,11 @@ BackupClientInodeToIDMap::~BackupClientInodeToIDMap() #ifndef BACKIPCLIENTINODETOIDMAP_IN_MEMORY_IMPLEMENTATION if(dbp != 0) { +#ifdef BERKELY_V4 + dbp->close(0); +#else dbp->close(dbp); +#endif } #endif } @@ -90,7 +94,14 @@ void BackupClientInodeToIDMap::Open(const char *Filename, bool ReadOnly, bool Cr ASSERT(!mEmpty); // Open the database file +#ifdef BERKELY_V4 + dbp = new Db(0,0); + dbp->set_pagesize(1024); /* Page size: 1K. */ + dbp->set_cachesize(0, 32 * 1024, 0); + dbp->open(NULL, Filename, NULL, DB_HASH, DB_CREATE, 0664); +#else dbp = dbopen(Filename, (CreateNew?O_CREAT:0) | (ReadOnly?O_RDONLY:O_RDWR), S_IRUSR | S_IWUSR | S_IRGRP, TABLE_DATABASE_TYPE, NULL); +#endif if(dbp == NULL) { THROW_EXCEPTION(BackupStoreException, BerkelyDBFailure); @@ -135,7 +146,11 @@ void BackupClientInodeToIDMap::Close() #ifndef BACKIPCLIENTINODETOIDMAP_IN_MEMORY_IMPLEMENTATION if(dbp != 0) { +#ifdef BERKELY_V4 + if(dbp->close(0) != 0) +#else if(dbp->close(dbp) != 0) +#endif { THROW_EXCEPTION(BackupStoreException, BerkelyDBFailure); } @@ -172,6 +187,15 @@ void BackupClientInodeToIDMap::AddToMap(InodeRefType InodeRef, int64_t ObjectID, IDBRecord rec; rec.mObjectID = ObjectID; rec.mInDirectory = InDirectory; + +#ifdef BERKELY_V4 + Dbt key(&InodeRef, sizeof(InodeRef)); + Dbt data(&rec, sizeof(rec)); + + if (dbp->put(0, &key, &data, 0) != 0) { + THROW_EXCEPTION(BackupStoreException, BerkelyDBFailure); + } +#else DBT key; key.data = &InodeRef; @@ -187,6 +211,7 @@ void BackupClientInodeToIDMap::AddToMap(InodeRefType InodeRef, int64_t ObjectID, THROW_EXCEPTION(BackupStoreException, BerkelyDBFailure); } #endif +#endif } // -------------------------------------------------------------------------- @@ -225,6 +250,11 @@ bool BackupClientInodeToIDMap::Lookup(InodeRefType InodeRef, int64_t &rObjectIDO THROW_EXCEPTION(BackupStoreException, InodeMapNotOpen); } +#ifdef BERKELY_V4 + Dbt key(&InodeRef, sizeof(InodeRef)); + Dbt data(0, 0); + switch(dbp->get(NULL, &key, &data, 0)) +#else DBT key; key.data = &InodeRef; key.size = sizeof(InodeRef); @@ -234,6 +264,8 @@ bool BackupClientInodeToIDMap::Lookup(InodeRefType InodeRef, int64_t &rObjectIDO data.size = 0; switch(dbp->get(dbp, &key, &data, 0)) +#endif + { case 1: // key not in file return false; @@ -248,6 +280,21 @@ bool BackupClientInodeToIDMap::Lookup(InodeRefType InodeRef, int64_t &rObjectIDO } // Check for sensible return +#ifdef BERKELY_V4 + if(key.get_data() == 0 || data.get_size() != sizeof(IDBRecord)) + { + // Assert in debug version + ASSERT(key.get_data() == 0 || data.get_size() != sizeof(IDBRecord)); + + // Invalid entries mean it wasn't found + return false; + } + + // Data alignment isn't guaranteed to be on a suitable boundary + IDBRecord rec; + + ::memcpy(&rec, data.get_data(), sizeof(rec)); +#else if(key.data == 0 || data.size != sizeof(IDBRecord)) { // Assert in debug version @@ -257,9 +304,11 @@ bool BackupClientInodeToIDMap::Lookup(InodeRefType InodeRef, int64_t &rObjectIDO return false; } - // Data alignment isn't guarentted to be on a suitable bounday + // Data alignment isn't guaranteed to be on a suitable boundary IDBRecord rec; + ::memcpy(&rec, data.data, sizeof(rec)); +#endif // Return data rObjectIDOut = rec.mObjectID; diff --git a/bin/bbackupd/BackupClientInodeToIDMap.h b/bin/bbackupd/BackupClientInodeToIDMap.h index 121e88fd..1dfef702 100755 --- a/bin/bbackupd/BackupClientInodeToIDMap.h +++ b/bin/bbackupd/BackupClientInodeToIDMap.h @@ -20,12 +20,14 @@ #define BACKIPCLIENTINODETOIDMAP_IN_MEMORY_IMPLEMENTATION #endif -typedef ino_t InodeRefType; - // avoid having to include the DB files when not necessary #ifndef BACKIPCLIENTINODETOIDMAP_IMPLEMENTATION +#ifdef BERKELY_V4 + class Db; +#else class DB; #endif +#endif // -------------------------------------------------------------------------- // @@ -58,8 +60,12 @@ private: #else bool mReadOnly; bool mEmpty; +#ifdef BERKELY_V4 + Db *dbp; // c++ style implimentation +#else DB *dbp; // C style interface, use notation from documentation -#endif +#endif // BERKELY_V4 +#endif // BACKIPCLIENTINODETOIDMAP_IN_MEMORY_IMPLEMENTATION }; #endif // BACKUPCLIENTINODETOIDMAP__H diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp index f22de591..c56aaa59 100755 --- a/bin/bbackupd/BackupDaemon.cpp +++ b/bin/bbackupd/BackupDaemon.cpp @@ -9,26 +9,31 @@ #include "Box.h" +#include #include -#include -#include -#include + +#ifndef WIN32 + #include + #include + #include + #include +#endif #ifdef HAVE_SYS_MOUNT_H - #include + #include #endif #ifdef HAVE_MNTENT_H - #include -#endif + #include +#endif #ifdef HAVE_SYS_MNTTAB_H #include #include #endif -#include #include "Configuration.h" #include "IOStream.h" #include "MemBlockStream.h" #include "CommonException.h" +#include "BoxPortsAndFiles.h" #include "SSLLib.h" #include "TLSContext.h" @@ -160,8 +165,9 @@ const ConfigurationVerify *BackupDaemon::GetConfigVerify() const // // Function // Name: BackupDaemon::SetupInInitialProcess() -// Purpose: Platforms with non-checkable credientals on local sockets only. -// Prints a warning if the command socket is used. +// Purpose: Platforms with non-checkable credentials on +// local sockets only. +// Prints a warning if the command socket is used. // Created: 25/2/04 // // -------------------------------------------------------------------------- @@ -206,6 +212,133 @@ void BackupDaemon::DeleteAllLocations() mIDMapMounts.clear(); } +#ifdef WIN32 +// -------------------------------------------------------------------------- +// +// Function +// Name: HelperThread() +// Purpose: Background thread function, called by Windows, +// calls the BackupDaemon's RunHelperThread method +// to listen for and act on control communications +// Created: 18/2/04 +// +// -------------------------------------------------------------------------- +unsigned int WINAPI HelperThread( LPVOID lpParam ) +{ + printf( "Parameter = %lu.\n", *(DWORD*)lpParam ); + ((BackupDaemon *)lpParam)->RunHelperThread(); + + return 0; +} + +void BackupDaemon::RunHelperThread(void) +{ + mpCommandSocketInfo = new CommandSocketInfo; + this->mReceivedCommandConn = false; + + while ( !IsTerminateWanted() ) + { + try + { + mpCommandSocketInfo->mListeningSocket.Accept( + BOX_NAMED_PIPE_NAME); + + // This next section comes from Ben's original function + // Log + ::syslog(LOG_INFO, "Connection from command socket"); + + // Send a header line summarising the configuration + // and current state + const Configuration &conf(GetConfiguration()); + char summary[256]; + size_t summarySize = sprintf(summary, + "bbackupd: %d %d %d %d\nstate %d\n", + conf.GetKeyValueBool("AutomaticBackup"), + conf.GetKeyValueInt("UpdateStoreInterval"), + conf.GetKeyValueInt("MinimumFileAge"), + conf.GetKeyValueInt("MaxUploadWait"), + mState); + + mpCommandSocketInfo->mListeningSocket.Write(summary, summarySize); + mpCommandSocketInfo->mListeningSocket.Write("ping\n", 5); + + IOStreamGetLine readLine(mpCommandSocketInfo->mListeningSocket); + std::string command; + + while (mpCommandSocketInfo->mListeningSocket.IsConnected() && + readLine.GetLine(command) ) + { + TRACE1("Receiving command '%s' over " + "command socket\n", command.c_str()); + + bool sendOK = false; + bool sendResponse = true; + bool disconnect = false; + + // Command to process! + if(command == "quit" || command == "") + { + // Close the socket. + disconnect = true; + sendResponse = false; + } + else if(command == "sync") + { + // Sync now! + this->mDoSyncFlagOut = true; + this->mSyncIsForcedOut = false; + sendOK = true; + } + else if(command == "force-sync") + { + // Sync now (forced -- overrides any SyncAllowScript) + this->mDoSyncFlagOut = true; + this->mSyncIsForcedOut = true; + sendOK = true; + } + else if(command == "reload") + { + // Reload the configuration + SetReloadConfigWanted(); + sendOK = true; + } + else if(command == "terminate") + { + // Terminate the daemon cleanly + SetTerminateWanted(); + sendOK = true; + } + + // Send a response back? + if (sendResponse) + { + const char* response = sendOK ? "ok\n" : "error\n"; + mpCommandSocketInfo->mListeningSocket.Write( + response, strlen(response)); + } + + if (disconnect) + { + break; + } + + this->mReceivedCommandConn = true; + } + + mpCommandSocketInfo->mListeningSocket.Close(); + } + catch (BoxException &e) + { + ::syslog(LOG_ERR, "Communication error with " + "control client: %s", e.what()); + } + catch (...) + { + ::syslog(LOG_ERR, "Communication error with control client"); + } + } +} +#endif // -------------------------------------------------------------------------- // @@ -217,6 +350,25 @@ void BackupDaemon::DeleteAllLocations() // -------------------------------------------------------------------------- void BackupDaemon::Run() { +#ifdef WIN32 + + // Create a thread to handle the named pipe + HANDLE hThread; + unsigned int dwThreadId; + + hThread = (HANDLE) _beginthreadex( + NULL, // default security attributes + 0, // use default stack size + HelperThread, // thread function + this, // argument to thread function + 0, // use default creation flags + &dwThreadId); // returns the thread identifier + + // init our own timer for file diff timeouts + InitTimer(); + +#else // ! WIN32 + // Ignore SIGPIPE (so that if a command connection is broken, the daemon doesn't terminate) ::signal(SIGPIPE, SIG_IGN); @@ -230,6 +382,8 @@ void BackupDaemon::Run() ::unlink(socketName); mpCommandSocketInfo->mListeningSocket.Listen(Socket::TypeUNIX, socketName); } + +#endif // WIN32 // Handle things nicely on exceptions try @@ -253,6 +407,11 @@ void BackupDaemon::Run() delete mpCommandSocketInfo; mpCommandSocketInfo = 0; } + +#ifdef WIN32 + // clean up windows specific stuff. + FiniTimer(); +#endif } // -------------------------------------------------------------------------- @@ -303,9 +462,9 @@ void BackupDaemon::Run2() // When the last sync started (only updated if the store was not full when the sync ended) box_time_t lastSyncTime = 0; - - // -------------------------------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------- + // And what's the current client store marker? int64_t clientStoreMarker = BackupClientContext::ClientStoreMarker_NotKnown; // haven't contacted the store yet @@ -409,6 +568,8 @@ void BackupDaemon::Run2() // Do sync bool errorOccurred = false; int errorCode = 0, errorSubCode = 0; + const char* errorString = "unknown"; + try { // Set state and log start @@ -512,6 +673,7 @@ void BackupDaemon::Run2() catch(BoxException &e) { errorOccurred = true; + errorString = e.what(); errorCode = e.GetType(); errorSubCode = e.GetSubType(); } @@ -555,8 +717,13 @@ void BackupDaemon::Run2() { // Not restart/terminate, pause and retry SetState(State_Error); - ::syslog(LOG_ERR, "Exception caught (%d/%d), reset state and waiting to retry...", errorCode, errorSubCode); - ::sleep(100); + ::syslog(LOG_ERR, + "Exception caught (%s %d/%d), " + "reset state and waiting " + "to retry...", + errorString, errorCode, + errorSubCode); + ::sleep(10); } } @@ -665,6 +832,29 @@ 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 = BoxTimeToMilliSeconds(RequiredDelay); + + while ( this->mReceivedCommandConn == false ) + { + Sleep(1); + + if ( timeout == 0 ) + { + DoSyncFlagOut = false; + SyncIsForcedOut = false; + return; + } + timeout--; + } + this->mReceivedCommandConn = false; + DoSyncFlagOut = this->mDoSyncFlagOut; + SyncIsForcedOut = this->mSyncIsForcedOut; + + return; +#else // ! WIN32 ASSERT(mpCommandSocketInfo != 0); if(mpCommandSocketInfo == 0) {::sleep(1); return;} // failure case isn't too bad @@ -713,9 +903,9 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla } } } -#endif +#endif // PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET - // Is this an acceptible connection? + // Is this an acceptable connection? if(!uidOK) { // Dump the connection @@ -833,6 +1023,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla CloseCommandConnection(); } } +#endif // WIN32 } @@ -849,13 +1040,17 @@ void BackupDaemon::CloseCommandConnection() try { TRACE0("Closing command connection\n"); - + +#ifdef WIN32 + mpCommandSocketInfo->mListeningSocket.Close(); +#else if(mpCommandSocketInfo->mpGetLine) { delete mpCommandSocketInfo->mpGetLine; mpCommandSocketInfo->mpGetLine = 0; } mpCommandSocketInfo->mpConnectedSocket.reset(); +#endif } catch(...) { @@ -875,15 +1070,27 @@ 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. - if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0) + if (mpCommandSocketInfo != NULL && +#ifdef WIN32 + mpCommandSocketInfo->mListeningSocket.IsConnected() +#else + mpCommandSocketInfo->mpConnectedSocket.get() != 0 +#endif + ) { + const char* message = SendStart ? "start-sync\n" : "finish-sync\n"; try { - mpCommandSocketInfo->mpConnectedSocket->Write(SendStart?"start-sync\n":"finish-sync\n", SendStart?11:12); +#ifdef WIN32 + mpCommandSocketInfo->mListeningSocket.Write(message, + strlen(message)); +#else + mpCommandSocketInfo->mpConnectedSocket->Write(message, + strlen(message)); +#endif } catch(...) { @@ -958,6 +1165,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con std::map mounts; int numIDMaps = 0; +#ifdef HAVE_MOUNTS #ifndef HAVE_STRUCT_STATFS_F_MNTONNAME // Linux and others can't tell you where a directory is mounted. So we // have to read the mount entries from /etc/mtab! Bizarre that the OS @@ -996,7 +1204,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con ::endmntent(mountPointsFile); throw; } -#else +#else // ! HAVE_STRUCT_MNTENT_MNT_DIR // Open mounts file mountPointsFile = ::fopen("/etc/mnttab", "r"); if(mountPointsFile == 0) @@ -1023,7 +1231,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con ::fclose(mountPointsFile); throw; } -#endif +#endif // HAVE_STRUCT_MNTENT_MNT_DIR // Check sorting and that things are as we expect ASSERT(mountPoints.size() > 0); #ifndef NDEBUG @@ -1033,6 +1241,7 @@ void BackupDaemon::SetupLocations(BackupClientContext &rClientContext, const Con } #endif // n NDEBUG #endif // n HAVE_STRUCT_STATFS_F_MNTONNAME +#endif // HAVE_MOUNTS // Then... go through each of the entries in the configuration, // making sure there's a directory created for it. @@ -1054,7 +1263,9 @@ TRACE0("new location\n"); // Do a fsstat on the pathname to find out which mount it's on { -#ifdef HAVE_STRUCT_STATFS_F_MNTONNAME + +#if defined HAVE_STRUCT_STATFS_F_MNTONNAME || defined WIN32 + // BSD style statfs -- includes mount point, which is nice. struct statfs s; if(::statfs(ploc->mPath.c_str(), &s) != 0) @@ -1064,7 +1275,9 @@ TRACE0("new location\n"); // Where the filesystem is mounted std::string mountName(s.f_mntonname); -#else + +#else // !HAVE_STRUCT_STATFS_F_MNTONNAME && !WIN32 + // Warn in logs if the directory isn't absolute if(ploc->mPath[0] != '/') { @@ -1090,6 +1303,7 @@ TRACE0("new location\n"); } TRACE2("mount point chosen for %s is %s\n", ploc->mPath.c_str(), mountName.c_str()); } + #endif // Got it? @@ -1376,6 +1590,10 @@ void BackupDaemon::CommitIDMapsAfterSync() std::string newmap(target + ".n"); // Try to rename +#ifdef WIN32 + // win32 rename doesn't overwrite existing files + ::remove(target.c_str()); +#endif if(::rename(newmap.c_str(), target.c_str()) != 0) { THROW_EXCEPTION(CommonException, OSFileError) @@ -1457,14 +1675,33 @@ void BackupDaemon::SetState(int State) // Set process title const static char *stateText[] = {"idle", "connected", "error -- waiting for retry", "over limit on server -- not backing up"}; SetProcessTitle(stateText[State]); - + // If there's a command socket connected, then inform it -- disconnecting from the // command socket if there's an error + + char newState[64]; + char newStateSize = sprintf(newState, "state %d\n", State); + +#ifdef WIN32 + #warning FIX ME: race condition + // 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()) + { + try + { + mpCommandSocketInfo->mListeningSocket.Write(newState, newStateSize); + } + catch(...) + { + CloseCommandConnection(); + } + } +#else if(mpCommandSocketInfo != 0 && mpCommandSocketInfo->mpConnectedSocket.get() != 0) { // Something connected to the command socket, tell it about the new state - char newState[64]; - char newStateSize = sprintf(newState, "state %d\n", State); try { mpCommandSocketInfo->mpConnectedSocket->Write(newState, newStateSize); @@ -1474,6 +1711,7 @@ void BackupDaemon::SetState(int State) CloseCommandConnection(); } } +#endif } @@ -1658,4 +1896,3 @@ BackupDaemon::CommandSocketInfo::~CommandSocketInfo() mpGetLine = 0; } } - diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h index ffaf5783..e6798798 100755 --- a/bin/bbackupd/BackupDaemon.h +++ b/bin/bbackupd/BackupDaemon.h @@ -19,6 +19,7 @@ #include "Socket.h" #include "SocketListen.h" #include "SocketStream.h" +#include "WinNamedPipeStream.h" class BackupClientDirectoryRecord; class BackupClientContext; @@ -146,8 +147,12 @@ private: CommandSocketInfo(const CommandSocketInfo &); // no copying CommandSocketInfo &operator=(const CommandSocketInfo &); public: +#ifdef WIN32 + WinNamedPipeStream mListeningSocket; +#else SocketListen mListeningSocket; std::auto_ptr mpConnectedSocket; +#endif IOStreamGetLine *mpGetLine; }; @@ -160,7 +165,14 @@ private: // Unused entries in the root directory wait a while before being deleted box_time_t mDeleteUnusedRootDirEntriesAfter; // time to delete them std::vector > mUnusedRootDirEntries; + +#ifdef WIN32 + public: + void RunHelperThread(void); + + private: + bool mDoSyncFlagOut, mSyncIsForcedOut, mReceivedCommandConn; +#endif }; #endif // BACKUPDAEMON__H - diff --git a/bin/bbackupd/Win32BackupService.cpp b/bin/bbackupd/Win32BackupService.cpp new file mode 100644 index 00000000..aa3bf55c --- /dev/null +++ b/bin/bbackupd/Win32BackupService.cpp @@ -0,0 +1,51 @@ +// Win32 service functions for Box Backup, by Nick Knight + +#ifdef WIN32 + +#include "Box.h" +#include "BackupDaemon.h" +#include "MainHelper.h" +#include "BoxPortsAndFiles.h" +#include "BackupStoreException.h" + +#include "MemLeakFindOn.h" + +#include "Win32BackupService.h" + +Win32BackupService gDaemonService; +extern HANDLE gStopServiceEvent; + +unsigned int WINAPI RunService(LPVOID lpParameter) +{ + DWORD retVal = gDaemonService.WinService(); + SetEvent( gStopServiceEvent ); + return retVal; +} + +void TerminateService(void) +{ + gDaemonService.SetTerminateWanted(); +} + +DWORD Win32BackupService::WinService(void) +{ + 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"); + + const char *argv[] = {conf.c_str(), cfile.c_str()}; + + MAINHELPER_START + + return this->Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); + + MAINHELPER_END +} + +#endif // WIN32 diff --git a/bin/bbackupd/Win32BackupService.h b/bin/bbackupd/Win32BackupService.h new file mode 100644 index 00000000..38cebacc --- /dev/null +++ b/bin/bbackupd/Win32BackupService.h @@ -0,0 +1,21 @@ +// Box Backup service daemon implementation by Nick Knight + +#ifndef WIN32BACKUPSERVICE_H +#define WIN32BACKUPSERVICE_H + +#ifdef WIN32 + +class Configuration; +class ConfigurationVerify; +class BackupDaemon; + +class Win32BackupService : public BackupDaemon +{ +public: + DWORD WinService(void); +}; + +#endif // WIN32 + +#endif // WIN32BACKUPSERVICE_H + diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp new file mode 100644 index 00000000..89f02f62 --- /dev/null +++ b/bin/bbackupd/Win32ServiceFunctions.cpp @@ -0,0 +1,236 @@ +//*************************************************************** +// From the book "Win32 System Services: The Heart of Windows 98 +// and Windows 2000" +// by Marshall Brain +// Published by Prentice Hall +// Copyright 1995 Prentice Hall. +// +// This code implements the Windows API Service interface +// for the Box Backup for Windows native port. +// Adapted for Box Backup by Nick Knight. +//*************************************************************** + +#ifdef WIN32 + +#include "Box.h" + +//#include +//#include +#include +//#include + +extern void TerminateService(void); +extern unsigned int WINAPI RunService(LPVOID lpParameter); + +// Global variables + +TCHAR* gServiceName = TEXT("Box Backup Service"); +SERVICE_STATUS gServiceStatus; +SERVICE_STATUS_HANDLE gServiceStatusHandle = 0; +HANDLE gStopServiceEvent = 0; + +#define SERVICE_NAME "boxbackup" + +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); + MessageBox(0, buf, "Error", + MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY); + ExitProcess(err); +} + + +void WINAPI ServiceControlHandler( DWORD controlCode ) +{ + switch ( controlCode ) + { + case SERVICE_CONTROL_INTERROGATE: + break; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + Beep(1000,100); + TerminateService(); + gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(gServiceStatusHandle, &gServiceStatus); + + SetEvent(gStopServiceEvent); + return; + + case SERVICE_CONTROL_PAUSE: + break; + + case SERVICE_CONTROL_CONTINUE: + break; + + default: + if ( controlCode >= 128 && controlCode <= 255 ) + // user defined control code + break; + else + // unrecognised control code + break; + } + + SetServiceStatus( gServiceStatusHandle, &gServiceStatus ); +} + +// ServiceMain is called when the SCM wants to +// start the service. When it returns, the service +// has stopped. It therefore waits on an event +// just before the end of the function, and +// that event gets set when it is time to stop. +// It also returns on any error because the +// service cannot start if there is an eror. + +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 ); + if (!gStopServiceEvent) + { + gServiceStatus.dwControlsAccepted &= + ~(SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN); + gServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(gServiceStatusHandle, &gServiceStatus); + return; + } + + HANDLE ourThread = (HANDLE)_beginthreadex( + NULL, + 0, + RunService, + 0, + CREATE_SUSPENDED, + NULL); + + SetThreadPriority(ourThread, THREAD_PRIORITY_LOWEST); + ResumeThread(ourThread); + + // we are now running so tell the SCM + gServiceStatus.dwControlsAccepted |= + (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + gServiceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(gServiceStatusHandle, &gServiceStatus); + + // do cleanup here + WaitForSingleObject(gStopServiceEvent, INFINITE); + CloseHandle(gStopServiceEvent); + gStopServiceEvent = 0; + + // service was stopped + gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(gServiceStatusHandle, &gServiceStatus); + + // service is now stopped + gServiceStatus.dwControlsAccepted &= + ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + gServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(gServiceStatusHandle, &gServiceStatus); + } +} + +void OurService(void) +{ + SERVICE_TABLE_ENTRY serviceTable[] = + { + { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain }, + { NULL, NULL } + }; + BOOL success; + + // Register with the SCM + success = StartServiceCtrlDispatcher(serviceTable); + + if (!success) + { + ErrorHandler("Failed to start service. Did you start " + "Box Backup from the Service Control Manager? " + "(StartServiceCtrlDispatcher)", GetLastError()); + } +} + +void InstallService(void) +{ + SC_HANDLE newService, scm; + + scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + + if (!scm) return; + + 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; + + newService = CreateService( + scm, + SERVICE_NAME, + "Box Backup", + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_DEMAND_START, + SERVICE_ERROR_NORMAL, + cmd_args, + 0,0,0,0,0); + + if (newService) CloseServiceHandle(newService); + CloseServiceHandle(scm); +} + +void RemoveService(void) +{ + SC_HANDLE service, scm; + SERVICE_STATUS status; + + scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE); + + if (!scm) return; + + service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE); + ControlService(service, SERVICE_CONTROL_STOP, &status); + + if (!service) + { + printf("Failed to open service manager"); + return; + } + if (DeleteService(service)) + { + printf("Service removed"); + } + else + { + printf("Failed to remove service"); + } + + CloseServiceHandle(service); + CloseServiceHandle(scm); +} + +#endif // WIN32 diff --git a/bin/bbackupd/Win32ServiceFunctions.h b/bin/bbackupd/Win32ServiceFunctions.h new file mode 100644 index 00000000..72f65479 --- /dev/null +++ b/bin/bbackupd/Win32ServiceFunctions.h @@ -0,0 +1,19 @@ +//*************************************************************** +// From the book "Win32 System Services: The Heart of Windows 98 +// and Windows 2000" +// by Marshall Brain +// Published by Prentice Hall +// Copyright 1995 Prentice Hall. +// +// This code implements the Windows API Service interface +// for the Box Backup for Windows native port. +//*************************************************************** + +#ifndef WIN32SERVICEFUNCTIONS_H +#define WIN32SERVICEFUNCTIONS_H + +void RemoveService(void); +void InstallService(void); +void OurService(void); + +#endif diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp index ca843105..1c870317 100755 --- a/bin/bbackupd/bbackupd.cpp +++ b/bin/bbackupd/bbackupd.cpp @@ -11,16 +11,84 @@ #include "BackupDaemon.h" #include "MainHelper.h" #include "BoxPortsAndFiles.h" +#include "BackupStoreException.h" #include "MemLeakFindOn.h" +#ifdef WIN32 + #include "Win32ServiceFunctions.h" + #include "Win32BackupService.h" + + extern Win32BackupService gDaemonService; +#endif + int main(int argc, const char *argv[]) { MAINHELPER_START +#ifdef WIN32 + + ::openlog("Box Backup (bbackupd)", 0, 0); + + if(argc == 2 && + (::strcmp(argv[1], "--help") == 0 || + ::strcmp(argv[1], "-h") == 0)) + { + printf("-h help, -i install service, -r remove service,\n" + "-c start daemon now"); + return 2; + } + if(argc == 2 && ::strcmp(argv[1], "-r") == 0) + { + RemoveService(); + return 0; + } + if(argc == 2 && ::strcmp(argv[1], "-i") == 0) + { + InstallService(); + return 0; + } + + // Under win32 we must initialise the Winsock library + // before using sockets + + WSADATA info; + + if (WSAStartup(MAKELONG(1, 1), &info) == SOCKET_ERROR) + { + // box backup will not run without sockets + ::syslog(LOG_ERR, "Failed to initialise Windows Sockets"); + THROW_EXCEPTION(BackupStoreException, Internal) + } + + EnableBackupRights(); + + int ExitCode = 0; + + if (argc == 2 && ::strcmp(argv[1], "--service") == 0) + { + syslog(LOG_INFO,"Starting Box Backup Service"); + OurService(); + } + else + { + ExitCode = gDaemonService.Main( + BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); + } + + // Clean up our sockets + WSACleanup(); + + ::closelog(); + + return ExitCode; + +#else // !WIN32 + BackupDaemon daemon; return daemon.Main(BOX_FILE_BBACKUPD_DEFAULT_CONFIG, argc, argv); - + +#endif // WIN32 + MAINHELPER_END } - diff --git a/bin/bbackupd/win32/ReadMe.txt b/bin/bbackupd/win32/ReadMe.txt new file mode 100644 index 00000000..3d260750 --- /dev/null +++ b/bin/bbackupd/win32/ReadMe.txt @@ -0,0 +1,24 @@ +Upgrade instructions + +Version 0.09g to 0.09h + +This version included patches to the server as well. The server for this +upgrade can be found at http://home.earthlink.net/~gniemcew/ but hopefully +will be merged into the core in the next release. + +New values in the bbackupd.conf can now be added: + +StoreObjectInfoFile = C:\Program Files\Box Backup\bbackupd\bbackupd.dat + +This stores the state when a backup daemon is shutdown. + +KeepAliveTime = 250 + +This is imperative if MaximumDiffingTime is larger than 300, this stops the ssl +layer timing out when a diff is performed. It is wise to set MaximumDiffingTime +long enough for the largest file you may have. If you do not wish to upgrade your +server then make KeepAliveTime greater than MaximumDiffingTime. + +Have fun + +Nick diff --git a/bin/bbackupd/win32/bbackupd.conf b/bin/bbackupd/win32/bbackupd.conf new file mode 100644 index 00000000..85915520 --- /dev/null +++ b/bin/bbackupd/win32/bbackupd.conf @@ -0,0 +1,143 @@ + +StoreHostname = yourhost +AccountNumber = 0x1 +KeysFile = C:\Program Files\Box Backup\1-FileEncKeys.raw + +CertificateFile = C:\Program Files\Box Backup\1-cert.pem +PrivateKeyFile = C:\Program Files\Box Backup\1-key.pem +TrustedCAsFile = C:\Program Files\Box Backup\serverCA.pem + +DataDirectory = C:\Program Files\Box Backup\bbackupd + +# If you do not install it in the default location - also do not forget to +# change the pid file location (below) + + +# This script is run whenever bbackupd encounters a problem which requires +# the system administrator to assist: +# 1) The store is full, and no more data can be uploaded. +# 2) Some files or directories were not readable. +# The default script emails the system administrator. + +# NotifyScript = NotifySysadmin.sh + + +# 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. + +UpdateStoreInterval = 3600 + + +# A file must have been modified at least 6 hours ago before it will be uploaded. + +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) + +MaxUploadWait = 86400 + + +# Files above this size (in bytes) are tracked, and if they are renamed they will simply be +# renamed on the server, rather than being uploaded again. (64k - 1) + +FileTrackingSizeThreshold = 65535 + + +# The daemon does "changes only" uploads for files above this size (in bytes). +# Files less than it are uploaded whole without this extra processing. + +DiffingUploadSizeThreshold = 8192 + + +# The limit on how much time is spent diffing files. Most files shouldn't take very long, +# but if you have really big files you can use this to limit the time spent diffing them. +# * Reduce if you are having problems with processor usage. +# * Increase if you have large files, and think the upload of changes is too large and want +# to spend more time searching for unchanged blocks. + +MaximumDiffingTime = 20 + +# KeepAliveTime requires Gary's SSL KeepAlive patches +# KeepAliveTime = 250 + +# Uncomment this line to see exactly what the daemon is going when it's connected to the server. + +# ExtendedLogging = yes + + +# Use this to temporarily stop bbackupd from syncronising or connecting to the store. +# This specifies a program or script script which is run just before each sync, and ideally +# the full path to the interpreter. It will be run as the same user bbackupd is running as, +# usually root. +# The script prints either "now" or a number to STDOUT (and a terminating newline, no quotes). +# If the result was "now", then the sync will happen. If it's a number, then the script will +# be asked again in that number of seconds. +# For example, you could use this on a laptop to only backup when on a specific network. + +# SyncAllowScript = /path/to/intepreter/or/exe script-name parameters etc + + +# Where the command socket is created in the filesystem. + +CommandSocket = pipe + + +Server +{ + PidFile = C:\Program Files\Box Backup\bbackupd\bbackupd.pid +} + +# StoreObjectInfoFile requires Gary's client marker serialisation patch +# StoreObjectInfoFile = C:\Program Files\Box Backup\bbackupd\bbackupd.dat + +# +# BackupLocations specifies which locations on disc should be backed up. Each +# directory is in the format +# +# name +# { +# Path = /path/of/directory +# (optional exclude directives) +# } +# +# 'name' is derived from the Path by the config script, but should merely be +# unique. +# +# The exclude directives are of the form +# +# [Exclude|AlwaysInclude][File|Dir][|sRegex] = regex or full pathname +# +# (The regex suffix is shown as 'sRegex' to make File or Dir plural) +# +# For example: +# +# ExcludeDir = /home/guest-user +# ExcludeFilesRegex = *.(mp3|MP3)$ +# AlwaysIncludeFile = /home/username/veryimportant.mp3 +# +# This excludes the directory /home/guest-user from the backup along with all mp3 +# files, except one MP3 file in particular. +# +# In general, Exclude excludes a file or directory, unless the directory is +# explicitly mentioned in a AlwaysInclude directive. +# +# If a directive ends in Regex, then it is a regular expression rather than a +# explicit full pathname. See +# +# man 7 re_format +# +# for the regex syntax on your platform. +# + +BackupLocations +{ + MyDocuments + { + Path = C:\Documents and Settings\ + } +} + diff --git a/bin/bbackupd/win32/installer.iss b/bin/bbackupd/win32/installer.iss new file mode 100644 index 00000000..20e3addb --- /dev/null +++ b/bin/bbackupd/win32/installer.iss @@ -0,0 +1,51 @@ +; Script to generate output file for Box Backup client for the Windows Platform +; +; Very important - this is the release process +; +; 1/ Upgrade BOX_VERSION in the file emu.h to the current version for example 0.09eWin32 - then perform a full rebuild +; +; 2/ Upgrade the AppVerName below to reflect the version +; +; 3/ Generate the output file, then rename it to the relevent filename to reflect the version + +[Setup] +AppName=Box Backup +AppVerName=BoxWin32 0.09h +AppPublisher=Fluffy & Omniis +AppPublisherURL=http://www.omniis.com +AppSupportURL=http://www.omniis.com +AppUpdatesURL=http://www.omniis.com +DefaultDirName={pf}\Box Backup +DefaultGroupName=Box Backup +Compression=lzma +SolidCompression=yes +PrivilegesRequired=admin + +[Files] +Source: "..\..\Release\bbackupd.exe"; DestDir: "{app}"; Flags: ignoreversion restartreplace +Source: "..\..\Release\bbackupctl.exe"; DestDir: "{app}"; Flags: ignoreversion restartreplace +Source: "..\..\Release\bbackupquery.exe"; DestDir: "{app}"; Flags: ignoreversion restartreplace +Source: "..\..\ExceptionCodes.txt"; DestDir: "{app}"; Flags: ignoreversion restartreplace +Source: "icon.ico"; DestDir: "{app}\"; Flags: ignoreversion restartreplace +Source: "msvcr71.dll"; DestDir: "{app}\"; Flags: restartreplace +Source: "bbackupd.conf"; DestDir: "{app}"; Flags: confirmoverwrite +Source: "..\..\..\zlib\zlib1.dll"; DestDir: "{app}"; Flags: ignoreversion restartreplace +Source: "..\..\..\openssl\bin\libeay32.dll"; DestDir: "{app}"; Flags: ignoreversion restartreplace +Source: "..\..\..\openssl\bin\ssleay32.dll"; DestDir: "{app}"; Flags: ignoreversion restartreplace +Source: "ReadMe.txt"; DestDir: "{app}"; Flags: ignoreversion restartreplace + +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\Box Backup Query"; Filename: "{app}\bbackupquery.exe"; IconFilename: "{app}\icon.ico" ;Parameters: "-c bbackupd.conf"; WorkingDir: "{app}" +Name: "{group}\Service\Install Service"; Filename: "{app}\bbackupd.exe"; IconFilename: "{app}\icon.ico" ;Parameters: "-i"; WorkingDir: "{app}" +Name: "{group}\Service\Remove Service"; Filename: "{app}\bbackupd.exe"; IconFilename: "{app}\icon.ico" ;Parameters: "-r"; WorkingDir: "{app}" +Name: "{group}\Initiate Backup Now"; Filename: "{app}\bbackupctl.exe"; IconFilename: "{app}\icon.ico" ;Parameters: "-c bbackupd.conf sync"; WorkingDir: "{app}" + +[Dirs] +Name: "{app}\bbackupd" + +[Run] +Filename: "{app}\bbackupd.exe"; Description: "Install Boxbackup as service"; Parameters: "-i"; Flags: postinstall +Filename: "{app}\Readme.txt"; Description: "View upgrade notes"; Flags: postinstall shellexec skipifsilent + diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index 27b5fa76..b37abc9d 100755 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -380,7 +380,11 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool { // add object ID to line char oid[32]; +#ifdef WIN32 + sprintf(oid, "%08I64x ", en->GetObjectID()); +#else sprintf(oid, "%08llx ", en->GetObjectID()); +#endif line += oid; } @@ -404,6 +408,7 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool } // attributes flags *(f++) = (en->HasAttributes())?'a':'-'; + // terminate *(f++) = ' '; *(f++) = '\0'; @@ -424,14 +429,22 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool if(opts[LIST_OPTION_DISPLAY_HASH]) { char hash[64]; +#ifdef WIN32 + ::sprintf(hash, "%016I64x ", en->GetAttributesHash()); +#else ::sprintf(hash, "%016llx ", en->GetAttributesHash()); +#endif line += hash; } if(opts[LIST_OPTION_SIZEINBLOCKS]) { char num[32]; +#ifdef WIN32 + sprintf(num, "%05I64d ", en->GetSizeInBlocks()); +#else sprintf(num, "%05lld ", en->GetSizeInBlocks()); +#endif line += num; } @@ -1034,7 +1047,8 @@ void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries: } // Then get it compared - Compare(std::string("/") + rLocation, loc.GetKeyValue("Path"), rParams); + Compare(std::string(DIRECTORY_SEPARATOR) + rLocation, + loc.GetKeyValue("Path"), rParams); } catch(...) { @@ -1165,7 +1179,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s #ifndef HAVE_VALID_DIRENT_D_TYPE std::string fn(rLocalDir); - fn += '/'; + fn += DIRECTORY_SEPARATOR_ASCHAR; fn += localDirEn->d_name; struct stat st; if(::lstat(fn.c_str(), &st) != 0) diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index 1eb86db6..d76664fb 100755 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -56,6 +56,19 @@ int main(int argc, const char *argv[]) { MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT("bbackupquery.memleaks", "bbackupquery") +#ifdef WIN32 + WSADATA info; + + // Under Win32 we must initialise the Winsock library + // before using it. + + if (WSAStartup(MAKELONG(1, 1), &info) == SOCKET_ERROR) + { + // throw error? perhaps give it its own id in the furture + THROW_EXCEPTION(BackupStoreException, Internal) + } +#endif + // Really don't want trace statements happening, even in debug mode #ifndef NDEBUG BoxDebugTraceOn = false; @@ -253,7 +266,11 @@ int main(int argc, const char *argv[]) MAINHELPER_END - exit(returnCode); +#ifdef WIN32 + // Clean up our sockets + WSACleanup(); +#endif + return returnCode; } diff --git a/bin/bbstoreaccounts/bbstoreaccounts.cpp b/bin/bbstoreaccounts/bbstoreaccounts.cpp index 89edd0b2..dd42458b 100755 --- a/bin/bbstoreaccounts/bbstoreaccounts.cpp +++ b/bin/bbstoreaccounts/bbstoreaccounts.cpp @@ -70,7 +70,11 @@ const char *BlockSizeToString(int64_t Blocks, int DiscSet) double mb = (Blocks * BlockSizeOfDiscSet(DiscSet)) / (1024.0*1024.0); // Format string +#ifdef WIN32 + sprintf(string, "%I64d (%.2fMb)", Blocks, mb); +#else sprintf(string, "%lld (%.2fMb)", Blocks, mb); +#endif return string; } -- cgit v1.2.3