From e370cf08364620cac777affb07088b59260025b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Feb 2014 15:44:07 +0000 Subject: Split bbstoreaccounts commands out into a separate class. Allows us to call them from tests without shelling out, making debugging easier. --- lib/backupstore/BackupStoreAccounts.cpp | 491 +++++++++++++++++++++++++++++++- 1 file changed, 486 insertions(+), 5 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 18500fc1..5aed4a6d 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -9,19 +9,29 @@ #include "Box.h" -#include +#include +#include +#include +#include +#include #include "BackupStoreAccounts.h" #include "BackupStoreAccountDatabase.h" +#include "BackupStoreCheck.h" +#include "BackupStoreConfigVerify.h" #include "BackupStoreConstants.h" #include "BackupStoreDirectory.h" #include "BackupStoreException.h" #include "BackupStoreInfo.h" #include "BackupStoreRefCountDatabase.h" #include "BoxPortsAndFiles.h" +#include "HousekeepStoreAccount.h" +#include "NamedLock.h" +#include "RaidFileController.h" #include "RaidFileWrite.h" #include "StoreStructure.h" #include "UnixUser.h" +#include "Utils.h" #include "MemLeakFindOn.h" @@ -110,10 +120,7 @@ void BackupStoreAccounts::Create(int32_t ID, int DiscSet, int64_t SizeSoftLimit, info->Save(); // Create the refcount database - BackupStoreRefCountDatabase::CreateNew(Entry); - std::auto_ptr refcount( - BackupStoreRefCountDatabase::Load(Entry, false)); - refcount->AddReference(BACKUPSTORE_ROOT_DIRECTORY_ID); + BackupStoreRefCountDatabase::Create(Entry)->Commit(); } // As the original user... @@ -201,3 +208,477 @@ void BackupStoreAccounts::LockAccount(int32_t ID, NamedLock& rNamedLock) "lock on account " << ID); } } + +BackupStoreAccountsControl::BackupStoreAccountsControl( + const Configuration& config, bool machineReadableOutput) +: mConfig(config), + mMachineReadableOutput(machineReadableOutput) +{ } + +void BackupStoreAccountsControl::CheckSoftHardLimits(int64_t SoftLimit, int64_t HardLimit) +{ + if(SoftLimit > HardLimit) + { + BOX_FATAL("Soft limit must be less than the hard limit."); + exit(1); + } + if(SoftLimit > ((HardLimit * MAX_SOFT_LIMIT_SIZE) / 100)) + { + BOX_WARNING("We recommend setting the soft limit below " << + MAX_SOFT_LIMIT_SIZE << "% of the hard limit, or " << + HumanReadableSize((HardLimit * MAX_SOFT_LIMIT_SIZE) + / 100) << " in this case."); + } +} + +int BackupStoreAccountsControl::BlockSizeOfDiscSet(int discSetNum) +{ + // Get controller, check disc set number + RaidFileController &controller(RaidFileController::GetController()); + if(discSetNum < 0 || discSetNum >= controller.GetNumDiscSets()) + { + BOX_FATAL("Disc set " << discSetNum << " does not exist."); + exit(1); + } + + // Return block size + return controller.GetDiscSet(discSetNum).GetBlockSize(); +} + +std::string BackupStoreAccountsControl::BlockSizeToString(int64_t Blocks, int64_t MaxBlocks, int discSetNum) +{ + return FormatUsageBar(Blocks, Blocks * BlockSizeOfDiscSet(discSetNum), + MaxBlocks * BlockSizeOfDiscSet(discSetNum), + mMachineReadableOutput); +} + +int64_t BackupStoreAccountsControl::SizeStringToBlocks(const char *string, int discSetNum) +{ + // Find block size + int blockSize = BlockSizeOfDiscSet(discSetNum); + + // Get number + char *endptr = (char*)string; + int64_t number = strtol(string, &endptr, 0); + if(endptr == string || number == LONG_MIN || number == LONG_MAX) + { + BOX_FATAL("'" << string << "' is not a valid number."); + exit(1); + } + + // Check units + switch(*endptr) + { + case 'M': + case 'm': + // Units: Mb + return (number * 1024*1024) / blockSize; + break; + + case 'G': + case 'g': + // Units: Gb + return (number * 1024*1024*1024) / blockSize; + break; + + case 'B': + case 'b': + // Units: Blocks + // Easy! Just return the number specified. + return number; + break; + + default: + BOX_FATAL(string << " has an invalid units specifier " + "(use B for blocks, M for MB, G for GB, eg 2GB)"); + exit(1); + break; + } +} + +int BackupStoreAccountsControl::SetLimit(int32_t ID, const char *SoftLimitStr, + const char *HardLimitStr) +{ + std::string rootDir; + int discSetNum; + std::auto_ptr user; // used to reset uid when we return + NamedLock writeLock; + + if(!OpenAccount(ID, rootDir, discSetNum, user, &writeLock)) + { + BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) + << " to change limits."); + return 1; + } + + // Load the info + std::auto_ptr info(BackupStoreInfo::Load(ID, rootDir, + discSetNum, false /* Read/Write */)); + + // Change the limits + int64_t softlimit = SizeStringToBlocks(SoftLimitStr, discSetNum); + int64_t hardlimit = SizeStringToBlocks(HardLimitStr, discSetNum); + CheckSoftHardLimits(softlimit, hardlimit); + info->ChangeLimits(softlimit, hardlimit); + + // Save + info->Save(); + + BOX_NOTICE("Limits on account " << BOX_FORMAT_ACCOUNT(ID) << + " changed to " << softlimit << " soft, " << + hardlimit << " hard."); + + return 0; +} + +int BackupStoreAccountsControl::SetAccountName(int32_t ID, const std::string& rNewAccountName) +{ + std::string rootDir; + int discSetNum; + std::auto_ptr user; // used to reset uid when we return + NamedLock writeLock; + + if(!OpenAccount(ID, rootDir, discSetNum, user, &writeLock)) + { + BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) + << " to change name."); + return 1; + } + + // Load the info + std::auto_ptr info(BackupStoreInfo::Load(ID, + rootDir, discSetNum, false /* Read/Write */)); + + info->SetAccountName(rNewAccountName); + + // Save + info->Save(); + + BOX_NOTICE("Account " << BOX_FORMAT_ACCOUNT(ID) << + " name changed to " << rNewAccountName); + + return 0; +} + +int BackupStoreAccountsControl::PrintAccountInfo(int32_t ID) +{ + std::string rootDir; + int discSetNum; + std::auto_ptr user; // used to reset uid when we return + + if(!OpenAccount(ID, rootDir, discSetNum, user, + NULL /* no write lock needed for this read-only operation */)) + { + BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) + << " to display info."); + return 1; + } + + // Load it in + std::auto_ptr info(BackupStoreInfo::Load(ID, + rootDir, discSetNum, true /* ReadOnly */)); + + // Then print out lots of info + std::cout << FormatUsageLineStart("Account ID", mMachineReadableOutput) << + BOX_FORMAT_ACCOUNT(ID) << std::endl; + std::cout << FormatUsageLineStart("Account Name", mMachineReadableOutput) << + info->GetAccountName() << std::endl; + std::cout << FormatUsageLineStart("Last object ID", mMachineReadableOutput) << + BOX_FORMAT_OBJECTID(info->GetLastObjectIDUsed()) << std::endl; + std::cout << FormatUsageLineStart("Used", mMachineReadableOutput) << + BlockSizeToString(info->GetBlocksUsed(), + info->GetBlocksHardLimit(), discSetNum) << std::endl; + std::cout << FormatUsageLineStart("Current files", + mMachineReadableOutput) << + BlockSizeToString(info->GetBlocksInCurrentFiles(), + info->GetBlocksHardLimit(), discSetNum) << std::endl; + std::cout << FormatUsageLineStart("Old files", mMachineReadableOutput) << + BlockSizeToString(info->GetBlocksInOldFiles(), + info->GetBlocksHardLimit(), discSetNum) << std::endl; + std::cout << FormatUsageLineStart("Deleted files", mMachineReadableOutput) << + BlockSizeToString(info->GetBlocksInDeletedFiles(), + info->GetBlocksHardLimit(), discSetNum) << std::endl; + std::cout << FormatUsageLineStart("Directories", mMachineReadableOutput) << + BlockSizeToString(info->GetBlocksInDirectories(), + info->GetBlocksHardLimit(), discSetNum) << std::endl; + std::cout << FormatUsageLineStart("Soft limit", mMachineReadableOutput) << + BlockSizeToString(info->GetBlocksSoftLimit(), + info->GetBlocksHardLimit(), discSetNum) << std::endl; + std::cout << FormatUsageLineStart("Hard limit", mMachineReadableOutput) << + BlockSizeToString(info->GetBlocksHardLimit(), + info->GetBlocksHardLimit(), discSetNum) << std::endl; + std::cout << FormatUsageLineStart("Client store marker", mMachineReadableOutput) << + info->GetLastObjectIDUsed() << std::endl; + std::cout << FormatUsageLineStart("Current Files", mMachineReadableOutput) << + info->GetNumCurrentFiles() << std::endl; + std::cout << FormatUsageLineStart("Old Files", mMachineReadableOutput) << + info->GetNumOldFiles() << std::endl; + std::cout << FormatUsageLineStart("Deleted Files", mMachineReadableOutput) << + info->GetNumDeletedFiles() << std::endl; + std::cout << FormatUsageLineStart("Directories", mMachineReadableOutput) << + info->GetNumDirectories() << std::endl; + std::cout << FormatUsageLineStart("Enabled", mMachineReadableOutput) << + (info->IsAccountEnabled() ? "yes" : "no") << std::endl; + + return 0; +} + +int BackupStoreAccountsControl::SetAccountEnabled(int32_t ID, bool enabled) +{ + std::string rootDir; + int discSetNum; + std::auto_ptr user; // used to reset uid when we return + NamedLock writeLock; + + if(!OpenAccount(ID, rootDir, discSetNum, user, &writeLock)) + { + BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) + << " to change enabled flag."); + return 1; + } + + // Load it in + std::auto_ptr info(BackupStoreInfo::Load(ID, + rootDir, discSetNum, false /* ReadOnly */)); + info->SetAccountEnabled(enabled); + info->Save(); + return 0; +} + +int BackupStoreAccountsControl::DeleteAccount(int32_t ID, bool AskForConfirmation) +{ + std::string rootDir; + int discSetNum; + std::auto_ptr user; // used to reset uid when we return + NamedLock writeLock; + + // Obtain a write lock, as the daemon user + if(!OpenAccount(ID, rootDir, discSetNum, user, &writeLock)) + { + BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) + << " for deletion."); + return 1; + } + + // Check user really wants to do this + if(AskForConfirmation) + { + 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) + { + BOX_NOTICE("Deletion cancelled."); + return 0; + } + } + + // Back to original user, but write lock is maintained + user.reset(); + + std::auto_ptr db( + BackupStoreAccountDatabase::Read( + mConfig.GetKeyValue("AccountDatabase"))); + + // Delete from account database + db->DeleteEntry(ID); + + // Write back to disc + db->Write(); + + // Remove the store files... + + // First, become the user specified in the config file + std::string username; + { + const Configuration &rserverConfig(mConfig.GetSubConfiguration("Server")); + if(rserverConfig.KeyExists("User")) + { + username = rserverConfig.GetKeyValue("User"); + } + } + + // Become the right user + if(!username.empty()) + { + // Username specified, change... + user.reset(new UnixUser(username)); + user->ChangeProcessUser(true /* temporary */); + // Change will be undone when user goes out of scope + } + + // Secondly, work out which directories need wiping + std::vector toDelete; + RaidFileController &rcontroller(RaidFileController::GetController()); + RaidFileDiscSet discSet(rcontroller.GetDiscSet(discSetNum)); + for(RaidFileDiscSet::const_iterator i(discSet.begin()); i != discSet.end(); ++i) + { + if(std::find(toDelete.begin(), toDelete.end(), *i) == toDelete.end()) + { + toDelete.push_back((*i) + DIRECTORY_SEPARATOR + rootDir); + } + } + +#ifdef WIN32 + // Cannot remove files while holding a lock on them + writeLock.ReleaseLock(); +#endif + + int retcode = 0; + + // Thirdly, delete the directories... + for(std::vector::const_iterator d(toDelete.begin()); d != toDelete.end(); ++d) + { + 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) + { + BOX_ERROR("Failed to delete files in " << (*d) << + ", delete them manually."); + retcode = 1; + } + } + + // Success! + return retcode; +} + +bool BackupStoreAccountsControl::OpenAccount(int32_t ID, std::string &rRootDirOut, + int &rDiscSetOut, std::auto_ptr apUser, NamedLock* pLock) +{ + // Load in the account database + std::auto_ptr db( + BackupStoreAccountDatabase::Read( + mConfig.GetKeyValue("AccountDatabase"))); + + // Exists? + if(!db->EntryExists(ID)) + { + BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << + " does not exist."); + return false; + } + + // Get info from the database + BackupStoreAccounts acc(*db); + acc.GetAccountRoot(ID, rRootDirOut, rDiscSetOut); + + // Get the user under which the daemon runs + std::string username; + { + const Configuration &rserverConfig(mConfig.GetSubConfiguration("Server")); + if(rserverConfig.KeyExists("User")) + { + username = rserverConfig.GetKeyValue("User"); + } + } + + // Become the right user + if(!username.empty()) + { + // Username specified, change... + apUser.reset(new UnixUser(username)); + apUser->ChangeProcessUser(true /* temporary */); + // Change will be undone when apUser goes out of scope + // in the caller. + } + + if(pLock) + { + acc.LockAccount(ID, *pLock); + } + + return true; +} + +int BackupStoreAccountsControl::CheckAccount(int32_t ID, bool FixErrors, bool Quiet) +{ + std::string rootDir; + int discSetNum; + std::auto_ptr user; // used to reset uid when we return + NamedLock writeLock; + + if(!OpenAccount(ID, rootDir, discSetNum, user, &writeLock)) + { + BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) + << " for checking."); + return 1; + } + + // Check it + BackupStoreCheck check(rootDir, discSetNum, ID, FixErrors, Quiet); + check.Check(); + + return check.ErrorsFound()?1:0; +} + +int BackupStoreAccountsControl::CreateAccount(int32_t ID, int32_t DiscNumber, + int32_t SoftLimit, int32_t HardLimit) +{ + // Load in the account database + std::auto_ptr db( + BackupStoreAccountDatabase::Read( + mConfig.GetKeyValue("AccountDatabase"))); + + // Already exists? + if(db->EntryExists(ID)) + { + BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << + " already exists."); + return 1; + } + + // Get the user under which the daemon runs + std::string username; + { + const Configuration &rserverConfig(mConfig.GetSubConfiguration("Server")); + if(rserverConfig.KeyExists("User")) + { + username = rserverConfig.GetKeyValue("User"); + } + } + + // Create it. + BackupStoreAccounts acc(*db); + acc.Create(ID, DiscNumber, SoftLimit, HardLimit, username); + + BOX_NOTICE("Account " << BOX_FORMAT_ACCOUNT(ID) << " created."); + + return 0; +} + +int BackupStoreAccountsControl::HousekeepAccountNow(int32_t ID) +{ + std::string rootDir; + int discSetNum; + std::auto_ptr user; // used to reset uid when we return + + if(!OpenAccount(ID, rootDir, discSetNum, user, + NULL /* housekeeping locks the account itself */)) + { + BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) + << " for housekeeping."); + return 1; + } + + HousekeepStoreAccount housekeeping(ID, rootDir, discSetNum, NULL); + bool success = housekeeping.DoHousekeeping(); + + if(!success) + { + BOX_ERROR("Failed to lock account " << BOX_FORMAT_ACCOUNT(ID) + << " for housekeeping: perhaps a client is " + "still connected?"); + return 1; + } + else + { + BOX_TRACE("Finished housekeeping on account " << + BOX_FORMAT_ACCOUNT(ID)); + return 0; + } +} + -- cgit v1.2.3 From b5ad923c87a1977875966b82ea8b421b7a71f9eb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Feb 2014 19:57:27 +0000 Subject: Fix compile error introduced by bbstoreaccounts refactor. --- lib/backupstore/BackupStoreAccounts.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 5aed4a6d..d9efcd5d 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -120,7 +120,10 @@ void BackupStoreAccounts::Create(int32_t ID, int DiscSet, int64_t SizeSoftLimit, info->Save(); // Create the refcount database - BackupStoreRefCountDatabase::Create(Entry)->Commit(); + BackupStoreRefCountDatabase::CreateNew(Entry); + std::auto_ptr refcount( + BackupStoreRefCountDatabase::Load(Entry, false)); + refcount->AddReference(BACKUPSTORE_ROOT_DIRECTORY_ID); } // As the original user... @@ -410,7 +413,7 @@ int BackupStoreAccountsControl::PrintAccountInfo(int32_t ID) std::cout << FormatUsageLineStart("Client store marker", mMachineReadableOutput) << info->GetLastObjectIDUsed() << std::endl; std::cout << FormatUsageLineStart("Current Files", mMachineReadableOutput) << - info->GetNumCurrentFiles() << std::endl; + info->GetNumFiles() << std::endl; std::cout << FormatUsageLineStart("Old Files", mMachineReadableOutput) << info->GetNumOldFiles() << std::endl; std::cout << FormatUsageLineStart("Deleted Files", mMachineReadableOutput) << -- cgit v1.2.3 From b2501248e2251d6601fbf2ad60ceb328d110593a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Feb 2014 20:03:30 +0000 Subject: Revert "Fix compile error introduced by bbstoreaccounts refactor." This reverts commit 9d0580c58025ba94bee02cdc2aae3fe0b6ccf604. --- lib/backupstore/BackupStoreAccounts.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index d9efcd5d..5aed4a6d 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -120,10 +120,7 @@ void BackupStoreAccounts::Create(int32_t ID, int DiscSet, int64_t SizeSoftLimit, info->Save(); // Create the refcount database - BackupStoreRefCountDatabase::CreateNew(Entry); - std::auto_ptr refcount( - BackupStoreRefCountDatabase::Load(Entry, false)); - refcount->AddReference(BACKUPSTORE_ROOT_DIRECTORY_ID); + BackupStoreRefCountDatabase::Create(Entry)->Commit(); } // As the original user... @@ -413,7 +410,7 @@ int BackupStoreAccountsControl::PrintAccountInfo(int32_t ID) std::cout << FormatUsageLineStart("Client store marker", mMachineReadableOutput) << info->GetLastObjectIDUsed() << std::endl; std::cout << FormatUsageLineStart("Current Files", mMachineReadableOutput) << - info->GetNumFiles() << std::endl; + info->GetNumCurrentFiles() << std::endl; std::cout << FormatUsageLineStart("Old Files", mMachineReadableOutput) << info->GetNumOldFiles() << std::endl; std::cout << FormatUsageLineStart("Deleted Files", mMachineReadableOutput) << -- cgit v1.2.3 From e5dc0fdadb638d74dffa4bcee8954d8ce4c550b9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Feb 2014 20:30:43 +0000 Subject: Revert "Revert "Fix compile error introduced by bbstoreaccounts refactor."" This reverts commit b3bc7ad5be2c5b2588793aaa9fbc05e4a1c0aea5. Should not have been applied in SVN (not just yet, anyway). --- lib/backupstore/BackupStoreAccounts.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 5aed4a6d..d9efcd5d 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -120,7 +120,10 @@ void BackupStoreAccounts::Create(int32_t ID, int DiscSet, int64_t SizeSoftLimit, info->Save(); // Create the refcount database - BackupStoreRefCountDatabase::Create(Entry)->Commit(); + BackupStoreRefCountDatabase::CreateNew(Entry); + std::auto_ptr refcount( + BackupStoreRefCountDatabase::Load(Entry, false)); + refcount->AddReference(BACKUPSTORE_ROOT_DIRECTORY_ID); } // As the original user... @@ -410,7 +413,7 @@ int BackupStoreAccountsControl::PrintAccountInfo(int32_t ID) std::cout << FormatUsageLineStart("Client store marker", mMachineReadableOutput) << info->GetLastObjectIDUsed() << std::endl; std::cout << FormatUsageLineStart("Current Files", mMachineReadableOutput) << - info->GetNumCurrentFiles() << std::endl; + info->GetNumFiles() << std::endl; std::cout << FormatUsageLineStart("Old Files", mMachineReadableOutput) << info->GetNumOldFiles() << std::endl; std::cout << FormatUsageLineStart("Deleted Files", mMachineReadableOutput) << -- cgit v1.2.3 From 58f09a365624705b25d29aa3caeefa0d97d1c9ba Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Feb 2014 23:05:04 +0000 Subject: Create new refcount database atomically during account check. Use a temporary refcount db for check instead of an in-memory vector. This avoid the memory usage problems created by using the vector on large accounts, but may require us to improve the efficiency of the refcount database itself to avoid large numbers of small I/O operations. That is very doable now that we're using a class for it. Fix some inconsistencies and mistakes in handling reference counts and info counters during account checks (more to come). --- lib/backupstore/BackupStoreAccounts.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index d9efcd5d..6a4d846c 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -120,10 +120,7 @@ void BackupStoreAccounts::Create(int32_t ID, int DiscSet, int64_t SizeSoftLimit, info->Save(); // Create the refcount database - BackupStoreRefCountDatabase::CreateNew(Entry); - std::auto_ptr refcount( - BackupStoreRefCountDatabase::Load(Entry, false)); - refcount->AddReference(BACKUPSTORE_ROOT_DIRECTORY_ID); + BackupStoreRefCountDatabase::Create(Entry)->Commit(); } // As the original user... -- cgit v1.2.3 From c7d7ad5dd7d158866da84edce1b2adb4a77d517c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 9 Feb 2014 16:39:40 +0000 Subject: Rename BackupStoreInfo variable NumFiles to NumCurrentFiles. Will hopefully prevent future confusion about the meaning of this info variable. --- lib/backupstore/BackupStoreAccounts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 6a4d846c..5aed4a6d 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -410,7 +410,7 @@ int BackupStoreAccountsControl::PrintAccountInfo(int32_t ID) std::cout << FormatUsageLineStart("Client store marker", mMachineReadableOutput) << info->GetLastObjectIDUsed() << std::endl; std::cout << FormatUsageLineStart("Current Files", mMachineReadableOutput) << - info->GetNumFiles() << std::endl; + info->GetNumCurrentFiles() << std::endl; std::cout << FormatUsageLineStart("Old Files", mMachineReadableOutput) << info->GetNumOldFiles() << std::endl; std::cout << FormatUsageLineStart("Deleted Files", mMachineReadableOutput) << -- cgit v1.2.3 From e60a40bd6e5b1f95541115afb8ea976f79662158 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Feb 2014 13:51:52 +0000 Subject: Fix wrong output of client store marker in bbstoraccounts info. --- lib/backupstore/BackupStoreAccounts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 5aed4a6d..3fa9d242 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -408,7 +408,7 @@ int BackupStoreAccountsControl::PrintAccountInfo(int32_t ID) BlockSizeToString(info->GetBlocksHardLimit(), info->GetBlocksHardLimit(), discSetNum) << std::endl; std::cout << FormatUsageLineStart("Client store marker", mMachineReadableOutput) << - info->GetLastObjectIDUsed() << std::endl; + info->GetClientStoreMarker() << std::endl; std::cout << FormatUsageLineStart("Current Files", mMachineReadableOutput) << info->GetNumCurrentFiles() << std::endl; std::cout << FormatUsageLineStart("Old Files", mMachineReadableOutput) << -- cgit v1.2.3 From 6532d211951a52c62d2617340447f6bafd540e92 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 Feb 2014 23:35:24 +0000 Subject: Allow read-only account check without taking a write lock on account. --- lib/backupstore/BackupStoreAccounts.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 3fa9d242..bbf85f8a 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -601,7 +601,8 @@ int BackupStoreAccountsControl::CheckAccount(int32_t ID, bool FixErrors, bool Qu std::auto_ptr user; // used to reset uid when we return NamedLock writeLock; - if(!OpenAccount(ID, rootDir, discSetNum, user, &writeLock)) + if(!OpenAccount(ID, rootDir, discSetNum, user, + FixErrors ? &writeLock : NULL)) // don't need a write lock if not making changes { BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) << " for checking."); -- cgit v1.2.3 From 15677eb9461ef9f868d0cb56b1b7fb2c8601d377 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 2 Mar 2014 09:00:53 +0000 Subject: Whitespace, comments and log messages cleanups. --- lib/backupstore/BackupStoreAccounts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index bbf85f8a..22628017 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -205,7 +205,7 @@ void BackupStoreAccounts::LockAccount(int32_t ID, NamedLock& rNamedLock) { THROW_EXCEPTION_MESSAGE(BackupStoreException, CouldNotLockStoreAccount, "Failed to get exclusive " - "lock on account " << ID); + "lock on account " << BOX_FORMAT_ACCOUNT(ID)); } } -- cgit v1.2.3 From 6622bfe4eb59a2f38f7012349525ec64f0368118 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 22 Dec 2014 23:09:31 +0000 Subject: Replace sprintf() with snprintf(), fixes compile warnings on OpenBSD. And compile errors on recent MinGW. --- lib/backupstore/BackupStoreAccounts.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 22628017..7bfa029d 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -158,9 +158,9 @@ void BackupStoreAccounts::GetAccountRoot(int32_t ID, std::string &rRootDirOut, i std::string BackupStoreAccounts::MakeAccountRootDir(int32_t ID, int DiscSet) { char accid[64]; // big enough! - ::sprintf(accid, "%08x" DIRECTORY_SEPARATOR, ID); - return std::string(std::string(BOX_RAIDFILE_ROOT_BBSTORED - DIRECTORY_SEPARATOR) + accid); + ::snprintf(accid, sizeof(accid) - 1, "%08x" DIRECTORY_SEPARATOR, ID); + return std::string(BOX_RAIDFILE_ROOT_BBSTORED DIRECTORY_SEPARATOR) + + accid; } -- cgit v1.2.3 From af310e1e3f03557d52c4ea69d2e5730de213a9b7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 4 May 2015 18:56:34 +0000 Subject: Fix tests failing because they can't delete the lock file. Deleting the account deletes the lockfile, so unlocking fails. --- lib/backupstore/BackupStoreAccounts.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 7bfa029d..5f51917b 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -519,10 +519,10 @@ int BackupStoreAccountsControl::DeleteAccount(int32_t ID, bool AskForConfirmatio } } -#ifdef WIN32 - // Cannot remove files while holding a lock on them + // NamedLock will throw an exception if it can't delete the lockfile, + // which it can't if it doesn't exist. Now that we've deleted the account, + // nobody can open it anyway, so it's safe to unlock. writeLock.ReleaseLock(); -#endif int retcode = 0; -- cgit v1.2.3 From 41b716a473e2efae0993a0dc323cd786c329ff7a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 6 May 2015 21:29:39 +0000 Subject: Fix missing account lock while checking for errors. The old assertion, that the write lock file exists before starting checking, was erroneously passing before when no lock was held, because the lockfile was never deleted. Now that we delete it when unlocking the account, this started causing test failures. Changed the way that accounts are checked for errors to use a function that acquires a write lock first, and modified test to disconnect open clients before starting checking the account, to fix it. --- lib/backupstore/BackupStoreAccounts.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 5f51917b..d1c7430f 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -594,7 +594,8 @@ bool BackupStoreAccountsControl::OpenAccount(int32_t ID, std::string &rRootDirOu return true; } -int BackupStoreAccountsControl::CheckAccount(int32_t ID, bool FixErrors, bool Quiet) +int BackupStoreAccountsControl::CheckAccount(int32_t ID, bool FixErrors, bool Quiet, + bool ReturnNumErrorsFound) { std::string rootDir; int discSetNum; @@ -612,8 +613,15 @@ int BackupStoreAccountsControl::CheckAccount(int32_t ID, bool FixErrors, bool Qu // Check it BackupStoreCheck check(rootDir, discSetNum, ID, FixErrors, Quiet); check.Check(); - - return check.ErrorsFound()?1:0; + + if(ReturnNumErrorsFound) + { + return check.GetNumErrorsFound(); + } + else + { + return check.ErrorsFound() ? 1 : 0; + } } int BackupStoreAccountsControl::CreateAccount(int32_t ID, int32_t DiscNumber, -- cgit v1.2.3 From 66e4d036cea1eac39394c9064f50eee5c993926a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 28 Jun 2015 19:36:47 +0000 Subject: Refactor store account control to allow other store types. Move common code into a base class, leaving bbstored-specific code. Add skeleton of an S3 store type. --- lib/backupstore/BackupStoreAccounts.cpp | 125 ++------------------------------ 1 file changed, 6 insertions(+), 119 deletions(-) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index d1c7430f..6650b12a 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -209,28 +209,6 @@ void BackupStoreAccounts::LockAccount(int32_t ID, NamedLock& rNamedLock) } } -BackupStoreAccountsControl::BackupStoreAccountsControl( - const Configuration& config, bool machineReadableOutput) -: mConfig(config), - mMachineReadableOutput(machineReadableOutput) -{ } - -void BackupStoreAccountsControl::CheckSoftHardLimits(int64_t SoftLimit, int64_t HardLimit) -{ - if(SoftLimit > HardLimit) - { - BOX_FATAL("Soft limit must be less than the hard limit."); - exit(1); - } - if(SoftLimit > ((HardLimit * MAX_SOFT_LIMIT_SIZE) / 100)) - { - BOX_WARNING("We recommend setting the soft limit below " << - MAX_SOFT_LIMIT_SIZE << "% of the hard limit, or " << - HumanReadableSize((HardLimit * MAX_SOFT_LIMIT_SIZE) - / 100) << " in this case."); - } -} - int BackupStoreAccountsControl::BlockSizeOfDiscSet(int discSetNum) { // Get controller, check disc set number @@ -245,57 +223,6 @@ int BackupStoreAccountsControl::BlockSizeOfDiscSet(int discSetNum) return controller.GetDiscSet(discSetNum).GetBlockSize(); } -std::string BackupStoreAccountsControl::BlockSizeToString(int64_t Blocks, int64_t MaxBlocks, int discSetNum) -{ - return FormatUsageBar(Blocks, Blocks * BlockSizeOfDiscSet(discSetNum), - MaxBlocks * BlockSizeOfDiscSet(discSetNum), - mMachineReadableOutput); -} - -int64_t BackupStoreAccountsControl::SizeStringToBlocks(const char *string, int discSetNum) -{ - // Find block size - int blockSize = BlockSizeOfDiscSet(discSetNum); - - // Get number - char *endptr = (char*)string; - int64_t number = strtol(string, &endptr, 0); - if(endptr == string || number == LONG_MIN || number == LONG_MAX) - { - BOX_FATAL("'" << string << "' is not a valid number."); - exit(1); - } - - // Check units - switch(*endptr) - { - case 'M': - case 'm': - // Units: Mb - return (number * 1024*1024) / blockSize; - break; - - case 'G': - case 'g': - // Units: Gb - return (number * 1024*1024*1024) / blockSize; - break; - - case 'B': - case 'b': - // Units: Blocks - // Easy! Just return the number specified. - return number; - break; - - default: - BOX_FATAL(string << " has an invalid units specifier " - "(use B for blocks, M for MB, G for GB, eg 2GB)"); - exit(1); - break; - } -} - int BackupStoreAccountsControl::SetLimit(int32_t ID, const char *SoftLimitStr, const char *HardLimitStr) { @@ -316,8 +243,9 @@ int BackupStoreAccountsControl::SetLimit(int32_t ID, const char *SoftLimitStr, discSetNum, false /* Read/Write */)); // Change the limits - int64_t softlimit = SizeStringToBlocks(SoftLimitStr, discSetNum); - int64_t hardlimit = SizeStringToBlocks(HardLimitStr, discSetNum); + int blocksize = BlockSizeOfDiscSet(discSetNum); + int64_t softlimit = SizeStringToBlocks(SoftLimitStr, blocksize); + int64_t hardlimit = SizeStringToBlocks(HardLimitStr, blocksize); CheckSoftHardLimits(softlimit, hardlimit); info->ChangeLimits(softlimit, hardlimit); @@ -377,50 +305,9 @@ int BackupStoreAccountsControl::PrintAccountInfo(int32_t ID) // Load it in std::auto_ptr info(BackupStoreInfo::Load(ID, rootDir, discSetNum, true /* ReadOnly */)); - - // Then print out lots of info - std::cout << FormatUsageLineStart("Account ID", mMachineReadableOutput) << - BOX_FORMAT_ACCOUNT(ID) << std::endl; - std::cout << FormatUsageLineStart("Account Name", mMachineReadableOutput) << - info->GetAccountName() << std::endl; - std::cout << FormatUsageLineStart("Last object ID", mMachineReadableOutput) << - BOX_FORMAT_OBJECTID(info->GetLastObjectIDUsed()) << std::endl; - std::cout << FormatUsageLineStart("Used", mMachineReadableOutput) << - BlockSizeToString(info->GetBlocksUsed(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Current files", - mMachineReadableOutput) << - BlockSizeToString(info->GetBlocksInCurrentFiles(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Old files", mMachineReadableOutput) << - BlockSizeToString(info->GetBlocksInOldFiles(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Deleted files", mMachineReadableOutput) << - BlockSizeToString(info->GetBlocksInDeletedFiles(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Directories", mMachineReadableOutput) << - BlockSizeToString(info->GetBlocksInDirectories(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Soft limit", mMachineReadableOutput) << - BlockSizeToString(info->GetBlocksSoftLimit(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Hard limit", mMachineReadableOutput) << - BlockSizeToString(info->GetBlocksHardLimit(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Client store marker", mMachineReadableOutput) << - info->GetClientStoreMarker() << std::endl; - std::cout << FormatUsageLineStart("Current Files", mMachineReadableOutput) << - info->GetNumCurrentFiles() << std::endl; - std::cout << FormatUsageLineStart("Old Files", mMachineReadableOutput) << - info->GetNumOldFiles() << std::endl; - std::cout << FormatUsageLineStart("Deleted Files", mMachineReadableOutput) << - info->GetNumDeletedFiles() << std::endl; - std::cout << FormatUsageLineStart("Directories", mMachineReadableOutput) << - info->GetNumDirectories() << std::endl; - std::cout << FormatUsageLineStart("Enabled", mMachineReadableOutput) << - (info->IsAccountEnabled() ? "yes" : "no") << std::endl; - - return 0; + + return BackupAccountControl::PrintAccountInfo(*info, + BlockSizeOfDiscSet(discSetNum)); } int BackupStoreAccountsControl::SetAccountEnabled(int32_t ID, bool enabled) -- cgit v1.2.3 From 1a91d5f642d6cbbca871cae63ef6b3b1caef068d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 17 Dec 2015 23:00:55 +0000 Subject: Fix account deletion on Windows. Use the rmdir command instead of rm -rf. --- lib/backupstore/BackupStoreAccounts.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lib/backupstore/BackupStoreAccounts.cpp') diff --git a/lib/backupstore/BackupStoreAccounts.cpp b/lib/backupstore/BackupStoreAccounts.cpp index 6650b12a..7955b3c4 100644 --- a/lib/backupstore/BackupStoreAccounts.cpp +++ b/lib/backupstore/BackupStoreAccounts.cpp @@ -418,8 +418,23 @@ int BackupStoreAccountsControl::DeleteAccount(int32_t ID, bool AskForConfirmatio { BOX_NOTICE("Deleting store directory " << (*d) << "..."); // Just use the rm command to delete the files +#ifdef WIN32 + std::string cmd("rmdir /s/q "); + std::string dir = *d; + + // rmdir doesn't understand forward slashes, so replace them all. + for(std::string::iterator i = dir.begin(); i != dir.end(); i++) + { + if(*i == '/') + { + *i = '\\'; + } + } + cmd += dir; +#else std::string cmd("rm -rf "); cmd += *d; +#endif // Run command if(::system(cmd.c_str()) != 0) { -- cgit v1.2.3