Switch to side-by-side view

--- a/pxattr.cpp
+++ b/pxattr.cpp
@@ -1,4 +1,4 @@
-/* @(#$Id: pxattr.cpp,v 1.9 2009-01-20 13:48:34 dockes Exp $  (C) 2009 J.F.Dockes
+/*
 Copyright (c) 2009 Jean-Francois Dockes
 
 Permission is hereby granted, free of charge, to any person
@@ -22,6 +22,10 @@
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 */
+
+/** \file pxattr.cpp 
+    \brief This is a comment for file pxattr.cpp 
+ */
 
 // We want this to compile even to empty on non-supported systems. makes
 // things easier for autoconf
@@ -489,128 +493,7 @@
 
 #include "pxattr.h"
 
-static void dotests()
-{
-    static const char *tfn = "pxattr_testtmp.xyz";
-    static const char *NAMES[] = {"ORG.PXATTR.NAME1", "ORG.PXATTR.N2", 
-				  "ORG.PXATTR.LONGGGGGGGGisSSSHHHHHHHHHNAME3"};
-    static const char *VALUES[] = {"VALUE1", "VALUE2", "VALUE3"};
-    static bool verbose = true;
-
-    /* Create test file if it doesn't exist, remove all attributes */
-    int fd = open(tfn, O_RDWR|O_CREAT, 0755);
-    if (fd < 0) {
-	perror("open/create");
-	exit(1);
-    }
-
-
-    if (verbose)
-	fprintf(stdout, "Cleanup old attrs\n");
-    vector<string> names;
-    if (!pxattr::list(tfn, &names)) {
-	perror("pxattr::list");
-	exit(1);
-    }
-    for (vector<string>::const_iterator it = names.begin(); 
-	 it != names.end(); it++) {
-	string value;
-	if (!pxattr::del(fd, *it)) {
-	    perror("pxattr::del");
-	    exit(1);
-	}
-    }
-    /* Check that there are no attributes left */
-    names.clear();
-    if (!pxattr::list(tfn, &names)) {
-	perror("pxattr::list");
-	exit(1);
-    }
-    if (names.size() != 0) {
-	fprintf(stderr, "Attributes remain after initial cleanup !\n");
-	for (vector<string>::const_iterator it = names.begin();
-	     it != names.end(); it++) {
-	    fprintf(stderr, "%s\n", (*it).c_str());
-	}
-	exit(1);
-    }
-
-    /* Create attributes, check existence and value */
-    if (verbose)
-	fprintf(stdout, "Creating extended attributes\n");
-    for (int i = 0; i < 3; i++) {
-	if (!pxattr::set(fd, NAMES[i], VALUES[i])) {
-	    perror("pxattr::set");
-	    exit(1);
-	}
-    }
-    if (verbose)
-	fprintf(stdout, "Checking creation\n");
-    for (int i = 0; i < 3; i++) {
-	string value;
-	if (!pxattr::get(tfn, NAMES[i], &value)) {
-	    perror("pxattr::get");
-	    exit(1);
-	}
-	if (value.compare(VALUES[i])) {
-	    fprintf(stderr, "Wrong value after create !\n");
-	    exit(1);
-	}
-    }
-
-    /* Delete one, check list */
-    if (verbose)
-	fprintf(stdout, "Delete one\n");
-    if (!pxattr::del(tfn, NAMES[1])) {
-	perror("pxattr::del one name");
-	exit(1);
-    }
-    if (verbose)
-	fprintf(stdout, "Check list\n");
-    for (int i = 0; i < 3; i++) {
-	string value;
-	if (!pxattr::get(fd, NAMES[i], &value)) {
-	    if (i == 1)
-		continue;
-	    perror("pxattr::get");
-	    exit(1);
-	} else if (i == 1) {
-	    fprintf(stderr, "Name at index 1 still exists after deletion\n");
-	    exit(1);
-	}
-	if (value.compare(VALUES[i])) {
-	    fprintf(stderr, "Wrong value after delete 1 !\n");
-	    exit(1);
-	}
-    }
-
-    /* Test the CREATE/REPLACE flags */
-    // Set existing with flag CREATE should fail
-    if (verbose)
-	fprintf(stdout, "Testing CREATE/REPLACE flags use\n");
-    if (pxattr::set(tfn, NAMES[0], VALUES[0], pxattr::PXATTR_CREATE)) {
-	fprintf(stderr, "Create existing with flag CREATE succeeded !\n");
-	exit(1);
-    }
-    // Set new with flag REPLACE should fail
-    if (pxattr::set(tfn, NAMES[1], VALUES[1], pxattr::PXATTR_REPLACE)) {
-	fprintf(stderr, "Create new with flag REPLACE succeeded !\n");
-	exit(1);
-    }
-    // Set new with flag CREATE should succeed
-    if (!pxattr::set(fd, NAMES[1], VALUES[1], pxattr::PXATTR_CREATE)) {
-	fprintf(stderr, "Create new with flag CREATE failed !\n");
-	exit(1);
-    }
-    // Set existing with flag REPLACE should succeed
-    if (!pxattr::set(fd, NAMES[0], VALUES[0], pxattr::PXATTR_REPLACE)) {
-	fprintf(stderr, "Create existing with flag REPLACE failed !\n");
-	exit(1);
-    }
-    close(fd);
-    unlink(tfn);
-    exit(0);
-}
+static void dotests();
 
 // \-quote character c in input \ -> \\, nl -> \n cr -> \rc -> \c
 static void quote(const string& in, string& out, int c)
