ewmscp  ..
fixGpfsAcls.cpp
Go to the documentation of this file.
1 
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <unistd.h>
5 
6 #include <gpfs.h>
7 #include <string>
8 #include <forward_list>
9 #include <Options.h>
10 #include <throwcall.h>
11 #include <scoped.h>
12 
13 
24 class aclBuffer {
25  gpfs_opaque_acl_t acls;
26  char spaceForData[0x10000 - sizeof(gpfs_opaque_acl_t)];
27  const std::string& path;
28  bool isDir;
30  public:
31  aclBuffer(const std::string& aPath, bool aIsDir = false) : path(aPath), isDir(aIsDir), initialized(false) {
32  acls.acl_buffer_len = sizeof(spaceForData);
33  acls.acl_version = 0;
34  acls.acl_type = GPFS_ACL_TYPE_ACCESS;
35  };
36  operator void* () {
37  if (!initialized) {
38  static const std::string pattern("/.aclgetXXXXXX");
39  std::vector<char> tmpName;
40  tmpName.reserve(path.size() + pattern.size());
41  tmpName.insert(tmpName.end(), path.cbegin(), path.cend());
42  tmpName.insert(tmpName.end(), pattern.cbegin(), pattern.cend());
43  tmpName.push_back('\0');
44  if (isDir) {
45  throwcall::badval(mkdtemp(tmpName.data()), nullptr, "can't create tmp dir '", tmpName.data(), "'");
46  } else {
47  auto fd = throwcall::badval(mkstemp(tmpName.data()), -1, "can't create tmp file '", tmpName.data(), "'");
48  throwcall::good0(close(fd), "can't close ", tmpName.data());
49  }
50  throwcall::good0(gpfs_getacl(tmpName.data(), 0, &acls), "can't get acl for '", tmpName.data(), "'");
51  if (isDir) {
52  throwcall::good0(rmdir(tmpName.data()), "can't remove '", tmpName.data(), "'");
53  } else {
54  throwcall::good0(unlink(tmpName.data()), "can't remove '", tmpName.data(), "'");
55  }
56  initialized = true;
57  }
58  return &acls;
59  }
60 };
61 
62 static unsigned long nDirs = 0;
63 static unsigned long nFiles = 0;
64 
65 
66 void handleDir(const std::string& path) {
67  std::forward_list<std::string> subdirs;
68  {
69  scoped::Dir dir(path);
70  aclBuffer fileAcls(path);
71  while (auto entry = readdir(dir)) {
72  if (entry->d_name[entry->d_name[0] != '.' ? 0 : entry->d_name[1] != '.' ? 1 : 2] == '\0') {
73  continue; // skip . .. and empty strings
74  }
75  struct stat statbuf;
76  throwcall::good0(fstatat(dirfd(dir), entry->d_name, &statbuf, AT_SYMLINK_NOFOLLOW), "can't stat '", entry->d_name, "' in '", path, "'");
77  if (S_ISDIR(statbuf.st_mode)) {
78  subdirs.emplace_front(path + "/" + entry->d_name);
79  } else if (S_ISREG(statbuf.st_mode)) {
80  std::string filePath(path);
81  filePath += "/";
82  filePath += entry->d_name;
83  nFiles++;
84  throwcall::good0(gpfs_putacl(filePath.c_str(), 0, fileAcls), "can't set acl for '", filePath, "'");
85  } else {
86  std::cerr << "ignoring '" << entry->d_name << "' in '" << path << "', it's neither dir nor file\n";
87  }
88  }
89  }
90  if (!subdirs.empty()) {
91  aclBuffer dirAcls(path, true);
92  for (const auto& subdir : subdirs) {
93  nDirs++;
94  throwcall::good0(gpfs_putacl(subdir.c_str(), 0, dirAcls), "can't set acl for '", subdir, "'");
95  }
96  }
97  for (const auto& subdir : subdirs) {
98  handleDir(subdir);
99  }
100 }
101 
102 
103 int main(int argc, const char *argv[]) {
104  options::parser parser(
105  "set the ACLs of the files given on the command line\n"
106  "\t to those they would inherit from theirparent directories.\n"
107  "\tDirectories given on the command line are left unchanged,\n"
108  "\t but all their content is recursively scanned and the ACLs\n"
109  "\t of all their sub-directories and files are set\n"
110  "\t as if freshly inherited.\n"
111  , "", {});
113  "files to be fixed");
114  parser.fParse(argc, argv);
115  std::map<std::string, aclBuffer> fileAcls;
116  for (const auto& file : files) {
117  struct stat statbuf;
118  throwcall::good0(lstat(file.c_str(), &statbuf), "can't stat ", file);
119  if (S_ISDIR(statbuf.st_mode)) {
120  handleDir(file);
121  } else if (S_ISREG(statbuf.st_mode)) {
122  auto lastSlash = file.find_last_of('/');
123  auto dirPath = lastSlash == std::string::npos ? "." : file.substr(0, lastSlash);
124  auto bla = fileAcls.emplace(dirPath, dirPath);
125  nFiles++;
126  throwcall::good0(gpfs_putacl(file.c_str(), 0, bla.first->second), "can't set acl for '", file, "'");
127  } else {
128  std::cerr << "ignoring '" << file << "', it's neither dir nor file\n";
129  }
130  }
131  std::cout << "processed " << nFiles << " files in " << nDirs << " directories\n";
132  return 0;
133 }
options::parser
class that contains the parser, i.e. does that option handling
Definition: Options.h:363
throwcall::badval
T badval(T call, t badvalue, const Args &... args)
template function to wrap system calls that return a special bad value on failure
Definition: throwcall.h:54
main
int main(int argc, const char *argv[])
Definition: fixGpfsAcls.cpp:103
aclBuffer
Definition: fixGpfsAcls.cpp:24
scoped.h
Options.h
aclBuffer::acls
gpfs_opaque_acl_t acls
Definition: fixGpfsAcls.cpp:25
throwcall.h
aclBuffer::initialized
bool initialized
Definition: fixGpfsAcls.cpp:29
handleDir
void handleDir(const std::string &path)
Definition: fixGpfsAcls.cpp:66
aclBuffer::aclBuffer
aclBuffer(const std::string &aPath, bool aIsDir=false)
Definition: fixGpfsAcls.cpp:31
nFiles
static unsigned long nFiles
Definition: fixGpfsAcls.cpp:63
nDirs
static unsigned long nDirs
Definition: fixGpfsAcls.cpp:62
aclBuffer::spaceForData
char spaceForData[0x10000 - sizeof(gpfs_opaque_acl_t)]
Definition: fixGpfsAcls.cpp:26
scoped::Dir
Definition: scoped.h:71
options::positional
Definition: Options.h:876
throwcall::good0
void good0(T call, const Args &... args)
template function to wrap system calls that return 0 on success
Definition: throwcall.h:40
aclBuffer::path
const std::string & path
Definition: fixGpfsAcls.cpp:27
aclBuffer::isDir
bool isDir
Definition: fixGpfsAcls.cpp:28