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.cpp720
1 files changed, 537 insertions, 183 deletions
diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp
index d254ba9c..ee650b9c 100644
--- a/bin/bbackupquery/BackupQueries.cpp
+++ b/bin/bbackupquery/BackupQueries.cpp
@@ -1,4 +1,4 @@
-// distribution boxbackup-0.10 (svn version: 494)
+// distribution boxbackup-0.11rc1 (svn version: 2023_2024)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
@@ -64,6 +64,7 @@
#endif
#include <set>
+#include <limits>
#include "BackupQueries.h"
#include "Utils.h"
@@ -83,13 +84,19 @@
#include "BackupStoreException.h"
#include "ExcludeList.h"
#include "BackupClientMakeExcludeList.h"
+#include "PathUtils.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
-#define COMPARE_RETURN_SAME 1
+// min() and max() macros from stdlib.h break numeric_limits<>::min(), etc.
+#undef min
+#undef max
+
+#define COMPARE_RETURN_SAME 1
#define COMPARE_RETURN_DIFFERENT 2
#define COMPARE_RETURN_ERROR 3
-
+#define COMMAND_RETURN_ERROR 4
// --------------------------------------------------------------------------
//
@@ -107,7 +114,11 @@ BackupQueries::BackupQueries(BackupProtocolClient &rConnection, const Configurat
mWarnedAboutOwnerAttributes(false),
mReturnCode(0) // default return code
{
+ #ifdef WIN32
+ mRunningAsRoot = TRUE;
+ #else
mRunningAsRoot = (::geteuid() == 0);
+ #endif
}
// --------------------------------------------------------------------------
@@ -122,15 +133,21 @@ BackupQueries::~BackupQueries()
{
}
+typedef struct
+{
+ const char* name;
+ const char* opts;
+} QueryCommandSpecification;
+
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupQueries::DoCommand(const char *)
+// Name: BackupQueries::DoCommand(const char *, bool)
// Purpose: Perform a command
// Created: 2003/10/10
//
// --------------------------------------------------------------------------
-void BackupQueries::DoCommand(const char *Command)
+void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
{
// is the command a shell command?
if(Command[0] == 's' && Command[1] == 'h' && Command[2] == ' ' && Command[3] != '\0')
@@ -191,6 +208,25 @@ void BackupQueries::DoCommand(const char *Command)
if(!s.empty()) cmdElements.push_back(s);
}
+ #ifdef WIN32
+ if (isFromCommandLine)
+ {
+ for (std::vector<std::string>::iterator
+ i = cmdElements.begin();
+ i != cmdElements.end(); i++)
+ {
+ std::string converted;
+ if (!ConvertEncoding(*i, CP_ACP, converted,
+ GetConsoleCP()))
+ {
+ BOX_ERROR("Failed to convert encoding");
+ return;
+ }
+ *i = converted;
+ }
+ }
+ #endif
+
// Check...
if(cmdElements.size() < 1)
{
@@ -199,8 +235,24 @@ void BackupQueries::DoCommand(const char *Command)
}
// Data about commands
- static const char *commandNames[] = {"quit", "exit", "list", "pwd", "cd", "lcd", "sh", "getobject", "get", "compare", "restore", "help", "usage", "undelete", 0};
- static const char *validOptions[] = {"", "", "rodIFtsh", "", "od", "", "", "", "i", "alcqE", "dri", "", "", "", 0};
+ static QueryCommandSpecification commands[] =
+ {
+ { "quit", "" },
+ { "exit", "" },
+ { "list", "rodIFtTsh", },
+ { "pwd", "" },
+ { "cd", "od" },
+ { "lcd", "" },
+ { "sh", "" },
+ { "getobject", "" },
+ { "get", "i" },
+ { "compare", "alcqAEQ" },
+ { "restore", "dri" },
+ { "help", "" },
+ { "usage", "" },
+ { "undelete", "" },
+ { NULL, NULL }
+ };
#define COMMAND_Quit 0
#define COMMAND_Exit 1
#define COMMAND_List 2
@@ -220,11 +272,11 @@ void BackupQueries::DoCommand(const char *Command)
// Work out which command it is...
int cmd = 0;
- while(commandNames[cmd] != 0 && ::strcmp(cmdElements[0].c_str(), commandNames[cmd]) != 0)
+ while(commands[cmd].name != 0 && ::strcmp(cmdElements[0].c_str(), commands[cmd].name) != 0)
{
cmd++;
}
- if(commandNames[cmd] == 0)
+ if(commands[cmd].name == 0)
{
// Check for aliases
int a;
@@ -241,7 +293,7 @@ void BackupQueries::DoCommand(const char *Command)
// No such command
if(alias[a] == 0)
{
- printf("Unrecognised command: %s\n", Command);
+ BOX_ERROR("Unrecognised command: " << Command);
return;
}
}
@@ -259,9 +311,10 @@ void BackupQueries::DoCommand(const char *Command)
while(*c != 0)
{
// Valid option?
- if(::strchr(validOptions[cmd], *c) == NULL)
+ if(::strchr(commands[cmd].opts, *c) == NULL)
{
- printf("Invalid option '%c' for command %s\n", *c, commandNames[cmd]);
+ BOX_ERROR("Invalid option '" << *c << "' for "
+ "command " << commands[cmd].name);
return;
}
opts[(int)*c] = true;
@@ -290,9 +343,8 @@ void BackupQueries::DoCommand(const char *Command)
case COMMAND_pwd:
{
// Simple implementation, so do it here
- printf("%s (%08llx)\n",
- GetCurrentDirectoryName().c_str(),
- (long long)GetCurrentDirectoryID());
+ BOX_INFO(GetCurrentDirectoryName() << " (" <<
+ BOX_FORMAT_OBJECTID(GetCurrentDirectoryID()));
}
break;
@@ -305,7 +357,7 @@ void BackupQueries::DoCommand(const char *Command)
break;
case COMMAND_sh:
- printf("The command to run must be specified as an argument.\n");
+ BOX_ERROR("The command to run must be specified as an argument.");
break;
case COMMAND_GetObject:
@@ -356,8 +408,9 @@ void BackupQueries::CommandList(const std::vector<std::string> &args, const bool
#define LIST_OPTION_ALLOWOLD 'o'
#define LIST_OPTION_ALLOWDELETED 'd'
#define LIST_OPTION_NOOBJECTID 'I'
- #define LIST_OPTION_NOFLAGS 'F'
- #define LIST_OPTION_TIMES 't'
+ #define LIST_OPTION_NOFLAGS 'F'
+ #define LIST_OPTION_TIMES_LOCAL 't'
+ #define LIST_OPTION_TIMES_UTC 'T'
#define LIST_OPTION_SIZEINBLOCKS 's'
#define LIST_OPTION_DISPLAY_HASH 'h'
@@ -385,8 +438,8 @@ void BackupQueries::CommandList(const std::vector<std::string> &args, const bool
if(rootDir == 0)
{
- printf("Directory '%s' not found on store\n",
- args[0].c_str());
+ BOX_ERROR("Directory '" << args[0] << "' not found "
+ "on store.");
return;
}
}
@@ -399,7 +452,7 @@ void BackupQueries::CommandList(const std::vector<std::string> &args, const bool
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupQueries::CommandList2(int64_t, const std::string &, const bool *)
+// Name: BackupQueries::List(int64_t, const std::string &, const bool *, bool)
// Purpose: Do the actual listing of directories and files
// Created: 2003/10/10
//
@@ -474,11 +527,19 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
}
}
- if(opts[LIST_OPTION_TIMES])
+ if(opts[LIST_OPTION_TIMES_UTC])
+ {
+ // Show UTC times...
+ std::string time = BoxTimeToISO8601String(
+ en->GetModificationTime(), false);
+ printf("%s ", time.c_str());
+ }
+
+ if(opts[LIST_OPTION_TIMES_LOCAL])
{
- // Show times...
+ // Show local times...
std::string time = BoxTimeToISO8601String(
- en->GetModificationTime());
+ en->GetModificationTime(), true);
printf("%s ", time.c_str());
}
@@ -723,7 +784,7 @@ void BackupQueries::CommandChangeDir(const std::vector<std::string> &args, const
{
if(args.size() != 1 || args[0].size() == 0)
{
- printf("Incorrect usage.\ncd [-o] [-d] <directory>\n");
+ BOX_ERROR("Incorrect usage. cd [-o] [-d] <directory>");
return;
}
@@ -740,7 +801,7 @@ void BackupQueries::CommandChangeDir(const std::vector<std::string> &args, const
if(id == 0)
{
- printf("Directory '%s' not found\n", args[0].c_str());
+ BOX_ERROR("Directory '" << args[0] << "' not found.");
return;
}
@@ -761,22 +822,37 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
{
if(args.size() != 1 || args[0].size() == 0)
{
- printf("Incorrect usage.\nlcd <local-directory>\n");
+ BOX_ERROR("Incorrect usage. lcd <local-directory>");
+ SetReturnCode(COMMAND_RETURN_ERROR);
return;
}
// Try changing directory
#ifdef WIN32
std::string dirName;
- if(!ConvertConsoleToUtf8(args[0].c_str(), dirName)) return;
+ if(!ConvertConsoleToUtf8(args[0].c_str(), dirName))
+ {
+ BOX_ERROR("Failed to convert path from console encoding.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ return;
+ }
int result = ::chdir(dirName.c_str());
#else
int result = ::chdir(args[0].c_str());
#endif
if(result != 0)
{
- printf((errno == ENOENT || errno == ENOTDIR)?"Directory '%s' does not exist\n":"Error changing dir to '%s'\n",
- args[0].c_str());
+ if(errno == ENOENT || errno == ENOTDIR)
+ {
+ BOX_ERROR("Directory '" << args[0] << "' does not exist.");
+ }
+ else
+ {
+ BOX_ERROR("Error changing to directory '" <<
+ args[0] << ": " << strerror(errno));
+ }
+
+ SetReturnCode(COMMAND_RETURN_ERROR);
return;
}
@@ -784,15 +860,22 @@ void BackupQueries::CommandChangeLocalDir(const std::vector<std::string> &args)
char wd[PATH_MAX];
if(::getcwd(wd, PATH_MAX) == 0)
{
- printf("Error getting current directory\n");
+ BOX_ERROR("Error getting current directory: " <<
+ strerror(errno));
+ SetReturnCode(COMMAND_RETURN_ERROR);
return;
}
#ifdef WIN32
- if(!ConvertUtf8ToConsole(wd, dirName)) return;
- printf("Local current directory is now '%s'\n", dirName.c_str());
+ if(!ConvertUtf8ToConsole(wd, dirName))
+ {
+ BOX_ERROR("Failed to convert new path from console encoding.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ return;
+ }
+ BOX_INFO("Local current directory is now '" << dirName << "'.");
#else
- printf("Local current directory is now '%s'\n", wd);
+ BOX_INFO("Local current directory is now '" << wd << "'.");
#endif
}
@@ -810,14 +893,15 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
// Check args
if(args.size() != 2)
{
- printf("Incorrect usage.\ngetobject <object-id> <local-filename>\n");
+ BOX_ERROR("Incorrect usage. getobject <object-id> "
+ "<local-filename>");
return;
}
int64_t id = ::strtoll(args[0].c_str(), 0, 16);
- if(id == LLONG_MIN || id == LLONG_MAX || id == 0)
+ if(id == std::numeric_limits<long long>::min() || id == std::numeric_limits<long long>::max() || id == 0)
{
- printf("Not a valid object ID (specified in hex)\n");
+ BOX_ERROR("Not a valid object ID (specified in hex).");
return;
}
@@ -825,7 +909,7 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
struct stat st;
if(::stat(args[1].c_str(), &st) == 0 || errno != ENOENT)
{
- printf("The local file %s already exists\n", args[1].c_str());
+ BOX_ERROR("The local file '" << args[1] << " already exists.");
return;
}
@@ -843,18 +927,20 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
std::auto_ptr<IOStream> objectStream(mrConnection.ReceiveStream());
objectStream->CopyStreamTo(out);
- printf("Object ID %08llx fetched successfully.\n", id);
+ BOX_INFO("Object ID " << BOX_FORMAT_OBJECTID(id) <<
+ " fetched successfully.");
}
else
{
- printf("Object does not exist on store.\n");
+ BOX_ERROR("Object ID " << BOX_FORMAT_OBJECTID(id) <<
+ " does not exist on store.");
::unlink(args[1].c_str());
}
}
catch(...)
{
::unlink(args[1].c_str());
- printf("Error occured fetching object.\n");
+ BOX_ERROR("Error occured fetching object.");
}
}
@@ -868,26 +954,65 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
// Created: 2003/10/12
//
// --------------------------------------------------------------------------
-void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool *opts)
+void BackupQueries::CommandGet(std::vector<std::string> args, const bool *opts)
{
// At least one argument?
// Check args
if(args.size() < 1 || (opts['i'] && args.size() != 2) || args.size() > 2)
{
- printf("Incorrect usage.\n"
+ BOX_ERROR("Incorrect usage.\n"
"get <remote-filename> [<local-filename>] or\n"
- "get -i <object-id> <local-filename>\n");
+ "get -i <object-id> <local-filename>");
return;
}
// Find object ID somehow
- int64_t id;
+ int64_t fileId;
+ int64_t dirId = GetCurrentDirectoryID();
std::string localName;
+
// BLOCK
{
+#ifdef WIN32
+ for (std::vector<std::string>::iterator
+ i = args.begin(); i != args.end(); i++)
+ {
+ std::string out;
+ if(!ConvertConsoleToUtf8(i->c_str(), out))
+ {
+ BOX_ERROR("Failed to convert encoding.");
+ return;
+ }
+ *i = out;
+ }
+#endif
+
+ std::string fileName(args[0]);
+
+ 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;
+ }
+ }
+ }
+
+ BackupStoreFilenameClear fn(fileName);
+
// Need to look it up in the current directory
mrConnection.QueryListDirectory(
- GetCurrentDirectoryID(),
+ dirId,
BackupProtocolClientListDirectory::Flags_File, // just files
(opts['i'])?(BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING):(BackupProtocolClientListDirectory::Flags_OldVersion | BackupProtocolClientListDirectory::Flags_Deleted), // only current versions
false /* don't want attributes */);
@@ -900,17 +1025,24 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
if(opts['i'])
{
// Specified as ID.
- id = ::strtoll(args[0].c_str(), 0, 16);
- if(id == LLONG_MIN || id == LLONG_MAX || id == 0)
+ 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)
{
- printf("Not a valid object ID (specified in hex)\n");
+ BOX_ERROR("Not a valid object ID (specified in hex).");
return;
}
// Check that the item is actually in the directory
- if(dir.FindEntryByID(id) == 0)
+ if(dir.FindEntryByID(fileId) == 0)
{
- printf("ID '%08llx' not found in current directory on store.\n(You can only download objects by ID from the current directory.)\n", id);
+ 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;
}
@@ -921,26 +1053,23 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
{
// Specified by name, find the object in the directory to get the ID
BackupStoreDirectory::Iterator i(dir);
-#ifdef WIN32
- std::string fileName;
- if(!ConvertConsoleToUtf8(args[0].c_str(), fileName))
- return;
- BackupStoreFilenameClear fn(fileName);
-#else
- BackupStoreFilenameClear fn(args[0]);
-#endif
BackupStoreDirectory::Entry *en = i.FindMatchingClearName(fn);
if(en == 0)
{
- printf("Filename '%s' not found in current directory on store.\n(Subdirectories in path not searched.)\n", args[0].c_str());
+ BOX_ERROR("Filename '" << args[0] << "' "
+ "not found in current "
+ "directory on store.\n"
+ "(Subdirectories in path not "
+ "searched.)");
return;
}
- id = en->GetObjectID();
+ fileId = en->GetObjectID();
- // Local name is the last argument, which is either the looked up filename, or
- // a filename specified by the user.
+ // Local name is the last argument, which is either
+ // the looked up filename, or a filename specified
+ // by the user.
localName = args[args.size() - 1];
}
}
@@ -949,7 +1078,9 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
struct stat st;
if(::stat(localName.c_str(), &st) == 0 || errno != ENOENT)
{
- printf("The local file %s already exists, will not overwrite it.\n", localName.c_str());
+ BOX_ERROR("The local file " << localName << " already exists, "
+ "will not overwrite it.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
return;
}
@@ -957,7 +1088,7 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
try
{
// Request object
- mrConnection.QueryGetFile(GetCurrentDirectoryID(), id);
+ mrConnection.QueryGetFile(dirId, fileId);
// Stream containing encoded file
std::auto_ptr<IOStream> objectStream(mrConnection.ReceiveStream());
@@ -966,12 +1097,25 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
BackupStoreFile::DecodeFile(*objectStream, localName.c_str(), mrConnection.GetTimeout());
// Done.
- printf("Object ID %08llx fetched sucessfully.\n", id);
+ BOX_INFO("Object ID " << BOX_FORMAT_OBJECTID(fileId) <<
+ " fetched successfully.");
+ }
+ catch (BoxException &e)
+ {
+ BOX_ERROR("Failed to fetch file: " <<
+ e.what());
+ ::unlink(localName.c_str());
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to fetch file: " <<
+ e.what());
+ ::unlink(localName.c_str());
}
catch(...)
{
+ BOX_ERROR("Failed to fetch file: unknown error");
::unlink(localName.c_str());
- printf("Error occured fetching file.\n");
}
}
@@ -987,8 +1131,10 @@ void BackupQueries::CommandGet(const std::vector<std::string> &args, const bool
BackupQueries::CompareParams::CompareParams()
: mQuickCompare(false),
mIgnoreExcludes(false),
+ mIgnoreAttributes(false),
mDifferences(0),
mDifferencesExplainedByModTime(0),
+ mUncheckedFiles(0),
mExcludedDirs(0),
mExcludedFiles(0),
mpExcludeFiles(0),
@@ -1048,7 +1194,9 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
// Parameters, including count of differences
BackupQueries::CompareParams params;
params.mQuickCompare = opts['q'];
+ params.mQuietCompare = opts['Q'];
params.mIgnoreExcludes = opts['E'];
+ params.mIgnoreAttributes = opts['A'];
// Try and work out the time before which all files should be on the server
{
@@ -1064,14 +1212,16 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
}
else
{
- printf("Warning: couldn't determine the time of the last synchronisation -- checks not performed.\n");
+ BOX_WARNING("Failed to determine the time of the last "
+ "synchronisation -- checks not performed.");
}
}
// Quick compare?
if(params.mQuickCompare)
{
- printf("WARNING: Quick compare used -- file attributes are not checked.\n");
+ BOX_WARNING("Quick compare used -- file attributes are not "
+ "checked.");
}
if(!opts['l'] && opts['a'] && args.size() == 0)
@@ -1096,7 +1246,7 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
// Can't be bothered to do all the hard work to work out which location it's on, and hence which exclude list
if(!params.mIgnoreExcludes)
{
- printf("Cannot use excludes on directory to directory comparison -- use -E flag to specify ignored excludes\n");
+ BOX_ERROR("Cannot use excludes on directory to directory comparison -- use -E flag to specify ignored excludes.");
return;
}
else
@@ -1107,17 +1257,38 @@ void BackupQueries::CommandCompare(const std::vector<std::string> &args, const b
}
else
{
- printf("Incorrect usage.\ncompare -a\n or compare -l <location-name>\n or compare <store-dir-name> <local-dir-name>\n");
+ BOX_ERROR("Incorrect usage.\ncompare -a\n or compare -l <location-name>\n or compare <store-dir-name> <local-dir-name>");
return;
}
-
- printf("\n[ %d (of %d) differences probably due to file modifications after the last upload ]\nDifferences: %d (%d dirs excluded, %d files excluded)\n",
- params.mDifferencesExplainedByModTime, params.mDifferences, params.mDifferences, params.mExcludedDirs, params.mExcludedFiles);
+
+ if (!params.mQuietCompare)
+ {
+ BOX_INFO("[ " <<
+ params.mDifferencesExplainedByModTime << " (of " <<
+ params.mDifferences << ") differences probably "
+ "due to file modifications after the last upload ]");
+ }
+
+ BOX_INFO("Differences: " << params.mDifferences << " (" <<
+ params.mExcludedDirs << " dirs excluded, " <<
+ params.mExcludedFiles << " files excluded, " <<
+ params.mUncheckedFiles << " files not checked)");
// Set return code?
if(opts['c'])
{
- SetReturnCode((params.mDifferences == 0)?COMPARE_RETURN_SAME:COMPARE_RETURN_DIFFERENT);
+ if (params.mUncheckedFiles != 0)
+ {
+ SetReturnCode(COMPARE_RETURN_ERROR);
+ }
+ else if (params.mDifferences != 0)
+ {
+ SetReturnCode(COMPARE_RETURN_DIFFERENT);
+ }
+ else
+ {
+ SetReturnCode(COMPARE_RETURN_SAME);
+ }
}
}
@@ -1136,10 +1307,23 @@ void BackupQueries::CompareLocation(const std::string &rLocation, BackupQueries:
const Configuration &locations(mrConfiguration.GetSubConfiguration("BackupLocations"));
if(!locations.SubConfigurationExists(rLocation.c_str()))
{
- printf("Location %s does not exist.\n", rLocation.c_str());
+ BOX_ERROR("Location " << rLocation << " does not exist.");
return;
}
const Configuration &loc(locations.GetSubConfiguration(rLocation.c_str()));
+
+ #ifdef WIN32
+ {
+ std::string path = loc.GetKeyValue("Path");
+ if (path.size() > 0 && path[path.size()-1] ==
+ DIRECTORY_SEPARATOR_ASCHAR)
+ {
+ BOX_WARNING("Location '" << rLocation << "' path ends "
+ "with '" DIRECTORY_SEPARATOR "', "
+ "compare may fail!");
+ }
+ }
+ #endif
try
{
@@ -1189,9 +1373,9 @@ void BackupQueries::Compare(const std::string &rStoreDir, const std::string &rLo
// Found?
if(dirID == 0)
{
- printf("Local directory '%s' exists, but "
- "server directory '%s' does not exist\n",
- rLocalDir.c_str(), rStoreDir.c_str());
+ BOX_WARNING("Local directory '" << rLocalDir << "' exists, "
+ "but server directory '" << rStoreDir << "' does not "
+ "exist.");
rParams.mDifferences ++;
return;
}
@@ -1222,14 +1406,14 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
#ifdef WIN32
// By this point, rStoreDir and rLocalDir should be in UTF-8 encoding
- std::string localName;
- std::string storeName;
+ std::string localDirDisplay;
+ std::string storeDirDisplay;
- if(!ConvertUtf8ToConsole(rLocalDir.c_str(), localName)) return;
- if(!ConvertUtf8ToConsole(rStoreDir.c_str(), storeName)) return;
+ if(!ConvertUtf8ToConsole(rLocalDir.c_str(), localDirDisplay)) return;
+ if(!ConvertUtf8ToConsole(rStoreDir.c_str(), storeDirDisplay)) return;
#else
- const std::string& localName(rLocalDir);
- const std::string& storeName(rStoreDir);
+ const std::string& localDirDisplay(rLocalDir);
+ const std::string& storeDirDisplay(rStoreDir);
#endif
// Get info on the local directory
@@ -1239,21 +1423,24 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// What kind of error?
if(errno == ENOTDIR)
{
- printf("Local object '%s' is a file, "
- "server object '%s' is a directory\n",
- localName.c_str(), storeName.c_str());
+ BOX_WARNING("Local object '" << localDirDisplay << "' "
+ "is a file, server object '" <<
+ storeDirDisplay << "' is a directory.");
rParams.mDifferences ++;
}
else if(errno == ENOENT)
{
- printf("Local directory '%s' does not exist "
- "(compared to server directory '%s')\n",
- localName.c_str(), storeName.c_str());
+ BOX_WARNING("Local directory '" << localDirDisplay <<
+ "' does not exist (compared to server "
+ "directory '" << storeDirDisplay << "').");
+ rParams.mDifferences ++;
}
else
{
- printf("ERROR: stat on local dir '%s'\n",
- localName.c_str());
+ BOX_WARNING("Failed to access local directory '" <<
+ localDirDisplay << ": " << strerror(errno) <<
+ "'.");
+ rParams.mUncheckedFiles ++;
}
return;
}
@@ -1273,8 +1460,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Test out the attributes
if(!dir.HasAttributes())
{
- printf("Store directory '%s' doesn't have attributes.\n",
- storeName.c_str());
+ BOX_WARNING("Store directory '" << storeDirDisplay << "' "
+ "doesn't have attributes.");
}
else
{
@@ -1289,9 +1476,9 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
if(!(attr.Compare(localAttr, true, true /* ignore modification times */)))
{
- printf("Local directory '%s' has different attributes "
- "to store directory '%s'.\n",
- localName.c_str(), storeName.c_str());
+ BOX_WARNING("Local directory '" << localDirDisplay <<
+ "' has different attributes to store "
+ "directory '" << storeDirDisplay << "'.");
rParams.mDifferences ++;
}
}
@@ -1300,7 +1487,9 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
DIR *dirhandle = ::opendir(rLocalDir.c_str());
if(dirhandle == 0)
{
- printf("ERROR: opendir on local dir '%s'\n", localName.c_str());
+ BOX_WARNING("Failed to open local directory '" <<
+ localDirDisplay << "': " << strerror(errno));
+ rParams.mUncheckedFiles ++;
return;
}
try
@@ -1316,13 +1505,23 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
(localDirEn->d_name[1] == '\0' || (localDirEn->d_name[1] == '.' && localDirEn->d_name[2] == '\0')))
{
// ignore, it's . or ..
+
+#ifdef HAVE_VALID_DIRENT_D_TYPE
+ if (localDirEn->d_type != DT_DIR)
+ {
+ BOX_ERROR("d_type does not really "
+ "work on your platform. "
+ "Reconfigure Box!");
+ return;
+ }
+#endif
+
continue;
}
#ifndef HAVE_VALID_DIRENT_D_TYPE
- std::string fn(rLocalDir);
- fn += DIRECTORY_SEPARATOR_ASCHAR;
- fn += localDirEn->d_name;
+ std::string fn(MakeFullPath
+ (rLocalDir, localDirEn->d_name));
struct stat st;
if(::lstat(fn.c_str(), &st) != 0)
{
@@ -1339,7 +1538,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
{
// Directory
localDirs.insert(std::string(localDirEn->d_name));
- }
+ }
#else
// Entry -- file or dir?
if(localDirEn->d_type == DT_REG || localDirEn->d_type == DT_LNK)
@@ -1357,8 +1556,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Close directory
if(::closedir(dirhandle) != 0)
{
- printf("ERROR: closedir on local dir '%s'\n",
- localName.c_str());
+ BOX_ERROR("Failed to close local directory '" <<
+ localDirDisplay << "': " << strerror(errno));
}
dirhandle = 0;
@@ -1395,25 +1594,39 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Now compare files.
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);
+
// Does the file exist locally?
- string_set_iter_t local(localFiles.find(i->first));
+ string_set_iter_t local(localFiles.find(fileName));
if(local == localFiles.end())
{
// Not found -- report
- printf("Local file '%s" DIRECTORY_SEPARATOR
- "%s' does not exist, "
- "but store file '%s/%s' does.\n",
- localName.c_str(), i->first.c_str(),
- storeName.c_str(), i->first.c_str());
+ BOX_WARNING("Local file '" <<
+ localPathDisplay << "' does not exist, "
+ "but store file '" <<
+ storePathDisplay << "' does.");
rParams.mDifferences ++;
}
else
{
try
{
- // make local name of file for comparison
- std::string localName(rLocalDir + DIRECTORY_SEPARATOR + i->first);
-
// Files the same flag?
bool equal = true;
@@ -1429,7 +1642,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
std::auto_ptr<IOStream> blockIndexStream(mrConnection.ReceiveStream());
// Compare
- equal = BackupStoreFile::CompareFileContentsAgainstBlockIndex(localName.c_str(), *blockIndexStream, mrConnection.GetTimeout());
+ equal = BackupStoreFile::CompareFileContentsAgainstBlockIndex(localPath.c_str(), *blockIndexStream, mrConnection.GetTimeout());
}
else
{
@@ -1441,7 +1654,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Decode it
std::auto_ptr<BackupStoreFile::DecodedStream> fileOnServerStream;
- // Got additional attibutes?
+ // Got additional attributes?
if(i->second->HasAttributes())
{
// Use these attributes
@@ -1464,26 +1677,39 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
// Compare attributes
BackupClientFileAttributes localAttr;
box_time_t fileModTime = 0;
- localAttr.ReadAttributes(localName.c_str(), false /* don't zero mod times */, &fileModTime);
+ localAttr.ReadAttributes(localPath.c_str(), false /* don't zero mod times */, &fileModTime);
modifiedAfterLastSync = (fileModTime > rParams.mLatestFileUploadTime);
- if(!localAttr.Compare(fileOnServerStream->GetAttributes(),
- true /* ignore attr mod time */,
+ bool ignoreAttrModTime = true;
+
+ #ifdef WIN32
+ // attr mod time is really
+ // creation time, so check it
+ ignoreAttrModTime = false;
+ #endif
+
+ if(!rParams.mIgnoreAttributes &&
+ #ifdef PLATFORM_DISABLE_SYMLINK_ATTRIB_COMPARE
+ !fileOnServerStream->IsSymLink() &&
+ #endif
+ !localAttr.Compare(fileOnServerStream->GetAttributes(),
+ ignoreAttrModTime,
fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */))
{
- printf("Local file '%s"
- DIRECTORY_SEPARATOR
- "%s' has different attributes "
- "to store file '%s/%s'.\n",
- localName.c_str(), i->first.c_str(), storeName.c_str(), i->first.c_str());
+ BOX_WARNING("Local file '" <<
+ localPathDisplay <<
+ "' has different attributes "
+ "to store file '" <<
+ storePathDisplay <<
+ "'.");
rParams.mDifferences ++;
if(modifiedAfterLastSync)
{
rParams.mDifferencesExplainedByModTime ++;
- printf("(the file above was modified after the last sync time -- might be reason for difference)\n");
+ BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
}
else if(i->second->HasAttributes())
{
- printf("(the file above has had new attributes applied)\n");
+ BOX_INFO("(the file above has had new attributes applied)\n");
}
}
@@ -1492,7 +1718,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
if(!fileOnServerStream->IsSymLink())
{
// Open the local file
- FileStream l(localName.c_str());
+ FileStream l(localPath.c_str());
// Size
IOStream::pos_type fileSizeLocal = l.BytesLeftToRead();
@@ -1522,7 +1748,7 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
equal = false;
}
- // Must always read the entire decoded string, if it's not a symlink
+ // Must always read the entire decoded stream, if it's not a symlink
if(fileOnServerStream->StreamDataLeft())
{
// Absorb all the data remaining
@@ -1532,40 +1758,65 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
fileOnServerStream->Read(buffer, sizeof(buffer), mrConnection.GetTimeout());
}
}
+
+ // Must always read the entire encoded stream
+ if(objectStream->StreamDataLeft())
+ {
+ // Absorb all the data remaining
+ char buffer[2048];
+ while(objectStream->StreamDataLeft())
+ {
+ objectStream->Read(buffer, sizeof(buffer), mrConnection.GetTimeout());
+ }
+ }
}
}
// Report if not equal.
if(!equal)
{
- printf("Local file '%s"
- DIRECTORY_SEPARATOR
- "%s' has different contents "
- "to store file '%s/%s'.\n",
- localName.c_str(), i->first.c_str(), storeName.c_str(), i->first.c_str());
+ BOX_WARNING("Local file '" <<
+ localPathDisplay << "' "
+ "has different contents "
+ "to store file '" <<
+ storePathDisplay <<
+ "'.");
rParams.mDifferences ++;
if(modifiedAfterLastSync)
{
rParams.mDifferencesExplainedByModTime ++;
- printf("(the file above was modified after the last sync time -- might be reason for difference)\n");
+ BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
}
else if(i->second->HasAttributes())
{
- printf("(the file above has had new attributes applied)\n");
+ BOX_INFO("(the file above has had new attributes applied)\n");
}
}
}
catch(BoxException &e)
{
- printf("ERROR: (%d/%d) during file fetch and comparsion for '%s/%s'\n",
- e.GetType(),
- e.GetSubType(),
- storeName.c_str(),
- i->first.c_str());
+ BOX_ERROR("Failed to fetch and compare "
+ "'" <<
+ storePathDisplay.c_str() <<
+ "': error " << e.what() <<
+ " (" << e.GetType() <<
+ "/" << e.GetSubType() << ")");
+ rParams.mUncheckedFiles ++;
}
- catch(...)
+ catch(std::exception &e)
{
- printf("ERROR: (unknown) during file fetch and comparsion for '%s/%s'\n", storeName.c_str(), i->first.c_str());
+ BOX_ERROR("Failed to fetch and compare "
+ "'" <<
+ storePathDisplay.c_str() <<
+ "': " << e.what());
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to fetch and compare "
+ "'" <<
+ storePathDisplay.c_str() <<
+ "': unknown error");
+ rParams.mUncheckedFiles ++;
}
// Remove from set so that we know it's been compared
@@ -1576,28 +1827,43 @@ 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
for(string_set_iter_t i = localFiles.begin(); i != localFiles.end(); ++i)
{
- std::string localFileName(rLocalDir +
- DIRECTORY_SEPARATOR + *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);
+
// Should this be ignored (ie is excluded)?
if(rParams.mpExcludeFiles == 0 ||
- !(rParams.mpExcludeFiles->IsExcluded(localFileName)))
+ !(rParams.mpExcludeFiles->IsExcluded(localPath)))
{
- printf("Local file '%s" DIRECTORY_SEPARATOR
- "%s' exists, but store file '%s/%s' "
- "does not exist.\n",
- localName.c_str(), (*i).c_str(),
- storeName.c_str(), (*i).c_str());
+ BOX_WARNING("Local file '" <<
+ localPathDisplay <<
+ "' exists, but store file '" <<
+ storePathDisplay <<
+ "' does not.");
rParams.mDifferences ++;
// Check the file modification time
{
struct stat st;
- if(::stat(localFileName.c_str(), &st) == 0)
+ if(::stat(localPath.c_str(), &st) == 0)
{
if(FileModificationTime(st) > rParams.mLatestFileUploadTime)
{
rParams.mDifferencesExplainedByModTime ++;
- printf("(the file above was modified after the last sync time -- might be reason for difference)\n");
+ BOX_INFO("(the file above was modified after the last sync time -- might be reason for difference)");
}
}
}
@@ -1612,26 +1878,58 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir, const s
localFiles.clear();
storeFiles.clear();
- // Now do the directories, recusively to check subdirectories
+ // Now do the directories, recursively to check subdirectories
for(std::set<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);
+
// Does the directory exist locally?
string_set_iter_t local(localDirs.find(i->first));
- if(local == localDirs.end())
+ if(local == localDirs.end() &&
+ rParams.mpExcludeDirs != NULL &&
+ rParams.mpExcludeDirs->IsExcluded(localPath))
+ {
+ // Not found -- report
+ BOX_WARNING("Local directory '" <<
+ localPathDisplay << "' is excluded, "
+ "but store directory '" <<
+ storePathDisplay << "' still exists.");
+ rParams.mDifferences ++;
+ }
+ else if(local == localDirs.end())
{
// Not found -- report
- printf("Local directory '%s"
- DIRECTORY_SEPARATOR "%s' "
- "does not exist, but store directory "
- "'%s/%s' does.\n",
- localName.c_str(), i->first.c_str(),
- storeName.c_str(), i->first.c_str());
+ BOX_WARNING("Local directory '" <<
+ localPathDisplay << "' does not exist, "
+ "but store directory '" <<
+ storePathDisplay << "' does.");
rParams.mDifferences ++;
}
+ else if(rParams.mpExcludeDirs != NULL &&
+ rParams.mpExcludeDirs->IsExcluded(localPath))
+ {
+ // don't recurse into excluded directories
+ }
else
{
// Compare directory
- Compare(i->second->GetObjectID(), rStoreDir + "/" + i->first, rLocalDir + DIRECTORY_SEPARATOR + i->first, rParams);
+ Compare(i->second->GetObjectID(), rStoreDir + "/" + i->first, localPath, rParams);
// Remove from set so that we know it's been compared
localDirs.erase(local);
@@ -1641,14 +1939,33 @@ 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
for(std::set<std::string>::const_iterator i = localDirs.begin(); i != localDirs.end(); ++i)
{
- std::string localName(rLocalDir + DIRECTORY_SEPARATOR + *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);
+
// Should this be ignored (ie is excluded)?
- if(rParams.mpExcludeDirs == 0 || !(rParams.mpExcludeDirs->IsExcluded(localName)))
+ if(rParams.mpExcludeDirs == 0 || !(rParams.mpExcludeDirs->IsExcluded(localPath)))
{
- printf("Local directory '%s/%s' exists, but "
- "store directory '%s/%s' does not exist.\n",
- localName.c_str(), (*i).c_str(),
- storeName.c_str(), (*i).c_str());
+ BOX_WARNING("Local directory '" <<
+ localPathDisplay << "' exists, but "
+ "store directory '" <<
+ storePathDisplay << "' does not.");
rParams.mDifferences ++;
}
else
@@ -1681,7 +1998,7 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
// Check arguments
if(args.size() != 2)
{
- printf("Incorrect usage.\nrestore [-d] [-r] [-i] <directory-name> <local-directory-name>\n");
+ BOX_ERROR("Incorrect usage. restore [-d] [-r] [-i] <remote-name> <local-name>");
return;
}
@@ -1694,9 +2011,9 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
{
// Specified as ID.
dirID = ::strtoll(args[0].c_str(), 0, 16);
- if(dirID == LLONG_MIN || dirID == LLONG_MAX || dirID == 0)
+ if(dirID == std::numeric_limits<long long>::min() || dirID == std::numeric_limits<long long>::max() || dirID == 0)
{
- printf("Not a valid object ID (specified in hex)\n");
+ BOX_ERROR("Not a valid object ID (specified in hex)");
return;
}
}
@@ -1719,12 +2036,12 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
// Allowable?
if(dirID == 0)
{
- printf("Directory '%s' not found on server\n", args[0].c_str());
+ BOX_ERROR("Directory '" << args[0] << "' not found on server");
return;
}
if(dirID == BackupProtocolClientListDirectory::RootDirectory)
{
- printf("Cannot restore the root directory -- restore locations individually.\n");
+ BOX_ERROR("Cannot restore the root directory -- restore locations individually.");
return;
}
@@ -1736,25 +2053,62 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
#endif
// Go and restore...
- switch(BackupClientRestore(mrConnection, dirID, localName.c_str(),
- true /* print progress dots */, restoreDeleted,
- false /* don't undelete after restore! */,
- opts['r'] /* resume? */))
+ int result;
+
+ try
+ {
+ result = BackupClientRestore(mrConnection, dirID,
+ localName.c_str(),
+ true /* print progress dots */, restoreDeleted,
+ false /* don't undelete after restore! */,
+ opts['r'] /* resume? */);
+ }
+ catch(std::exception &e)
+ {
+ BOX_ERROR("Failed to restore: " << e.what());
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ return;
+ }
+ catch(...)
+ {
+ BOX_ERROR("Failed to restore: unknown exception");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ return;
+ }
+
+ switch(result)
{
case Restore_Complete:
- printf("Restore complete\n");
+ BOX_INFO("Restore complete.");
break;
case Restore_ResumePossible:
- printf("Resume possible -- repeat command with -r flag to resume\n");
+ BOX_ERROR("Resume possible -- repeat command with -r flag to resume");
+ SetReturnCode(COMMAND_RETURN_ERROR);
break;
case Restore_TargetExists:
- printf("The target directory exists. You cannot restore over an existing directory.\n");
+ BOX_ERROR("The target directory exists. You cannot restore over an existing directory.");
+ SetReturnCode(COMMAND_RETURN_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);
+ break;
+ #endif
+
+ case Restore_UnknownError:
+ BOX_ERROR("Unknown error during restore.");
+ SetReturnCode(COMMAND_RETURN_ERROR);
+ break;
+
default:
- printf("ERROR: Unknown restore result.\n");
+ BOX_ERROR("Unknown restore result " << result << ".");
+ SetReturnCode(COMMAND_RETURN_ERROR);
break;
}
}
@@ -1874,7 +2228,7 @@ void BackupQueries::CommandUndelete(const std::vector<std::string> &args, const
// Check arguments
if(args.size() != 1)
{
- printf("Incorrect usage.\nundelete <directory-name>\n");
+ BOX_ERROR("Incorrect usage. undelete <directory-name>");
return;
}
@@ -1892,12 +2246,12 @@ void BackupQueries::CommandUndelete(const std::vector<std::string> &args, const
// Allowable?
if(dirID == 0)
{
- printf("Directory '%s' not found on server\n", args[0].c_str());
+ BOX_ERROR("Directory '" << args[0] << "' not found on server.");
return;
}
if(dirID == BackupProtocolClientListDirectory::RootDirectory)
{
- printf("Cannot undelete the root directory.\n");
+ BOX_ERROR("Cannot undelete the root directory.");
return;
}