[Box Backup-dev] COMMIT r300 - in box/trunk: lib/backupclient lib/common test/bbackupd

boxbackup-dev at fluffy.co.uk boxbackup-dev at fluffy.co.uk
Fri Jan 6 10:02:46 GMT 2006


Author: ben
Date: 2006-01-06 10:02:44 +0000 (Fri, 06 Jan 2006)
New Revision: 300

Modified:
   box/trunk/lib/backupclient/BackupClientFileAttributes.cpp
   box/trunk/lib/common/BoxPlatform.h
   box/trunk/test/bbackupd/testbbackupd.cpp
Log:
Simple test for xattr support in test/bbackupd, fix xattr support for Darwin, move xattr adjustments to BoxPlatform.h to use globally

Modified: box/trunk/lib/backupclient/BackupClientFileAttributes.cpp
===================================================================
--- box/trunk/lib/backupclient/BackupClientFileAttributes.cpp	2006-01-05 22:01:34 UTC (rev 299)
+++ box/trunk/lib/backupclient/BackupClientFileAttributes.cpp	2006-01-06 10:02:44 UTC (rev 300)
@@ -33,19 +33,6 @@
 
 #include "MemLeakFindOn.h"
 
-// Handle differing xattr APIs
-#ifdef HAVE_SYS_XATTR_H
-	#if !defined(HAVE_LLISTXATTR) && defined(HAVE_LISTXATTR) && HAVE_DECL_XATTR_NOFOLLOW
-		#define llistxattr(a,b,c) listxattr(a,b,c,XATTR_NOFOLLOW)
-	#endif
-	#if !defined(HAVE_LGETXATTR) && defined(HAVE_GETXATTR) && HAVE_DECL_XATTR_NOFOLLOW
-		#define lgetxattr(a,b,c,d) getxattr(a,b,c,d,0,XATTR_NOFOLLOW)
-	#endif
-	#if !defined(HAVE_LSETXATTR) && defined(HAVE_SETXATTR) && HAVE_DECL_XATTR_NOFOLLOW
-		#define lsetxattr(a,b,c,d,e) setxattr(a,b,c,d,0,(e)|XATTR_NOFOLLOW)
-	#endif
-#endif
-
 // set packing to one byte
 #ifdef STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
 #include "BeginStructPackForWire.h"
@@ -521,18 +508,21 @@
 				int valueSizeOffset = xattrSize;
 				xattrSize += sizeof(u_int32_t);
 
-				// This gets the attribute value (may be text or binary), no termination
-				int valueSize = ::lgetxattr(Filename, attrKey.c_str(), buffer+xattrSize, xattrBufferSize-xattrSize);
+				// 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);
 
+				// Resize block, if needed
 				if(xattrSize+valueSize>xattrBufferSize)
 				{
 					xattrBufferSize = (xattrBufferSize+valueSize)*2;
 					outputBlock.ResizeBlock(xattrBufferSize);
 					buffer = static_cast<unsigned char*>(outputBlock.GetBuffer());
-
-					valueSize = ::lgetxattr(Filename, attrKey.c_str(), buffer+xattrSize, xattrBufferSize-xattrSize);
 				}
 
