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.cpp688
1 files changed, 319 insertions, 369 deletions
diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp
index 60724800..b8b9525b 100644
--- a/bin/bbackupquery/BackupQueries.cpp
+++ b/bin/bbackupquery/BackupQueries.cpp
@@ -48,9 +48,9 @@
#include "Logging.h"
#include "PathUtils.h"
#include "SelfFlushingStream.h"
-#include "TemporaryDirectory.h"
#include "Utils.h"
-#include "autogen_BackupProtocolClient.h"
+#include "autogen_BackupProtocol.h"
+#include "autogen_CipherException.h"
#include "MemLeakFindOn.h"
@@ -100,12 +100,6 @@ BackupQueries::~BackupQueries()
{
}
-typedef struct
-{
- const char* name;
- const char* opts;
-} QueryCommandSpecification;
-
// --------------------------------------------------------------------------
//
// Function
@@ -114,173 +108,46 @@ typedef struct
// Created: 2003/10/10
//
// --------------------------------------------------------------------------
-void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
+void BackupQueries::DoCommand(ParsedCommand& rCommand)
{
- // is the command a shell command?
- if(Command[0] == 's' && Command[1] == 'h' && Command[2] == ' ' && Command[3] != '\0')
+ // Check...
+
+ if(rCommand.mFailed)
{
- // Yes, run shell command
- int result = ::system(Command + 3);
- if(result != 0)
- {
- BOX_WARNING("System command returned error code " <<
- result);
- SetReturnCode(ReturnCode::Command_Error);
- }
+ BOX_ERROR("Parse failed");
return;
}
- // split command into components
- std::vector<std::string> cmdElements;
- std::string options;
+ if(rCommand.mCmdElements.size() < 1)
{
- const char *c = Command;
- bool inQuoted = false;
- bool inOptions = false;
-
- std::string s;
- while(*c != 0)
- {
- // Terminating char?
- if(*c == ((inQuoted)?'"':' '))
- {
- if(!s.empty()) cmdElements.push_back(s);
- s.resize(0);
- inQuoted = false;
- inOptions = false;
- }
- else
- {
- // No. Start of quoted parameter?
- if(s.empty() && *c == '"')
- {
- inQuoted = true;
- }
- // Start of options?
- else if(s.empty() && *c == '-')
- {
- inOptions = true;
- }
- else
- {
- if(inOptions)
- {
- // Option char
- options += *c;
- }
- else
- {
- // Normal string char
- s += *c;
- }
- }
- }
-
- ++c;
- }
- if(!s.empty()) cmdElements.push_back(s);
+ // blank command
+ return;
}
-
- #ifdef WIN32
- if (isFromCommandLine)
+
+ if(rCommand.pSpec->type == Command_sh &&
+ rCommand.mCmdElements.size() == 2)
{
- for (std::vector<std::string>::iterator
- i = cmdElements.begin();
- i != cmdElements.end(); i++)
+ // Yes, run shell command
+ int result = ::system(rCommand.mCmdElements[1].c_str());
+ if(result != 0)
{
- std::string converted;
- if (!ConvertEncoding(*i, CP_ACP, converted,
- GetConsoleCP()))
- {
- BOX_ERROR("Failed to convert encoding");
- return;
- }
- *i = converted;
+ BOX_WARNING("System command returned error code " <<
+ result);
+ SetReturnCode(ReturnCode::Command_Error);
}
- }
- #endif
-
- // Check...
- if(cmdElements.size() < 1)
- {
- // blank command
return;
}
-
- // Data about commands
- static QueryCommandSpecification commands[] =
- {
- { "quit", "" },
- { "exit", "" },
- { "list", "rodIFtTash", },
- { "pwd", "" },
- { "cd", "od" },
- { "lcd", "" },
- { "sh", "" },
- { "getobject", "" },
- { "get", "i" },
- { "compare", "alcqAEQ" },
- { "restore", "drif" },
- { "help", "" },
- { "usage", "m" },
- { "undelete", "i" },
- { "delete", "i" },
- { NULL, NULL }
- };
-
- 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;
- while(commands[cmd].name != 0 && ::strcmp(cmdElements[0].c_str(), commands[cmd].name) != 0)
- {
- cmd++;
- }
- if(commands[cmd].name == 0)
+
+ if(rCommand.pSpec->type == Command_Unknown)
{
- // Check for aliases
- int a;
- for(a = 0; alias[a] != 0; ++a)
- {
- if(::strcmp(cmdElements[0].c_str(), alias[a]) == 0)
- {
- // Found an alias
- cmd = aliasIs[a];
- break;
- }
- }
-
// No such command
- if(alias[a] == 0)
- {
- BOX_ERROR("Unrecognised command: " << Command);
- return;
- }
+ BOX_ERROR("Unrecognised command: " << rCommand.mCmdElements[0]);
+ return;
}
// Arguments
- std::vector<std::string> args(cmdElements.begin() + 1, cmdElements.end());
+ std::vector<std::string> args(rCommand.mCmdElements.begin() + 1,
+ rCommand.mCmdElements.end());
// Set up options
bool opts[256];
@@ -288,14 +155,14 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
// BLOCK
{
// options
- const char *c = options.c_str();
+ const char *c = rCommand.mOptions.c_str();
while(*c != 0)
{
// Valid option?
- if(::strchr(commands[cmd].opts, *c) == NULL)
+ if(::strchr(rCommand.pSpec->opts, *c) == NULL)
{
BOX_ERROR("Invalid option '" << *c << "' for "
- "command " << commands[cmd].name);
+ "command " << rCommand.pSpec->name);
return;
}
opts[(int)*c] = true;
@@ -303,17 +170,16 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
}
}
- if(cmd != Command_Quit && cmd != Command_Exit)
+ if(rCommand.pSpec->type != Command_Quit)
{
// If not a quit command, set the return code to zero
SetReturnCode(ReturnCode::Command_OK);
}
// Handle command
- switch(cmd)
+ switch(rCommand.pSpec->type)
{
case Command_Quit:
- case Command_Exit:
mQuitNow = true;
break;
@@ -375,7 +241,7 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
break;
default:
- BOX_ERROR("Unknown command: " << Command);
+ BOX_ERROR("Unknown command: " << rCommand.mCmdElements[0]);
break;
}
}
@@ -392,8 +258,6 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine)
void BackupQueries::CommandList(const std::vector<std::string> &args, const bool *opts)
{
#define LIST_OPTION_RECURSIVE 'r'
- #define LIST_OPTION_ALLOWOLD 'o'
- #define LIST_OPTION_ALLOWDELETED 'd'
#define LIST_OPTION_NOOBJECTID 'I'
#define LIST_OPTION_NOFLAGS 'F'
#define LIST_OPTION_TIMES_LOCAL 't'
@@ -492,22 +356,28 @@ static std::string GetTimeString(BackupStoreDirectory::Entry& en,
// Created: 2003/10/10
//
// --------------------------------------------------------------------------
-void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool *opts, bool FirstLevel)
+void BackupQueries::List(int64_t DirID, const std::string &rListRoot,
+ const bool *opts, bool FirstLevel, std::ostream* pOut)
{
+#ifdef WIN32
+ DWORD n_chars;
+ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+#endif
+
// Generate exclude flags
- int16_t excludeFlags = BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING;
- if(!opts[LIST_OPTION_ALLOWOLD]) excludeFlags |= BackupProtocolClientListDirectory::Flags_OldVersion;
- if(!opts[LIST_OPTION_ALLOWDELETED]) excludeFlags |= BackupProtocolClientListDirectory::Flags_Deleted;
+ int16_t excludeFlags = BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING;
+ if(!opts[LIST_OPTION_ALLOWOLD]) excludeFlags |= BackupProtocolListDirectory::Flags_OldVersion;
+ if(!opts[LIST_OPTION_ALLOWDELETED]) excludeFlags |= BackupProtocolListDirectory::Flags_Deleted;
// Do communication
try
{
mrConnection.QueryListDirectory(
- DirID,
- BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
- // both files and directories
- excludeFlags,
- true /* want attributes */);
+ DirID,
+ BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
+ // both files and directories
+ excludeFlags,
+ true /* want attributes */);
}
catch (std::exception &e)
{
@@ -522,7 +392,6 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
return;
}
-
// Retrieve the directory from the stream following
BackupStoreDirectory dir;
std::auto_ptr<IOStream> dirstream(mrConnection.ReceiveStream());
@@ -533,6 +402,8 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
BackupStoreDirectory::Entry *en = 0;
while((en = i.Next()) != 0)
{
+ std::ostringstream buf;
+
// Display this entry
BackupStoreFilenameClear clear(en->GetName());
@@ -540,11 +411,9 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
if(!opts[LIST_OPTION_NOOBJECTID])
{
// add object ID to line
-#ifdef _MSC_VER
- printf("%08I64x ", (int64_t)en->GetObjectID());
-#else
- printf("%08llx ", (long long)en->GetObjectID());
-#endif
+ buf << std::hex << std::internal << std::setw(8) <<
+ std::setfill('0') << en->GetObjectID() <<
+ std::dec << " ";
}
// Flags?
@@ -571,44 +440,40 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
// terminate
*(f++) = ' ';
*(f++) = '\0';
- printf(displayflags);
+ buf << displayflags;
if(en_flags != 0)
{
- printf("[ERROR: Entry has additional flags set] ");
+ buf << "[ERROR: Entry has additional flags set] ";
}
}
if(opts[LIST_OPTION_TIMES_UTC])
{
// Show UTC times...
- printf("%s ", GetTimeString(*en, false,
- opts[LIST_OPTION_TIMES_ATTRIBS]).c_str());
+ buf << GetTimeString(*en, false,
+ opts[LIST_OPTION_TIMES_ATTRIBS]) << " ";
}
if(opts[LIST_OPTION_TIMES_LOCAL])
{
// Show local times...
- printf("%s ", GetTimeString(*en, true,
- opts[LIST_OPTION_TIMES_ATTRIBS]).c_str());
+ buf << GetTimeString(*en, true,
+ opts[LIST_OPTION_TIMES_ATTRIBS]) << " ";
}
if(opts[LIST_OPTION_DISPLAY_HASH])
{
-#ifdef _MSC_VER
- printf("%016I64x ", (int64_t)en->GetAttributesHash());
-#else
- printf("%016llx ", (long long)en->GetAttributesHash());
-#endif
+ buf << std::hex << std::internal << std::setw(16) <<
+ std::setfill('0') << en->GetAttributesHash() <<
+ std::dec;
}
if(opts[LIST_OPTION_SIZEINBLOCKS])
{
-#ifdef _MSC_VER
- printf("%05I64d ", (int64_t)en->GetSizeInBlocks());
-#else
- printf("%05lld ", (long long)en->GetSizeInBlocks());
-#endif
+ buf << std::internal << std::setw(5) <<
+ std::setfill('0') << en->GetSizeInBlocks() <<
+ " ";
}
// add name
@@ -618,30 +483,60 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
std::string listRootDecoded;
if(!ConvertUtf8ToConsole(rListRoot.c_str(),
listRootDecoded)) return;
- printf("%s/", listRootDecoded.c_str());
+ listRootDecoded += "/";
+ buf << listRootDecoded;
+ WriteConsole(hOut, listRootDecoded.c_str(),
+ strlen(listRootDecoded.c_str()), &n_chars, NULL);
#else
- printf("%s/", rListRoot.c_str());
+ buf << rListRoot << "/";
#endif
}
+ std::string fileName;
+ try
+ {
+ fileName = clear.GetClearFilename();
+ }
+ catch(CipherException &e)
+ {
+ fileName = "<decrypt failed>";
+ }
+
#ifdef WIN32
+ std::string fileNameUtf8 = fileName;
+ if(!ConvertUtf8ToConsole(fileNameUtf8, fileName))
{
- std::string fileName;
- if(!ConvertUtf8ToConsole(
- clear.GetClearFilename().c_str(), fileName))
- return;
- printf("%s", fileName.c_str());
+ fileName = fileNameUtf8 + " [convert encoding failed]";
}
-#else
- printf("%s", clear.GetClearFilename().c_str());
#endif
-
+
+ buf << fileName;
+
if(!en->GetName().IsEncrypted())
{
- printf("[FILENAME NOT ENCRYPTED]");
+ buf << " [FILENAME NOT ENCRYPTED]";
}
- printf("\n");
+ buf << std::endl;
+
+ if(pOut)
+ {
+ (*pOut) << buf.str();
+ }
+ else
+ {
+#ifdef WIN32
+ std::string line = buf.str();
+ if (!WriteConsole(hOut, line.c_str(), line.size(),
+ &n_chars, NULL))
+ {
+ // WriteConsole failed, try standard method
+ std::cout << buf.str();
+ }
+#else
+ std::cout << buf.str();
+#endif
+ }
// Directory?
if((en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) != 0)
@@ -652,7 +547,9 @@ void BackupQueries::List(int64_t DirID, const std::string &rListRoot, const bool
std::string subroot(rListRoot);
if(!FirstLevel) subroot += '/';
subroot += clear.GetClearFilename();
- List(en->GetObjectID(), subroot, opts, false /* not the first level to list */);
+ List(en->GetObjectID(), subroot, opts,
+ false /* not the first level to list */,
+ pOut);
}
}
}
@@ -681,7 +578,7 @@ int64_t BackupQueries::FindDirectoryObjectID(const std::string &rDirName,
// Start from current stack, or root, whichever is required
std::vector<std::pair<std::string, int64_t> > stack;
- int64_t dirID = BackupProtocolClientListDirectory::RootDirectory;
+ int64_t dirID = BackupProtocolListDirectory::RootDirectory;
if(rDirName.size() > 0 && rDirName[0] == '/')
{
// Root, do nothing
@@ -697,9 +594,9 @@ int64_t BackupQueries::FindDirectoryObjectID(const std::string &rDirName,
}
// Generate exclude flags
- int16_t excludeFlags = BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING;
- if(!AllowOldVersion) excludeFlags |= BackupProtocolClientListDirectory::Flags_OldVersion;
- if(!AllowDeletedDirs) excludeFlags |= BackupProtocolClientListDirectory::Flags_Deleted;
+ int16_t excludeFlags = BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING;
+ if(!AllowOldVersion) excludeFlags |= BackupProtocolListDirectory::Flags_OldVersion;
+ if(!AllowDeletedDirs) excludeFlags |= BackupProtocolListDirectory::Flags_Deleted;
// Read directories
for(unsigned int e = 0; e < dirElements.size(); ++e)
@@ -719,20 +616,20 @@ int64_t BackupQueries::FindDirectoryObjectID(const std::string &rDirName,
stack.pop_back();
// New dir ID
- dirID = (stack.size() > 0)?(stack[stack.size() - 1].second):BackupProtocolClientListDirectory::RootDirectory;
+ dirID = (stack.size() > 0)?(stack[stack.size() - 1].second):BackupProtocolListDirectory::RootDirectory;
}
else
{
// At root anyway
- dirID = BackupProtocolClientListDirectory::RootDirectory;
+ dirID = BackupProtocolListDirectory::RootDirectory;
}
}
else
{
// Not blank element. Read current directory.
- std::auto_ptr<BackupProtocolClientSuccess> dirreply(mrConnection.QueryListDirectory(
+ std::auto_ptr<BackupProtocolSuccess> dirreply(mrConnection.QueryListDirectory(
dirID,
- BackupProtocolClientListDirectory::Flags_Dir, // just directories
+ BackupProtocolListDirectory::Flags_Dir, // just directories
excludeFlags,
true /* want attributes */));
@@ -783,7 +680,7 @@ int64_t BackupQueries::GetCurrentDirectoryID()
// Special case for root
if(mDirStack.size() == 0)
{
- return BackupProtocolClientListDirectory::RootDirectory;
+ return BackupProtocolListDirectory::RootDirectory;
}
// Otherwise, get from the last entry on the stack
@@ -955,7 +852,8 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
int64_t id = ::strtoll(args[0].c_str(), 0, 16);
if(id == std::numeric_limits<long long>::min() || id == std::numeric_limits<long long>::max() || id == 0)
{
- BOX_ERROR("Not a valid object ID (specified in hex).");
+ BOX_ERROR("Not a valid object ID (specified in hex): " <<
+ args[0]);
return;
}
@@ -974,8 +872,8 @@ void BackupQueries::CommandGetObject(const std::vector<std::string> &args, const
try
{
// Request object
- std::auto_ptr<BackupProtocolClientSuccess> getobj(mrConnection.QueryGetObject(id));
- if(getobj->GetObjectID() != BackupProtocolClientGetObject::NoObject)
+ std::auto_ptr<BackupProtocolSuccess> getobj(mrConnection.QueryGetObject(id));
+ if(getobj->GetObjectID() != BackupProtocolGetObject::NoObject)
{
// Stream that object out to the file
std::auto_ptr<IOStream> objectStream(mrConnection.ReceiveStream());
@@ -1062,7 +960,8 @@ int64_t BackupQueries::FindFileID(const std::string& rNameOrIdString,
fileId == std::numeric_limits<long long>::max() ||
fileId == 0)
{
- BOX_ERROR("Not a valid object ID (specified in hex).");
+ BOX_ERROR("Not a valid object ID (specified in hex): "
+ << rNameOrIdString);
return 0;
}
@@ -1154,19 +1053,19 @@ void BackupQueries::CommandGet(std::vector<std::string> args, const bool *opts)
if(opts['i'])
{
// can retrieve anything by ID
- flagsExclude = BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING;
+ flagsExclude = BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING;
}
else
{
// only current versions by name
flagsExclude =
- BackupProtocolClientListDirectory::Flags_OldVersion |
- BackupProtocolClientListDirectory::Flags_Deleted;
+ BackupProtocolListDirectory::Flags_OldVersion |
+ BackupProtocolListDirectory::Flags_Deleted;
}
fileId = FindFileID(args[0], opts, &dirId, &localName,
- BackupProtocolClientListDirectory::Flags_File, // just files
+ BackupProtocolListDirectory::Flags_File, // just files
flagsExclude, NULL /* don't care about flags found */);
if (fileId == 0)
@@ -1469,6 +1368,159 @@ void BackupQueries::Compare(const std::string &rStoreDir,
Compare(dirID, storeDirEncoded, localDirEncoded, rParams);
}
+void BackupQueries::CompareOneFile(int64_t DirID,
+ BackupStoreDirectory::Entry *pEntry,
+ const std::string& rLocalPath,
+ const std::string& rStorePath,
+ BoxBackupCompareParams &rParams)
+{
+ int64_t fileId = pEntry->GetObjectID();
+ int64_t fileSize = 0;
+
+ EMU_STRUCT_STAT st;
+ if(EMU_STAT(rLocalPath.c_str(), &st) == 0)
+ {
+ fileSize = st.st_size;
+ }
+
+ try
+ {
+ // Files the same flag?
+ bool equal = true;
+
+ // File modified after last sync flag
+ bool modifiedAfterLastSync = false;
+
+ bool hasDifferentAttribs = false;
+
+ bool alreadyReported = false;
+
+ if(rParams.QuickCompare())
+ {
+ // Compare file -- fetch it
+ mrConnection.QueryGetBlockIndexByID(fileId);
+
+ // Stream containing block index
+ std::auto_ptr<IOStream> blockIndexStream(mrConnection.ReceiveStream());
+
+ // Compare
+ equal = BackupStoreFile::CompareFileContentsAgainstBlockIndex(
+ rLocalPath.c_str(), *blockIndexStream,
+ mrConnection.GetTimeout());
+ }
+ else
+ {
+ // Compare file -- fetch it
+ mrConnection.QueryGetFile(DirID, pEntry->GetObjectID());
+
+ // Stream containing encoded file
+ std::auto_ptr<IOStream> objectStream(mrConnection.ReceiveStream());
+
+ // Decode it
+ std::auto_ptr<BackupStoreFile::DecodedStream> fileOnServerStream;
+
+ // Got additional attributes?
+ if(pEntry->HasAttributes())
+ {
+ // Use these attributes
+ const StreamableMemBlock &storeAttr(pEntry->GetAttributes());
+ BackupClientFileAttributes attr(storeAttr);
+ fileOnServerStream.reset(
+ BackupStoreFile::DecodeFileStream(
+ *objectStream,
+ mrConnection.GetTimeout(),
+ &attr).release());
+ }
+ else
+ {
+ // Use attributes stored in file
+ fileOnServerStream.reset(BackupStoreFile::DecodeFileStream(*objectStream, mrConnection.GetTimeout()).release());
+ }
+
+ // Should always be something in the auto_ptr, it's how the interface is defined. But be paranoid.
+ if(!fileOnServerStream.get())
+ {
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ // Compare attributes
+ BackupClientFileAttributes localAttr;
+ box_time_t fileModTime = 0;
+ localAttr.ReadAttributes(rLocalPath.c_str(), false /* don't zero mod times */, &fileModTime);
+ modifiedAfterLastSync = (fileModTime > rParams.LatestFileUploadTime());
+ bool ignoreAttrModTime = true;
+
+ #ifdef WIN32
+ // attr mod time is really
+ // creation time, so check it
+ ignoreAttrModTime = false;
+ #endif
+
+ if(!rParams.IgnoreAttributes() &&
+ #ifdef PLATFORM_DISABLE_SYMLINK_ATTRIB_COMPARE
+ !fileOnServerStream->IsSymLink() &&
+ #endif
+ !localAttr.Compare(fileOnServerStream->GetAttributes(),
+ ignoreAttrModTime,
+ fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */))
+ {
+ 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
+ std::auto_ptr<FileStream> apLocalFile;
+
+ try
+ {
+ apLocalFile.reset(new FileStream(rLocalPath.c_str()));
+ }
+ catch(std::exception &e)
+ {
+ rParams.NotifyLocalFileReadFailed(rLocalPath,
+ rStorePath, fileSize, e);
+ alreadyReported = true;
+ }
+ catch(...)
+ {
+ rParams.NotifyLocalFileReadFailed(rLocalPath,
+ rStorePath, fileSize);
+ alreadyReported = true;
+ }
+
+ if(apLocalFile.get())
+ {
+ equal = apLocalFile->CompareWith(*fileOnServerStream,
+ mrConnection.GetTimeout());
+ }
+ }
+ }
+
+ rParams.NotifyFileCompared(rLocalPath, rStorePath, fileSize,
+ hasDifferentAttribs, !equal, modifiedAfterLastSync,
+ pEntry->HasAttributes());
+ }
+ catch(BoxException &e)
+ {
+ rParams.NotifyDownloadFailed(rLocalPath, rStorePath, fileSize,
+ e);
+ }
+ catch(std::exception &e)
+ {
+ rParams.NotifyDownloadFailed(rLocalPath, rStorePath, fileSize,
+ e);
+ }
+ catch(...)
+ {
+ rParams.NotifyDownloadFailed(rLocalPath, rStorePath, fileSize);
+ }
+}
// --------------------------------------------------------------------------
//
@@ -1503,10 +1555,10 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir,
// Get the directory listing from the store
mrConnection.QueryListDirectory(
DirID,
- BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
// get everything
- BackupProtocolClientListDirectory::Flags_OldVersion |
- BackupProtocolClientListDirectory::Flags_Deleted,
+ BackupProtocolListDirectory::Flags_OldVersion |
+ BackupProtocolListDirectory::Flags_Deleted,
// except for old versions and deleted files
true /* want attributes */);
@@ -1700,124 +1752,8 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir,
}
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?
- bool equal = true;
-
- // File modified after last sync flag
- bool modifiedAfterLastSync = false;
-
- bool hasDifferentAttribs = false;
-
- if(rParams.QuickCompare())
- {
- // Compare file -- fetch it
- mrConnection.QueryGetBlockIndexByID(i->second->GetObjectID());
-
- // Stream containing block index
- std::auto_ptr<IOStream> blockIndexStream(mrConnection.ReceiveStream());
-
- // Compare
- equal = BackupStoreFile::CompareFileContentsAgainstBlockIndex(localPath.c_str(), *blockIndexStream, mrConnection.GetTimeout());
- }
- else
- {
- // Compare file -- fetch it
- mrConnection.QueryGetFile(DirID, i->second->GetObjectID());
-
- // Stream containing encoded file
- std::auto_ptr<IOStream> objectStream(mrConnection.ReceiveStream());
-
- // Decode it
- std::auto_ptr<BackupStoreFile::DecodedStream> fileOnServerStream;
- // Got additional attributes?
- if(i->second->HasAttributes())
- {
- // Use these attributes
- const StreamableMemBlock &storeAttr(i->second->GetAttributes());
- BackupClientFileAttributes attr(storeAttr);
- fileOnServerStream.reset(BackupStoreFile::DecodeFileStream(*objectStream, mrConnection.GetTimeout(), &attr).release());
- }
- else
- {
- // Use attributes stored in file
- fileOnServerStream.reset(BackupStoreFile::DecodeFileStream(*objectStream, mrConnection.GetTimeout()).release());
- }
-
- // Should always be something in the auto_ptr, it's how the interface is defined. But be paranoid.
- if(!fileOnServerStream.get())
- {
- THROW_EXCEPTION(BackupStoreException, Internal)
- }
-
- // Compare attributes
- BackupClientFileAttributes localAttr;
- box_time_t fileModTime = 0;
- localAttr.ReadAttributes(localPath.c_str(), false /* don't zero mod times */, &fileModTime);
- modifiedAfterLastSync = (fileModTime > rParams.LatestFileUploadTime());
- bool ignoreAttrModTime = true;
-
- #ifdef WIN32
- // attr mod time is really
- // creation time, so check it
- ignoreAttrModTime = false;
- #endif
-
- if(!rParams.IgnoreAttributes() &&
- #ifdef PLATFORM_DISABLE_SYMLINK_ATTRIB_COMPARE
- !fileOnServerStream->IsSymLink() &&
- #endif
- !localAttr.Compare(fileOnServerStream->GetAttributes(),
- ignoreAttrModTime,
- fileOnServerStream->IsSymLink() /* ignore modification time if it's a symlink */))
- {
- 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());
- equal = l.CompareWith(*fileOnServerStream,
- mrConnection.GetTimeout());
- }
- }
-
- rParams.NotifyFileCompared(localPath,
- storePath, fileSize,
- hasDifferentAttribs, !equal,
- modifiedAfterLastSync,
- i->second->HasAttributes());
- }
- catch(BoxException &e)
- {
- rParams.NotifyDownloadFailed(localPath,
- storePath, fileSize, e);
- }
- catch(std::exception &e)
- {
- rParams.NotifyDownloadFailed(localPath,
- storePath, fileSize, e);
- }
- catch(...)
- {
- rParams.NotifyDownloadFailed(localPath,
- storePath, fileSize);
- }
+ CompareOneFile(DirID, i->second, localPath,
+ storePath, rParams);
// Remove from set so that we know it's been compared
localFiles.erase(local);
@@ -1947,9 +1883,10 @@ void BackupQueries::Compare(int64_t DirID, const std::string &rStoreDir,
void BackupQueries::CommandRestore(const std::vector<std::string> &args, const bool *opts)
{
// Check arguments
- if(args.size() != 2)
+ if(args.size() < 1 || args.size() > 2)
{
- BOX_ERROR("Incorrect usage. restore [-drif] <remote-name> <local-name>");
+ BOX_ERROR("Incorrect usage. restore [-drif] <remote-name> "
+ "[<local-name>]");
return;
}
@@ -1966,7 +1903,8 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
dirID = ::strtoll(args[0].c_str(), 0, 16);
if(dirID == std::numeric_limits<long long>::min() || dirID == std::numeric_limits<long long>::max() || dirID == 0)
{
- BOX_ERROR("Not a valid object ID (specified in hex)");
+ BOX_ERROR("Not a valid object ID (specified in hex): "
+ << args[0]);
return;
}
std::ostringstream oss;
@@ -1994,18 +1932,30 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
BOX_ERROR("Directory '" << args[0] << "' not found on server");
return;
}
- if(dirID == BackupProtocolClientListDirectory::RootDirectory)
+
+ if(dirID == BackupProtocolListDirectory::RootDirectory)
{
BOX_ERROR("Cannot restore the root directory -- restore locations individually.");
return;
}
-
-#ifdef WIN32
+
std::string localName;
- if(!ConvertConsoleToUtf8(args[1].c_str(), localName)) return;
-#else
- std::string localName(args[1]);
-#endif
+
+ if(args.size() == 2)
+ {
+ #ifdef WIN32
+ if(!ConvertConsoleToUtf8(args[1].c_str(), localName))
+ {
+ return;
+ }
+ #else
+ localName = args[1];
+ #endif
+ }
+ else
+ {
+ localName = args[0];
+ }
// Go and restore...
int result;
@@ -2082,8 +2032,8 @@ void BackupQueries::CommandRestore(const std::vector<std::string> &args, const b
// These are autogenerated by a script.
-extern char *help_commands[];
-extern char *help_text[];
+extern const char *help_commands[];
+extern const char *help_text[];
// --------------------------------------------------------------------------
@@ -2140,7 +2090,7 @@ void BackupQueries::CommandUsage(const bool *opts)
bool MachineReadable = opts['m'];
// Request full details from the server
- std::auto_ptr<BackupProtocolClientAccountUsage> usage(mrConnection.QueryGetAccountUsage());
+ std::auto_ptr<BackupProtocolAccountUsage> usage(mrConnection.QueryGetAccountUsage());
// Display each entry in turn
int64_t hardLimit = usage->GetBlocksHardLimit();
@@ -2216,9 +2166,9 @@ void BackupQueries::CommandUndelete(const std::vector<std::string> &args, const
fileId = FindFileID(storeDirEncoded, opts, &parentId, &fileName,
/* include files and directories */
- BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
/* include old and deleted files */
- BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
&flagsOut);
if (fileId == 0)
@@ -2231,7 +2181,7 @@ void BackupQueries::CommandUndelete(const std::vector<std::string> &args, const
try
{
// Undelete object
- if(flagsOut & BackupProtocolClientListDirectory::Flags_File)
+ if(flagsOut & BackupProtocolListDirectory::Flags_File)
{
mrConnection.QueryUndeleteFile(parentId, fileId);
}
@@ -2296,10 +2246,10 @@ void BackupQueries::CommandDelete(const std::vector<std::string> &args,
fileId = FindFileID(storeDirEncoded, opts, &parentId, &fileName,
/* include files and directories */
- BackupProtocolClientListDirectory::Flags_EXCLUDE_NOTHING,
+ BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING,
/* exclude old and deleted files */
- BackupProtocolClientListDirectory::Flags_OldVersion |
- BackupProtocolClientListDirectory::Flags_Deleted,
+ BackupProtocolListDirectory::Flags_OldVersion |
+ BackupProtocolListDirectory::Flags_Deleted,
&flagsOut);
if (fileId == 0)
@@ -2314,7 +2264,7 @@ void BackupQueries::CommandDelete(const std::vector<std::string> &args,
try
{
// Delete object
- if(flagsOut & BackupProtocolClientListDirectory::Flags_File)
+ if(flagsOut & BackupProtocolListDirectory::Flags_File)
{
mrConnection.QueryDeleteFile(parentId, fn);
}