CernVM-FS  2.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
fs_traversal.h
Go to the documentation of this file.
1 
8 #ifndef CVMFS_FS_TRAVERSAL_H_
9 #define CVMFS_FS_TRAVERSAL_H_
10 
11 #include <errno.h>
12 
13 #include <cassert>
14 #include <cstdlib>
15 
16 #include <set>
17 #include <string>
18 
19 #include "logging.h"
20 #include "platform.h"
21 #include "util/async.h"
22 #include "util/exception.h"
23 
24 #ifdef CVMFS_NAMESPACE_GUARD
25 namespace CVMFS_NAMESPACE_GUARD {
26 #endif
27 
36 template <class T>
38  public:
39  typedef void (T::*VoidCallback)(const std::string &relative_path,
40  const std::string &dir_name);
41  typedef bool (T::*BoolCallback)(const std::string &relative_path,
42  const std::string &dir_name);
43 
44 
45  VoidCallback fn_enter_dir;
46  VoidCallback fn_leave_dir;
47  VoidCallback fn_new_file;
48  VoidCallback fn_new_symlink;
49  VoidCallback fn_new_socket;
50  VoidCallback fn_new_block_dev;
51  VoidCallback fn_new_character_dev;
52  VoidCallback fn_new_fifo;
53 
62  BoolCallback fn_ignore_file;
63 
69  BoolCallback fn_new_dir_prefix;
70 
76  VoidCallback fn_new_dir_postfix;
77 
78 
87  FileSystemTraversal(T *delegate,
88  const std::string &relative_to_directory,
89  const bool recurse) :
90  fn_enter_dir(NULL),
91  fn_leave_dir(NULL),
92  fn_new_file(NULL),
93  fn_new_symlink(NULL),
94  fn_new_socket(NULL),
95  fn_new_block_dev(NULL),
96  fn_new_character_dev(NULL),
97  fn_new_fifo(NULL),
98  fn_ignore_file(NULL),
99  fn_new_dir_prefix(NULL),
100  fn_new_dir_postfix(NULL),
101  delegate_(delegate),
102  relative_to_directory_(relative_to_directory),
103  recurse_(recurse)
104  {
105  Init();
106  }
107 
112  void Recurse(const std::string &dir_path) const {
113  assert(fn_enter_dir != NULL ||
114  fn_leave_dir != NULL ||
115  fn_new_file != NULL ||
116  fn_new_symlink != NULL ||
117  fn_new_dir_prefix != NULL ||
118  fn_new_block_dev != NULL ||
119  fn_new_character_dev != NULL ||
120  fn_new_fifo != NULL ||
121  fn_new_socket != NULL);
122 
123  assert(relative_to_directory_.length() == 0 ||
124  dir_path.substr(0, relative_to_directory_.length()) ==
125  relative_to_directory_);
126 
127  DoRecursion(dir_path, "");
128  }
129 
130  private:
131  // The delegate all hooks are called on
133 
136  bool recurse_;
137 
138 
139  void Init() {
140  }
141 
142  void DoRecursion(const std::string &parent_path, const std::string &dir_name)
143  const
144  {
145  DIR *dip;
146  platform_dirent64 *dit;
147  const std::string path = parent_path + ((!dir_name.empty()) ?
148  ("/" + dir_name) : "");
149 
150  // Change into directory and notify the user
151  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "entering %s (%s -- %s)",
152  path.c_str(), parent_path.c_str(), dir_name.c_str());
153  dip = opendir(path.c_str());
154  if (!dip) {
156  "Failed to open %s (%d).\n"
157  "Please check directory permissions.",
158  path.c_str(), errno);
159  }
160  Notify(fn_enter_dir, parent_path, dir_name);
161 
162  // Walk through the open directory notifying the user about contents
163  while ((dit = platform_readdir(dip)) != NULL) {
164  // Check if file should be ignored
165  if (std::string(dit->d_name) == "." || std::string(dit->d_name) == "..") {
166  continue;
167  } else if (fn_ignore_file != NULL) {
168  if (Notify(fn_ignore_file, path, dit->d_name)) {
169  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "ignoring %s/%s",
170  path.c_str(), dit->d_name);
171  continue;
172  }
173  } else {
175  "not ignoring %s/%s (fn_ignore_file not set)",
176  path.c_str(), dit->d_name);
177  }
178 
179  // Notify user about found directory entry
180  platform_stat64 info;
181  int retval = platform_lstat((path + "/" + dit->d_name).c_str(), &info);
182  if (retval != 0) {
183  PANIC(kLogStderr, "failed to lstat '%s' errno: %d",
184  (path + "/" + dit->d_name).c_str(), errno);
185  }
186  if (S_ISDIR(info.st_mode)) {
187  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing directory %s/%s",
188  path.c_str(), dit->d_name);
189  if (Notify(fn_new_dir_prefix, path, dit->d_name) && recurse_) {
190  DoRecursion(path, dit->d_name);
191  }
192  Notify(fn_new_dir_postfix, path, dit->d_name);
193  } else if (S_ISREG(info.st_mode)) {
194  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing regular file %s/%s",
195  path.c_str(), dit->d_name);
196  Notify(fn_new_file, path, dit->d_name);
197  } else if (S_ISLNK(info.st_mode)) {
198  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing symlink %s/%s",
199  path.c_str(), dit->d_name);
200  Notify(fn_new_symlink, path, dit->d_name);
201  } else if (S_ISSOCK(info.st_mode)) {
202  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing socket %s/%s",
203  path.c_str(), dit->d_name);
204  Notify(fn_new_socket, path, dit->d_name);
205  } else if (S_ISBLK(info.st_mode)) {
206  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing block-device %s/%s",
207  path.c_str(), dit->d_name);
208  Notify(fn_new_block_dev, path, dit->d_name);
209  } else if (S_ISCHR(info.st_mode)) {
210  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing character-device "
211  "%s/%s",
212  path.c_str(), dit->d_name);
213  Notify(fn_new_character_dev, path, dit->d_name);
214  } else if (S_ISFIFO(info.st_mode)) {
215  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing FIFO %s/%s",
216  path.c_str(), dit->d_name);
217  Notify(fn_new_fifo, path, dit->d_name);
218  } else {
219  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "unknown file type %s/%s",
220  path.c_str(), dit->d_name);
221  }
222  }
223 
224  // Close directory and notify user
225  closedir(dip);
226  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "leaving %s", path.c_str());
227  Notify(fn_leave_dir, parent_path, dir_name);
228  }
229 
230  inline bool Notify(const BoolCallback callback,
231  const std::string &parent_path,
232  const std::string &entry_name) const
233  {
234  return (callback == NULL) ? true :
235  (delegate_->*callback)(GetRelativePath(parent_path),
236  entry_name);
237  }
238 
239  inline void Notify(const VoidCallback callback,
240  const std::string &parent_path,
241  const std::string &entry_name) const
242  {
243  if (callback != NULL) {
244  (delegate_->*callback)(GetRelativePath(parent_path),
245  entry_name);
246  }
247  }
248 
249  std::string GetRelativePath(const std::string &absolute_path) const {
250  const unsigned int rel_dir_len = relative_to_directory_.length();
251  if (rel_dir_len >= absolute_path.length()) {
252  return "";
253  } else if (rel_dir_len > 1) {
254  return absolute_path.substr(rel_dir_len + 1);
255  } else if (rel_dir_len == 0) {
256  return absolute_path;
257  } else if (relative_to_directory_ == "/") {
258  return absolute_path.substr(1);
259  }
260 
261  return "";
262  }
263 }; // FileSystemTraversal
264 
265 #ifdef CVMFS_NAMESPACE_GUARD
266 } // namespace CVMFS_NAMESPACE_GUARD
267 #endif
268 
269 #endif // CVMFS_FS_TRAVERSAL_H_
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
struct stat64 platform_stat64
VoidCallback fn_new_symlink
Definition: fs_traversal.h:48
VoidCallback fn_new_character_dev
Definition: fs_traversal.h:51
void Recurse(const std::string &dir_path) const
Definition: fs_traversal.h:112
void DoRecursion(const std::string &parent_path, const std::string &dir_name) const
Definition: fs_traversal.h:142
#define PANIC(...)
Definition: exception.h:26
A simple recursion engine to abstract the recursion of directories. It provides several callback hook...
Definition: fs_traversal.h:37
assert((mem||(size==0))&&"Out Of Memory")
VoidCallback fn_leave_dir
Definition: fs_traversal.h:46
std::string relative_to_directory_
Definition: fs_traversal.h:135
BoolCallback fn_ignore_file
Definition: fs_traversal.h:62
FileSystemTraversal(T *delegate, const std::string &relative_to_directory, const bool recurse)
Definition: fs_traversal.h:87
VoidCallback fn_new_file
Definition: fs_traversal.h:47
VoidCallback fn_enter_dir
Definition: fs_traversal.h:45
std::string GetRelativePath(const std::string &absolute_path) const
Definition: fs_traversal.h:249
bool Notify(const BoolCallback callback, const std::string &parent_path, const std::string &entry_name) const
Definition: fs_traversal.h:230
VoidCallback fn_new_block_dev
Definition: fs_traversal.h:50
int platform_lstat(const char *path, platform_stat64 *buf)
static int Init(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:1755
VoidCallback fn_new_dir_postfix
Definition: fs_traversal.h:76
void Notify(const VoidCallback callback, const std::string &parent_path, const std::string &entry_name) const
Definition: fs_traversal.h:239
VoidCallback fn_new_socket
Definition: fs_traversal.h:49
BoolCallback fn_new_dir_prefix
Definition: fs_traversal.h:69
VoidCallback fn_new_fifo
Definition: fs_traversal.h:52
platform_dirent64 * platform_readdir(DIR *dirp)
const int kLogVerboseMsg
struct dirent64 platform_dirent64