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