Switch to unified view

a/src/utils/pxattr.cpp b/src/utils/pxattr.cpp
...
...
403
    }
403
    }
404
    }
404
    }
405
    return true;
405
    return true;
406
}
406
}
407
407
408
static const string cstr_nullstring("");
408
static const string nullstring("");
409
409
410
bool get(const string& path, const string& _name, string *value,
410
bool get(const string& path, const string& _name, string *value,
411
     flags flags, nspace dom)
411
     flags flags, nspace dom)
412
{
412
{
413
    return get(-1, path, _name, value, flags, dom);
413
    return get(-1, path, _name, value, flags, dom);
414
}
414
}
415
bool get(int fd, const string& _name, string *value, flags flags, nspace dom)
415
bool get(int fd, const string& _name, string *value, flags flags, nspace dom)
416
{
416
{
417
    return get(fd, cstr_nullstring, _name, value, flags, dom);
417
    return get(fd, nullstring, _name, value, flags, dom);
418
}
418
}
419
bool set(const string& path, const string& _name, const string& value,
419
bool set(const string& path, const string& _name, const string& value,
420
     flags flags, nspace dom)
420
     flags flags, nspace dom)
421
{
421
{
422
    return set(-1, path, _name, value, flags, dom);
422
    return set(-1, path, _name, value, flags, dom);
423
}
423
}
424
bool set(int fd, const string& _name, const string& value, 
424
bool set(int fd, const string& _name, const string& value, 
425
     flags flags, nspace dom)
425
     flags flags, nspace dom)
