summaryrefslogtreecommitdiff
path: root/bin/bbackupquery/BackupQueries.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'bin/bbackupquery/BackupQueries.cpp')
-rw-r--r--bin/bbackupquery/BackupQueries.cpp1240
1 files changed, 643 insertions, 597 deletions
diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp
index b6984641..687dcb05 100644
--- a/bin/bbackupquery/BackupQueries.cpp
+++ b/bin/bbackupquery/BackupQueries.cpp
@@ -13,7 +13,6 @@
#include <unistd.h>
#endif
-#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
@@ -25,29 +24,33 @@
#include <dirent.h>
#endif
-#include <set>
+#include <cstring>
#include <limits>
+#include <iostream>
+#include <ostream>
+#include <set>
+#include "BackupClientFileAttributes.h"
+#include "BackupClientMakeExcludeList.h"
+#include "BackupClientRestore.h"
#include "BackupQueries.h"
-#include "Utils.h"
-#include "Configuration.h"
-#include "autogen_BackupProtocolClient.h"
-#include "BackupStoreFilenameClear.h"
#include "BackupStoreDirectory.h"
-#include "IOStream.h"
-#include "BoxTimeToText.h"
-#include "FileStream.h"
+#include "BackupStoreException.h"
#include "BackupStoreFile.h"
-#include "TemporaryDirectory.h"
-#include "FileModificationTime.h"
-#include "BackupClientFileAttributes.h"
+#include "BackupStoreFilenameClear.h"
+#include "BoxTimeToText.h"
#include "CommonException.h"
-#include "BackupClientRestore.h"
-#include "BackupStoreException.h"
+#include "Configuration.h"
#include "ExcludeList.h"
-#include "BackupClientMakeExcludeList.h"
-#include "PathUtils.h"
+#include "FileModificationTime.h"
+#include "FileStream.h"
+#include "IOStream.h"
#include "Logging.h"
+#include "PathUtils.h"
+#include "SelfFlushingStream.h"
+#include "TemporaryDirectory.h"
+#include "Utils.h"
+#include "autogen_BackupProtocolClient.h"
#include "MemLeakFindOn.h"
@@ -68,8 +71,10 @@
// Created: 2003/10/10
//
// --------------------------------------------------------------------------
-BackupQueries::BackupQueries(BackupProtocolClient &rConnection, const Configuration &rConfiguration)
- : mrConnection(rConnection),
+BackupQueries::BackupQueries(BackupProtocolClient &rConnection,
+ const Configuration &rConfiguration, bool readWrite)
+ : mReadWrite(readWrite),
+ mrConnection(rConnection),
mrConfiguration(rConfiguration),
mQuitNow(false),
mRunningAsRoot(false),
@@ -115,7 +120,13 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
if(Command[0] == 's' && Command[1] == 'h' && Command[2] == ' ' && Command[3] != '\0')
{
// Yes, run shell command
- ::system(Command + 3);
+ int result = ::system(Command + 3);
+ if(result != 0)
+ {
+ BOX_WARNING("System command returned error code " <<
+ result);
+ SetReturnCode(ReturnCode::Command_Error);
+ }
return;
}
@@ -209,28 +220,36 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
{ "getobject", "" },
{ "get", "i" },
{ "compare", "alcqAEQ" },
- { "restore", "dri" },
+ { "restore", "drif" },
{ "help", "" },
- { "usage", "" },
+ { "usage", "m" },
{ "undelete", "" },
+ { "delete", "" },
{ NULL, NULL }
};
- #define COMMAND_Quit 0
- #define COMMAND_Exit 1
- #define COMMAND_List 2
- #define COMMAND_pwd 3
- #define COMMAND_cd 4
- #define COMMAND_lcd 5
- #define COMMAND_sh 6
- #define COMMAND_GetObject 7
- #define COMMAND_Get 8
- #define COMMAND_Compare 9
- #define COMMAND_Restore 10
- #define COMMAND_Help 11
- #define COMMAND_Usage 12
- #define COMMAND_Undelete 13
- static const char *alias[] = {"ls", 0};
- static const int aliasIs[] = {COMMAND_List, 0};
+
+ typedef enum
+ {
+ Command_Quit = 0,
+ Command_Exit,
+ Command_List,
+ Command_pwd,
+ Command_cd,
+ Command_lcd,
+ Command_sh,
+ Command_GetObject,
+ Command_Get,
+ Command_Compare,
+ Command_Restore,
+ Command_Help,
+ Command_Usage,
+ Command_Undelete,
+ Command_Delete,
+ }
+ CommandType;
+
+ static const char *alias[] = {"ls", 0};
+ static const int aliasIs[] = {Command_List, 0};
// Work out which command it is...
int cmd = 0;
@@ -284,25 +303,25 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
}
}
- if(cmd != COMMAND_Quit && cmd != COMMAND_Exit)
+ if(cmd != Command_Quit && cmd != Command_Exit)
{
// If not a quit command, set the return code to zero
- SetReturnCode(0);
+ SetReturnCode(ReturnCode::Command_OK);
}
// Handle command
switch(cmd)
{
- case COMMAND_Quit:
- case COMMAND_Exit:
+ case Command_Quit:
+ case Command_Exit:
mQuitNow = true;
break;
- case COMMAND_List:
+ case Command_List:
CommandList(args, opts);
break;
- case COMMAND_pwd:
+ case Command_pwd:
{
// Simple implementation, so do it here
BOX_INFO(GetCurrentDirectoryName() << " (" <<
@@ -310,47 +329,52 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
}
break;
- case COMMAND_cd:
+ case Command_cd:
CommandChangeDir(args, opts);
break;
- case COMMAND_lcd:
+ case Command_lcd:
CommandChangeLocalDir(args);
break;
- case COMMAND_sh:
+ case Command_sh:
BOX_ERROR("The command to run must be specified as an argument.");
break;
- case COMMAND_GetObject:
+ case Command_GetObject:
CommandGetObject(args, opts);
break;
- case COMMAND_Get:
+ case Command_Get:
CommandGet(args, opts);
break;
- case COMMAND_Compare:
+ case Command_Compare:
CommandCompare(args, opts);
break;
- case COMMAND_Restore:
+ case Command_Restore:
CommandRestore(args, opts);
break;
- case COMMAND_Usage:
- CommandUsage();
+ case Command_Usage:
+ CommandUsage(opts);
break;
- case COMMAND_Help:
+ case Command_Help:
CommandHelp(args);
break;
- case COMMAND_Undelete:
+ case Command_Undelete:
CommandUndelete(args, opts);
break;
+ case Command_Delete:
+ CommandDelete(args, opts);
+ break;
+
default:
+ BOX_ERROR("Unknown command: " << Command);
break;
}
}
@@ -402,6 +426,7 @@ void BackupQueries::CommandList(const std::vector<std::string> &args, const bool
{
BOX_ERROR("Directory '" << args[0] << "' not found "
"on store.");
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
}
@@ -427,11 +452,28 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
if(!opts[LIST_OPTION_ALLOWDELETED]) excludeFlags |= BackupProtocolClientListDirectory::Flags_Deleted;
// Do communication
- mrConnection.QueryListDirectory(
- DirID,
- BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING, // both files and directories
- excludeFlags,
- true /* want attributes */);
+ try
+ {
+ mrConnection.QueryListDirectory(
+ DirID,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ // both files and directories
+ excludeFlags,
+ true /* want attributes */);
+ }
+ catch (std::exception &e)
+ {
+ BOX_ERROR("Failed to list directory: " << e.what());
+ SetReturnCode(ReturnCode::Command_Error);
+ return;
+ }
+ catch (...)
+ {
+ BOX_ERROR("Failed to list directory: unknown error");
+ SetReturnCode(ReturnCode::Command_Error);
+ return;
+ }
+
// Retrieve the directory from the stream following
BackupStoreDirectory dir;
@@ -574,15 +616,18 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupQueries::FindDirectoryObjectID(const std::string &)
-// Purpose: Find the object ID of a directory on the store, or return 0 for not found.
-// If pStack != 0, the object is set to the stack of directories.
-// Will start from the current directory stack.
+// Name: BackupQueries::FindDirectoryObjectID(const
+// std::string &)
+// Purpose: Find the object ID of a directory on the store,
+// or return 0 for not found. If pStack != 0, the
+// object is set to the stack of directories.
+// Will start from the current directory stack.
// Created: 2003/10/10
//
// --------------------------------------------------------------------------
-int64_t BackupQueries::FindDirectoryObjectID(const std::string &rDirName, bool AllowOldVersion,
- bool AllowDeletedDirs, std::vector<std::pair<std::string, int64_t> > *pStack)
+int64_t BackupQueries::FindDirectoryObjectID(const std::string &rDirName,
+ bool AllowOldVersion, bool AllowDeletedDirs,
+ std::vector<std::pair<std::string, int64_t> > *pStack)
{
// Split up string into elements
std::vector<std::string> dirElements;
@@ -747,6 +792,7 @@ void BackupQueries::CommandChangeDir(const std::vector<std::string> &args, const
if(args.size() != 1 || args[0].size() == 0)
{
BOX_ERROR("Incorrect usage. cd [-o] [-d] <directory>");
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
@@ -764,6 +810,7 @@ void BackupQueries::CommandChangeDir(const std::vector<std::string> &args, const
if(id == 0)
{
BOX_ERROR("Directory '" << args[0] << "' not found.");
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
@@ -785,7 +832,7 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
if(args.size() != 1 || args[0].size() == 0)
{
BOX_ERROR("Incorrect usage. lcd <local-directory>");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
@@ -795,7 +842,7 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
if(!ConvertConsoleToUtf8(args[0].c_str(), dirName))
{
BOX_ERROR("Failed to convert path from console encoding.");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
int result = ::chdir(dirName.c_str());
@@ -810,11 +857,11 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
}
else
{
- BOX_ERROR("Error changing to directory '" <<
- args[0] << ": " << strerror(errno));
+ BOX_LOG_SYS_ERROR("Failed to change to directory "
+ "'" << args[0] << "'");
}
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
@@ -822,9 +869,8 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
char wd[PATH_MAX];
if(::getcwd(wd, PATH_MAX) == 0)
{
- BOX_ERROR("Error getting current directory: " <<
- strerror(errno));
- SetReturnCode(COMMAND_RETURN_ERROR);
+ BOX_LOG_SYS_ERROR("Error getting current directory");
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
@@ -832,7 +878,7 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
if(!ConvertUtf8ToConsole(wd, dirName))
{
BOX_ERROR("Failed to convert new path from console encoding.");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
BOX_INFO("Local current directory is now '" << dirName << "'.");
@@ -868,8 +914,8 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
}
// Does file exist?
- struct stat st;
- if(::stat(args[1].c_str(), &st) == 0 || errno != ENOENT)
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(args[1].c_str(), &st) == 0 || errno != ENOENT)
{
BOX_ERROR("The local file '" << args[1] << " already exists.");
return;
@@ -907,6 +953,117 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
}
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupQueries::FindFileID(const std::string&
+// rNameOrIdString, const bool *options,
+// int64_t *pDirIdOut, std::string* pFileNameOut)
+// Purpose: Locate a file on the store (either by name or by
+// object ID, depending on opts['i'], where name can
+// include a path) and return the file ID, placing the
+// directory ID in *pDirIdOut and the filename part
+// of the path (if not looking up by ID and not NULL)
+// in *pFileNameOut.
+// Created: 2008-09-12
+//
+// --------------------------------------------------------------------------
+int64_t BackupQueries::FindFileID(const std::string& rNameOrIdString,
+ const bool *opts, int64_t *pDirIdOut, std::string* pFileNameOut,
+ int16_t flagsInclude, int16_t flagsExclude, int16_t* pFlagsOut)
+{
+ // Find object ID somehow
+ int64_t fileId;
+ int64_t dirId = GetCurrentDirectoryID();
+ std::string fileName = rNameOrIdString;
+
+ if(!opts['i'])
+ {
+ // does this remote filename include a path?
+ std::string::size_type index = fileName.rfind('/');
+ if(index != std::string::npos)
+ {
+ std::string dirName(fileName.substr(0, index));
+ fileName = fileName.substr(index + 1);
+
+ dirId = FindDirectoryObjectID(dirName);
+ if(dirId == 0)
+ {
+ BOX_ERROR("Directory '" << dirName <<
+ "' not found.");
+ return 0;
+ }
+ }
+
+ if(pFileNameOut)
+ {
+ *pFileNameOut = fileName;
+ }
+ }
+
+ BackupStoreFilenameClear fn(fileName);
+
+ // Need to look it up in the current directory
+ mrConnection.QueryListDirectory(
+ dirId, flagsInclude, flagsExclude,
+ true /* do want attributes */);
+
+ // Retrieve the directory from the stream following
+ BackupStoreDirectory dir;
+ std::auto_ptr<IOStream> dirstream(mrConnection.ReceiveStream());
+ dir.ReadFromStream(*dirstream, mrConnection.GetTimeout());
+ BackupStoreDirectory::Entry *en;
+
+ if(opts['i'])
+ {
+ // Specified as ID.
+ fileId = ::strtoll(rNameOrIdString.c_str(), 0, 16);
+ if(fileId == std::numeric_limits<long long>::min() ||
+ fileId == std::numeric_limits<long long>::max() ||
+ fileId == 0)
+ {
+ BOX_ERROR("Not a valid object ID (specified in hex).");
+ return 0;
+ }
+
+ // Check that the item is actually in the directory
+ en = dir.FindEntryByID(fileId);
+ if(en == 0)
+ {
+ BOX_ERROR("File ID " <<
+ BOX_FORMAT_OBJECTID(fileId) <<
+ " not found in current directory on store.\n"
+ "(You can only access files by ID from the "
+ "current directory.)");
+ return 0;
+ }
+ }
+ else
+ {
+ // Specified by name, find the object in the directory to get the ID
+ BackupStoreDirectory::Iterator i(dir);
+ en = i.FindMatchingClearName(fn);
+ if(en == 0)
+ {
+ BOX_ERROR("Filename '" << rNameOrIdString << "' "
+ "not found in current directory on store.\n"
+ "(Subdirectories in path not searched.)");
+ return 0;
+ }
+
+ fileId = en->GetObjectID();
+ }
+
+ *pDirIdOut = dirId;
+
+ if(pFlagsOut)
+ {
+ *pFlagsOut = en->GetFlags();
+ }
+
+ return fileId;
+}
+
// --------------------------------------------------------------------------
//
@@ -929,120 +1086,72 @@ void BackupQueries::CommandGet(std::vector<std::string> args, const bool *opts)
}
// Find object ID somehow
- int64_t fileId;
- int64_t dirId = GetCurrentDirectoryID();
+ int64_t fileId, dirId;
std::string localName;
- // BLOCK
- {
#ifdef WIN32
- for (std::vector<std::string>::iterator
- i = args.begin(); i != args.end(); i++)
+ for (std::vector<std::string>::iterator
+ i = args.begin(); i != args.end(); i++)
+ {
+ std::string out;
+ if(!ConvertConsoleToUtf8(i->c_str(), out))
{
- std::string out;
- if(!ConvertConsoleToUtf8(i->c_str(), out))
- {
- BOX_ERROR("Failed to convert encoding.");
- return;
- }
- *i = out;
+ BOX_ERROR("Failed to convert encoding.");
+ return;
}
+ *i = out;
+ }
#endif
- std::string fileName(args[0]);
+ int16_t flagsExclude;
- if(!opts['i'])
- {
- // does this remote filename include a path?
- std::string::size_type index = fileName.rfind('/');
- if(index != std::string::npos)
- {
- std::string dirName(fileName.substr(0, index));
- fileName = fileName.substr(index + 1);
-
- dirId = FindDirectoryObjectID(dirName);
- if(dirId == 0)
- {
- BOX_ERROR("Directory '" << dirName <<
- "' not found.");
- return;
- }
- }
- }
+ if(opts['i'])
+ {
+ // can retrieve anything by ID
+ flagsExclude = BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING;
+ }
+ else
+ {
+ // only current versions by name
+ flagsExclude =
+ BackupProtocolClientListDirectory::Flags_OldVersion |
+ BackupProtocolClientListDirectory::Flags_Deleted;
+ }
- BackupStoreFilenameClear fn(fileName);
- // Need to look it up in the current directory
- mrConnection.QueryListDirectory(
- 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 */);
+ fileId = FindFileID(args[0], opts, &dirId, &localName,
+ BackupProtocolClientListDirectory::Flags_File, // just files
+ flagsExclude, NULL /* don't care about flags found */);
- // Retrieve the directory from the stream following
- BackupStoreDirectory dir;
- std::auto_ptr<IOStream> dirstream(mrConnection.ReceiveStream());
- dir.ReadFromStream(*dirstream, mrConnection.GetTimeout());
+ if (fileId == 0)
+ {
+ // error already reported
+ return;
+ }
- if(opts['i'])
+ if(opts['i'])
+ {
+ // Specified as ID. Must have a local name in the arguments
+ // (check at beginning of function ensures this)
+ localName = args[1];
+ }
+ else
+ {
+ // Specified by name. Local name already set by FindFileID,
+ // but may be overridden by user supplying a second argument.
+ if(args.size() == 2)
{
- // Specified as ID.
- fileId = ::strtoll(args[0].c_str(), 0, 16);
- if(fileId == std::numeric_limits<long long>::min() ||
- fileId == std::numeric_limits<long long>::max() ||
- fileId == 0)
- {
- 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)
- {
- BOX_ERROR("File ID " <<
- BOX_FORMAT_OBJECTID(fileId) <<
- " not found in current "
- "directory on store.\n"
- "(You can only download files by ID "
- "from the current directory.)");
- return;
- }
-
- // Must have a local name in the arguments (check at beginning of function ensures this)
localName = args[1];
}
- else
- {
- // Specified by name, find the object in the directory to get the ID
- BackupStoreDirectory::Iterator i(dir);
- BackupStoreDirectory::Entry *en = i.FindMatchingClearName(fn);
-
- if(en == 0)
- {
- BOX_ERROR("Filename '" << args[0] << "' "
- "not found in current "
- "directory on store.\n"
- "(Subdirectories in path not "
- "searched.)");
- return;
- }
-
- fileId = en->GetObjectID();
-
- // 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];
- }
}
// Does local file already exist? (don't want to overwrite)
- struct stat st;
- if(::stat(localName.c_str(), &st) == 0 || errno != ENOENT)
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(localName.c_str(), &st) == 0 || errno != ENOENT)
{
BOX_ERROR("The local file " << localName << " already exists, "
"will not overwrite it.");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
@@ -1081,7 +1190,6 @@ void BackupQueries::CommandGet(std::vector<std::string> args, const bool *opts)
}
}
-
// --------------------------------------------------------------------------
//
// Function
@@ -1090,58 +1198,17 @@ void BackupQueries::CommandGet(std::vector<std::string> args, const bool *opts)
// Created: 29/1/04
//
// --------------------------------------------------------------------------
-BackupQueries::CompareParams::CompareParams()
- : mQuickCompare(false),
- mIgnoreExcludes(false),
- mIgnoreAttributes(false),
- mDifferences(0),
- mDifferencesExplainedByModTime(0),
- mUncheckedFiles(0),
- mExcludedDirs(0),
- mExcludedFiles(0),
- mpExcludeFiles(0),
- mpExcludeDirs(0),
- mLatestFileUploadTime(0)
-{
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupQueries::CompareParams::~CompareParams()
-// Purpose: Destructor
-// Created: 29/1/04
-//
-// --------------------------------------------------------------------------
-BackupQueries::CompareParams::~CompareParams()
-{
- DeleteExcludeLists();
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupQueries::CompareParams::DeleteExcludeLists()
-// Purpose: Delete the include lists contained
-// Created: 29/1/04
-//
-// --------------------------------------------------------------------------
-void BackupQueries::CompareParams::DeleteExcludeLists()
-{
- if(mpExcludeFiles != 0)
- {
- delete mpExcludeFiles;
- mpExcludeFiles = 0;
- }
- if(mpExcludeDirs != 0)
- {
- delete mpExcludeDirs;
- mpExcludeDirs = 0;
- }
-}
-
+BackupQueries::CompareParams::CompareParams(bool QuickCompare,
+ bool IgnoreExcludes, bool IgnoreAttributes,
+ box_time_t LatestFileUploadTime)
+: BoxBackupCompareParams(QuickCompare, IgnoreExcludes, IgnoreAttributes,
+ LatestFileUploadTime),
+ mDifferences(0),
+ mDifferencesExplainedByModTime(0),
+ mUncheckedFiles(0),
+ mExcludedDirs(0),
+ mExcludedFiles(0)
+{ }
// --------------------------------------------------------------------------
//
@@ -1153,24 +1220,19 @@ void BackupQueries::CompareParams::DeleteExcludeLists()
// --------------------------------------------------------------------------
void BackupQueries::CommandCompare(const std::vector<std::string> &args, const bool *opts)
{
- // Parameters, including count of differences
- BackupQueries::CompareParams params;
- params.mQuickCompare = opts['q'];
- params.mQuietCompare = opts['Q'];
- params.mIgnoreExcludes = opts['E'];
- params.mIgnoreAttributes = opts['A'];
+ box_time_t LatestFileUploadTime = GetCurrentBoxTime();
// Try and work out the time before which all files should be on the server
{
std::string syncTimeFilename(mrConfiguration.GetKeyValue("DataDirectory") + DIRECTORY_SEPARATOR_ASCHAR);
syncTimeFilename += "last_sync_start";
// Stat it to get file time
- struct stat st;
- if(::stat(syncTimeFilename.c_str(), &st) == 0)
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(syncTimeFilename.c_str(), &st) == 0)
{
// Files modified after this time shouldn't be on the server, so report errors slightly differently
- params.mLatestFileUploadTime = FileModificationTime(st)
- - SecondsToBoxTime(mrConfiguration.GetKeyValueInt("MinimumFileAge"));
+ LatestFileUploadTime = FileModificationTime(st) -
+ SecondsToBoxTime(mrConfiguration.GetKeyValueInt("MinimumFileAge"));
}
else
{
@@ -1179,8 +1241,16 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
}
}
+ // Parameters, including count of differences
+ BackupQueries::CompareParams params(opts['q'], // quick compare?
+ opts['E'], // ignore excludes
+ opts['A'], // ignore attributes
+ LatestFileUploadTime);
+
+ params.mQuietCompare = opts['Q'];
+
// Quick compare?
- if(params.mQuickCompare)
+ if(params.QuickCompare())
{
BOX_WARNING("Quick compare used -- file attributes are not "
"checked.");
@@ -1189,11 +1259,16 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
if(!opts['l'] && opts['a'] && args.size() == 0)
{
// Compare all locations
- const Configuration &locations(mrConfiguration.GetSubConfiguration("BackupLocations"));
- for(std::list<std::pair<std::string, Configuration> >::const_iterator i = locations.mSubConfigurations.begin();
- i != locations.mSubConfigurations.end(); ++i)
+ const Configuration &rLocations(
+ mrConfiguration.GetSubConfiguration("BackupLocations"));
+ std::vector<std::string> locNames =
+ rLocations.GetSubConfigurationNames();
+ for(std::vector<std::string>::iterator
+ pLocName = locNames.begin();
+ pLocName != locNames.end();
+ pLocName++)
{
- CompareLocation(i->first, params);
+ CompareLocation(*pLocName, params);
}
}
else if(opts['l'] && !opts['a'] && args.size() == 1)
@@ -1206,7 +1281,7 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
// Compare directory to directory
// 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)
+ if(!params.IgnoreExcludes())
{
BOX_ERROR("Cannot use excludes on directory to directory comparison -- use -E flag to specify ignored excludes.");
return;
@@ -1241,15 +1316,15 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
{
if (params.mUncheckedFiles != 0)
{
- SetReturnCode(COMPARE_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Compare_Error);
}
else if (params.mDifferences != 0)
{
- SetReturnCode(COMPARE_RETURN_DIFFERENT);
+ SetReturnCode(ReturnCode::Compare_Different);
}
else
{
- SetReturnCode(COMPARE_RETURN_SAME);
+ SetReturnCode(ReturnCode::Compare_Same);
}
}
}
@@ -1263,7 +1338,8 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
// Created: 2003/10/13
//
// --------------------------------------------------------------------------
-void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries::CompareParams &rParams)
+void BackupQueries::CompareLocation(const std::string &rLocation,
+ BoxBackupCompareParams &rParams)
{
// Find the location's sub configuration
const Configuration &locations(mrConfiguration.GetSubConfiguration("BackupLocations"));
@@ -1287,45 +1363,36 @@ void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries:
}
#endif
- try
- {
- // Generate the exclude lists
- if(!rParams.mIgnoreExcludes)
- {
- rParams.mpExcludeFiles = BackupClientMakeExcludeList_Files(loc);
- rParams.mpExcludeDirs = BackupClientMakeExcludeList_Dirs(loc);
- }
-
- // Then get it compared
- Compare(std::string("/") + rLocation,
- loc.GetKeyValue("Path"), rParams);
- }
- catch(...)
+ // Generate the exclude lists
+ if(!rParams.IgnoreExcludes())
{
- // Clean up
- rParams.DeleteExcludeLists();
- throw;
+ rParams.LoadExcludeLists(loc);
}
-
- // Delete exclude lists
- rParams.DeleteExcludeLists();
+
+ // Then get it compared
+ Compare(std::string("/") + rLocation, loc.GetKeyValue("Path"), rParams);
}
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupQueries::Compare(const std::string &, const std::string &, BackupQueries::CompareParams &)
+// Name: BackupQueries::Compare(const std::string &,
+// const std::string &, BackupQueries::CompareParams &)
// Purpose: Compare a store directory against a local directory
// Created: 2003/10/13
//
// --------------------------------------------------------------------------
-void BackupQueries::Compare(const std::string &rStoreDir, const std::string &rLocalDir, BackupQueries::CompareParams &rParams)
+void BackupQueries::Compare(const std::string &rStoreDir,
+ const std::string &rLocalDir, BoxBackupCompareParams &rParams)
{
#ifdef WIN32
+ std::string localDirEncoded;
std::string storeDirEncoded;
+ if(!ConvertConsoleToUtf8(rLocalDir.c_str(), localDirEncoded)) return;
if(!ConvertConsoleToUtf8(rStoreDir.c_str(), storeDirEncoded)) return;
#else
+ const std::string& localDirEncoded(rLocalDir);
const std::string& storeDirEncoded(rStoreDir);
#endif
@@ -1335,19 +1402,22 @@ void BackupQueries::Compare(const std::string &rStoreDir, const std::string &rLo
// Found?
if(dirID == 0)
{
- BOX_WARNING("Local directory '" << rLocalDir << "' exists, "
- "but server directory '" << rStoreDir << "' does not "
- "exist.");
- rParams.mDifferences ++;
+ bool modifiedAfterLastSync = false;
+
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(rLocalDir.c_str(), &st) == 0)
+ {
+ if(FileAttrModificationTime(st) >
+ rParams.LatestFileUploadTime())
+ {
+ modifiedAfterLastSync = true;
+ }
+ }
+
+ rParams.NotifyRemoteFileMissing(localDirEncoded,
+ storeDirEncoded, modifiedAfterLastSync);
return;
}
-
-#ifdef WIN32
- std::string localDirEncoded;
- if(!ConvertConsoleToUtf8(rLocalDir.c_str(), localDirEncoded)) return;
-#else
- std::string localDirEncoded(rLocalDir);
-#endif
// Go!
Compare(dirID, storeDirEncoded, localDirEncoded, rParams);
@@ -1363,56 +1433,36 @@ void BackupQueries::Compare(const std::string &rStoreDir, const std::string &rLo
// Created: 2003/10/13
//
// --------------------------------------------------------------------------
-void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const std::string &rLocalDir, BackupQueries::CompareParams &rParams)
+void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir,
+ const std::string &rLocalDir, BoxBackupCompareParams &rParams)
{
-#ifdef WIN32
- // By this point, rStoreDir and rLocalDir should be in UTF-8 encoding
-
- std::string localDirDisplay;
- std::string storeDirDisplay;
-
- if(!ConvertUtf8ToConsole(rLocalDir.c_str(), localDirDisplay)) return;
- if(!ConvertUtf8ToConsole(rStoreDir.c_str(), storeDirDisplay)) return;
-#else
- const std::string& localDirDisplay(rLocalDir);
- const std::string& storeDirDisplay(rStoreDir);
-#endif
+ rParams.NotifyDirComparing(rLocalDir, rStoreDir);
// Get info on the local directory
- struct stat st;
- if(::lstat(rLocalDir.c_str(), &st) != 0)
+ EMU_STRUCT_STAT st;
+ if(EMU_LSTAT(rLocalDir.c_str(), &st) != 0)
{
// What kind of error?
- if(errno == ENOTDIR)
- {
- BOX_WARNING("Local object '" << localDirDisplay << "' "
- "is a file, server object '" <<
- storeDirDisplay << "' is a directory.");
- rParams.mDifferences ++;
- }
- else if(errno == ENOENT)
+ if(errno == ENOTDIR || errno == ENOENT)
{
- BOX_WARNING("Local directory '" << localDirDisplay <<
- "' does not exist (compared to server "
- "directory '" << storeDirDisplay << "').");
- rParams.mDifferences ++;
+ rParams.NotifyLocalDirMissing(rLocalDir, rStoreDir);
}
else
{
- BOX_WARNING("Failed to access local directory '" <<
- localDirDisplay << ": " << strerror(errno) <<
- "'.");
- rParams.mUncheckedFiles ++;
+ rParams.NotifyLocalDirAccessFailed(rLocalDir, rStoreDir);
}
return;
}
// Get the directory listing from the store
mrConnection.QueryListDirectory(
- DirID,
- BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING, // get everything
- BackupProtocolClientListDirectory::Flags_OldVersion | BackupProtocolClientListDirectory::Flags_Deleted, // except for old versions and deleted files
- true /* want attributes */);
+ DirID,
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ // get everything
+ BackupProtocolClientListDirectory::Flags_OldVersion |
+ BackupProtocolClientListDirectory::Flags_Deleted,
+ // except for old versions and deleted files
+ true /* want attributes */);
// Retrieve the directory from the stream following
BackupStoreDirectory dir;
@@ -1422,8 +1472,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Test out the attributes
if(!dir.HasAttributes())
{
- BOX_WARNING("Store directory '" << storeDirDisplay << "' "
- "doesn't have attributes.");
+ rParams.NotifyStoreDirMissingAttributes(rLocalDir, rStoreDir);
}
else
{
@@ -1436,12 +1485,27 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
localAttr.ReadAttributes(rLocalDir.c_str(),
true /* directories have zero mod times */);
- if(!(attr.Compare(localAttr, true, true /* ignore modification times */)))
+ if(attr.Compare(localAttr, true, true /* ignore modification times */))
{
- BOX_WARNING("Local directory '" << localDirDisplay <<
- "' has different attributes to store "
- "directory '" << storeDirDisplay << "'.");
- rParams.mDifferences ++;
+ rParams.NotifyDirCompared(rLocalDir, rStoreDir,
+ false, false /* actually we didn't check :) */);
+ }
+ else
+ {
+ bool modifiedAfterLastSync = false;
+
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(rLocalDir.c_str(), &st) == 0)
+ {
+ if(FileAttrModificationTime(st) >
+ rParams.LatestFileUploadTime())
+ {
+ modifiedAfterLastSync = true;
+ }
+ }
+
+ rParams.NotifyDirCompared(rLocalDir, rStoreDir,
+ true, modifiedAfterLastSync);
}
}
@@ -1449,11 +1513,10 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
DIR *dirhandle = ::opendir(rLocalDir.c_str());
if(dirhandle == 0)
{
- BOX_WARNING("Failed to open local directory '" <<
- localDirDisplay << "': " << strerror(errno));
- rParams.mUncheckedFiles ++;
+ rParams.NotifyLocalDirAccessFailed(rLocalDir, rStoreDir);
return;
}
+
try
{
// Read the files and directories into sets
@@ -1484,8 +1547,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
#ifndef HAVE_VALID_DIRENT_D_TYPE
std::string fn(MakeFullPath
(rLocalDir, localDirEn->d_name));
- struct stat st;
- if(::lstat(fn.c_str(), &st) != 0)
+ EMU_STRUCT_STAT st;
+ if(EMU_LSTAT(fn.c_str(), &st) != 0)
{
THROW_EXCEPTION(CommonException, OSFileError)
}
@@ -1518,8 +1581,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Close directory
if(::closedir(dirhandle) != 0)
{
- BOX_ERROR("Failed to close local directory '" <<
- localDirDisplay << "': " << strerror(errno));
+ BOX_LOG_SYS_ERROR("Failed to close local directory "
+ "'" << rLocalDir << "'");
}
dirhandle = 0;
@@ -1557,36 +1620,30 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
for(std::set<std::pair<std::string, BackupStoreDirectory::Entry *> >::const_iterator i = storeFiles.begin(); i != storeFiles.end(); ++i)
{
const std::string& fileName(i->first);
-#ifdef WIN32
- // File name is also in UTF-8 encoding,
- // need to convert to console
- std::string fileNameDisplay;
- if(!ConvertUtf8ToConsole(i->first.c_str(),
- fileNameDisplay)) return;
-#else
- const std::string& fileNameDisplay(i->first);
-#endif
- std::string localPath(MakeFullPath
- (rLocalDir, fileName));
- std::string localPathDisplay(MakeFullPath
- (localDirDisplay, fileNameDisplay));
- std::string storePathDisplay
- (storeDirDisplay + "/" + fileNameDisplay);
+ std::string localPath(MakeFullPath(rLocalDir, fileName));
+ std::string storePath(rStoreDir + "/" + fileName);
+ rParams.NotifyFileComparing(localPath, storePath);
+
// Does the file exist locally?
string_set_iter_t local(localFiles.find(fileName));
if(local == localFiles.end())
{
// Not found -- report
- BOX_WARNING("Local file '" <<
- localPathDisplay << "' does not exist, "
- "but store file '" <<
- storePathDisplay << "' does.");
- rParams.mDifferences ++;
+ rParams.NotifyLocalFileMissing(localPath,
+ storePath);
}
else
- {
+ {
+ int64_t fileSize = 0;
+
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(localPath.c_str(), &st) == 0)
+ {
+ fileSize = st.st_size;
+ }
+
try
{
// Files the same flag?
@@ -1594,8 +1651,10 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// File modified after last sync flag
bool modifiedAfterLastSync = false;
+
+ bool hasDifferentAttribs = false;
- if(rParams.mQuickCompare)
+ if(rParams.QuickCompare())
{
// Compare file -- fetch it
mrConnection.QueryGetBlockIndexByID(i->second->GetObjectID());
@@ -1640,7 +1699,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
BackupClientFileAttributes localAttr;
box_time_t fileModTime = 0;
localAttr.ReadAttributes(localPath.c_str(), false /* don't zero mod times */, &fileModTime);
- modifiedAfterLastSync = (fileModTime > rParams.mLatestFileUploadTime);
+ modifiedAfterLastSync = (fileModTime > rParams.LatestFileUploadTime());
bool ignoreAttrModTime = true;
#ifdef WIN32
@@ -1649,7 +1708,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
ignoreAttrModTime = false;
#endif
- if(!rParams.mIgnoreAttributes &&
+ if(!rParams.IgnoreAttributes() &&
#ifdef PLATFORM_DISABLE_SYMLINK_ATTRIB_COMPARE
!fileOnServerStream->IsSymLink() &&
#endif
@@ -1657,128 +1716,43 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
ignoreAttrModTime,
fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */))
{
- BOX_WARNING("Local file '" <<
- localPathDisplay <<
- "' has different attributes "
- "to store file '" <<
- storePathDisplay <<
- "'.");
- rParams.mDifferences ++;
- if(modifiedAfterLastSync)
- {
- rParams.mDifferencesExplainedByModTime ++;
- BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
- }
- else if(i->second->HasAttributes())
- {
- BOX_INFO("(the file above has had new attributes applied)\n");
- }
+ hasDifferentAttribs = true;
}
// Compare contents, if it's a regular file not a link
// Remember, we MUST read the entire stream from the server.
+ SelfFlushingStream flushObject(*objectStream);
+
if(!fileOnServerStream->IsSymLink())
{
+ SelfFlushingStream flushFile(*fileOnServerStream);
// Open the local file
FileStream l(localPath.c_str());
-
- // Size
- IOStream::pos_type fileSizeLocal = l.BytesLeftToRead();
- IOStream::pos_type fileSizeServer = 0;
-
- // Test the contents
- char buf1[2048];
- char buf2[2048];
- while(fileOnServerStream->StreamDataLeft() && l.StreamDataLeft())
- {
- int size = fileOnServerStream->Read(buf1, sizeof(buf1), mrConnection.GetTimeout());
- fileSizeServer += size;
-
- if(l.Read(buf2, size) != size
- || ::memcmp(buf1, buf2, size) != 0)
- {
- equal = false;
- break;
- }
- }
-
- // Check read all the data from the server and file -- can't be equal if local and remote aren't the same length
- // Can't use StreamDataLeft() test on file, because if it's the same size, it won't know
- // it's EOF yet.
- if(fileOnServerStream->StreamDataLeft() || fileSizeServer != fileSizeLocal)
- {
- equal = false;
- }
-
- // Must always read the entire decoded stream, if it's not a symlink
- if(fileOnServerStream->StreamDataLeft())
- {
- // Absorb all the data remaining
- char buffer[2048];
- while(fileOnServerStream->StreamDataLeft())
- {
- 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());
- }
- }
+ equal = l.CompareWith(*fileOnServerStream,
+ mrConnection.GetTimeout());
}
}
- // Report if not equal.
- if(!equal)
- {
- BOX_WARNING("Local file '" <<
- localPathDisplay << "' "
- "has different contents "
- "to store file '" <<
- storePathDisplay <<
- "'.");
- rParams.mDifferences ++;
- if(modifiedAfterLastSync)
- {
- rParams.mDifferencesExplainedByModTime ++;
- BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
- }
- else if(i->second->HasAttributes())
- {
- BOX_INFO("(the file above has had new attributes applied)\n");
- }
- }
+ rParams.NotifyFileCompared(localPath,
+ storePath, fileSize,
+ hasDifferentAttribs, !equal,
+ modifiedAfterLastSync,
+ i->second->HasAttributes());
}
catch(BoxException &e)
{
- BOX_ERROR("Failed to fetch and compare "
- "'" <<
- storePathDisplay.c_str() <<
- "': error " << e.what() <<
- " (" << e.GetType() <<
- "/" << e.GetSubType() << ")");
- rParams.mUncheckedFiles ++;
+ rParams.NotifyDownloadFailed(localPath,
+ storePath, fileSize, e);
}
catch(std::exception &e)
{
- BOX_ERROR("Failed to fetch and compare "
- "'" <<
- storePathDisplay.c_str() <<
- "': " << e.what());
+ rParams.NotifyDownloadFailed(localPath,
+ storePath, fileSize, e);
}
catch(...)
{
- BOX_ERROR("Failed to fetch and compare "
- "'" <<
- storePathDisplay.c_str() <<
- "': unknown error");
- rParams.mUncheckedFiles ++;
+ rParams.NotifyDownloadFailed(localPath,
+ storePath, fileSize);
}
// Remove from set so that we know it's been compared
@@ -1786,53 +1760,34 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
}
}
- // Report any files which exist on the locally, but not on the store
+ // Report any files which exist locally, but not on the store
for(string_set_iter_t i = localFiles.begin(); i != localFiles.end(); ++i)
{
-#ifdef WIN32
- // File name is also in UTF-8 encoding,
- // need to convert to console
- std::string fileNameDisplay;
- if(!ConvertUtf8ToConsole(i->c_str(), fileNameDisplay))
- return;
-#else
- const std::string& fileNameDisplay(*i);
-#endif
-
- std::string localPath(MakeFullPath
- (rLocalDir, *i));
- std::string localPathDisplay(MakeFullPath
- (localDirDisplay, fileNameDisplay));
- std::string storePathDisplay
- (storeDirDisplay + "/" + fileNameDisplay);
+ std::string localPath(MakeFullPath(rLocalDir, *i));
+ std::string storePath(rStoreDir + "/" + *i);
// Should this be ignored (ie is excluded)?
- if(rParams.mpExcludeFiles == 0 ||
- !(rParams.mpExcludeFiles->IsExcluded(localPath)))
+ if(!rParams.IsExcludedFile(localPath))
{
- BOX_WARNING("Local file '" <<
- localPathDisplay <<
- "' exists, but store file '" <<
- storePathDisplay <<
- "' does not.");
- rParams.mDifferences ++;
+ bool modifiedAfterLastSync = false;
- // Check the file modification time
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(localPath.c_str(), &st) == 0)
{
- struct stat st;
- if(::stat(localPath.c_str(), &st) == 0)
+ if(FileModificationTime(st) >
+ rParams.LatestFileUploadTime())
{
- if(FileModificationTime(st) > rParams.mLatestFileUploadTime)
- {
- rParams.mDifferencesExplainedByModTime ++;
- BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
- }
+ modifiedAfterLastSync = true;
}
}
+
+ rParams.NotifyRemoteFileMissing(localPath,
+ storePath, modifiedAfterLastSync);
}
else
{
- rParams.mExcludedFiles ++;
+ rParams.NotifyExcludedFile(localPath,
+ storePath);
}
}
@@ -1843,99 +1798,69 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Now do the directories, recursively to check subdirectories
for(std::set<std::pair<std::string, BackupStoreDirectory::Entry *> >::const_iterator i = storeDirs.begin(); i != storeDirs.end(); ++i)
{
-#ifdef WIN32
- // Directory name is also in UTF-8 encoding,
- // need to convert to console
- std::string subdirNameDisplay;
- if(!ConvertUtf8ToConsole(i->first.c_str(),
- subdirNameDisplay))
- return;
-#else
- const std::string& subdirNameDisplay(i->first);
-#endif
-
- std::string localPath(MakeFullPath
- (rLocalDir, i->first));
- std::string localPathDisplay(MakeFullPath
- (localDirDisplay, subdirNameDisplay));
- std::string storePathDisplay
- (storeDirDisplay + "/" + subdirNameDisplay);
+ std::string localPath(MakeFullPath(rLocalDir, i->first));
+ std::string storePath(rLocalDir + "/" + i->first);
// Does the directory exist locally?
string_set_iter_t local(localDirs.find(i->first));
if(local == localDirs.end() &&
- rParams.mpExcludeDirs != NULL &&
- rParams.mpExcludeDirs->IsExcluded(localPath))
+ rParams.IsExcludedDir(localPath))
{
- // Not found -- report
- BOX_WARNING("Local directory '" <<
- localPathDisplay << "' is excluded, "
- "but store directory '" <<
- storePathDisplay << "' still exists.");
- rParams.mDifferences ++;
+ rParams.NotifyExcludedFileNotDeleted(localPath,
+ storePath);
}
else if(local == localDirs.end())
{
// Not found -- report
- BOX_WARNING("Local directory '" <<
- localPathDisplay << "' does not exist, "
- "but store directory '" <<
- storePathDisplay << "' does.");
- rParams.mDifferences ++;
+ rParams.NotifyRemoteFileMissing(localPath,
+ storePath, false);
}
- else if(rParams.mpExcludeDirs != NULL &&
- rParams.mpExcludeDirs->IsExcluded(localPath))
+ else if(rParams.IsExcludedDir(localPath))
{
// don't recurse into excluded directories
}
else
{
// Compare directory
- Compare(i->second->GetObjectID(), rStoreDir + "/" + i->first, localPath, rParams);
+ Compare(i->second->GetObjectID(),
+ rStoreDir + "/" + i->first,
+ localPath, rParams);
// Remove from set so that we know it's been compared
localDirs.erase(local);
}
}
- // Report any files which exist on the locally, but not on the store
- for(std::set<std::string>::const_iterator i = localDirs.begin(); i != localDirs.end(); ++i)
+ // Report any directories which exist locally, but not on the store
+ for(std::set<std::string>::const_iterator
+ i = localDirs.begin();
+ i != localDirs.end(); ++i)
{
-#ifdef WIN32
- // File name is also in UTF-8 encoding,
- // need to convert to console
- std::string fileNameDisplay;
- if(!ConvertUtf8ToConsole(i->c_str(), fileNameDisplay))
- return;
-#else
- const std::string& fileNameDisplay(*i);
-#endif
-
- std::string localPath(MakeFullPath
- (rLocalDir, *i));
- std::string localPathDisplay(MakeFullPath
- (localDirDisplay, fileNameDisplay));
-
- std::string storePath
- (rStoreDir + "/" + *i);
- std::string storePathDisplay
- (storeDirDisplay + "/" + fileNameDisplay);
+ std::string localPath(MakeFullPath(rLocalDir, *i));
+ std::string storePath(rStoreDir + "/" + *i);
// Should this be ignored (ie is excluded)?
- if(rParams.mpExcludeDirs == 0 || !(rParams.mpExcludeDirs->IsExcluded(localPath)))
+ if(!rParams.IsExcludedDir(localPath))
{
- BOX_WARNING("Local directory '" <<
- localPathDisplay << "' exists, but "
- "store directory '" <<
- storePathDisplay << "' does not.");
- rParams.mDifferences ++;
+ bool modifiedAfterLastSync = false;
+
+ // Check the dir modification time
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(localPath.c_str(), &st) == 0 &&
+ FileModificationTime(st) >
+ rParams.LatestFileUploadTime())
+ {
+ modifiedAfterLastSync = true;
+ }
+
+ rParams.NotifyRemoteFileMissing(localPath,
+ storePath, modifiedAfterLastSync);
}
else
{
- rParams.mExcludedDirs ++;
+ rParams.NotifyExcludedDir(localPath, storePath);
}
}
-
}
catch(...)
{
@@ -1943,6 +1868,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
{
::closedir(dirhandle);
}
+ throw;
}
}
@@ -1960,7 +1886,7 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
// Check arguments
if(args.size() != 2)
{
- BOX_ERROR("Incorrect usage. restore [-d] [-r] [-i] <remote-name> <local-name>");
+ BOX_ERROR("Incorrect usage. restore [-drif] <remote-name> <local-name>");
return;
}
@@ -2023,18 +1949,19 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
localName.c_str(),
true /* print progress dots */, restoreDeleted,
false /* don't undelete after restore! */,
- opts['r'] /* resume? */);
+ opts['r'] /* resume? */,
+ opts['f'] /* force continue after errors */);
}
catch(std::exception &e)
{
BOX_ERROR("Failed to restore: " << e.what());
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
catch(...)
{
BOX_ERROR("Failed to restore: unknown exception");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
return;
}
@@ -2044,33 +1971,38 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
BOX_INFO("Restore complete.");
break;
+ case Restore_CompleteWithErrors:
+ BOX_WARNING("Restore complete, but some files could not be "
+ "restored.");
+ break;
+
case Restore_ResumePossible:
- BOX_ERROR("Resume possible -- repeat command with -r flag to resume");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ BOX_ERROR("Resume possible -- repeat command with -r flag "
+ "to resume.");
+ SetReturnCode(ReturnCode::Command_Error);
break;
case Restore_TargetExists:
- BOX_ERROR("The target directory exists. You cannot restore over an existing directory.");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ BOX_ERROR("The target directory exists. You cannot restore "
+ "over an existing directory.");
+ SetReturnCode(ReturnCode::Command_Error);
break;
- #ifdef WIN32
case Restore_TargetPathNotFound:
BOX_ERROR("The target directory path does not exist.\n"
"To restore to a directory whose parent "
"does not exist, create the parent first.");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
break;
- #endif
case Restore_UnknownError:
BOX_ERROR("Unknown error during restore.");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
break;
default:
BOX_ERROR("Unknown restore result " << result << ".");
- SetReturnCode(COMMAND_RETURN_ERROR);
+ SetReturnCode(ReturnCode::Command_Error);
break;
}
}
@@ -2131,49 +2063,46 @@ void BackupQueries::CommandHelp(const std::vector<std::string> &args)
// Created: 19/4/04
//
// --------------------------------------------------------------------------
-void BackupQueries::CommandUsage()
+void BackupQueries::CommandUsage(const bool *opts)
{
+ bool MachineReadable = opts['m'];
+
// Request full details from the server
std::auto_ptr<BackupProtocolClientAccountUsage> usage(mrConnection.QueryGetAccountUsage());
// Display each entry in turn
int64_t hardLimit = usage->GetBlocksHardLimit();
int32_t blockSize = usage->GetBlockSize();
- CommandUsageDisplayEntry("Used", usage->GetBlocksUsed(), hardLimit, blockSize);
- CommandUsageDisplayEntry("Old files", usage->GetBlocksInOldFiles(), hardLimit, blockSize);
- CommandUsageDisplayEntry("Deleted files", usage->GetBlocksInDeletedFiles(), hardLimit, blockSize);
- CommandUsageDisplayEntry("Directories", usage->GetBlocksInDirectories(), hardLimit, blockSize);
- CommandUsageDisplayEntry("Soft limit", usage->GetBlocksSoftLimit(), hardLimit, blockSize);
- CommandUsageDisplayEntry("Hard limit", hardLimit, hardLimit, blockSize);
+ CommandUsageDisplayEntry("Used", usage->GetBlocksUsed(), hardLimit,
+ blockSize, MachineReadable);
+ CommandUsageDisplayEntry("Old files", usage->GetBlocksInOldFiles(),
+ hardLimit, blockSize, MachineReadable);
+ CommandUsageDisplayEntry("Deleted files", usage->GetBlocksInDeletedFiles(),
+ hardLimit, blockSize, MachineReadable);
+ CommandUsageDisplayEntry("Directories", usage->GetBlocksInDirectories(),
+ hardLimit, blockSize, MachineReadable);
+ CommandUsageDisplayEntry("Soft limit", usage->GetBlocksSoftLimit(),
+ hardLimit, blockSize, MachineReadable);
+ CommandUsageDisplayEntry("Hard limit", hardLimit, hardLimit, blockSize,
+ MachineReadable);
}
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupQueries::CommandUsageDisplayEntry(const char *, int64_t, int64_t, int32_t)
+// Name: BackupQueries::CommandUsageDisplayEntry(const char *,
+// int64_t, int64_t, int32_t, bool)
// Purpose: Display an entry in the usage table
// Created: 19/4/04
//
// --------------------------------------------------------------------------
-void BackupQueries::CommandUsageDisplayEntry(const char *Name, int64_t Size, int64_t HardLimit, int32_t BlockSize)
+void BackupQueries::CommandUsageDisplayEntry(const char *Name, int64_t Size,
+int64_t HardLimit, int32_t BlockSize, bool MachineReadable)
{
- // Calculate size in Mb
- double mb = (((double)Size) * ((double)BlockSize)) / ((double)(1024*1024));
- int64_t percent = (Size * 100) / HardLimit;
-
- // Bar graph
- char bar[41];
- unsigned int b = (int)((Size * (sizeof(bar)-1)) / HardLimit);
- if(b > sizeof(bar)-1) {b = sizeof(bar)-1;}
- for(unsigned int l = 0; l < b; l++)
- {
- bar[l] = '*';
- }
- bar[b] = '\0';
-
- // Print the entryj
- ::printf("%14s %10.1fMb %3d%% %s\n", Name, mb, (int32_t)percent, bar);
+ std::cout << FormatUsageLineStart(Name, MachineReadable) <<
+ FormatUsageBar(Size, Size * BlockSize, HardLimit * BlockSize,
+ MachineReadable) << std::endl;
}
@@ -2187,10 +2116,17 @@ void BackupQueries::CommandUsageDisplayEntry(const char *Name, int64_t Size, int
// --------------------------------------------------------------------------
void BackupQueries::CommandUndelete(const std::vector<std::string> &args, const bool *opts)
{
+ if (!mReadWrite)
+ {
+ BOX_ERROR("This command requires a read-write connection. "
+ "Please reconnect with the -w option.");
+ return;
+ }
+
// Check arguments
if(args.size() != 1)
{
- BOX_ERROR("Incorrect usage. undelete <directory-name>");
+ BOX_ERROR("Incorrect usage. undelete <name> or undelete -i <object-id>");
return;
}
@@ -2200,23 +2136,133 @@ void BackupQueries::CommandUndelete(const std::vector<std::string> &args, const
#else
const std::string& storeDirEncoded(args[0]);
#endif
-
- // Get directory ID
- int64_t dirID = FindDirectoryObjectID(storeDirEncoded,
- false /* no old versions */, true /* find deleted dirs */);
-
- // Allowable?
- if(dirID == 0)
+
+ // Find object ID somehow
+ int64_t fileId, parentId;
+ std::string fileName;
+ int16_t flagsOut;
+
+ fileId = FindFileID(storeDirEncoded, opts, &parentId, &fileName,
+ /* include files and directories */
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING,
+ /* include old and deleted files */
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING,
+ &flagsOut);
+
+ if (fileId == 0)
{
- BOX_ERROR("Directory '" << args[0] << "' not found on server.");
+ // error already reported
return;
}
- if(dirID == BackupProtocolClientListDirectory::RootDirectory)
+
+ // Undelete it on the store
+ try
+ {
+ // Undelete object
+ if(flagsOut & BackupProtocolClientListDirectory::Flags_File)
+ {
+ mrConnection.QueryUndeleteFile(parentId, fileId);
+ }
+ else
+ {
+ mrConnection.QueryUndeleteDirectory(fileId);
+ }
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to undelete object: " <<
+ e.what());
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to undelete object: " <<
+ e.what());
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to undelete object: unknown error");
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupQueries::CommandDelete(const
+// std::vector<std::string> &, const bool *)
+// Purpose: Deletes a file
+// Created: 23/11/03
+//
+// --------------------------------------------------------------------------
+void BackupQueries::CommandDelete(const std::vector<std::string> &args,
+ const bool *opts)
+{
+ if (!mReadWrite)
+ {
+ BOX_ERROR("This command requires a read-write connection. "
+ "Please reconnect with the -w option.");
+ return;
+ }
+
+ // Check arguments
+ if(args.size() != 1)
{
- BOX_ERROR("Cannot undelete the root directory.");
+ BOX_ERROR("Incorrect usage. delete <name>");
return;
}
- // Undelete
- mrConnection.QueryUndeleteDirectory(dirID);
+#ifdef WIN32
+ std::string storeDirEncoded;
+ if(!ConvertConsoleToUtf8(args[0].c_str(), storeDirEncoded)) return;
+#else
+ const std::string& storeDirEncoded(args[0]);
+#endif
+
+ // Find object ID somehow
+ int64_t fileId, parentId;
+ std::string fileName;
+ int16_t flagsOut;
+
+ fileId = FindFileID(storeDirEncoded, opts, &parentId, &fileName,
+ /* include files and directories */
+ BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING,
+ /* exclude old and deleted files */
+ BackupProtocolClientListDirectory::Flags_OldVersion |
+ BackupProtocolClientListDirectory::Flags_Deleted,
+ &flagsOut);
+
+ if (fileId == 0)
+ {
+ // error already reported
+ return;
+ }
+
+ BackupStoreFilenameClear fn(fileName);
+
+ // Delete it on the store
+ try
+ {
+ // Delete object
+ if(flagsOut & BackupProtocolClientListDirectory::Flags_File)
+ {
+ mrConnection.QueryDeleteFile(parentId, fn);
+ }
+ else
+ {
+ mrConnection.QueryDeleteDirectory(fileId);
+ }
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to delete object: " <<
+ e.what());
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to delete object: " <<
+ e.what());
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to delete object: unknown error");
+ }
}