+				// 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)
 				{
 					THROW_EXCEPTION(CommonException, OSFileError);

Modified: box/trunk/lib/common/BoxPlatform.h
===================================================================
--- box/trunk/lib/common/BoxPlatform.h	2006-01-05 22:01:34 UTC (rev 299)
+++ box/trunk/lib/common/BoxPlatform.h	2006-01-06 10:02:44 UTC (rev 300)
@@ -62,6 +62,19 @@
 	#define STRUCTURE_PACKING_FOR_WIRE_USE_HEADERS
 #endif
 
+// Handle differing xattr APIs
+#ifdef HAVE_SYS_XATTR_H
+	#if !defined(HAVE_LLISTXATTR) && defined(HAVE_LISTXATTR) && HAVE_DECL_XATTR_NOFOLLOW
+		#define llistxattr(a,b,c) listxattr(a,b,c,XATTR_NOFOLLOW)
+	#endif
+	#if !defined(HAVE_LGETXATTR) && defined(HAVE_GETXATTR) && HAVE_DECL_XATTR_NOFOLLOW
+		#define lgetxattr(a,b,c,d) getxattr(a,b,c,d,0,XATTR_NOFOLLOW)
+	#endif
+	#if !defined(HAVE_LSETXATTR) && defined(HAVE_SETXATTR) && HAVE_DECL_XATTR_NOFOLLOW
+		#define lsetxattr(a,b,c,d,e) setxattr(a,b,c,d,0,(e)|XATTR_NOFOLLOW)
+	#endif
+#endif
+
 #if defined WIN32 && !defined __MINGW32__
 	typedef __int8  int8_t;
 	typedef __int16 int16_t;

Modified: box/trunk/test/bbackupd/testbbackupd.cpp
===================================================================
--- box/trunk/test/bbackupd/testbbackupd.cpp	2006-01-05 22:01:34 UTC (rev 299)
+++ box/trunk/test/bbackupd/testbbackupd.cpp	2006-01-06 10:02:44 UTC (rev 300)
@@ -16,6 +16,11 @@
 #include <string.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#ifdef HAVE_SYS_XATTR_H
+#include <cerrno>
+#include <sys/xattr.h>
+#endif
+#include <map>
 
 #include "Test.h"
 #include "BackupClientFileAttributes.h"
@@ -57,12 +62,188 @@
 
 int bbstored_pid = 0;
 
+#ifdef HAVE_SYS_XATTR_H
+bool readxattr_into_map(const char *filename, std::map<std::string,std::string> &rOutput)
+{
+	rOutput.clear();
+	
+	ssize_t xattrNamesBufferSize = llistxattr(filename, NULL, 0);
+	if(xattrNamesBufferSize < 0)
+	{
+		return false;
+	}
+	else if(xattrNamesBufferSize > 0)
+	{
+		// There is some data there to look at
+		char *xattrNamesBuffer = (char*)malloc(xattrNamesBufferSize + 4);
+		if(xattrNamesBuffer == NULL) return false;
+		char *xattrDataBuffer = 0;
+		int xattrDataBufferSize = 0;
+		// note: will leak these buffers if a read error occurs. (test code, so doesn't matter)
+		
+		ssize_t ns = llistxattr(filename, xattrNamesBuffer, xattrNamesBufferSize);
+		if(ns < 0)
+		{
+			return false;
+		}
+		else if(ns > 0)
+		{
+			// Read all the attribute values
+			const char *xattrName = xattrNamesBuffer;
+			while(xattrName < (xattrNamesBuffer + ns))
+			{
+				// Store size of name
+				int xattrNameSize = strlen(xattrName);
+				
+				bool ok = true;
+					
+				ssize_t dataSize = lgetxattr(filename, xattrName, NULL, 0);
+				if(dataSize < 0)
+				{
+					if(errno == ENOATTR)
+					{
+						// Deleted from under us
+						ok = false;
+					}
+					else
+					{
+						return false;
+					}
+				}
+				else if(dataSize == 0)
+				{
+					// something must have removed all the data from under us
+					ok = false;
+				}
+				else
+				{
+					// Make sure there's enough space in the buffer to get the attribute
+					if(xattrDataBuffer == 0)
+					{
+						xattrDataBuffer = (char*)malloc(dataSize + 4);
+						xattrDataBufferSize = dataSize + 4;
+					}
+					else if(xattrDataBufferSize < (dataSize + 4))
+					{
+						char *resized = (char*)realloc(xattrDataBuffer, dataSize + 4);
+						if(resized == NULL) return false;
+						xattrDataBuffer = resized;
+						xattrDataBufferSize = dataSize + 4;
+					}
+				}
+
+				// Read the data!
+				dataSize = 0;
+				if(ok)
+				{
+					dataSize = lgetxattr(filename, xattrName, xattrDataBuffer,
+						xattrDataBufferSize - 1 /*for terminator*/);
+					if(dataSize < 0)
+					{
+						if(errno == ENOATTR)
+						{
+							// Deleted from under us
+							ok = false;
+						}
+						else
+						{
+							return false;
+						}
+					}
+					else if(dataSize == 0)
+					{
+						// something must have deleted this from under us
+						ok = false;
+					}
+					else
+					{
+						// Terminate the data
+						xattrDataBuffer[dataSize] = '\0';
+					}
+					// Got the data in the buffer
+				}
+				
+				// Store in map
+				if(ok)
+				{
+					rOutput[std::string(xattrName)] = std::string(xattrDataBuffer, dataSize);
+				}
+
+				// Next attribute
+				xattrName += xattrNameSize + 1;
+			}
+		}
+		
+		if(xattrNamesBuffer != 0) ::free(xattrNamesBuffer);
+		if(xattrDataBuffer != 0) ::free(xattrDataBuffer);
+	}
+
+	return true;
+}
+
+static FILE *xattrTestDataHandle = 0;
+bool write_xattr_test(const char *filename, const char *attrName, unsigned int length, bool *pNotSupported = 0)
+{
+	if(xattrTestDataHandle == 0)
+	{
+		xattrTestDataHandle = ::fopen("testfiles/test3.tgz", "rb");	// largest test file
+	}
+	if(xattrTestDataHandle == 0)
+	{
+		return false;
+	}
+	else
+	{
+		char data[4096];
+		if(length > sizeof(data)) length = sizeof(data);
+		
+		if(::fread(data, length, 1, xattrTestDataHandle) != 1)
+		{
+			return false;
+		}
+		
+		if(::lsetxattr(filename, attrName, data, length, 0) != 0)
+		{
+			if(pNotSupported != 0)
+			{
+				*pNotSupported = (errno == ENOTSUP);
+			}
+			return false;
+		}
+	}
+
+	return true;
+}
+void finish_with_write_xattr_test()
+{
+	if(xattrTestDataHandle != 0)
+	{
+		::fclose(xattrTestDataHandle);
+	}
+}
+#endif // HAVE_SYS_XATTR_H
+
 bool attrmatch(const char *f1, const char *f2)
 {
 	struct stat s1, s2;
 	TEST_THAT(::lstat(f1, &s1) == 0);
 	TEST_THAT(::lstat(f2, &s2) == 0);
 
+#ifdef HAVE_SYS_XATTR_H
+	{
+		std::map<std::string,std::string> xattr1, xattr2;
+		if(!readxattr_into_map(f1, xattr1)
+			|| !readxattr_into_map(f2, xattr2))
+		{
+			return false;
+		}
+		if(!(xattr1 == xattr2))
+		{
+			return false;
+		}
+	}
+#endif // HAVE_SYS_XATTR_H
+
 	// if link, just make sure other file is a link too, and that the link to names match
 	if((s1.st_mode & S_IFMT) == S_IFLNK)
 	{
@@ -143,6 +324,49 @@
 	TEST_THAT(t1_r == t1b);
 	TEST_THAT(t1b_r == t1);
 
+#ifdef HAVE_SYS_XATTR_H
+	// Write some attributes to the file, checking for ENOTSUP
+	bool xattrNotSupported = false;
+	if(!write_xattr_test("testfiles/test1", "attr_1", 1276, &xattrNotSupported) && xattrNotSupported)
+	{
+		::printf("***********\nYour platform supports xattr, but your filesystem does not.\nSkipping tests.\n***********\n");
+	}
+	else
+	{
+		BackupClientFileAttributes x1, x2, x3, x4;
+
+		// Write more attributes
+		TEST_THAT(write_xattr_test("testfiles/test1", "attr_2", 3427));
+		TEST_THAT(write_xattr_test("testfiles/test1", "sadfohij39998.3hj", 123));
+	
+		// Read file attributes
+		x1.ReadAttributes("testfiles/test1");
+		
+		// Write file attributes
+		FILE *f = fopen("testfiles/test1_nx", "w");
+		fclose(f);
+		x1.WriteAttributes("testfiles/test1_nx");
+		
+		// Compare to see if xattr copied
+		TEST_THAT(attrmatch("testfiles/test1", "testfiles/test1_nx"));
+		
+		// Add more attributes to a file
+		x2.ReadAttributes("testfiles/test1");
+		TEST_THAT(write_xattr_test("testfiles/test1", "328989sj..sdf", 23));
+		
+		// Read them again, and check that the Compare() function detects that they're different
+		x3.ReadAttributes("testfiles/test1");
+		TEST_THAT(x1.Compare(x2, true, true));
+		TEST_THAT(!x1.Compare(x3, true, true));
+		
+		// Change the value of one of them, leaving the size the same.
+		TEST_THAT(write_xattr_test("testfiles/test1", "328989sj..sdf", 23));
+		x4.ReadAttributes("testfiles/test1");
+		TEST_THAT(!x1.Compare(x4, true, true));
+	}
+	finish_with_write_xattr_test();
+#endif // HAVE_SYS_XATTR_H
+
 	return 0;
 }
 




More information about the Boxbackup-dev mailing list