426
{
426
{
427
    return set(fd, cstr_nullstring, _name, value, flags, dom);
427
    return set(fd, nullstring, _name, value, flags, dom);
428
}
428
}
429
bool del(const string& path, const string& _name, flags flags, nspace dom) 
429
bool del(const string& path, const string& _name, flags flags, nspace dom) 
430
{
430
{
431
    return del(-1, path, _name, flags, dom);
431
    return del(-1, path, _name, flags, dom);
432
}
432
}
433
bool del(int fd, const string& _name, flags flags, nspace dom) 
433
bool del(int fd, const string& _name, flags flags, nspace dom) 
434
{
434
{
435
    return del(fd, cstr_nullstring, _name, flags, dom);
435
    return del(fd, nullstring, _name, flags, dom);
436
}
436
}
437
bool list(const string& path, vector<string>* names, flags flags, nspace dom)
437
bool list(const string& path, vector<string>* names, flags flags, nspace dom)
438
{
438
{
439
    return list(-1, path, names, flags, dom);
439
    return list(-1, path, names, flags, dom);
440
}
440
}
441
bool list(int fd, vector<string>* names, flags flags, nspace dom)
441
bool list(int fd, vector<string>* names, flags flags, nspace dom)
442
{
442
{
443
    return list(fd, cstr_nullstring, names, flags, dom);
443
    return list(fd, nullstring, names, flags, dom);
444
}
444
}
445
445
446
#if defined(__gnu_linux__) || defined(COMPAT1)
446
static const string cstr_userstring("user.");
447
static const string userstring("user.");
448
#else
449
static const string userstring("");
450
#endif
447
bool sysname(nspace dom, const string& pname, string* sname)
451
bool sysname(nspace dom, const string& pname, string* sname)
448
{
452
{
449
    if (dom != PXATTR_USER) {
453
    if (dom != PXATTR_USER) {
450
    errno = EINVAL;
454
    errno = EINVAL;
451
    return false;
455
    return false;
452
     }
456
     }
453
    *sname = cstr_userstring + pname;
457
    *sname = userstring + pname;
454
    return true;
458
    return true;
455
}
459
}
456
460
457
bool pxname(nspace dom, const string& sname, string* pname) 
461
bool pxname(nspace dom, const string& sname, string* pname) 
458
{
462
{
459
    if (sname.find("user.") != 0) {
463
    if (!userstring.empty() && sname.find(userstring) != 0) {
460
    errno = EINVAL;
464
    errno = EINVAL;
461
    return false;
465
    return false;
462
    }
466
    }
463
    *pname = sname.substr(cstr_userstring.length());
467
    *pname = sname.substr(userstring.length());
464
    return true;
468
    return true;
465
}
469
}
466
470
467
} // namespace pxattr
471
} // namespace pxattr
468
472
469
#else // Testing / driver ->
473
#else // TEST_PXATTR Testing / driver ->
470
474
471
#include <stdio.h>
475
#include <stdio.h>
472
#include <stdlib.h>
476
#include <stdlib.h>
473
#include <unistd.h>
477
#include <unistd.h>
474
#include <fcntl.h>
478
#include <fcntl.h>
475
#include <errno.h>
479
#include <errno.h>
476
#include <string.h>
480
#include <string.h>
481
#include <ftw.h>
477
482
478
#include <iostream>
483
#include <iostream>
484
#include <fstream>
485
#include <map>
486
#include <algorithm>
487
#include <string>
488
using namespace std;
479
489
480
#include "pxattr.h"
490
#include "pxattr.h"
481
482
static char *thisprog;
483
static char usage [] =
484
"pxattr [-h] -n name [-v value] pathname...\n"
485
"pxattr [-h] -x name pathname...\n"
486
"pxattr [-h] -l pathname...\n"
487
" [-h] : don't follow symbolic links (act on link itself)\n"
488
"pxattr -T: run tests on temp file in current directory" 
489
"\n"
490
;
491
static void
492
Usage(void)
493
{
494
    fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
495
    exit(1);
496
}
497
498
static int     op_flags;
499
#define OPT_MOINS 0x1
500
#define OPT_n   0x2 
501
#define OPT_v   0x4 
502
#define OPT_h     0x8
503
#define OPT_x     0x10
504
#define OPT_l     0x20
505
#define OPT_T     0x40
506
491
507
static void dotests()
492
static void dotests()
508
{
493
{
509
    static const char *tfn = "pxattr_testtmp.xyz";
494
    static const char *tfn = "pxattr_testtmp.xyz";
510
    static const char *NAMES[] = {"ORG.PXATTR.NAME1", "ORG.PXATTR.N2", 
495
    static const char *NAMES[] = {"ORG.PXATTR.NAME1", "ORG.PXATTR.N2", 
...
...
625
    close(fd);
610
    close(fd);
626
    unlink(tfn);
611
    unlink(tfn);
627
    exit(0);
612
    exit(0);
628
}
613
}
629
614
615
// \-quote character c in input \ -> \\, nl -> \n cr -> \rc -> \c
616
static void quote(const string& in, string& out, int c)
617
{
618
    out.clear();
619
    for (string::const_iterator it = in.begin(); it != in.end(); it++) {
620
  if (*it == '\\') {
621
      out += "\\\\";
622
  } else if (*it == "\n"[0]) {
623
      out += "\\n";
624
  } else if (*it == "\r"[0]) {
625
      out += "\\r";
626
  } else if (*it == c) {
627
      out += "\\";
628
      out += c;
629
  } else {
630
      out += *it;
631
  }
632
    }
633
}
634
635
// \-unquote input \n -> nl, \r -> cr, \c -> c
636
static void unquote(const string& in, string& out)
637
{
638
    out.clear();
639
    for (unsigned int i = 0; i < in.size(); i++) {
640
  if (in[i] == '\\') {
641
      if (i == in.size() -1) {
642
      out += in[i];
643
      } else {
644
      int c = in[++i];
645
      switch (c) {
646
      case 'n': out += "\n";break;
647
      case 'r': out += "\r";break;
648
      default: out += c;
649
      }
650
      }
651
  } else {
652
      out += in[i];
653
  }
654
    }
655
}
656
657
// Find first unquoted c in input: c preceded by odd number of backslashes
658
string::size_type find_first_unquoted(const string& in, int c)
659
{
660
    int q = 0;
661
    for (unsigned int i = 0;i < in.size(); i++) {
662
  if (in[i] == '\\') {
663
      q++;
664
  } else if (in[i] == c) {
665
      if (q&1) {
666
      // quoted
667
      q = 0;
668
      } else {
669
      return i;
670
      }
671
  } else {
672
      q = 0;
673
  }
674
    }
675
    return string::npos;
676
}
677
static const string PATH_START("Path: ");
630
static void listattrs(const string& path)
678
static void listattrs(const string& path)
631
{
679
{
632
    std::cout << "Path: " << path << std::endl;
633
    vector<string> names;
680
    vector<string> names;
634
    if (!pxattr::list(path, &names)) {
681
    if (!pxattr::list(path, &names)) {
682
  if (errno == ENOENT) {
683
      return;
684
  }
635
    perror("pxattr::list");
685
    perror("pxattr::list");
636
    exit(1);
686
    exit(1);
637
    }
687
    }
688
    if (names.empty())
689
  return;
690
691
    // Sorting the names would not be necessary but it makes easier comparing
692
    // backups
693
    sort(names.begin(), names.end());
694
695
    string quoted;
696
    quote(path, quoted, 0);
697
    cout << PATH_START << quoted << endl;
638
    for (vector<string>::const_iterator it = names.begin(); 
698
    for (vector<string>::const_iterator it = names.begin(); 
639
     it != names.end(); it++) {
699
     it != names.end(); it++) {
640
    string value;
700
    string value;
641
    if (!pxattr::get(path, *it, &value)) {
701
    if (!pxattr::get(path, *it, &value)) {
702
      if (errno == ENOENT) {
703
      return;
704
      }
642
        perror("pxattr::get");
705
        perror("pxattr::get");
643
        exit(1);
706
        exit(1);
644
    }
707
    }
645
  std::cout << " " << *it << " => " << value << std::endl;
708
  quote(*it, quoted, '=');
709
  cout << " " << quoted << "=";
710
  quote(value, quoted, 0);
711
  cout << quoted << endl;
646
    }
712
    }
647
}
713
}
648
714
649
void setxattr(const string& path, const string& name, const string& value)
715
void setxattr(const string& path, const string& name, const string& value)
650
{
716
{
...
...
652
    perror("pxattr::set");
718
    perror("pxattr::set");
653
    exit(1);
719
    exit(1);
654
    }
720
    }
655
}
721
}
656
722
723
// Restore xattrs stored in file created by pxattr -lR output
724
static void restore(const char *backupnm)
725
{
726
    istream *input;
727
    ifstream fin;
728
    if (!strcmp(backupnm, "stdin")) {
729
  input = &cin;
730
    } else {
731
  fin.open(backupnm, ios::in);
732
  input = &fin;
733
    }
734
735
    bool done = false;
736
    int linenum = 0;
737
    string path;
738
    map<string, string> attrs;
739
    while (!done) {
740
  string line;
741
  getline(*input, line);
742
  if (!input->good()) {
743
      if (input->bad()) {
744
                cerr << "Input I/O error" << endl;
745
      exit(1);
746
      }
747
      done = true;
748
  } else {
749
      linenum++;
750
  }
751
752
  // cout << "Got line " << linenum << " : [" << line << "] done " << 
753
  // done << endl;
754
755
  if (line.find(PATH_START) == 0 || done) {
756
      if (!path.empty() && !attrs.empty()) {
757
      for (map<string,string>::const_iterator it = attrs.begin();
758
           it != attrs.end(); it++) {
759
          setxattr(path, it->first, it->second);
760
      }
761
      }
762
      if (!done) {
763
      line = line.substr(PATH_START.size(), string::npos);
764
      unquote(line, path);
765
      attrs.clear();
766
      }
767
  } else if (line.empty()) {
768
      continue;
769
  } else {
770
      // Should be attribute line
771
      if (line[0] != ' ') {
772
      cerr << "Found bad line (no space) at " << linenum << endl;
773
      exit(1);
774
      }
775
      string::size_type pos = find_first_unquoted(line, '=');
776
      if (pos == string::npos || pos < 2 || pos >= line.size()) {
777
      cerr << "Found bad line at " << linenum << endl;
778
      exit(1);
779
      }
780
      string qname = line.substr(1, pos-1);
781
      pair<string,string> entry;
782
      unquote(qname, entry.first);
783
      unquote(line.substr(pos+1), entry.second);
784
      attrs.insert(entry);
785
  }
786
    }
787
}
788
657
void  printxattr(const string &path, const string& name)
789
void  printxattr(const string &path, const string& name)
658
{
790
{
659
    std::cout << "Path: " << path << std::endl;
791
    cout << "Path: " << path << endl;
660
    string value;
792
    string value;
661
    if (!pxattr::get(path, name, &value)) {
793
    if (!pxattr::get(path, name, &value)) {
794
  if (errno == ENOENT) {
795
      return;
796
  }
662
    perror("pxattr::get");
797
    perror("pxattr::get");
663
    exit(1);
798
    exit(1);
664
    }
799
    }
665
    std::cout << " " << name << " => " << value << std::endl;
800
    cout << " " << name << " => " << value << endl;
666
}
801
}
667
802
668
void delxattr(const string &path, const string& name) 
803
void delxattr(const string &path, const string& name) 
669
{
804
{
670
    if (pxattr::del(path, name) < 0) {
805
    if (pxattr::del(path, name) < 0) {
671
    perror("pxattr::del");
806
    perror("pxattr::del");
672
    exit(1);
807
    exit(1);
673
    }
808
    }
674
}
809
}
675
810
811
static char *thisprog;
812
static char usage [] =
813
"pxattr [-h] -n name pathname [...] : show value for name\n"
814
"pxattr [-h] -n name -v value pathname [...] : add/replace attribute\n"
815
"pxattr [-h] -x name pathname [...] : delete attribute\n"
816
"pxattr [-h] [-l] [-R] pathname [...] : list attribute names and values\n"
817
" [-h] : don't follow symbolic links (act on link itself)\n"
818
" [-R] : recursive listing. Args should be directory(ies)\n"
819
"  For all the options above, if no pathname arguments are given, pxattr\n"
820
"  will read file names on stdin, one per line.\n"
821
"pxattr -S <backupfile> Restore xattrs from file created by pxattr -lR output\n"
822
"               if backupfile is 'stdin', reads from stdin\n"
823
"pxattr -T: run tests on temp file in current directory" 
824
"\n"
825
;
826
static void
827
Usage(void)
828
{
829
    fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
830
    exit(1);
831
}
832
833
static int     op_flags;
834
#define OPT_MOINS 0x1
835
#define OPT_n   0x2 
836
#define OPT_v   0x4 
837
#define OPT_h     0x8
838
#define OPT_x     0x10
839
#define OPT_l     0x20
840
#define OPT_T     0x40
841
#define OPT_R     0x80
842
#define OPT_S     0x100
843
844
static string name, value;
845
846
int processfile(const char* fn, const struct stat *sb, int typeflag)
847
{
848
    //cout << "processfile " << fn << " opflags " << op_flags << endl;
849
850
    if (op_flags & OPT_l) {
851
  listattrs(fn);
852
    } else if (op_flags & OPT_n) {
853
  if (op_flags & OPT_v) {
854
      setxattr(fn, name, value);
855
  } else {
856
      printxattr(fn, name);
857
  } 
858
    } else if (op_flags & OPT_x) {
859
  delxattr(fn, name);
860
    } 
861
    return 0;
862
}
676
863
677
int main(int argc, char **argv)
864
int main(int argc, char **argv)
678
{
865
{
679
  thisprog = argv[0];
866
    thisprog = argv[0];
680
  argc--; argv++;
867
    argc--; argv++;
681
868
682
  string name, value;
683
684
  while (argc > 0 && **argv == '-') {
869
    while (argc > 0 && **argv == '-') {
685
    (*argv)++;
870
  (*argv)++;
686
    if (!(**argv))
871
  if (!(**argv))
687
      /* Cas du "adb - core" */
872
      /* Cas du "adb - core" */
688
      Usage();
873
      Usage();
689
    while (**argv)
874
  while (**argv)
690
      switch (*(*argv)++) {
875
      switch (*(*argv)++) {
691
      case 'T':   op_flags |= OPT_T; break;
692
      case 'l':  op_flags |= OPT_l; break;
876
      case 'l':  op_flags |= OPT_l; break;
693
      case 'x':   op_flags |= OPT_x; if (argc < 2)  Usage();
694
    name = *(++argv); argc--; 
695
  goto b1;
696
      case 'n':  op_flags |= OPT_n; if (argc < 2)  Usage();
877
      case 'n':  op_flags |= OPT_n; if (argc < 2)  Usage();
697
      name = *(++argv); argc--; 
878
      name = *(++argv); argc--; 
698
    goto b1;
879
     goto b1;
880
      case 'R':   op_flags |= OPT_R; break;
881
      case 'S':   op_flags |= OPT_S; break;
882
      case 'T':   op_flags |= OPT_T; break;
699
      case 'v':  op_flags |= OPT_v; if (argc < 2)  Usage();
883
      case 'v':  op_flags |= OPT_v; if (argc < 2)  Usage();
700
      value = *(++argv); argc--; 
884
      value = *(++argv); argc--; 
701
    goto b1;
885
     goto b1;
886
      case 'x':   op_flags |= OPT_x; if (argc < 2)  Usage();
887
      name = *(++argv); argc--; 
888
      goto b1;
702
      default: Usage();  break;
889
      default: Usage();  break;
703
      }
890
      }
704
  b1: argc--; argv++;
891
    b1: argc--; argv++;
705
  }
892
    }
706
893
707
  if (argc < 1 && !(op_flags & OPT_T))
894
    if (op_flags & OPT_T)  {
895
  if (argc > 0)
708
    Usage();
896
      Usage();
709
  if (op_flags & OPT_l) {
897
  dotests();
710
      while (argc > 0) {
898
  exit(0);
711
    listattrs(*argv++);argc--;
712
      } 
899
    }
713
  } else if (op_flags & OPT_n) {
900
714
      if (op_flags & OPT_v) {
901
    if (op_flags & OPT_S)  {
715
    while (argc > 0) {
902
  if (argc != 1)
716
        setxattr(*argv++, name, value);argc--;
903
      Usage();
717
    } 
904
  restore(argv[0]);
718
      } else {
905
  exit(0);
719
    while (argc > 0) {
720
        printxattr(*argv++, name);argc--;
721
    } 
722
      }
906
    }
907
908
    // Default option is 'list'
909
    if ((op_flags&(OPT_l|OPT_n|OPT_x)) == 0)
910
  op_flags |= OPT_l;
911
912
    bool readstdin = false;
913
    if (argc == 0)
914
  readstdin = true;
915
916
    for (;;) {
917
  const char *fn = 0;
918
  if (argc > 0) {
919
      fn = *argv++; 
920
      argc--;
921
  } else if (readstdin) {
922
      static char filename[1025];
923
      if (!fgets(filename, 1024, stdin))
924
      break;
925
      filename[strlen(filename)-1] = 0;
926
      fn = filename;
927
  } else
928
      break;
929
723
  } else if (op_flags & OPT_x) {
930
  if (op_flags & OPT_R) {
724
      while (argc > 0) {
931
      if (ftw(fn, processfile, 20))
725
    delxattr(*argv++, name);argc--;
932
      exit(1);
933
  } else {
934
      processfile(fn, 0, 0);
935
  }
726
      } 
936
    } 
727
  } else if (op_flags & OPT_T)  {
937
728
      dotests();
729
  }
730
  exit(0);
938
    exit(0);
731
}
939
}
732
940
733
941
734
#endif // Testing pxattr
942
#endif // Testing pxattr
735
943