@@ -938,7 +821,227 @@
     exit(0);
 }
 
-
+static void fatal(const string& s)
+{
+    perror(s.c_str());
+    exit(1);
+}
+
+static bool testbackups()
+{
+    static const char *top = "ttop";
+    static const char *d1 = "d1";
+    static const char *d2 = "d2";
+    static const char *tfn1 = "tpxattr1.txt";
+    static const char *tfn2 = "tpxattr2.txt";
+    static const char *dump = "attrdump.txt";
+    static const char *NAMES[] = {"ORG.PXATTR.NAME1", 
+				  "ORG=PXATTR\"=\\=\n", 
+				  "=", "Name4"};
+    static const char *VALUES[] = 
+	{"VALUE1", "VALUE2", "VALUE3=VALUE3equal",
+	 "VALUE4\n is more like"
+	 " normal text\n with new lines and \"\\\" \\\" backslashes"};
+
+    static const int nattrs = sizeof(NAMES) / sizeof(char *);
+
+    if (mkdir(top, 0777))
+	fatal("Cant mkdir ttop");
+    if (chdir(top))
+	fatal("cant chdir ttop");
+    if (mkdir(d1, 0777) || mkdir(d2, 0777))
+	fatal("Can't mkdir ttdop/dx\n");
+    if (chdir(d1))
+	fatal("chdir d1");
+
+    int fd;
+    if ((fd = open(tfn1, O_RDWR|O_CREAT, 0755)) < 0)
+	fatal("create d1/tpxattr1.txt");
+    /* Set attrs */
+    for (int i = 0; i < nattrs; i++) {
+	if (!pxattr::set(fd, NAMES[i], VALUES[i]))
+	    fatal("pxattr::set");
+    }
+    close(fd);
+    if ((fd = open(tfn2, O_RDWR|O_CREAT, 0755)) < 0)
+	fatal("create d1/tpxattr2.txt");
+    /* Set attrs */
+    for (int i = 0; i < nattrs; i++) {
+	if (!pxattr::set(fd, NAMES[i], VALUES[i]))
+	    fatal("pxattr::set");
+    }
+    close(fd);
+
+    /* Create dump */
+    string cmd;
+    cmd = string("pxattr -lR . > " ) + dump;
+    if (system(cmd.c_str()))
+	fatal(cmd + " in d1");
+    if (chdir("../d2"))
+	fatal("chdir ../d2");
+    if (close(open(tfn1, O_RDWR|O_CREAT, 0755)))
+	fatal("create d2/tpxattr.txt");
+    if (close(open(tfn2, O_RDWR|O_CREAT, 0755)))
+	fatal("create d2/tpxattr.txt");
+    cmd = string("pxattr -S ../d1/" ) + dump;
+    if (system(cmd.c_str()))
+	fatal(cmd);
+    cmd = string("pxattr -lR . > " ) + dump;
+    if (system(cmd.c_str()))
+	fatal(cmd + " in d2");
+    cmd = string("diff ../d1/") + dump + " " + dump;
+    if (system(cmd.c_str()))
+	fatal(cmd);
+    cmd = string("cat ") + dump;
+    system(cmd.c_str());
+
+    if (1) {
+	unlink(dump);
+	unlink(tfn1);
+	unlink(tfn2);
+	if (chdir("../d1"))
+	    fatal("chdir ../d1");
+	unlink(dump);
+	unlink(tfn1);
+	unlink(tfn2);
+	if (chdir("../"))
+	    fatal("chdir .. 1");
+	if (rmdir(d1))
+	    fatal("rmdir d1");
+	if (rmdir(d2))
+	    fatal("rmdir d2");
+	if (chdir("../"))
+	    fatal("chdir .. 2");
+	if (rmdir(top))
+	    fatal("rmdir ttop");
+    }
+    return true;
+}
+
+static void dotests()
+{
+    static const char *tfn = "pxattr_testtmp.xyz";
+    static const char *NAMES[] = {"ORG.PXATTR.NAME1", "ORG.PXATTR.N2", 
+				  "ORG.PXATTR.LONGGGGGGGGisSSSHHHHHHHHHNAME3"};
+    static const char *VALUES[] = {"VALUE1", "VALUE2", "VALUE3"};
+    static bool verbose = true;
+
+    /* Create test file if it doesn't exist, remove all attributes */
+    int fd = open(tfn, O_RDWR|O_CREAT, 0755);
+    if (fd < 0) {
+	perror("open/create");
+	exit(1);
+    }
+
+    if (verbose)
+	fprintf(stdout, "Cleanup old attrs\n");
+    vector<string> names;
+    if (!pxattr::list(tfn, &names)) {
+	perror("pxattr::list");
+	exit(1);
+    }
+    for (vector<string>::const_iterator it = names.begin(); 
+	 it != names.end(); it++) {
+	string value;
+	if (!pxattr::del(fd, *it)) {
+	    perror("pxattr::del");
+	    exit(1);
+	}
+    }
+    /* Check that there are no attributes left */
+    names.clear();
+    if (!pxattr::list(tfn, &names)) {
+	perror("pxattr::list");
+	exit(1);
+    }
+    if (names.size() != 0) {
+	fprintf(stderr, "Attributes remain after initial cleanup !\n");
+	for (vector<string>::const_iterator it = names.begin();
+	     it != names.end(); it++) {
+	    fprintf(stderr, "%s\n", (*it).c_str());
+	}
+	exit(1);
+    }
+
+    /* Create attributes, check existence and value */
+    if (verbose)
+	fprintf(stdout, "Creating extended attributes\n");
+    for (int i = 0; i < 3; i++) {
+	if (!pxattr::set(fd, NAMES[i], VALUES[i])) {
+	    perror("pxattr::set");
+	    exit(1);
+	}
+    }
+    if (verbose)
+	fprintf(stdout, "Checking creation\n");
+    for (int i = 0; i < 3; i++) {
+	string value;
+	if (!pxattr::get(tfn, NAMES[i], &value)) {
+	    perror("pxattr::get");
+	    exit(1);
+	}
+	if (value.compare(VALUES[i])) {
+	    fprintf(stderr, "Wrong value after create !\n");
+	    exit(1);
+	}
+    }
+
+    /* Delete one, check list */
+    if (verbose)
+	fprintf(stdout, "Delete one\n");
+    if (!pxattr::del(tfn, NAMES[1])) {
+	perror("pxattr::del one name");
+	exit(1);
+    }
+    if (verbose)
+	fprintf(stdout, "Check list\n");
+    for (int i = 0; i < 3; i++) {
+	string value;
+	if (!pxattr::get(fd, NAMES[i], &value)) {
+	    if (i == 1)
+		continue;
+	    perror("pxattr::get");
+	    exit(1);
+	} else if (i == 1) {
+	    fprintf(stderr, "Name at index 1 still exists after deletion\n");
+	    exit(1);
+	}
+	if (value.compare(VALUES[i])) {
+	    fprintf(stderr, "Wrong value after delete 1 !\n");
+	    exit(1);
+	}
+    }
+
+    /* Test the CREATE/REPLACE flags */
+    // Set existing with flag CREATE should fail
+    if (verbose)
+	fprintf(stdout, "Testing CREATE/REPLACE flags use\n");
+    if (pxattr::set(tfn, NAMES[0], VALUES[0], pxattr::PXATTR_CREATE)) {
+	fprintf(stderr, "Create existing with flag CREATE succeeded !\n");
+	exit(1);
+    }
+    // Set new with flag REPLACE should fail
+    if (pxattr::set(tfn, NAMES[1], VALUES[1], pxattr::PXATTR_REPLACE)) {
+	fprintf(stderr, "Create new with flag REPLACE succeeded !\n");
+	exit(1);
+    }
+    // Set new with flag CREATE should succeed
+    if (!pxattr::set(fd, NAMES[1], VALUES[1], pxattr::PXATTR_CREATE)) {
+	fprintf(stderr, "Create new with flag CREATE failed !\n");
+	exit(1);
+    }
+    // Set existing with flag REPLACE should succeed
+    if (!pxattr::set(fd, NAMES[0], VALUES[0], pxattr::PXATTR_REPLACE)) {
+	fprintf(stderr, "Create existing with flag REPLACE failed !\n");
+	exit(1);
+    }
+    close(fd);
+    unlink(tfn);
+
+    if (testbackups())
+	exit(0);
+    exit(1);
+}
 #endif // Testing pxattr
 
 #endif // Supported systems.