[Box Backup-dev] COMMIT r806 - in box/chris/acl: bin/bbackupd bin/bbackupquery infrastructure/msvc/2005 lib/backupclient lib/common lib/win32 test/win32
boxbackup-dev@fluffy.co.uk
boxbackup-dev@fluffy.co.uk
Sun, 20 Aug 2006 23:52:09 +0100
Author: chris
Date: 2006-08-20 23:52:09 +0100 (Sun, 20 Aug 2006)
New Revision: 806
Added:
box/chris/acl/lib/common/DiscardStream.cpp
box/chris/acl/lib/common/DiscardStream.h
Modified:
box/chris/acl/bin/bbackupd/BackupClientDirectoryRecord.cpp
box/chris/acl/bin/bbackupd/BackupDaemon.cpp
box/chris/acl/bin/bbackupquery/BackupQueries.cpp
box/chris/acl/bin/bbackupquery/documentation.txt
box/chris/acl/infrastructure/msvc/2005/common.vcproj
box/chris/acl/lib/backupclient/BackupClientFileAttributes.cpp
box/chris/acl/lib/backupclient/BackupClientFileAttributes.h
box/chris/acl/lib/backupclient/BackupClientRestore.cpp
box/chris/acl/lib/backupclient/BackupStoreException.txt
box/chris/acl/lib/win32/emu.cpp
box/chris/acl/lib/win32/emu.h
box/chris/acl/test/win32/testlibwin32.cpp
Log:
* test/win32/testlibwin32.cpp
* infrastructure/msvc/2005/common.vcproj
* lib/win32/emu.cpp
* lib/win32/emu.h
* lib/backupclient/BackupStoreException.txt
* lib/backupclient/BackupClientRestore.cpp
* lib/backupclient/BackupClientFileAttributes.cpp
* lib/backupclient/BackupClientFileAttributes.h
* lib/common/DiscardStream.h
* lib/common/DiscardStream.cpp
* bin/bbackupd/BackupClientDirectoryRecord.cpp
* bin/bbackupd/BackupDaemon.cpp
* bin/bbackupquery/BackupQueries.cpp
* bin/bbackupquery/documentation.txt
- Checking in work in progress
Modified: box/chris/acl/bin/bbackupd/BackupClientDirectoryRecord.cpp
===================================================================
--- box/chris/acl/bin/bbackupd/BackupClientDirectoryRecord.cpp 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/bin/bbackupd/BackupClientDirectoryRecord.cpp 2006-08-20 22:52:09 UTC (rev 806)
@@ -156,6 +156,12 @@
// Build the current state checksum to compare against while getting info from dirs
// Note checksum is used locally only, so byte order isn't considered.
MD5Digest currentStateChecksum;
+
+ bool logChanges = false;
+ if (rLocalPath == "C:\\Cygwin\\Home\\Administrator\\pcre-6.3")
+ {
+ logChanges = true;
+ }
// Stat the directory, to get attribute info
{
@@ -186,6 +192,14 @@
StreamableMemBlock xattr;
BackupClientFileAttributes::FillExtendedAttr(xattr, rLocalPath.c_str());
currentStateChecksum.Add(xattr.GetBuffer(), xattr.GetSize());
+
+ if (logChanges)
+ {
+ ::syslog(LOG_INFO, "%s: mode %.3o, uid %d, gid %d, "
+ "ino %d, xattr %d\n", rLocalPath.c_str(),
+ st.st_mode, st.st_uid, st.st_gid, st.st_ino,
+ xattr.GetSize());
+ }
}
// Read directory entries, building arrays of names
@@ -236,6 +250,11 @@
// Stat file to get info
filename = MakeFullPath(rLocalPath, en->d_name);
+ if (logChanges && strcmp(en->d_name, ".libs") == 0)
+ {
+ printf("foo");
+ }
+
#ifdef WIN32
int type = en->d_type;
#else
@@ -312,6 +331,15 @@
checksum_info.mSize = st.st_size;
currentStateChecksum.Add(&checksum_info, sizeof(checksum_info));
currentStateChecksum.Add(en->d_name, strlen(en->d_name));
+ if (logChanges && strcmp(en->d_name, ".libs") == 0)
+ {
+ ::syslog(LOG_INFO, "%s: mod %lld, "
+ "attr %lld, size %lld\n",
+ filename.c_str(),
+ (long long)checksum_info.mModificationTime,
+ (long long)checksum_info.mAttributeModificationTime,
+ (long long)checksum_info.mSize);
+ }
// If the file has been modified madly into the future, download the
// directory record anyway to ensure that it doesn't get uploaded
@@ -353,6 +381,12 @@
// The checksum is the same, and there was one to compare with
checksumDifferent = false;
}
+ else
+ {
+ std::string digest(currentStateChecksum.DigestAsString());
+ ::syslog(LOG_INFO, "Checksum changed on %s: %s\n",
+ rLocalPath.c_str(), digest.c_str());
+ }
// Pointer to potentially downloaded store directory info
BackupStoreDirectory *pdirOnStore = 0;
Modified: box/chris/acl/bin/bbackupd/BackupDaemon.cpp
===================================================================
--- box/chris/acl/bin/bbackupd/BackupDaemon.cpp 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/bin/bbackupd/BackupDaemon.cpp 2006-08-20 22:52:09 UTC (rev 806)
@@ -75,6 +75,7 @@
#include "IOStreamGetLine.h"
#include "Conversion.h"
#include "Archive.h"
+#include "BoxTimeToText.h"
#include "MemLeakFindOn.h"
@@ -852,6 +853,12 @@
SerializeStoreObjectInfo(
clientStoreMarker,
lastSyncTime, nextSyncTime);
+ std::string last(BoxTimeToISO8601String(
+ lastSyncTime, true));
+ std::string next(BoxTimeToISO8601String(
+ nextSyncTime, true));
+ printf("Last sync was at %s, next will be %s\n",
+ last.c_str(), next.c_str());
// --------------------------------------------------------------------------------------------
}
Modified: box/chris/acl/bin/bbackupquery/BackupQueries.cpp
===================================================================
--- box/chris/acl/bin/bbackupquery/BackupQueries.cpp 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/bin/bbackupquery/BackupQueries.cpp 2006-08-20 22:52:09 UTC (rev 806)
@@ -7,6 +7,11 @@
//
// --------------------------------------------------------------------------
+#ifdef WIN32
+// we need features from Windows 2000 and above for ACL support
+#define WINVER 0x0500
+#endif
+
#include "Box.h"
#ifdef HAVE_UNISTD_H
@@ -28,6 +33,12 @@
#include <set>
#include <limits>
+#ifdef WIN32
+#include <AccCtrl.h>
+#include <Aclapi.h>
+#include <Sddl.h>
+#endif
+
#include "BackupQueries.h"
#include "Utils.h"
#include "Configuration.h"
@@ -46,6 +57,9 @@
#include "BackupStoreException.h"
#include "ExcludeList.h"
#include "BackupClientMakeExcludeList.h"
+#include "DiscardStream.h"
+#include "Archive.h"
+#include "CollectInBufferStream.h"
#include "MemLeakFindOn.h"
@@ -180,7 +194,7 @@
{
{ "quit", "" },
{ "exit", "" },
- { "list", "rodIFtTsh", },
+ { "list", "rodIFtTshw", },
{ "pwd", "" },
{ "cd", "od" },
{ "lcd", "" },
@@ -355,6 +369,7 @@
#define LIST_OPTION_TIMES_UTC 'T'
#define LIST_OPTION_SIZEINBLOCKS 's'
#define LIST_OPTION_DISPLAY_HASH 'h'
+ #define LIST_OPTION_WINDOWS_ATTR 'w'
// default to using the current directory
int64_t rootDir = GetCurrentDirectoryID();
@@ -391,6 +406,264 @@
}
+#ifdef WIN32
+bool PrintSid(Archive& rArchive)
+{
+ int nametype;
+ rArchive.Read(nametype);
+
+ std::string sid;
+ rArchive.Read(sid);
+
+ std::string domain;
+ rArchive.Read(domain);
+
+ std::string name;
+ rArchive.Read(name);
+
+ printf("%s\\%s (%s)", domain.c_str(), name.c_str(), sid.c_str());
+ return true;
+}
+
+void PrintWindowsAttributes(const StreamableMemBlock& rBlock)
+{
+ attr_StreamFormat_Generic* attr =
+ (attr_StreamFormat_Generic*)
+ rBlock.GetBuffer();
+
+ if (attr->AttributeType != htonl(ATTRIBUTETYPE_GENERIC_WINDOWS))
+ {
+ return;
+ }
+
+ attr_StreamFormat_Windows* wattr =
+ (attr_StreamFormat_Windows*)
+ rBlock.GetBuffer();
+
+ DWORD attribs = wattr->Attributes;
+ printf("\tFile attributes: ");
+
+ #define PRINT_ATTR(x) \
+ if (attribs & FILE_ATTRIBUTE_ ## x) \
+ { \
+ printf(#x " "); \
+ attribs &= ~FILE_ATTRIBUTE_ ## x; \
+ }
+
+ PRINT_ATTR(ARCHIVE);
+ PRINT_ATTR(COMPRESSED);
+ PRINT_ATTR(DIRECTORY);
+ PRINT_ATTR(ENCRYPTED);
+ PRINT_ATTR(HIDDEN);
+ PRINT_ATTR(OFFLINE);
+ PRINT_ATTR(READONLY);
+ PRINT_ATTR(REPARSE_POINT);
+ PRINT_ATTR(SPARSE_FILE);
+ PRINT_ATTR(SYSTEM);
+ PRINT_ATTR(TEMPORARY);
+
+ #undef PRINT_ATTR
+
+ attribs &= ~FILE_ATTRIBUTE_NORMAL;
+
+ if (wattr->Attributes)
+ {
+ if (attribs)
+ {
+ printf("Other (%08x)",
+ (unsigned int)attribs);
+ }
+ }
+ else
+ {
+ printf("None");
+ }
+
+ printf("\n");
+
+ CollectInBufferStream buffer;
+ buffer.Write(wattr + 1,
+ rBlock.GetSize() - sizeof(attr_StreamFormat_Windows));
+ buffer.SetForReading();
+
+ Archive archive(buffer, 0);
+ int data;
+
+ #define ERR_MSG "\tWindows attributes error: "
+
+ archive.Read(data);
+ if (data != ACL_FORMAT_MAGIC)
+ {
+ printf(ERR_MSG "wrong magic\n");
+ return;
+ }
+
+ archive.Read(data);
+ if (data != ACL_FORMAT_VERSION)
+ {
+ printf(ERR_MSG "wrong version\n");
+ return;
+ }
+
+ EXPLICIT_ACCESS* pEntries = NULL;
+
+ try
+ {
+ printf("\tOwner: ");
+ if (!PrintSid(archive))
+ {
+ printf(ERR_MSG "failed to read owner\n");
+ throw 1;
+ }
+
+ printf("\n\tGroup: ");
+ if (!PrintSid(archive))
+ {
+ printf(ERR_MSG "failed to read group\n");
+ throw 1;
+ }
+ printf("\n");
+
+ int numEntries;
+ archive.Read(numEntries);
+
+ pEntries = (EXPLICIT_ACCESS*)calloc(numEntries,
+ sizeof(EXPLICIT_ACCESS));
+
+ if (!pEntries)
+ {
+ printf(ERR_MSG "failed to allocate enough memory\n");
+ throw 1;
+ }
+
+ for (int i = 0; i < numEntries; i++)
+ {
+ PEXPLICIT_ACCESS pEntry = &(pEntries[i]);
+
+ archive.Read(data); pEntry->grfAccessPermissions =
+ data;
+ archive.Read(data); pEntry->grfAccessMode =
+ (ACCESS_MODE)data;
+ archive.Read(data); pEntry->Trustee.TrusteeForm =
+ (TRUSTEE_FORM)data;
+ archive.Read(data); pEntry->Trustee.TrusteeType =
+ (TRUSTEE_TYPE)data;
+
+ if (pEntry->Trustee.TrusteeForm != TRUSTEE_IS_SID)
+ {
+ printf(ERR_MSG "trustee is not a SID\n");
+ throw 1;
+ }
+
+ printf("\t");
+ if (!PrintSid(archive))
+ {
+ printf(ERR_MSG "failed to read trustee SID\n");
+ throw 1;
+ }
+
+ printf(" (");
+ switch(pEntry->Trustee.TrusteeType)
+ {
+ case TRUSTEE_IS_UNKNOWN:
+ printf("unknown type"); break;
+ case TRUSTEE_IS_USER:
+ printf("user"); break;
+ case TRUSTEE_IS_GROUP:
+ printf("group"); break;
+ case TRUSTEE_IS_DOMAIN:
+ printf("domain"); break;
+ case TRUSTEE_IS_ALIAS:
+ printf("alias"); break;
+ case TRUSTEE_IS_WELL_KNOWN_GROUP:
+ printf("well-known group"); break;
+ case TRUSTEE_IS_DELETED:
+ printf("deleted account"); break;
+ case TRUSTEE_IS_INVALID:
+ printf("invalid trustee type"); break;
+ case TRUSTEE_IS_COMPUTER:
+ printf("computer\n"); break;
+ default:
+ printf("unknown type %d\n",
+ pEntry->Trustee.TrusteeType);
+ }
+
+ printf("): ");
+
+ switch(pEntry->grfAccessMode)
+ {
+ case NOT_USED_ACCESS:
+ printf("NOT_USED_ACCESS "); break;
+ case GRANT_ACCESS:
+ printf("Grant "); break;
+ case DENY_ACCESS:
+ printf("Deny "); break;
+ case REVOKE_ACCESS:
+ printf("Revoke "); break;
+ case SET_AUDIT_SUCCESS:
+ printf("Audit Success "); break;
+ case SET_AUDIT_FAILURE:
+ printf("Audit Failure "); break;
+ default:
+ printf("Unknown (%08x)\n",
+ pEntry->grfAccessMode);
+ }
+
+ data = pEntry->grfAccessPermissions;
+
+ #define PRINT_PERM(name) \
+ if (data & name == name) \
+ { \
+ printf(#name " "); \
+ data &= ~name; \
+ }
+
+ PRINT_PERM(FILE_ADD_FILE);
+ PRINT_PERM(FILE_ADD_SUBDIRECTORY);
+ PRINT_PERM(FILE_ALL_ACCESS);
+ PRINT_PERM(FILE_APPEND_DATA);
+ PRINT_PERM(FILE_CREATE_PIPE_INSTANCE);
+ PRINT_PERM(FILE_DELETE_CHILD);
+ PRINT_PERM(FILE_EXECUTE);
+ PRINT_PERM(FILE_LIST_DIRECTORY);
+ PRINT_PERM(FILE_READ_ATTRIBUTES);
+ PRINT_PERM(FILE_READ_DATA);
+ PRINT_PERM(FILE_READ_EA);
+ PRINT_PERM(FILE_TRAVERSE);
+ PRINT_PERM(FILE_WRITE_ATTRIBUTES);
+ PRINT_PERM(FILE_WRITE_DATA);
+ PRINT_PERM(FILE_WRITE_EA);
+ PRINT_PERM(STANDARD_RIGHTS_READ);
+ PRINT_PERM(STANDARD_RIGHTS_WRITE);
+ PRINT_PERM(SYNCHRONIZE);
+ PRINT_PERM(DELETE);
+ PRINT_PERM(READ_CONTROL);
+ PRINT_PERM(WRITE_DAC);
+ PRINT_PERM(WRITE_OWNER);
+ PRINT_PERM(MAXIMUM_ALLOWED);
+ PRINT_PERM(GENERIC_ALL);
+ PRINT_PERM(GENERIC_EXECUTE);
+ PRINT_PERM(GENERIC_WRITE);
+ PRINT_PERM(GENERIC_READ);
+
+ if (data)
+ {
+ printf(" and others (%08x)", data);
+ }
+
+ printf("\n");
+ }
+
+ free(pEntries);
+ }
+ catch(...)
+ {
+ if (pEntries) free(pEntries);
+ }
+}
+#endif
+
+
// --------------------------------------------------------------------------
//
// Function
@@ -534,6 +807,75 @@
}
printf("\n");
+
+ BackupClientFileAttributes storeAttr;
+
+#ifdef WIN32
+ if (opts[LIST_OPTION_WINDOWS_ATTR])
+ {
+ if (en->HasAttributes())
+ {
+ const StreamableMemBlock &storeAttrEnc(
+ en->GetAttributes());
+ storeAttr = BackupClientFileAttributes(storeAttrEnc);
+ }
+ else if (en->GetFlags() &
+ BackupStoreDirectory::Entry::Flags_Dir)
+ {
+ // TODO: find a way to read the attributes of a directory
+ // without reading and discarding its contents :-(
+
+ mrConnection.QueryListDirectory(
+ en->GetObjectID(),
+ BackupProtocolClientListDirectory::Flags_INCLUDE_EVERYTHING,
+ // both files and directories
+ excludeFlags,
+ true /* want attributes */);
+
+ // Retrieve the directory from the stream following
+ BackupStoreDirectory dummy;
+ std::auto_ptr<IOStream> dummydirstream(
+ mrConnection.ReceiveStream());
+ dummy.ReadFromStream(*dummydirstream,
+ mrConnection.GetTimeout());
+
+ const StreamableMemBlock &storeAttrEnc(
+ dummy.GetAttributes());
+ storeAttr = BackupClientFileAttributes(
+ storeAttrEnc);
+ }
+ else
+ {
+ // TODO: find a way to read the attributes of a file
+ // without reading and discarding its contents :-(
+
+ mrConnection.QueryGetFile(DirID, en->GetObjectID());
+
+ // Stream containing encoded file
+ std::auto_ptr<IOStream> objectStream(
+ mrConnection.ReceiveStream());
+
+ DiscardStream out;
+
+ // Get the decoding stream
+ std::auto_ptr<BackupStoreFile::DecodedStream> stream(
+ BackupStoreFile::DecodeFileStream(
+ *objectStream, mrConnection.GetTimeout(), NULL));
+
+ // Is it a symlink?
+ if(!stream->IsSymLink())
+ {
+ // Copy it out to the file
+ stream->CopyStreamTo(out);
+ }
+
+ storeAttr = stream->GetAttributes();
+ }
+
+ StreamableMemBlock attrBlock(storeAttr.GetAttributes());
+ PrintWindowsAttributes(attrBlock);
+ }
+#endif // WIN32
// Directory?
if((en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) != 0)
Modified: box/chris/acl/bin/bbackupquery/documentation.txt
===================================================================
--- box/chris/acl/bin/bbackupquery/documentation.txt 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/bin/bbackupquery/documentation.txt 2006-08-20 22:52:09 UTC (rev 806)
@@ -39,9 +39,10 @@
-I -- don't display object ID
-F -- don't display flags
-t -- show file modification time
- (and attr mod time if has the object has attributes, ~ separated)
+ (and attr mod time if has the object has attributes, ~ separated)
-s -- show file size in blocks used on server
- (only very approximate indication of size locally)
+ (only very approximate indication of size locally)
+ -w -- show Windows attributes and access control list
ls can be used as an alias.
<
Modified: box/chris/acl/infrastructure/msvc/2005/common.vcproj
===================================================================
--- box/chris/acl/infrastructure/msvc/2005/common.vcproj 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/infrastructure/msvc/2005/common.vcproj 2006-08-20 22:52:09 UTC (rev 806)
@@ -220,6 +220,14 @@
>
</File>
<File
+ RelativePath="..\..\..\lib\common\DiscardStream.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\lib\common\DiscardStream.h"
+ >
+ </File>
+ <File
RelativePath="..\..\..\lib\common\EventWatchFilesystemObject.cpp"
>
</File>
Modified: box/chris/acl/lib/backupclient/BackupClientFileAttributes.cpp
===================================================================
--- box/chris/acl/lib/backupclient/BackupClientFileAttributes.cpp 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/lib/backupclient/BackupClientFileAttributes.cpp 2006-08-20 22:52:09 UTC (rev 806)
@@ -7,6 +7,12 @@
//
// --------------------------------------------------------------------------
+#ifdef WIN32
+// we need features from Windows 2000 and above for ACL support
+#define WINVER 0x0500
+#define _WIN32_WINNT 0x0500
+#endif
+
#include "Box.h"
#ifdef HAVE_UNISTD_H
@@ -25,6 +31,13 @@
#include <sys/xattr.h>
#endif
+#ifdef WIN32
+#include <windows.h>
+#include <AccCtrl.h>
+#include <Aclapi.h>
+#include <Sddl.h>
+#endif
+
#include "BackupClientFileAttributes.h"
#include "CommonException.h"
#include "FileModificationTime.h"
@@ -33,56 +46,13 @@
#include "CipherContext.h"
#include "CipherBlowfish.h"
#include "MD5Digest.h"
+#include "CollectInBufferStream.h"
+#include "Archive.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;
-} 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
@@ -234,45 +204,106 @@
// 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();
+ attr_StreamFormat_Generic *a1 = (attr_StreamFormat_Generic*)
+ mpClearAttributes->GetBuffer();
+ attr_StreamFormat_Generic *a2 = (attr_StreamFormat_Generic*)
+ rAttr.mpClearAttributes->GetBuffer();
- if(a1->AttributeType != a2->AttributeType
- || a1->UID != a2->UID
- || a1->GID != a2->GID
- || a1->UserDefinedFlags != a2->UserDefinedFlags
- || a1->Mode != a2->Mode)
+ if(a1->AttributeType != a2->AttributeType)
{
return false;
}
-
- if(!IgnoreModTime)
+
+ if (ntohl(a1->AttributeType) == ATTRIBUTETYPE_GENERIC_UNIX)
{
- if(a1->ModificationTime != a2->ModificationTime)
+ attr_StreamFormat_Unix* ua1 = (attr_StreamFormat_Unix*)a1;
+ attr_StreamFormat_Unix* ua2 = (attr_StreamFormat_Unix*)a2;
+ if (ua1->UID != ua2->UID
+ || ua1->GID != ua2->GID
+ || ua1->UserDefinedFlags != ua2->UserDefinedFlags
+ || ua1->Mode != ua2->Mode)
{
return false;
}
- }
+
+ if(!IgnoreModTime)
+ {
+ if(ua1->ModificationTime != ua2->ModificationTime)
+ {
+ return false;
+ }
+ }
- if(!IgnoreAttrModTime)
- {
- if(a1->AttrModificationTime != a2->AttrModificationTime)
+ if(!IgnoreAttrModTime)
{
+ if(ua1->AttrModificationTime != ua2->AttrModificationTime)
+ {
+ return false;
+ }
+ }
+
+ // Check symlink string?
+ unsigned int size = mpClearAttributes->GetSize();
+ if(size == sizeof(attr_StreamFormat_Unix))
+ {
+ return true;
+ }
+
+ // Check whether symlink strings and xattrs match
+ if(::memcmp(ua1 + 1, ua2 + 1,
+ size - sizeof(attr_StreamFormat_Unix)) != 0)
+ {
return false;
}
+
+ return true;
}
-
- // Check symlink string?
- unsigned int size = mpClearAttributes->GetSize();
- if(size > sizeof(attr_StreamFormat))
+ else if (ntohl(a1->AttributeType) == ATTRIBUTETYPE_GENERIC_WINDOWS)
{
- // Symlink strings don't match. This also compares xattrs
- if(::memcmp(a1 + 1, a2 + 1, size - sizeof(attr_StreamFormat)) != 0)
+ attr_StreamFormat_Windows* wa1 = (attr_StreamFormat_Windows*)a1;
+ attr_StreamFormat_Windows* wa2 = (attr_StreamFormat_Windows*)a2;
+
+ if(wa1->Attributes != wa2->Attributes)
{
return false;
}
+
+ if(wa1->CreationTime != wa2->CreationTime)
+ {
+ return false;
+ }
+
+ if(!IgnoreModTime)
+ {
+ if(wa1->LastWriteTime != wa2->LastWriteTime)
+ {
+ return false;
+ }
+ }
+
+ unsigned int size = mpClearAttributes->GetSize();
+ if(size == sizeof(attr_StreamFormat_Windows))
+ {
+ return true;
+ }
+
+ // The rest of the record is the Windows ACL data,
+ // which we can compare byte-for-byte for now.
+
+ if(::memcmp(wa1 + 1, wa2 + 1,
+ size - sizeof(attr_StreamFormat_Windows)) != 0)
+ {
+ return false;
+ }
+
+ return true;
}
-
+ else
+ {
+ // unknown attribute type
+ return false;
+ }
+
// Passes all test, must be OK
return true;
}
@@ -292,7 +323,7 @@
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;
+ StreamableMemBlock *pAttrBlock = 0;
try
{
struct stat st;
@@ -308,72 +339,40 @@
if(pInodeNumber) {*pInodeNumber = st.st_ino;}
if(pHasMultipleLinks) {*pHasMultipleLinks = (st.st_nlink > 1);}
- pnewAttr = new StreamableMemBlock;
+ pAttrBlock = new StreamableMemBlock;
- FillAttributes(*pnewAttr, Filename, st, ZeroModificationTimes);
+#ifdef WIN32
+ FillAttributesWindows(*pAttrBlock, Filename, st,
+ ZeroModificationTimes);
+#else // !WIN32
+ FillAttributes(*pAttrBlock, Filename, st,
+ ZeroModificationTimes);
-#ifndef WIN32
// Is it a link?
if((st.st_mode & S_IFMT) == S_IFLNK)
{
- FillAttributesLink(*pnewAttr, Filename, st);
+ FillAttributesLink(*pAttrBlock, Filename, st);
}
-#endif
- FillExtendedAttr(*pnewAttr, Filename);
+ FillExtendedAttr(*pAttrBlock, Filename);
+#endif // WIN32
-#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)
- {
- ::syslog(LOG_ERR, "Invalid Modification Time "
- "caught for file: %s", Filename);
- pattr->ModificationTime = 0;
- }
-
- modTime = box_ntoh64(pattr->AttrModificationTime);
- modSecs = BoxTimeToSeconds(modTime);
- winTime = modSecs;
-
- if (winTime > 0x100000000LL || _gmtime64(&winTime) == 0)
- {
- ::syslog(LOG_ERR, "Invalid Attribute Modification "
- "Time caught for file: %s", Filename);
- pattr->AttrModificationTime = 0;
- }
-#endif
-
// Attributes ready. Encrypt into this block
- EncryptAttr(*pnewAttr);
+ EncryptAttr(*pAttrBlock);
// Store the new attributes
RemoveClear();
- mpClearAttributes = pnewAttr;
- pnewAttr = 0;
+ mpClearAttributes = pAttrBlock;
+ pAttrBlock = 0;
}
catch(...)
{
// clean up
- delete pnewAttr;
- pnewAttr = 0;
+ if (pAttrBlock)
+ {
+ delete pAttrBlock;
+ pAttrBlock = 0;
+ }
throw;
}
}
@@ -388,8 +387,9 @@
// --------------------------------------------------------------------------
void BackupClientFileAttributes::FillAttributes(StreamableMemBlock &outputBlock, const char *Filename, struct stat &st, bool ZeroModificationTimes)
{
- outputBlock.ResizeBlock(sizeof(attr_StreamFormat));
- attr_StreamFormat *pattr = (attr_StreamFormat*)outputBlock.GetBuffer();
+ outputBlock.ResizeBlock(sizeof(attr_StreamFormat_Unix));
+ attr_StreamFormat_Unix *pattr = (attr_StreamFormat_Unix*)
+ outputBlock.GetBuffer();
ASSERT(pattr != 0);
// Fill in the entries
@@ -416,6 +416,242 @@
pattr->FileGenerationNumber = htonl(st.st_gen);
#endif
}
+
+
+#ifdef WIN32
+void WriteSid(Archive& rArchiver, PSID pSID)
+{
+ CHAR* pSidString;
+ if (!ConvertSidToStringSid(pSID, &pSidString))
+ {
+ ::syslog(LOG_WARNING, "Failed to convert Security Identifier "
+ "to a string: error %d", GetLastError());
+ THROW_EXCEPTION(BackupStoreException, LookupAccountFailed)
+ }
+
+ std::string sid(pSidString);
+ LocalFree((HLOCAL)pSidString);
+
+ char namebuf[1024];
+ char domainbuf[1024];
+ SID_NAME_USE nametype;
+ DWORD namelen = sizeof(namebuf);
+ DWORD domainlen = sizeof(domainbuf);
+
+ if(!LookupAccountSid(NULL, pSID, namebuf, &namelen,
+ domainbuf, &domainlen, &nametype))
+ {
+ ::syslog(LOG_WARNING, "Failed to find account details for "
+ "'%s': error %d", sid.c_str(), GetLastError());
+ THROW_EXCEPTION(BackupStoreException, LookupAccountFailed)
+ }
+
+ std::string domain(domainbuf);
+ std::string name(namebuf);
+
+ rArchiver.Write((int)nametype);
+ rArchiver.Write(sid);
+ rArchiver.Write(domain);
+ rArchiver.Write(name);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientFileAttributes::FillAttributesWindows()
+// Purpose: Private function, handles Windows attributes (ACL)
+// Created: 2006/02/27
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::FillAttributesWindows
+(
+ StreamableMemBlock &rOutputBlock, const char *pFilename,
+ struct stat &rStat, bool ZeroLastWriteTime
+)
+{
+ rOutputBlock.ResizeBlock(sizeof(attr_StreamFormat_Windows));
+ attr_StreamFormat_Windows *pAttr = (attr_StreamFormat_Windows*)
+ rOutputBlock.GetBuffer();
+ ASSERT(pAttr != 0);
+
+ // Fill in the entries
+ pAttr->AttributeType = htonl(ATTRIBUTETYPE_GENERIC_WINDOWS);
+ pAttr->CreationTime = box_hton64(rStat.st_ctime * MICRO_SEC_IN_SEC_LL);
+
+ if(ZeroLastWriteTime)
+ {
+ pAttr->LastWriteTime = 0;
+ }
+ else
+ {
+ pAttr->LastWriteTime = box_hton64(FileModificationTime(rStat));
+ }
+
+ // not very efficient to stat the file again, but emu_fstat
+ // doesn't return the information that we need.
+
+ HANDLE handle = OpenFileByNameUtf8(pFilename);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ ::syslog(LOG_WARNING, "Failed to open file to read "
+ "Windows attributes: '%s': error %d",
+ pFilename, GetLastError());
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ BY_HANDLE_FILE_INFORMATION fi;
+ bool result = GetFileInformationByHandle(handle, &fi);
+
+ if (!result)
+ {
+ CloseHandle(handle);
+ ::syslog(LOG_WARNING, "Failed to read Windows "
+ "file attributes for '%s': error %d",
+ pFilename, GetLastError());
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ if (INVALID_FILE_ATTRIBUTES == fi.dwFileAttributes)
+ {
+ CloseHandle(handle);
+ ::syslog(LOG_WARNING, "Failed to read valid Windows "
+ "file attributes for '%s': error %d",
+ pFilename, GetLastError());
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ pAttr->Attributes = fi.dwFileAttributes;
+
+ // Now start writing our custom data, with the magic and version
+ CollectInBufferStream buffer;
+ Archive archiver(buffer, 0);
+
+ archiver.Write((int) ACL_FORMAT_MAGIC);
+ archiver.Write((int) ACL_FORMAT_VERSION);
+
+ PSID psidOwner = NULL;
+ PSID psidGroup = NULL;
+ PACL pDacl = NULL;
+ PSECURITY_DESCRIPTOR pSecurityDesc = NULL;
+ PEXPLICIT_ACCESS pEntries = NULL;
+
+ try
+ {
+ DWORD result = GetSecurityInfo(
+ handle, // object handle
+ SE_FILE_OBJECT, // ObjectType
+ DACL_SECURITY_INFORMATION | // SecurityInfo
+ GROUP_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION,
+ &psidOwner, // ppsidOwner,
+ &psidGroup, // ppsidGroup,
+ &pDacl, // ppDacl,
+ NULL, // ppSacl,
+ &pSecurityDesc // ppSecurityDescriptor
+ );
+
+ CloseHandle(handle);
+
+ if (result != ERROR_SUCCESS)
+ {
+ ::syslog(LOG_WARNING, "Failed to get Windows "
+ "security info for '%s': error %d",
+ pFilename, result);
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ WriteSid(archiver, psidOwner);
+ WriteSid(archiver, psidGroup);
+
+ ULONG numEntries;
+ result = GetExplicitEntriesFromAcl
+ (
+ pDacl, // pAcl
+ &numEntries, // pcCountOfExplicitEntries,
+ &pEntries // pListOfExplicitEntries
+ );
+
+ if(result != ERROR_SUCCESS)
+ {
+ ::syslog(LOG_WARNING, "Failed to get Windows "
+ "access control list entries for '%s': "
+ "error %d", pFilename, result);
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ archiver.Write((int)numEntries);
+
+ for (ULONG i = 0; i < numEntries; i++)
+ {
+ EXPLICIT_ACCESS* pEntry = &(pEntries[i]);
+
+ archiver.Write((int)pEntry->grfAccessPermissions);
+ archiver.Write((int)pEntry->grfAccessMode);
+ archiver.Write((int)pEntry->grfInheritance);
+ archiver.Write((int)pEntry->Trustee.TrusteeForm);
+ archiver.Write((int)pEntry->Trustee.TrusteeType);
+
+ if(pEntry->Trustee.pMultipleTrustee != NULL)
+ {
+ ::syslog(LOG_WARNING, "Failed to process "
+ "access control entry for '%s': "
+ "multiple trustees not supported",
+ pFilename);
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+
+ if(pEntry->Trustee.MultipleTrusteeOperation !=
+ NO_MULTIPLE_TRUSTEE)
+ {
+ ::syslog(LOG_WARNING, "Failed to process "
+ "access control entry for '%s': "
+ "multiple trustees not supported (2)",
+ pFilename);
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+
+ switch(pEntry->Trustee.TrusteeForm)
+ {
+ case TRUSTEE_IS_SID:
+ {
+ PSID trusteeSid = (PSID)(
+ pEntry->Trustee.ptstrName);
+ WriteSid(archiver, trusteeSid);
+ }
+ break;
+ default:
+ ::syslog(LOG_WARNING, "Failed to process "
+ "access control entry for '%s': "
+ "trustee form %d not supported",
+ pFilename,
+ pEntry->Trustee.TrusteeForm);
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+
+ }
+ }
+ catch(...)
+ {
+ if (pEntries) LocalFree((HLOCAL)pEntries);
+ if (pSecurityDesc) LocalFree((HLOCAL)pSecurityDesc);
+ throw;
+ }
+
+ LocalFree((HLOCAL)pEntries);
+ LocalFree((HLOCAL)pSecurityDesc);
+
+ // Copy the serialised data into the output block
+ buffer.SetForReading();
+ rOutputBlock.ResizeBlock(rOutputBlock.GetSize() + buffer.GetSize());
+
+ // block might have moved after resize
+ pAttr = (attr_StreamFormat_Windows *)(rOutputBlock.GetBuffer());
+ memcpy(pAttr + 1, buffer.GetBuffer(), buffer.GetSize());
+}
+#endif // WIN32
+
+
#ifndef WIN32
// --------------------------------------------------------------------------
//
@@ -597,6 +833,15 @@
}
int32_t *type = (int32_t*)mpClearAttributes->GetBuffer();
ASSERT(type != 0);
+
+#ifdef WIN32
+ if(ntohl(*type) == ATTRIBUTETYPE_GENERIC_WINDOWS)
+ {
+ WriteAttributesWindows(Filename);
+ return;
+ }
+#endif
+
if(ntohl(*type) != ATTRIBUTETYPE_GENERIC_UNIX)
{
// Don't know what to do with these
@@ -604,22 +849,24 @@
}
// Check there is enough space for an attributes block
- if(mpClearAttributes->GetSize() < (int)sizeof(attr_StreamFormat))
+ if(mpClearAttributes->GetSize() < (int)sizeof(attr_StreamFormat_Unix))
{
// Too small
THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
}
// Get pointer to structure
- attr_StreamFormat *pattr = (attr_StreamFormat*)mpClearAttributes->GetBuffer();
- int xattrOffset = sizeof(attr_StreamFormat);
+ attr_StreamFormat_Unix *pattr = (attr_StreamFormat_Unix*)
+ mpClearAttributes->GetBuffer();
+ int xattrOffset = sizeof(attr_StreamFormat_Unix);
// 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)
+ if(mpClearAttributes->GetSize() <
+ (int)sizeof(attr_StreamFormat_Unix) + 1)
{
// Too small
THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
@@ -715,9 +962,248 @@
}
+#ifdef WIN32
+bool ReadSid(Archive& rArchive, PSID* pPSID)
+{
+ int nametype;
+ rArchive.Read(nametype);
+
+ std::string sid;
+ rArchive.Read(sid);
+
+ std::string domain;
+ rArchive.Read(domain);
+
+ std::string name;
+ rArchive.Read(name);
+
+ name = domain + '\\' + name;
+
+ DWORD sidBufSize = 0;
+ DWORD domainBufSize = 0;
+ SID_NAME_USE use;
+
+ // TODO: if we don't find the account name,
+ // use the stored SID instead
+
+ if (!LookupAccountName(NULL, name.c_str(), NULL, &sidBufSize,
+ NULL, &domainBufSize, &use) &&
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ ::syslog(LOG_ERR, "Failed to lookup account details for "
+ "'%s': error %d", name.c_str(), GetLastError());
+ return false;
+ }
+
+ *pPSID = malloc(sidBufSize);
+ TCHAR* domainstr = (TCHAR *)malloc(domainBufSize);
+
+ BOOL result = LookupAccountName(NULL, name.c_str(),
+ *pPSID, &sidBufSize, domainstr, &domainBufSize, &use);
+ free(domainstr);
+
+ if (!result)
+ {
+ ::syslog(LOG_ERR, "Failed to lookup account details for "
+ "'%s': error %d", name.c_str(), GetLastError());
+ free(*pPSID);
+ *pPSID = NULL;
+ return false;
+ }
+
+ return true;
+}
+
+
// --------------------------------------------------------------------------
//
// Function
+// Name: BackupClientFileAttributes::WriteAttributesWindows(
+// const char *)
+// Purpose: Apply the stored Windows attributes to the file
+// Created: 2006/03/12
+//
+// --------------------------------------------------------------------------
+void BackupClientFileAttributes::WriteAttributesWindows(const char *Filename)
+const
+{
+ // Check there is enough space for an attributes block
+ if(mpClearAttributes->GetSize() <
+ (int)sizeof(attr_StreamFormat_Windows))
+ {
+ // Too small
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ // Get pointer to structure
+ attr_StreamFormat_Windows *pAttr = (attr_StreamFormat_Windows*)
+ mpClearAttributes->GetBuffer();
+
+ std::wstring wideName;
+ if (!GetFileNameWide(Filename, wideName))
+ {
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+
+ DWORD attributes = pAttr->Attributes;
+ attributes &= ~FILE_ATTRIBUTE_OFFLINE;
+ attributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
+
+ if (!SetFileAttributesW(wideName.c_str(), attributes))
+ {
+ ::syslog(LOG_ERR, "Failed to restore attributes of '%s': "
+ "error %d", Filename, GetLastError());
+ return;
+ }
+
+ CollectInBufferStream buffer;
+ buffer.Write(pAttr + 1, mpClearAttributes->GetSize() -
+ sizeof(attr_StreamFormat_Windows));
+ buffer.SetForReading();
+
+ Archive archive(buffer, 0);
+ int data;
+
+ archive.Read(data);
+ if (data != ACL_FORMAT_MAGIC)
+ {
+ ::syslog(LOG_ERR, "Failed to restore ACL of '%s': "
+ "wrong magic in attribute block", Filename);
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ archive.Read(data);
+ if (data != ACL_FORMAT_VERSION)
+ {
+ ::syslog(LOG_ERR, "Failed to restore ACL of '%s': "
+ "wrong version in attribute block", Filename);
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ PACL pNewAcl = NULL;
+ PSID pSidOwner = NULL, pSidGroup = NULL;
+
+ if (!ReadSid(archive, &pSidOwner))
+ {
+ ::syslog(LOG_ERR, "Failed to restore ACL of '%s': "
+ "failed to decode file owner", Filename);
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ if (!ReadSid(archive, &pSidGroup))
+ {
+ ::syslog(LOG_ERR, "Failed to restore ACL of '%s': "
+ "failed to decode file group", Filename);
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ int numEntries;
+ archive.Read(numEntries);
+
+ EXPLICIT_ACCESS* pEntries = (EXPLICIT_ACCESS*)calloc(numEntries,
+ sizeof(EXPLICIT_ACCESS));
+
+ if (!pEntries)
+ {
+ ::syslog(LOG_ERR, "Failed to restore ACL of '%s': "
+ "out of memory", Filename);
+ if (pSidOwner) free(pSidOwner);
+ if (pSidGroup) free(pSidGroup);
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ for (int i = 0; i < numEntries; i++)
+ {
+ PEXPLICIT_ACCESS pEntry = &(pEntries[i]);
+
+ int data;
+ archive.Read(data); pEntry->grfAccessPermissions = data;
+ archive.Read(data); pEntry->grfAccessMode = (ACCESS_MODE)data;
+ archive.Read(data); pEntry->grfInheritance = data;
+ archive.Read(data); pEntry->Trustee.TrusteeForm =
+ (TRUSTEE_FORM)data;
+ archive.Read(data); pEntry->Trustee.TrusteeType =
+ (TRUSTEE_TYPE)data;
+
+ if (pEntry->Trustee.TrusteeForm != TRUSTEE_IS_SID)
+ {
+ ::syslog(LOG_ERR, "Failed to restore ACL of '%s': "
+ "only SID trustees are supported", Filename);
+ if (pSidOwner) free(pSidOwner);
+ if (pSidGroup) free(pSidGroup);
+ THROW_EXCEPTION(BackupStoreException,
+ AttributesNotLoaded);
+ }
+
+ LPSTR* pPSIDstr = &pEntry->Trustee.ptstrName;
+ if (!ReadSid(archive, (PSID*)pPSIDstr))
+ {
+ ::syslog(LOG_ERR, "Failed to restore ACL of '%s': "
+ "failed to read ACL entry %d SID", Filename, i);
+ if (pSidOwner) free(pSidOwner);
+ if (pSidGroup) free(pSidGroup);
+ THROW_EXCEPTION(BackupStoreException,
+ AttributesNotLoaded);
+ }
+ }
+
+ DWORD result = SetEntriesInAcl(numEntries, pEntries, NULL, &pNewAcl);
+
+ for (int i = 0; i < numEntries; i++)
+ {
+ PEXPLICIT_ACCESS pEntry = &(pEntries[i]);
+ PSID pSid = (PSID)(pEntry->Trustee.ptstrName);
+ free(pSid);
+ }
+
+ free(pEntries);
+
+ if (result != ERROR_SUCCESS)
+ {
+ ::syslog(LOG_ERR, "Failed to create access control list "
+ "for '%s': error %d", Filename, result);
+ if (pSidOwner) free(pSidOwner);
+ if (pSidGroup) free(pSidGroup);
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ WCHAR* pNameBuffer = new WCHAR [wideName.size() + 1];
+ if (!pNameBuffer)
+ {
+ ::syslog(LOG_ERR, "Failed to create access control list "
+ "for '%s': out of memory", Filename);
+ if (pSidOwner) free(pSidOwner);
+ if (pSidGroup) free(pSidGroup);
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+
+ memcpy(pNameBuffer, wideName.c_str(), wideName.size() * sizeof(WCHAR));
+
+ result = SetNamedSecurityInfoW(pNameBuffer, SE_FILE_OBJECT,
+ DACL_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION
+ /* | UNPROTECTED_DACL_SECURITY_INFORMATION */,
+ pSidOwner, pSidGroup, pNewAcl, NULL);
+
+ delete [] pNameBuffer;
+ LocalFree((HLOCAL)pNewAcl);
+
+ if (result != ERROR_SUCCESS)
+ {
+ ::syslog(LOG_ERR, "Failed to apply access control list "
+ "to '%s': error %d", Filename, result);
+ if (pSidOwner) free(pSidOwner);
+ if (pSidGroup) free(pSidGroup);
+ THROW_EXCEPTION(BackupStoreException, AttributesNotLoaded);
+ }
+}
+#endif
+
+
+// --------------------------------------------------------------------------
+//
+// Function
// Name: BackupClientFileAttributes::IsSymLink()
// Purpose: Do these attributes represent a symbolic link?
// Created: 2003/10/07
@@ -736,10 +1222,12 @@
// 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))
+ if(ntohl(*type) == ATTRIBUTETYPE_GENERIC_UNIX &&
+ mpClearAttributes->GetSize() > (int)sizeof(attr_StreamFormat_Unix))
{
// Check link
- attr_StreamFormat *pattr = (attr_StreamFormat*)mpClearAttributes->GetBuffer();
+ attr_StreamFormat_Unix *pattr = (attr_StreamFormat_Unix*)
+ mpClearAttributes->GetBuffer();
return ((ntohs(pattr->Mode)) & S_IFMT) == S_IFLNK;
}
Modified: box/chris/acl/lib/backupclient/BackupClientFileAttributes.h
===================================================================
--- box/chris/acl/lib/backupclient/BackupClientFileAttributes.h 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/lib/backupclient/BackupClientFileAttributes.h 2006-08-20 22:52:09 UTC (rev 806)
@@ -17,6 +17,69 @@
struct stat;
+// 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 ATTRIBUTETYPE_GENERIC_WINDOWS 2
+
+#ifdef WIN32
+#define ACL_FORMAT_MAGIC 0x31415927
+#define ACL_FORMAT_VERSION 0x1
+#endif
+
+typedef struct
+{
+ int32_t AttributeType;
+} attr_StreamFormat_Generic;
+
+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_Unix;
+
+typedef struct
+{
+ int32_t AttributeType;
+ u_int32_t Attributes;
+ u_int64_t CreationTime;
+ u_int64_t LastWriteTime;
+} attr_StreamFormat_Windows;
+
+// 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;
+} attributeHashData;
+
+// Use default packing
+#ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
+#include "EndStructPackForWire.h"
+#else
+END_STRUCTURE_PACKING_FOR_WIRE
+#endif
+
// --------------------------------------------------------------------------
//
// Class
@@ -58,6 +121,14 @@
private:
static void FillAttributes(StreamableMemBlock &outputBlock, const char *Filename, struct stat &st, bool ZeroModificationTimes);
static void FillAttributesLink(StreamableMemBlock &outputBlock, const char *Filename, struct stat &st);
+
+#ifdef WIN32
+ static void FillAttributesWindows(StreamableMemBlock &rOutputBlock,
+ const char* pFilename, struct stat &rStat,
+ bool ZeroModificationTimes);
+ void WriteAttributesWindows(const char *Filename) const;
+#endif
+
void WriteExtendedAttr(const char *Filename, int xattrOffset) const;
void RemoveClear() const;
@@ -65,6 +136,13 @@
static StreamableMemBlock *MakeClear(const StreamableMemBlock &rEncrypted);
void EncryptAttr(const StreamableMemBlock &rToEncrypt);
+public:
+ const StreamableMemBlock& GetAttributes()
+ {
+ EnsureClearAvailable();
+ return *mpClearAttributes;
+ }
+
private:
mutable StreamableMemBlock *mpClearAttributes;
};
Modified: box/chris/acl/lib/backupclient/BackupClientRestore.cpp
===================================================================
--- box/chris/acl/lib/backupclient/BackupClientRestore.cpp 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/lib/backupclient/BackupClientRestore.cpp 2006-08-20 22:52:09 UTC (rev 806)
@@ -325,7 +325,12 @@
// Apply attributes to the directory
const StreamableMemBlock &dirAttrBlock(dir.GetAttributes());
BackupClientFileAttributes dirAttr(dirAttrBlock);
+
+ // too early to apply attributes on Win32:
+ // might prevent us from accessing or writing to the directory
+#ifndef WIN32
dirAttr.WriteAttributes(rLocalDirectoryName.c_str());
+#endif
int64_t bytesWrittenSinceLastRestoreInfoSave = 0;
@@ -438,6 +443,10 @@
}
}
+#ifdef WIN32
+ dirAttr.WriteAttributes(rLocalDirectoryName.c_str());
+#endif
+
return Restore_Complete;
}
Modified: box/chris/acl/lib/backupclient/BackupStoreException.txt
===================================================================
--- box/chris/acl/lib/backupclient/BackupStoreException.txt 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/lib/backupclient/BackupStoreException.txt 2006-08-20 22:52:09 UTC (rev 806)
@@ -68,3 +68,4 @@
IncompatibleFromAndDiffFiles 65 Attempt to use a diff and a from file together, when they're not related
DiffFromIDNotFoundInDirectory 66 When uploading via a diff, the diff from file must be in the same directory
PatchChainInfoBadInDirectory 67 A directory contains inconsistent information. Run bbstoreaccounts check to fix it.
+LookupAccountFailed 68 The file's security information refers to an account that could not be found
Copied: box/chris/acl/lib/common/DiscardStream.cpp (from rev 532, box/chris/general/lib/common/CollectInBufferStream.cpp)
===================================================================
--- box/chris/acl/lib/common/DiscardStream.cpp (rev 0)
+++ box/chris/acl/lib/common/DiscardStream.cpp 2006-08-20 22:52:09 UTC (rev 806)
@@ -0,0 +1,131 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: DiscardStream.cpp
+// Purpose: Discards data written to it
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <string.h>
+
+#include "DiscardStream.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::DiscardStream()
+// Purpose: Constructor
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+DiscardStream::DiscardStream()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::~DiscardStream()
+// Purpose: Destructor
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+DiscardStream::~DiscardStream()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::Read(void *, int, int)
+// Purpose: As interface. Never reads anything :-)
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+int DiscardStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ return 0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::BytesLeftToRead()
+// Purpose: As interface. Never anything to read.
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type DiscardStream::BytesLeftToRead()
+{
+ return 0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::Write(void *, int)
+// Purpose: As interface. Dicards written data.
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+void DiscardStream::Write(const void *pBuffer, int NBytes)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::GetPosition()
+// Purpose: As interface. Always returns 0.
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type DiscardStream::GetPosition() const
+{
+ return 0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::Seek(pos_type, int)
+// Purpose: As interface. Does nothing.
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+void DiscardStream::Seek(pos_type Offset, int SeekType)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::StreamDataLeft()
+// Purpose: As interface. Always returns false.
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+bool DiscardStream::StreamDataLeft()
+{
+ return false;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: DiscardStream::StreamClosed()
+// Purpose: As interface. Always returns false.
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+bool DiscardStream::StreamClosed()
+{
+ return false;
+}
+
Copied: box/chris/acl/lib/common/DiscardStream.h (from rev 532, box/chris/general/lib/common/CollectInBufferStream.h)
===================================================================
--- box/chris/acl/lib/common/DiscardStream.h (rev 0)
+++ box/chris/acl/lib/common/DiscardStream.h 2006-08-20 22:52:09 UTC (rev 806)
@@ -0,0 +1,44 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: DiscardStream.h
+// Purpose: Discards data written to it
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+
+#ifndef DISCARDSTREAM__H
+#define DISCARDSTREAM__H
+
+#include "IOStream.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: DiscardStream
+// Purpose: Discards data written to it
+// Created: 2006/03/06
+//
+// --------------------------------------------------------------------------
+class DiscardStream : public IOStream
+{
+public:
+ DiscardStream();
+ ~DiscardStream();
+private:
+ // No copying
+ DiscardStream(const DiscardStream &);
+ DiscardStream(const IOStream &);
+public:
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual pos_type GetPosition() const;
+ virtual void Seek(pos_type Offset, int SeekType);
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+};
+
+#endif // DISCARDSTREAM__H
+
Modified: box/chris/acl/lib/win32/emu.cpp
===================================================================
--- box/chris/acl/lib/win32/emu.cpp 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/lib/win32/emu.cpp 2006-08-20 22:52:09 UTC (rev 806)
@@ -663,6 +663,43 @@
// --------------------------------------------------------------------------
//
// Function
+// Name: GetFileNameWide(const std::string& rIn, std::wstring&
+// rOut)
+// Purpose: Converts filename to Unicode and returns it
+// in rOut, returning true. In case of error,
+// sets errno, logs the error and returns false.
+// Created: 2006/03/13
+//
+// --------------------------------------------------------------------------
+bool GetFileNameWide(const std::string& rIn, std::wstring& rOut)
+{
+ std::string AbsPathWithUnicode =
+ ConvertPathToAbsoluteUnicode(rIn.c_str());
+
+ if (AbsPathWithUnicode.size() == 0)
+ {
+ // error already logged by ConvertPathToAbsoluteUnicode()
+ return false;
+ }
+
+ WCHAR* pBuffer = ConvertUtf8ToWideString(AbsPathWithUnicode.c_str());
+ // We are responsible for freeing pBuffer
+
+ if (pBuffer == NULL)
+ {
+ // error already logged by ConvertUtf8ToWideString()
+ return false;
+ }
+
+ rOut = pBuffer;
+ delete [] pBuffer;
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
// Name: OpenFileByNameUtf8
// Purpose: Converts filename to Unicode and returns
// a handle to it. In case of error, sets errno,
Modified: box/chris/acl/lib/win32/emu.h
===================================================================
--- box/chris/acl/lib/win32/emu.h 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/lib/win32/emu.h 2006-08-20 22:52:09 UTC (rev 806)
@@ -365,6 +365,10 @@
// replacement for _cgetws which requires a relatively recent C runtime lib
int console_read(char* pBuffer, size_t BufferSize);
+// used by BackupClientFileAttributes to get Windows file attributes
+HANDLE OpenFileByNameUtf8(const char* pFileName);
+bool GetFileNameWide(const std::string& rIn, std::wstring& rOut);
+
struct iovec {
void *iov_base; /* Starting address */
size_t iov_len; /* Number of bytes */
Modified: box/chris/acl/test/win32/testlibwin32.cpp
===================================================================
--- box/chris/acl/test/win32/testlibwin32.cpp 2006-08-20 22:46:33 UTC (rev 805)
+++ box/chris/acl/test/win32/testlibwin32.cpp 2006-08-20 22:52:09 UTC (rev 806)
@@ -329,6 +329,12 @@
closelog();
+ struct stat st;
+ assert(!emu_stat("c:\\cygwin\\home\\administrator\\pcre-6.3\\.libs", &st));
+ printf("%lld\n", (long long)st.st_size);
+ assert(!emu_stat("c:\\cygwin\\home\\administrator\\pcre-6.3\\.libs", &st));
+ printf("%lld\n", (long long)st.st_size);
+
/*
//first off get the path name for the default
char buf[MAX_PATH];