diff options
Diffstat (limited to 'lib/backupclient/BackupClientFileAttributes.cpp')
-rw-r--r-- | lib/backupclient/BackupClientFileAttributes.cpp | 1188 |
1 files changed, 0 insertions, 1188 deletions
diff --git a/lib/backupclient/BackupClientFileAttributes.cpp b/lib/backupclient/BackupClientFileAttributes.cpp deleted file mode 100644 index 0d7df4d7..00000000 --- a/lib/backupclient/BackupClientFileAttributes.cpp +++ /dev/null @@ -1,1188 +0,0 @@ -// -------------------------------------------------------------------------- -// -// File -// Name: BackupClientFileAttributes.cpp -// Purpose: Storage of file attributes -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- - -#include "Box.h" - -#ifdef HAVE_UNISTD_H - #include <unistd.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <limits.h> - -#include <algorithm> -#include <cstring> -#include <new> -#include <vector> - -#ifdef HAVE_SYS_XATTR_H -#include <cerrno> -#include <sys/xattr.h> -#endif - -#include <cstring> - -#include "BackupClientFileAttributes.h" -#include "CommonException.h" -#include "FileModificationTime.h" -#include "BoxTimeToUnix.h" -#include "BackupStoreException.h" -#include "CipherContext.h" -#include "CipherBlowfish.h" -#include "MD5Digest.h" - -#include "MemLeakFindOn.h" - -// set packing to one byte -#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS -#include "BeginStructPackForWire.h" -#else -BEGIN_STRUCTURE_PACKING_FOR_WIRE -#endif - -#define ATTRIBUTETYPE_GENERIC_UNIX 1 - -#define ATTRIBUTE_ENCODING_BLOWFISH 2 - -typedef struct -{ - int32_t AttributeType; - u_int32_t UID; - u_int32_t GID; - u_int64_t ModificationTime; - u_int64_t AttrModificationTime; - u_int32_t UserDefinedFlags; - u_int32_t FileGenerationNumber; - u_int16_t Mode; - // Symbolic link filename may follow - // Extended attribute (xattr) information may follow, format is: - // u_int32_t Size of extended attribute block (excluding this word) - // For each of NumberOfAttributes (sorted by AttributeName): - // u_int16_t AttributeNameLength - // char AttributeName[AttributeNameLength] - // u_int32_t AttributeValueLength - // unsigned char AttributeValue[AttributeValueLength] - // AttributeName is 0 terminated, AttributeValue is not (and may be binary data) -} attr_StreamFormat; - -// This has wire packing so it's compatible across platforms -// Use wider than necessary sizes, just to be careful. -typedef struct -{ - int32_t uid, gid, mode; - #ifdef WIN32 - int64_t fileCreationTime; - #endif -} attributeHashData; - -// Use default packing -#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS -#include "EndStructPackForWire.h" -#else -END_STRUCTURE_PACKING_FOR_WIRE -#endif - - -#define MAX_ATTRIBUTE_HASH_SECRET_LENGTH 256 - -// Hide private static variables from the rest of the world -// -- don't put them as static class variables to avoid openssl/evp.h being -// included all over the project. -namespace -{ - CipherContext sBlowfishEncrypt; - CipherContext sBlowfishDecrypt; - uint8_t sAttributeHashSecret[MAX_ATTRIBUTE_HASH_SECRET_LENGTH]; - int sAttributeHashSecretLength = 0; -} - - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::BackupClientFileAttributes() -// Purpose: Default constructor -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -BackupClientFileAttributes::BackupClientFileAttributes() - : mpClearAttributes(0) -{ - ASSERT(sizeof(u_int64_t) == sizeof(box_time_t)); -} - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::BackupClientFileAttributes(const BackupClientFileAttributes &) -// Purpose: Copy constructor -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -BackupClientFileAttributes::BackupClientFileAttributes(const BackupClientFileAttributes &rToCopy) - : StreamableMemBlock(rToCopy), // base class does the hard work - mpClearAttributes(0) -{ -} -BackupClientFileAttributes::BackupClientFileAttributes(const StreamableMemBlock &rToCopy) - : StreamableMemBlock(rToCopy), // base class does the hard work - mpClearAttributes(0) -{ -} - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::~BackupClientFileAttributes() -// Purpose: Destructor -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -BackupClientFileAttributes::~BackupClientFileAttributes() -{ - if(mpClearAttributes) - { - delete mpClearAttributes; - mpClearAttributes = 0; - } -} - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes &operator=(const BackupClientFileAttributes &) -// Purpose: Assignment operator -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -BackupClientFileAttributes &BackupClientFileAttributes::operator=(const BackupClientFileAttributes &rAttr) -{ - StreamableMemBlock::Set(rAttr); - RemoveClear(); // make sure no decrypted version held - return *this; -} -// Assume users play nice -BackupClientFileAttributes &BackupClientFileAttributes::operator=(const StreamableMemBlock &rAttr) -{ - StreamableMemBlock::Set(rAttr); - RemoveClear(); // make sure no decrypted version held - return *this; -} - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::operator==(const BackupClientFileAttributes &) -// Purpose: Comparison operator -// Created: 2003/10/09 -// -// -------------------------------------------------------------------------- -bool BackupClientFileAttributes::operator==(const BackupClientFileAttributes &rAttr) const -{ - EnsureClearAvailable(); - rAttr.EnsureClearAvailable(); - - return mpClearAttributes->operator==(*rAttr.mpClearAttributes); -} -// Too dangerous to allow -- put the two names the wrong way round, and it compares encrypted data. -/*bool BackupClientFileAttributes::operator==(const StreamableMemBlock &rAttr) const -{ - StreamableMemBlock *pDecoded = 0; - - try - { - EnsureClearAvailable(); - StreamableMemBlock *pDecoded = MakeClear(rAttr); - - // Compare using clear version - bool compared = mpClearAttributes->operator==(rAttr); - - // Delete temporary - delete pDecoded; - - return compared; - } - catch(...) - { - delete pDecoded; - throw; - } -}*/ - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::Compare(const BackupClientFileAttributes &, bool) -// Purpose: Compare, optionally ignoring the attribute -// modification time and/or modification time, and some -// data which is irrelevant in practise (eg file -// generation number) -// Created: 10/12/03 -// -// -------------------------------------------------------------------------- -bool BackupClientFileAttributes::Compare(const BackupClientFileAttributes &rAttr, - bool IgnoreAttrModTime, bool IgnoreModTime) const -{ - EnsureClearAvailable(); - rAttr.EnsureClearAvailable(); - - // Check sizes are the same, as a first check - if(mpClearAttributes->GetSize() != rAttr.mpClearAttributes->GetSize()) - { - BOX_TRACE("Attribute Compare: Attributes objects are " - "different sizes, cannot compare them: local " << - mpClearAttributes->GetSize() << " bytes, remote " << - rAttr.mpClearAttributes->GetSize() << " bytes"); - return false; - } - - // Then check the elements of the two things - // Bytes are checked in network order, but this doesn't matter as we're only checking for equality. - attr_StreamFormat *a1 = (attr_StreamFormat*)mpClearAttributes->GetBuffer(); - attr_StreamFormat *a2 = (attr_StreamFormat*)rAttr.mpClearAttributes->GetBuffer(); - - #define COMPARE(attribute, message) \ - if (a1->attribute != a2->attribute) \ - { \ - BOX_TRACE("Attribute Compare: " << message << " differ: " \ - "local " << ntoh(a1->attribute) << ", " \ - "remote " << ntoh(a2->attribute)); \ - return false; \ - } - COMPARE(AttributeType, "Attribute types"); - COMPARE(UID, "UIDs"); - COMPARE(GID, "GIDs"); - COMPARE(UserDefinedFlags, "User-defined flags"); - COMPARE(Mode, "Modes"); - - if(!IgnoreModTime) - { - uint64_t t1 = box_ntoh64(a1->ModificationTime); - uint64_t t2 = box_ntoh64(a2->ModificationTime); - time_t s1 = BoxTimeToSeconds(t1); - time_t s2 = BoxTimeToSeconds(t2); - if(s1 != s2) - { - BOX_TRACE("Attribute Compare: File modification " - "times differ: local " << - FormatTime(t1, true) << " (" << s1 << "), " - "remote " << - FormatTime(t2, true) << " (" << s2 << ")"); - return false; - } - } - - if(!IgnoreAttrModTime) - { - uint64_t t1 = box_ntoh64(a1->AttrModificationTime); - uint64_t t2 = box_ntoh64(a2->AttrModificationTime); - time_t s1 = BoxTimeToSeconds(t1); - time_t s2 = BoxTimeToSeconds(t2); - if(s1 != s2) - { - BOX_TRACE("Attribute Compare: Attribute modification " - "times differ: local " << - FormatTime(t1, true) << " (" << s1 << "), " - "remote " << - FormatTime(t2, true) << " (" << s2 << ")"); - return false; - } - } - - // Check symlink string? - unsigned int size = mpClearAttributes->GetSize(); - if(size > sizeof(attr_StreamFormat)) - { - // Symlink strings don't match. This also compares xattrs - int datalen = size - sizeof(attr_StreamFormat); - - if(::memcmp(a1 + 1, a2 + 1, datalen) != 0) - { - std::string s1((char *)(a1 + 1), datalen); - std::string s2((char *)(a2 + 1), datalen); - BOX_TRACE("Attribute Compare: Symbolic link target " - "or extended attributes differ: " - "local " << PrintEscapedBinaryData(s1) << ", " - "remote " << PrintEscapedBinaryData(s2)); - return false; - } - } - - // Passes all test, must be OK - return true; -} - - - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::ReadAttributes( -// const char *Filename, bool ZeroModificationTimes, -// box_time_t *pModTime, box_time_t *pAttrModTime, -// int64_t *pFileSize, InodeRefType *pInodeNumber, -// bool *pHasMultipleLinks) -// Purpose: Read the attributes of the file, and store them -// ready for streaming. Optionally retrieve the -// modification time and attribute modification time. -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::ReadAttributes(const char *Filename, - bool ZeroModificationTimes, box_time_t *pModTime, - box_time_t *pAttrModTime, int64_t *pFileSize, - InodeRefType *pInodeNumber, bool *pHasMultipleLinks) -{ - StreamableMemBlock *pnewAttr = 0; - try - { - EMU_STRUCT_STAT st; - if(EMU_LSTAT(Filename, &st) != 0) - { - BOX_LOG_SYS_ERROR("Failed to stat file: '" << - Filename << "'"); - THROW_EXCEPTION(CommonException, OSFileError) - } - - // Modification times etc - if(pModTime) {*pModTime = FileModificationTime(st);} - if(pAttrModTime) {*pAttrModTime = FileAttrModificationTime(st);} - if(pFileSize) {*pFileSize = st.st_size;} - if(pInodeNumber) {*pInodeNumber = st.st_ino;} - if(pHasMultipleLinks) {*pHasMultipleLinks = (st.st_nlink > 1);} - - pnewAttr = new StreamableMemBlock; - - FillAttributes(*pnewAttr, Filename, st, ZeroModificationTimes); - -#ifndef WIN32 - // Is it a link? - if((st.st_mode & S_IFMT) == S_IFLNK) - { - FillAttributesLink(*pnewAttr, Filename, st); - } -#endif - - FillExtendedAttr(*pnewAttr, Filename); - -#ifdef WIN32 - //this is to catch those problems with invalid time stamps stored... - //need to find out the reason why - but also a catch as well. - - attr_StreamFormat *pattr = - (attr_StreamFormat*)pnewAttr->GetBuffer(); - ASSERT(pattr != 0); - - // __time64_t winTime = BoxTimeToSeconds( - // pnewAttr->ModificationTime); - - u_int64_t modTime = box_ntoh64(pattr->ModificationTime); - box_time_t modSecs = BoxTimeToSeconds(modTime); - __time64_t winTime = modSecs; - - // _MAX__TIME64_T doesn't seem to be defined, but the code below - // will throw an assertion failure if we exceed it :-) - // Microsoft says dates up to the year 3000 are valid, which - // is a bit more than 15 * 2^32. Even that doesn't seem - // to be true (still aborts), but it can at least hold 2^32. - if (winTime >= 0x100000000LL || _gmtime64(&winTime) == 0) - { - BOX_ERROR("Invalid Modification Time caught for " - "file: '" << Filename << "'"); - pattr->ModificationTime = 0; - } - - modTime = box_ntoh64(pattr->AttrModificationTime); - modSecs = BoxTimeToSeconds(modTime); - winTime = modSecs; - - if (winTime > 0x100000000LL || _gmtime64(&winTime) == 0) - { - BOX_ERROR("Invalid Attribute Modification Time " - "caught for file: '" << Filename << "'"); - pattr->AttrModificationTime = 0; - } -#endif - - // Attributes ready. Encrypt into this block - EncryptAttr(*pnewAttr); - - // Store the new attributes - RemoveClear(); - mpClearAttributes = pnewAttr; - pnewAttr = 0; - } - catch(...) - { - // clean up - delete pnewAttr; - pnewAttr = 0; - throw; - } -} - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::ReadAttributesLink() -// Purpose: Private function, handles standard attributes for all objects -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::FillAttributes(StreamableMemBlock &outputBlock, const char *Filename, EMU_STRUCT_STAT &st, bool ZeroModificationTimes) -{ - outputBlock.ResizeBlock(sizeof(attr_StreamFormat)); - attr_StreamFormat *pattr = (attr_StreamFormat*)outputBlock.GetBuffer(); - ASSERT(pattr != 0); - - // Fill in the entries - pattr->AttributeType = htonl(ATTRIBUTETYPE_GENERIC_UNIX); - pattr->UID = htonl(st.st_uid); - pattr->GID = htonl(st.st_gid); - if(ZeroModificationTimes) - { - pattr->ModificationTime = 0; - pattr->AttrModificationTime = 0; - } - else - { - pattr->ModificationTime = box_hton64(FileModificationTime(st)); - pattr->AttrModificationTime = box_hton64(FileAttrModificationTime(st)); - } - pattr->Mode = htons(st.st_mode); - -#ifndef HAVE_STRUCT_STAT_ST_FLAGS - pattr->UserDefinedFlags = 0; - pattr->FileGenerationNumber = 0; -#else - pattr->UserDefinedFlags = htonl(st.st_flags); - pattr->FileGenerationNumber = htonl(st.st_gen); -#endif -} -#ifndef WIN32 -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::ReadAttributesLink() -// Purpose: Private function, handles the case where a symbolic link is needed -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::FillAttributesLink(StreamableMemBlock &outputBlock, const char *Filename, struct stat &st) -{ - // Make sure we're only called for symbolic links - ASSERT((st.st_mode & S_IFMT) == S_IFLNK); - - // Get the filename the link is linked to - char linkedTo[PATH_MAX+4]; - int linkedToSize = ::readlink(Filename, linkedTo, PATH_MAX); - if(linkedToSize == -1) - { - BOX_LOG_SYS_ERROR("Failed to readlink '" << Filename << "'"); - THROW_EXCEPTION(CommonException, OSFileError); - } - - int oldSize = outputBlock.GetSize(); - outputBlock.ResizeBlock(oldSize+linkedToSize+1); - char* buffer = static_cast<char*>(outputBlock.GetBuffer()); - - // Add the path name for the symbolic link, and add 0 termination - std::memcpy(buffer+oldSize, linkedTo, linkedToSize); - buffer[oldSize+linkedToSize] = '\0'; -} -#endif - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::ReadExtendedAttr(const char *, unsigned char**) -// Purpose: Private function, read the extended attributes of the file into the block -// Created: 2005/06/12 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::FillExtendedAttr(StreamableMemBlock &outputBlock, const char *Filename) -{ -#ifdef HAVE_SYS_XATTR_H - int listBufferSize = 10000; - char* list = new char[listBufferSize]; - - try - { - // This returns an unordered list of attribute names, each 0 terminated, - // concatenated together - int listSize = ::llistxattr(Filename, list, listBufferSize); - - if(listSize>listBufferSize) - { - delete[] list, list = NULL; - list = new char[listSize]; - listSize = ::llistxattr(Filename, list, listSize); - } - - if(listSize>0) - { - // Extract list of attribute names so we can sort them - std::vector<std::string> attrKeys; - for(int i = 0; i<listSize; ++i) - { - std::string attrKey(list+i); - i += attrKey.size(); - attrKeys.push_back(attrKey); - } - sort(attrKeys.begin(), attrKeys.end()); - - // Make initial space in block - int xattrSize = outputBlock.GetSize(); - int xattrBufferSize = (xattrSize+listSize)>500 ? (xattrSize+listSize)*2 : 1000; - outputBlock.ResizeBlock(xattrBufferSize); - unsigned char* buffer = static_cast<unsigned char*>(outputBlock.GetBuffer()); - - // Leave space for attr block size later - int xattrBlockSizeOffset = xattrSize; - xattrSize += sizeof(u_int32_t); - - // Loop for each attribute - for(std::vector<std::string>::const_iterator attrKeyI = attrKeys.begin(); attrKeyI!=attrKeys.end(); ++attrKeyI) - { - std::string attrKey(*attrKeyI); - - if(xattrSize+sizeof(u_int16_t)+attrKey.size()+1+sizeof(u_int32_t)>static_cast<unsigned int>(xattrBufferSize)) - { - xattrBufferSize = (xattrBufferSize+sizeof(u_int16_t)+attrKey.size()+1+sizeof(u_int32_t))*2; - outputBlock.ResizeBlock(xattrBufferSize); - buffer = static_cast<unsigned char*>(outputBlock.GetBuffer()); - } - - // Store length and text for attibute name - u_int16_t keyLength = htons(attrKey.size()+1); - std::memcpy(buffer+xattrSize, &keyLength, sizeof(u_int16_t)); - xattrSize += sizeof(u_int16_t); - std::memcpy(buffer+xattrSize, attrKey.c_str(), attrKey.size()+1); - xattrSize += attrKey.size()+1; - - // Leave space for value size - int valueSizeOffset = xattrSize; - xattrSize += sizeof(u_int32_t); - - // Find size of attribute (must call with buffer and length 0 on some platforms, - // as -1 is returned if the data doesn't fit.) - int valueSize = ::lgetxattr(Filename, attrKey.c_str(), 0, 0); - if(valueSize<0) - { - BOX_LOG_SYS_ERROR("Failed to get " - "extended attribute size of " - "'" << Filename << "': " << - attrKey); - THROW_EXCEPTION(CommonException, OSFileError); - } - - // Resize block, if needed - if(xattrSize+valueSize>xattrBufferSize) - { - xattrBufferSize = (xattrBufferSize+valueSize)*2; - outputBlock.ResizeBlock(xattrBufferSize); - buffer = static_cast<unsigned char*>(outputBlock.GetBuffer()); - } - - // This gets the attribute value (may be text or binary), no termination - valueSize = ::lgetxattr(Filename, attrKey.c_str(), buffer+xattrSize, xattrBufferSize-xattrSize); - if(valueSize<0) - { - BOX_LOG_SYS_ERROR("Failed to get " - "extended attribute of " - "'" << Filename << "': " << - attrKey); - THROW_EXCEPTION(CommonException, OSFileError); - } - xattrSize += valueSize; - - // Fill in value size - u_int32_t valueLength = htonl(valueSize); - std::memcpy(buffer+valueSizeOffset, &valueLength, sizeof(u_int32_t)); - } - - // Fill in attribute block size - u_int32_t xattrBlockLength = htonl(xattrSize-xattrBlockSizeOffset-sizeof(u_int32_t)); - std::memcpy(buffer+xattrBlockSizeOffset, &xattrBlockLength, sizeof(u_int32_t)); - - outputBlock.ResizeBlock(xattrSize); - } - else if(listSize<0) - { - if(errno == EOPNOTSUPP || errno == EACCES) - { - // fail silently - } - else if(errno == ERANGE) - { - BOX_ERROR("Failed to list extended " - "attributes of '" << Filename << "': " - "buffer too small, not backed up"); - } - else - { - BOX_LOG_SYS_ERROR("Failed to list extended " - "attributes of '" << Filename << "', " - "not backed up"); - THROW_EXCEPTION(CommonException, OSFileError); - } - } - } - catch(...) - { - delete[] list; - throw; - } - delete[] list; -#endif -} - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::GetModificationTimes() -// Purpose: Returns the modification time embedded in the -// attributes. -// Created: 2010/02/24 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::GetModificationTimes( - box_time_t *pModificationTime, - box_time_t *pAttrModificationTime) const -{ - // Got something loaded - if(GetSize() <= 0) - { - THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded); - } - - // Make sure there are clear attributes to use - EnsureClearAvailable(); - ASSERT(mpClearAttributes != 0); - - // Check if the decrypted attributes are small enough, and the type of attributes stored - if(mpClearAttributes->GetSize() < (int)sizeof(int32_t)) - { - THROW_EXCEPTION(BackupStoreException, AttributesNotUnderstood); - } - int32_t *type = (int32_t*)mpClearAttributes->GetBuffer(); - ASSERT(type != 0); - if(ntohl(*type) != ATTRIBUTETYPE_GENERIC_UNIX) - { - // Don't know what to do with these - THROW_EXCEPTION(BackupStoreException, AttributesNotUnderstood); - } - - // Check there is enough space for an attributes block - if(mpClearAttributes->GetSize() < (int)sizeof(attr_StreamFormat)) - { - // Too small - THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded); - } - - // Get pointer to structure - attr_StreamFormat *pattr = (attr_StreamFormat*)mpClearAttributes->GetBuffer(); - - if(pModificationTime) - { - *pModificationTime = box_ntoh64(pattr->ModificationTime); - } - - if(pAttrModificationTime) - { - *pAttrModificationTime = box_ntoh64(pattr->AttrModificationTime); - } -} - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::WriteAttributes(const char *) -// Purpose: Apply the stored attributes to the file -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::WriteAttributes(const char *Filename, - bool MakeUserWritable) const -{ - // Got something loaded - if(GetSize() <= 0) - { - THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded); - } - - // Make sure there are clear attributes to use - EnsureClearAvailable(); - ASSERT(mpClearAttributes != 0); - - // Check if the decrypted attributes are small enough, and the type of attributes stored - if(mpClearAttributes->GetSize() < (int)sizeof(int32_t)) - { - THROW_EXCEPTION(BackupStoreException, AttributesNotUnderstood); - } - int32_t *type = (int32_t*)mpClearAttributes->GetBuffer(); - ASSERT(type != 0); - if(ntohl(*type) != ATTRIBUTETYPE_GENERIC_UNIX) - { - // Don't know what to do with these - THROW_EXCEPTION(BackupStoreException, AttributesNotUnderstood); - } - - // Check there is enough space for an attributes block - if(mpClearAttributes->GetSize() < (int)sizeof(attr_StreamFormat)) - { - // Too small - THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded); - } - - // Get pointer to structure - attr_StreamFormat *pattr = (attr_StreamFormat*)mpClearAttributes->GetBuffer(); - int xattrOffset = sizeof(attr_StreamFormat); - - // is it a symlink? - int16_t mode = ntohs(pattr->Mode); - if((mode & S_IFMT) == S_IFLNK) - { - // Check things are sensible - if(mpClearAttributes->GetSize() < (int)sizeof(attr_StreamFormat) + 1) - { - // Too small - THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded); - } - -#ifdef WIN32 - BOX_WARNING("Cannot create symbolic links on Windows: '" << - Filename << "'"); -#else - // Make a symlink, first deleting anything in the way - ::unlink(Filename); - if(::symlink((char*)(pattr + 1), Filename) != 0) - { - BOX_LOG_SYS_ERROR("Failed to symlink '" << Filename << - "' to '" << (char*)(pattr + 1) << "'"); - THROW_EXCEPTION(CommonException, OSFileError) - } -#endif - - xattrOffset += std::strlen(reinterpret_cast<char*>(pattr+1))+1; - } - - // If working as root, set user IDs - if(::geteuid() == 0) - { - #ifndef HAVE_LCHOWN - // only if not a link, can't set their owner on this platform - if((mode & S_IFMT) != S_IFLNK) - { - // Not a link, use normal chown - if(::chown(Filename, ntohl(pattr->UID), ntohl(pattr->GID)) != 0) - { - BOX_LOG_SYS_ERROR("Failed to change " - "owner of file " - "'" << Filename << "'"); - THROW_EXCEPTION(CommonException, OSFileError) - } - } - #else - // use the version which sets things on symlinks - if(::lchown(Filename, ntohl(pattr->UID), ntohl(pattr->GID)) != 0) - { - BOX_LOG_SYS_ERROR("Failed to change owner of " - "symbolic link '" << Filename << "'"); - THROW_EXCEPTION(CommonException, OSFileError) - } - #endif - } - - if(static_cast<int>(xattrOffset+sizeof(u_int32_t))<=mpClearAttributes->GetSize()) - { - WriteExtendedAttr(Filename, xattrOffset); - } - - // Stop now if symlink, because otherwise it'll just be applied to the target - if((mode & S_IFMT) == S_IFLNK) - { - return; - } - - // Set modification time? - box_time_t modtime = box_ntoh64(pattr->ModificationTime); - if(modtime != 0) - { - // Work out times as timevals - struct timeval times[2]; - - #ifdef WIN32 - BoxTimeToTimeval(box_ntoh64(pattr->ModificationTime), - times[1]); - BoxTimeToTimeval(box_ntoh64(pattr->AttrModificationTime), - times[0]); - // Because stat() returns the creation time in the ctime - // field under Windows, and this gets saved in the - // AttrModificationTime field of the serialised attributes, - // we subvert the first parameter of emu_utimes() to allow - // it to be reset to the right value on the restored file. - #else - BoxTimeToTimeval(modtime, times[1]); - // Copy access time as well, why not, got to set it to something - times[0] = times[1]; - // Attr modification time will be changed anyway, - // nothing that can be done about it - #endif - - // Try to apply - if(::utimes(Filename, times) != 0) - { - BOX_LOG_SYS_WARNING("Failed to change times of " - "file '" << Filename << "' to ctime=" << - BOX_FORMAT_TIMESPEC(times[0]) << ", mtime=" << - BOX_FORMAT_TIMESPEC(times[1])); - } - } - - if (MakeUserWritable) - { - mode |= S_IRWXU; - } - - // Apply everything else... (allowable mode flags only) - // Mode must be done last (think setuid) - if(::chmod(Filename, mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID - | S_ISGID | S_ISVTX)) != 0) - { - BOX_LOG_SYS_ERROR("Failed to change permissions of file " - "'" << Filename << "'"); - THROW_EXCEPTION(CommonException, OSFileError) - } -} - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::IsSymLink() -// Purpose: Do these attributes represent a symbolic link? -// Created: 2003/10/07 -// -// -------------------------------------------------------------------------- -bool BackupClientFileAttributes::IsSymLink() const -{ - EnsureClearAvailable(); - - // Got the right kind of thing? - if(mpClearAttributes->GetSize() < (int)sizeof(int32_t)) - { - THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded); - } - - // Get the type of attributes stored - int32_t *type = (int32_t*)mpClearAttributes->GetBuffer(); - ASSERT(type != 0); - if(ntohl(*type) == ATTRIBUTETYPE_GENERIC_UNIX && mpClearAttributes->GetSize() > (int)sizeof(attr_StreamFormat)) - { - // Check link - attr_StreamFormat *pattr = (attr_StreamFormat*)mpClearAttributes->GetBuffer(); - return ((ntohs(pattr->Mode)) & S_IFMT) == S_IFLNK; - } - - return false; -} - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::RemoveClear() -// Purpose: Private. Deletes any clear version of the attributes that may be held -// Created: 3/12/03 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::RemoveClear() const -{ - if(mpClearAttributes) - { - delete mpClearAttributes; - } - mpClearAttributes = 0; -} - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::EnsureClearAvailable() -// Purpose: Private. Makes sure the clear version is available -// Created: 3/12/03 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::EnsureClearAvailable() const -{ - if(mpClearAttributes == 0) - { - mpClearAttributes = MakeClear(*this); - } -} - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::WriteExtendedAttr(const char *Filename, int xattrOffset) -// Purpose: Private function, apply the stored extended attributes to the file -// Created: 2005/06/13 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::WriteExtendedAttr(const char *Filename, int xattrOffset) const -{ -#ifdef HAVE_SYS_XATTR_H - const char* buffer = static_cast<char*>(mpClearAttributes->GetBuffer()); - - u_int32_t xattrBlockLength = 0; - std::memcpy(&xattrBlockLength, buffer+xattrOffset, sizeof(u_int32_t)); - int xattrBlockSize = ntohl(xattrBlockLength); - xattrOffset += sizeof(u_int32_t); - - int xattrEnd = xattrOffset+xattrBlockSize; - if(xattrEnd>mpClearAttributes->GetSize()) - { - // Too small - THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded); - } - - while(xattrOffset<xattrEnd) - { - u_int16_t keyLength = 0; - std::memcpy(&keyLength, buffer+xattrOffset, sizeof(u_int16_t)); - int keySize = ntohs(keyLength); - xattrOffset += sizeof(u_int16_t); - - const char* key = buffer+xattrOffset; - xattrOffset += keySize; - - u_int32_t valueLength = 0; - std::memcpy(&valueLength, buffer+xattrOffset, sizeof(u_int32_t)); - int valueSize = ntohl(valueLength); - xattrOffset += sizeof(u_int32_t); - - // FIXME: Warn on EOPNOTSUPP - if(::lsetxattr(Filename, key, buffer+xattrOffset, valueSize, 0)!=0 && errno!=EOPNOTSUPP) - { - BOX_LOG_SYS_ERROR("Failed to set extended attributes " - "on file '" << Filename << "'"); - THROW_EXCEPTION(CommonException, OSFileError); - } - - xattrOffset += valueSize; - } - - ASSERT(xattrOffset==xattrEnd); -#endif -} - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::MakeClear(const StreamableMemBlock &) -// Purpose: Static. Decrypts stored attributes. -// Created: 3/12/03 -// -// -------------------------------------------------------------------------- -StreamableMemBlock *BackupClientFileAttributes::MakeClear(const StreamableMemBlock &rEncrypted) -{ - // New block - StreamableMemBlock *pdecrypted = 0; - - try - { - // Check the block is big enough for IV and header - int ivSize = sBlowfishEncrypt.GetIVLength(); - if(rEncrypted.GetSize() <= (ivSize + 1)) - { - THROW_EXCEPTION(BackupStoreException, BadEncryptedAttributes); - } - - // How much space is needed for the output? - int maxDecryptedSize = sBlowfishDecrypt.MaxOutSizeForInBufferSize(rEncrypted.GetSize() - ivSize); - - // Allocate it - pdecrypted = new StreamableMemBlock(maxDecryptedSize); - - // ptr to block - uint8_t *encBlock = (uint8_t*)rEncrypted.GetBuffer(); - - // Check that the header has right type - if(encBlock[0] != ATTRIBUTE_ENCODING_BLOWFISH) - { - THROW_EXCEPTION(BackupStoreException, EncryptedAttributesHaveUnknownEncoding); - } - - // Set IV - sBlowfishDecrypt.SetIV(encBlock + 1); - - // Decrypt - int decryptedSize = sBlowfishDecrypt.TransformBlock(pdecrypted->GetBuffer(), maxDecryptedSize, encBlock + 1 + ivSize, rEncrypted.GetSize() - (ivSize + 1)); - - // Resize block to fit - pdecrypted->ResizeBlock(decryptedSize); - } - catch(...) - { - delete pdecrypted; - pdecrypted = 0; - } - - return pdecrypted; -} - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::SetBlowfishKey(const void *, int) -// Purpose: Static. Sets the key to use for encryption and decryption. -// Created: 3/12/03 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::SetBlowfishKey(const void *pKey, int KeyLength) -{ - // IVs set later - sBlowfishEncrypt.Reset(); - sBlowfishEncrypt.Init(CipherContext::Encrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength)); - sBlowfishDecrypt.Reset(); - sBlowfishDecrypt.Init(CipherContext::Decrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength)); -} - - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::EncryptAttr(const StreamableMemBlock &) -// Purpose: Private. Encrypt the given attributes into this block. -// Created: 3/12/03 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::EncryptAttr(const StreamableMemBlock &rToEncrypt) -{ - // Free any existing block - FreeBlock(); - - // Work out the maximum amount of space we need - int maxEncryptedSize = sBlowfishEncrypt.MaxOutSizeForInBufferSize(rToEncrypt.GetSize()); - // And the size of the IV - int ivSize = sBlowfishEncrypt.GetIVLength(); - - // Allocate this space - AllocateBlock(maxEncryptedSize + ivSize + 1); - - // Store the encoding byte - uint8_t *block = (uint8_t*)GetBuffer(); - block[0] = ATTRIBUTE_ENCODING_BLOWFISH; - - // Generate and store an IV for this attribute block - int ivSize2 = 0; - const void *iv = sBlowfishEncrypt.SetRandomIV(ivSize2); - ASSERT(ivSize == ivSize2); - - // Copy into the encrypted block - ::memcpy(block + 1, iv, ivSize); - - // Do the transform - int encrytedSize = sBlowfishEncrypt.TransformBlock(block + 1 + ivSize, maxEncryptedSize, rToEncrypt.GetBuffer(), rToEncrypt.GetSize()); - - // Resize this block - ResizeBlock(encrytedSize + ivSize + 1); -} - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::SetAttributeHashSecret(const void *, int) -// Purpose: Set the secret for the filename attribute hash -// Created: 25/4/04 -// -// -------------------------------------------------------------------------- -void BackupClientFileAttributes::SetAttributeHashSecret(const void *pSecret, int SecretLength) -{ - if(SecretLength > (int)sizeof(sAttributeHashSecret)) - { - SecretLength = sizeof(sAttributeHashSecret); - } - if(SecretLength < 0) - { - THROW_EXCEPTION(BackupStoreException, Internal) - } - - // Copy - ::memcpy(sAttributeHashSecret, pSecret, SecretLength); - sAttributeHashSecretLength = SecretLength; -} - - -// -------------------------------------------------------------------------- -// -// Function -// Name: BackupClientFileAttributes::GenerateAttributeHash( -// struct stat &, const std::string &, -// const std::string &) -// Purpose: Generate a 64 bit hash from the attributes, used to -// detect changes. Include filename in the hash, so -// that it changes from one file to another, so don't -// reveal identical attributes. -// Created: 25/4/04 -// -// -------------------------------------------------------------------------- -uint64_t BackupClientFileAttributes::GenerateAttributeHash(EMU_STRUCT_STAT &st, - const std::string &filename, const std::string &leafname) -{ - if(sAttributeHashSecretLength == 0) - { - THROW_EXCEPTION(BackupStoreException, AttributeHashSecretNotSet) - } - - // Assemble stuff we're interested in - attributeHashData hashData; - memset(&hashData, 0, sizeof(hashData)); - // Use network byte order and large sizes to be cross platform - hashData.uid = htonl(st.st_uid); - hashData.gid = htonl(st.st_gid); - hashData.mode = htonl(st.st_mode); - - #ifdef WIN32 - // On Windows, the "file attribute modification time" is the - // file creation time, and we want to back this up, restore - // it and compare it. - // - // On other platforms, it's not very important and can't - // reliably be set to anything other than the current time. - hashData.fileCreationTime = box_hton64(st.st_ctime); - #endif - - StreamableMemBlock xattr; - FillExtendedAttr(xattr, filename.c_str()); - - // Create a MD5 hash of the data, filename, and secret - MD5Digest digest; - digest.Add(&hashData, sizeof(hashData)); - digest.Add(xattr.GetBuffer(), xattr.GetSize()); - digest.Add(leafname.c_str(), leafname.size()); - digest.Add(sAttributeHashSecret, sAttributeHashSecretLength); - digest.Finish(); - - // Return the first 64 bits of the hash - uint64_t result = *((uint64_t *)(digest.DigestAsData())); - return result; -} |