merged pxattr versions. main() only, no effect on recoll

This commit is contained in:
Jean-Francois Dockes 2017-07-03 14:17:32 +02:00
parent 61064bcb7d
commit e5fe188127

View File

@ -509,6 +509,8 @@ bool pxname(nspace dom, const string& sname, string* pname)
#else // TEST_PXATTR Testing / driver -> #else // TEST_PXATTR Testing / driver ->
#include "pxattr.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -516,15 +518,33 @@ bool pxname(nspace dom, const string& sname, string* pname)
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <ftw.h> #include <ftw.h>
#include <sys/types.h>
#include <regex.h>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <algorithm> #include <algorithm>
#include <string> #include <string>
using namespace std; using namespace std;
#include "pxattr.h"
static int antiverbose;
static void printsyserr(const string& msg)
{
if (antiverbose >= 2)
return;
cerr << msg << " " << strerror(errno) << endl;
}
#define message(X) \
{ \
if (antiverbose == 0) { \
cout << X; \
} \
}
static void dotests(); static void dotests();
@ -590,19 +610,21 @@ string::size_type find_first_unquoted(const string& in, int c)
} }
return string::npos; return string::npos;
} }
static const string PATH_START("Path: "); static const string PATH_START("Path: ");
static void listattrs(const string& path) static bool listattrs(const string& path)
{ {
vector<string> names; vector<string> names;
if (!pxattr::list(path, &names)) { if (!pxattr::list(path, &names)) {
if (errno == ENOENT) { if (errno == ENOENT) {
return; return false;
} }
perror("pxattr::list"); printsyserr("pxattr::list");
exit(1); exit(1);
} }
if (names.empty()) if (names.empty()) {
return; return true;
}
// Sorting the names would not be necessary but it makes easier comparing // Sorting the names would not be necessary but it makes easier comparing
// backups // backups
@ -610,30 +632,56 @@ static void listattrs(const string& path)
string quoted; string quoted;
quote(path, quoted, 0); quote(path, quoted, 0);
cout << PATH_START << quoted << endl; message(PATH_START << quoted << endl);
for (vector<string>::const_iterator it = names.begin(); for (vector<string>::const_iterator it = names.begin();
it != names.end(); it++) { it != names.end(); it++) {
string value; string value;
if (!pxattr::get(path, *it, &value)) { if (!pxattr::get(path, *it, &value)) {
if (errno == ENOENT) { if (errno == ENOENT) {
return; return false;
} }
perror("pxattr::get"); printsyserr("pxattr::get");
exit(1); exit(1);
} }
quote(*it, quoted, '='); quote(*it, quoted, '=');
cout << " " << quoted << "="; message(" " << quoted << "=");
quote(value, quoted, 0); quote(value, quoted, 0);
cout << quoted << endl; message(quoted << endl);
} }
return true;
} }
void setxattr(const string& path, const string& name, const string& value) bool setxattr(const string& path, const string& name, const string& value)
{ {
if (!pxattr::set(path, name, value)) { if (!pxattr::set(path, name, value)) {
perror("pxattr::set"); printsyserr("pxattr::set");
exit(1); return false;
} }
return true;
}
bool printxattr(const string &path, const string& name)
{
string value;
if (!pxattr::get(path, name, &value)) {
if (errno == ENOENT) {
return false;
}
printsyserr("pxattr::get");
return false;
}
message(PATH_START << path << endl);
message(" " << name << " => " << value << endl);
return true;
}
bool delxattr(const string &path, const string& name)
{
if (pxattr::del(path, name) < 0) {
printsyserr("pxattr::del");
return false;
}
return true;
} }
// Restore xattrs stored in file created by pxattr -lR output // Restore xattrs stored in file created by pxattr -lR output
@ -665,8 +713,8 @@ static void restore(const char *backupnm)
linenum++; linenum++;
} }
// cout << "Got line " << linenum << " : [" << line << "] done " << // message("Got line " << linenum << " : [" << line << "] done " <<
// done << endl; // done << endl);
if (line.find(PATH_START) == 0 || done) { if (line.find(PATH_START) == 0 || done) {
if (!path.empty() && !attrs.empty()) { if (!path.empty() && !attrs.empty()) {
@ -702,38 +750,18 @@ static void restore(const char *backupnm)
} }
} }
void printxattr(const string &path, const string& name)
{
cout << "Path: " << path << endl;
string value;
if (!pxattr::get(path, name, &value)) {
if (errno == ENOENT) {
return;
}
perror("pxattr::get");
exit(1);
}
cout << " " << name << " => " << value << endl;
}
void delxattr(const string &path, const string& name)
{
if (pxattr::del(path, name) < 0) {
perror("pxattr::del");
exit(1);
}
}
static char *thisprog; static char *thisprog;
static char usage [] = static char usage [] =
"pxattr [-h] -n name pathname [...] : show value for name\n" "pxattr [-hs] -n name pathname [...] : show value for name\n"
"pxattr [-h] -n name -v value pathname [...] : add/replace attribute\n" "pxattr [-hs] -n name -r regexp pathname [...] : test value against regexp\n"
"pxattr [-h] -x name pathname [...] : delete attribute\n" "pxattr [-hs] -n name -v value pathname [...] : add/replace attribute\n"
"pxattr [-h] [-l] [-R] pathname [...] : list attribute names and values\n" "pxattr [-hs] -x name pathname [...] : delete attribute\n"
" [-h] : don't follow symbolic links (act on link itself)\n" "pxattr [-hs] [-l] [-R] pathname [...] : list attribute names and values\n"
" [-R] : recursive listing. Args should be directory(ies)\n"
" For all the options above, if no pathname arguments are given, pxattr\n" " For all the options above, if no pathname arguments are given, pxattr\n"
" will read file names on stdin, one per line.\n" " will read file names on stdin, one per line.\n"
" [-h] : don't follow symbolic links (act on link itself)\n"
" [-R] : recursive listing. Args should be directory(ies)\n"
" [-s] : be silent. With one option stdout is suppressed, with 2 stderr too\n"
"pxattr -S <backupfile> Restore xattrs from file created by pxattr -lR output\n" "pxattr -S <backupfile> Restore xattrs from file created by pxattr -lR output\n"
" if backupfile is 'stdin', reads from stdin\n" " if backupfile is 'stdin', reads from stdin\n"
"pxattr -T: run tests on temp file in current directory" "pxattr -T: run tests on temp file in current directory"
@ -748,37 +776,73 @@ Usage(void)
static int op_flags; static int op_flags;
#define OPT_MOINS 0x1 #define OPT_MOINS 0x1
#define OPT_n 0x2 #define OPT_h 0x2
#define OPT_v 0x4 #define OPT_l 0x4
#define OPT_h 0x8 #define OPT_n 0x8
#define OPT_x 0x10 #define OPT_r 0x10
#define OPT_l 0x20 #define OPT_R 0x20
#define OPT_T 0x40 #define OPT_S 0x40
#define OPT_R 0x80 #define OPT_T 0x80
#define OPT_S 0x100 #define OPT_s 0x100
#define OPT_v 0x200
#define OPT_x 0x400
// Static values for ftw
static string name, value; static string name, value;
int processfile(const char* fn, const struct stat *sb, int typeflag) bool regex_test(const char *path, regex_t *preg)
{ {
//cout << "processfile " << fn << " opflags " << op_flags << endl; string value;
if (!pxattr::get(path, name, &value)) {
if (errno == ENOENT) {
return false;
}
printsyserr("pxattr::get");
return false;
}
int ret = regexec(preg, value.c_str(), 0, 0, 0);
if (ret == 0) {
message(path << endl);
return true;
} else if (ret == REG_NOMATCH) {
return false;
} else {
char errmsg[200];
regerror(ret, preg, errmsg, 200);
errno = 0;
printsyserr("regexec");
return false;
}
}
bool processfile(const char* fn, const struct stat *, int)
{
//message("processfile " << fn << " opflags " << op_flags << endl);
if (op_flags & OPT_l) { if (op_flags & OPT_l) {
listattrs(fn); return listattrs(fn);
} else if (op_flags & OPT_n) { } else if (op_flags & OPT_n) {
if (op_flags & OPT_v) { if (op_flags & OPT_v) {
setxattr(fn, name, value); return setxattr(fn, name, value);
} else { } else {
printxattr(fn, name); return printxattr(fn, name);
} }
} else if (op_flags & OPT_x) { } else if (op_flags & OPT_x) {
delxattr(fn, name); return delxattr(fn, name);
} }
Usage();
}
int ftwprocessfile(const char* fn, const struct stat *sb, int typeflag)
{
processfile(fn, sb, typeflag);
return 0; return 0;
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
const char *regexp_string;
thisprog = argv[0]; thisprog = argv[0];
argc--; argv++; argc--; argv++;
@ -794,6 +858,10 @@ int main(int argc, char **argv)
name = *(++argv); argc--; name = *(++argv); argc--;
goto b1; goto b1;
case 'R': op_flags |= OPT_R; break; case 'R': op_flags |= OPT_R; break;
case 'r': op_flags |= OPT_r; if (argc < 2) Usage();
regexp_string = *(++argv); argc--;
goto b1;
case 's': antiverbose++; break;
case 'S': op_flags |= OPT_S; break; case 'S': op_flags |= OPT_S; break;
case 'T': op_flags |= OPT_T; break; case 'T': op_flags |= OPT_T; break;
case 'v': op_flags |= OPT_v; if (argc < 2) Usage(); case 'v': op_flags |= OPT_v; if (argc < 2) Usage();
@ -813,6 +881,9 @@ int main(int argc, char **argv)
dotests(); dotests();
exit(0); exit(0);
} }
if ((op_flags & OPT_r) && !(op_flags & OPT_n)) {
Usage();
}
if (op_flags & OPT_S) { if (op_flags & OPT_S) {
if (argc != 1) if (argc != 1)
@ -820,6 +891,17 @@ int main(int argc, char **argv)
restore(argv[0]); restore(argv[0]);
exit(0); exit(0);
} }
regex_t regexp;
if (op_flags & OPT_r) {
int err = regcomp(&regexp, regexp_string, REG_NOSUB|REG_EXTENDED);
if (err) {
char errmsg[200];
regerror(err, &regexp, errmsg, 200);
cerr << "regcomp(" << regexp_string << ") error: " << errmsg <<
endl;
exit(1);
}
}
// Default option is 'list' // Default option is 'list'
if ((op_flags&(OPT_l|OPT_n|OPT_x)) == 0) if ((op_flags&(OPT_l|OPT_n|OPT_x)) == 0)
@ -829,6 +911,7 @@ int main(int argc, char **argv)
if (argc == 0) if (argc == 0)
readstdin = true; readstdin = true;
int exitvalue = 0;
for (;;) { for (;;) {
const char *fn = 0; const char *fn = 0;
if (argc > 0) { if (argc > 0) {
@ -844,19 +927,25 @@ int main(int argc, char **argv)
break; break;
if (op_flags & OPT_R) { if (op_flags & OPT_R) {
if (ftw(fn, processfile, 20)) if (ftw(fn, ftwprocessfile, 20))
exit(1); exit(1);
} else { } else if (op_flags & OPT_r) {
processfile(fn, 0, 0); if (!regex_test(fn, &regexp)) {
exitvalue = 1;
}
} else {
if (!processfile(fn, 0, 0)) {
exitvalue = 1;
}
} }
} }
exit(0); exit(exitvalue);
} }
static void fatal(const string& s) static void fatal(const string& s)
{ {
perror(s.c_str()); printsyserr(s.c_str());
exit(1); exit(1);
} }
@ -957,115 +1046,113 @@ static void dotests()
static const char *NAMES[] = {"ORG.PXATTR.NAME1", "ORG.PXATTR.N2", static const char *NAMES[] = {"ORG.PXATTR.NAME1", "ORG.PXATTR.N2",
"ORG.PXATTR.LONGGGGGGGGisSSSHHHHHHHHHNAME3"}; "ORG.PXATTR.LONGGGGGGGGisSSSHHHHHHHHHNAME3"};
static const char *VALUES[] = {"VALUE1", "VALUE2", "VALUE3"}; static const char *VALUES[] = {"VALUE1", "VALUE2", "VALUE3"};
static bool verbose = true;
/* Create test file if it doesn't exist, remove all attributes */ /* Create test file if it doesn't exist, remove all attributes */
int fd = open(tfn, O_RDWR|O_CREAT, 0755); int fd = open(tfn, O_RDWR|O_CREAT, 0755);
if (fd < 0) { if (fd < 0) {
perror("open/create"); printsyserr("open/create");
exit(1); exit(1);
} }
if (verbose) if (!antiverbose)
fprintf(stdout, "Cleanup old attrs\n"); message("Cleanup old attrs\n");
vector<string> names; vector<string> names;
if (!pxattr::list(tfn, &names)) { if (!pxattr::list(tfn, &names)) {
perror("pxattr::list"); printsyserr("pxattr::list");
exit(1); exit(1);
} }
for (vector<string>::const_iterator it = names.begin(); for (vector<string>::const_iterator it = names.begin();
it != names.end(); it++) { it != names.end(); it++) {
string value; string value;
if (!pxattr::del(fd, *it)) { if (!pxattr::del(fd, *it)) {
perror("pxattr::del"); printsyserr("pxattr::del");
exit(1); exit(1);
} }
} }
/* Check that there are no attributes left */ /* Check that there are no attributes left */
names.clear(); names.clear();
if (!pxattr::list(tfn, &names)) { if (!pxattr::list(tfn, &names)) {
perror("pxattr::list"); printsyserr("pxattr::list");
exit(1); exit(1);
} }
if (names.size() != 0) { if (names.size() != 0) {
fprintf(stderr, "Attributes remain after initial cleanup !\n"); errno=0;printsyserr("Attributes remain after initial cleanup !\n");
for (vector<string>::const_iterator it = names.begin(); for (vector<string>::const_iterator it = names.begin();
it != names.end(); it++) { it != names.end(); it++) {
fprintf(stderr, "%s\n", (*it).c_str()); if (antiverbose < 2)
cerr << *it << endl;
} }
exit(1); exit(1);
} }
/* Create attributes, check existence and value */ /* Create attributes, check existence and value */
if (verbose) message("Creating extended attributes\n");
fprintf(stdout, "Creating extended attributes\n");
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (!pxattr::set(fd, NAMES[i], VALUES[i])) { if (!pxattr::set(fd, NAMES[i], VALUES[i])) {
perror("pxattr::set"); printsyserr("pxattr::set");
exit(1); exit(1);
} }
} }
if (verbose) message("Checking creation\n");
fprintf(stdout, "Checking creation\n");
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
string value; string value;
if (!pxattr::get(tfn, NAMES[i], &value)) { if (!pxattr::get(tfn, NAMES[i], &value)) {
perror("pxattr::get"); printsyserr("pxattr::get");
exit(1); exit(1);
} }
if (value.compare(VALUES[i])) { if (value.compare(VALUES[i])) {
fprintf(stderr, "Wrong value after create !\n"); errno = 0;
printsyserr("Wrong value after create !");
exit(1); exit(1);
} }
} }
/* Delete one, check list */ /* Delete one, check list */
if (verbose) message("Delete one\n");
fprintf(stdout, "Delete one\n");
if (!pxattr::del(tfn, NAMES[1])) { if (!pxattr::del(tfn, NAMES[1])) {
perror("pxattr::del one name"); printsyserr("pxattr::del one name");
exit(1); exit(1);
} }
if (verbose) message("Check list\n");
fprintf(stdout, "Check list\n");
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
string value; string value;
if (!pxattr::get(fd, NAMES[i], &value)) { if (!pxattr::get(fd, NAMES[i], &value)) {
if (i == 1) if (i == 1)
continue; continue;
perror("pxattr::get"); printsyserr("pxattr::get");
exit(1); exit(1);
} else if (i == 1) { } else if (i == 1) {
fprintf(stderr, "Name at index 1 still exists after deletion\n"); errno=0;
printsyserr("Name at index 1 still exists after deletion\n");
exit(1); exit(1);
} }
if (value.compare(VALUES[i])) { if (value.compare(VALUES[i])) {
fprintf(stderr, "Wrong value after delete 1 !\n"); errno = 0;
printsyserr("Wrong value after delete 1 !");
exit(1); exit(1);
} }
} }
/* Test the CREATE/REPLACE flags */ /* Test the CREATE/REPLACE flags */
// Set existing with flag CREATE should fail // Set existing with flag CREATE should fail
if (verbose) message("Testing CREATE/REPLACE flags use\n");
fprintf(stdout, "Testing CREATE/REPLACE flags use\n");
if (pxattr::set(tfn, NAMES[0], VALUES[0], pxattr::PXATTR_CREATE)) { if (pxattr::set(tfn, NAMES[0], VALUES[0], pxattr::PXATTR_CREATE)) {
fprintf(stderr, "Create existing with flag CREATE succeeded !\n"); errno=0;printsyserr("Create existing with flag CREATE succeeded !\n");
exit(1); exit(1);
} }
// Set new with flag REPLACE should fail // Set new with flag REPLACE should fail
if (pxattr::set(tfn, NAMES[1], VALUES[1], pxattr::PXATTR_REPLACE)) { if (pxattr::set(tfn, NAMES[1], VALUES[1], pxattr::PXATTR_REPLACE)) {
fprintf(stderr, "Create new with flag REPLACE succeeded !\n"); errno=0;printsyserr("Create new with flag REPLACE succeeded !\n");
exit(1); exit(1);
} }
// Set new with flag CREATE should succeed // Set new with flag CREATE should succeed
if (!pxattr::set(fd, NAMES[1], VALUES[1], pxattr::PXATTR_CREATE)) { if (!pxattr::set(fd, NAMES[1], VALUES[1], pxattr::PXATTR_CREATE)) {
fprintf(stderr, "Create new with flag CREATE failed !\n"); errno=0;printsyserr("Create new with flag CREATE failed !\n");
exit(1); exit(1);
} }
// Set existing with flag REPLACE should succeed // Set existing with flag REPLACE should succeed
if (!pxattr::set(fd, NAMES[0], VALUES[0], pxattr::PXATTR_REPLACE)) { if (!pxattr::set(fd, NAMES[0], VALUES[0], pxattr::PXATTR_REPLACE)) {
fprintf(stderr, "Create existing with flag REPLACE failed !\n"); errno=0;printsyserr("Create existing with flag REPLACE failed !\n");
exit(1); exit(1);
} }
close(fd); close(fd);