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  int retval = platform_lstat((path + "/" + dit->d_name).c_str(), &info);
173  if (retval != 0) {
174  PANIC(kLogStderr, "failed to lstat '%s' errno: %d",
175  (path + "/" + dit->d_name).c_str(), errno);
176  }
177  if (S_ISDIR(info.st_mode)) {
178  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing directory %s/%s",
179  path.c_str(), dit->d_name);
180  if (Notify(fn_new_dir_prefix, path, dit->d_name) && recurse_) {
181  DoRecursion(path, dit->d_name);
182  }
183  Notify(fn_new_dir_postfix, path, dit->d_name);
184  } else if (S_ISREG(info.st_mode)) {
185  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing regular file %s/%s",
186  path.c_str(), dit->d_name);
187  Notify(fn_new_file, path, dit->d_name);
188  } else if (S_ISLNK(info.st_mode)) {
189  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing symlink %s/%s",
190  path.c_str(), dit->d_name);
191  Notify(fn_new_symlink, path, dit->d_name);
192  } else if (S_ISSOCK(info.st_mode)) {
193  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing socket %s/%s",
194  path.c_str(), dit->d_name);
195  Notify(fn_new_socket, path, dit->d_name);
196  } else if (S_ISBLK(info.st_mode)) {
197  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing block-device %s/%s",
198  path.c_str(), dit->d_name);
199  Notify(fn_new_block_dev, path, dit->d_name);
200  } else if (S_ISCHR(info.st_mode)) {
202  "passing character-device "
203  "%s/%s",
204  path.c_str(), dit->d_name);
205  Notify(fn_new_character_dev, path, dit->d_name);
206  } else if (S_ISFIFO(info.st_mode)) {
207  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "passing FIFO %s/%s",
208  path.c_str(), dit->d_name);
209  Notify(fn_new_fifo, path, dit->d_name);
210  } else {
211  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "unknown file type %s/%s",
212  path.c_str(), dit->d_name);
213  }
214  }
215 
216  // Close directory and notify user
217  closedir(dip);
218  LogCvmfs(kLogFsTraversal, kLogVerboseMsg, "leaving %s", path.c_str());
219  Notify(fn_leave_dir, parent_path, dir_name);
220  }
221 
222  inline bool Notify(const BoolCallback callback,
223  const std::string &parent_path,
224  const std::string &entry_name) const {
225  return (callback == NULL) ? true
226  : (delegate_->*callback)(
227  GetRelativePath(parent_path), entry_name);
228  }
229 
230  inline void Notify(const VoidCallback callback,
231  const std::string &parent_path,
232  const std::string &entry_name) const {
233  if (callback != NULL) {
234  (delegate_->*callback)(GetRelativePath(parent_path), entry_name);
235  }
236  }
237 
238  std::string GetRelativePath(const std::string &absolute_path) const {
239  const unsigned int rel_dir_len = relative_to_directory_.length();
240  if (rel_dir_len >= absolute_path.length()) {
241  return "";
242  } else if (rel_dir_len > 1) {
243  return absolute_path.substr(rel_dir_len + 1);
244  } else if (rel_dir_len == 0) {
245  return absolute_path;
246  } else if (relative_to_directory_ == "/") {
247  return absolute_path.substr(1);
248  }
249 
250  return "";
251  }
252 }; // FileSystemTraversal
253 
254 #ifdef CVMFS_NAMESPACE_GUARD
255 } // namespace CVMFS_NAMESPACE_GUARD
256 #endif
257 
258 #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:238
bool Notify(const BoolCallback callback, const std::string &parent_path, const std::string &entry_name) const
Definition: fs_traversal.h:222
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:2309
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:230
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