--- a/src/utils/fstreewalk.cpp
+++ b/src/utils/fstreewalk.cpp
@@ -20,6 +20,7 @@
#ifndef TEST_FSTREEWALK
+#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
@@ -58,8 +59,15 @@
};
class FsTreeWalker::Internal {
+public:
+ Internal(int opts)
+ : options(opts), depthswitch(4), maxdepth(-1), errors(0)
+ {
+ }
int options;
int depthswitch;
+ int maxdepth;
+ int basedepth;
stringstream reason;
vector<string> skippedNames;
vector<string> skippedPaths;
@@ -74,29 +82,42 @@
reason << call << "(" << param << ") : " << errno << " : " <<
strerror(errno) << endl;
}
- friend class FsTreeWalker;
};
FsTreeWalker::FsTreeWalker(int opts)
{
- data = new Internal;
+ data = new Internal(opts);
+}
+
+FsTreeWalker::~FsTreeWalker()
+{
+ delete data;
+}
+
+void FsTreeWalker::setOpts(int opts)
+{
if (data) {
data->options = opts;
- data->depthswitch = 4;
- data->errors = 0;
- }
-}
-
-FsTreeWalker::~FsTreeWalker()
-{
- delete data;
-}
-
-void FsTreeWalker::setOpts(Options opts, int depthswitch)
+ }
+}
+int FsTreeWalker::getOpts()
{
if (data) {
- data->options = opts;
- data->depthswitch = depthswitch;
+ return data->options;
+ } else {
+ return 0;
+ }
+}
+void FsTreeWalker::setDepthSwitch(int ds)
+{
+ if (data) {
+ data->depthswitch = ds;
+ }
+}
+void FsTreeWalker::setMaxDepth(int md)
+{
+ if (data) {
+ data->maxdepth = md;
}
}
@@ -198,8 +219,7 @@
data->options |= FtwTravNatural;
}
- int basedepth = slashcount(top); // Only used for breadthThenDepth
-
+ data->basedepth = slashcount(top); // Only used for breadthxx
struct stat st;
// We always follow symlinks at this point. Makes more sense.
if (stat(top.c_str(), &st) == -1) {
@@ -240,7 +260,7 @@
if (data->options & FtwTravBreadthThenDepth) {
// Check if new depth warrants switch to depth first
// traversal (will happen on next loop iteration).
- int curdepth = slashcount(dir) - basedepth;
+ int curdepth = slashcount(dir) - data->basedepth;
if (curdepth >= data->depthswitch) {
//fprintf(stderr, "SWITCHING TO DEPTH FIRST\n");
data->options &= ~FtwTravMask;
@@ -309,6 +329,13 @@
return status;
}
+
+ int curdepth = slashcount(top) - data->basedepth;
+ if (data->maxdepth >= 0 && curdepth >= data->maxdepth) {
+ LOGDEB1(("FsTreeWalker::iwalk: Maxdepth reached: [%s]\n", top.c_str()));
+ return status;
+ }
+
// This is a directory, read it and process entries:
// Detect if directory already seen. This could just be several
@@ -345,6 +372,9 @@
while ((ent = readdir(d)) != 0) {
string fn;
struct stat st;
+ // Maybe skip dotfiles
+ if ((data->options & FtwSkipDotFiles) && ent->d_name[0] == '.')
+ continue;
// Skip . and ..
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
continue;
@@ -439,6 +469,8 @@
#define OPT_m 0x80
#define OPT_L 0x100
#define OPT_w 0x200
+#define OPT_M 0x400
+#define OPT_D 0x800
class myCB : public FsTreeWalkerCB {
public:
@@ -489,6 +521,8 @@
" -d : use almost depth first (dir files, then subdirs)\n"
" -m : use breadth up to 4 deep then switch to -d\n"
" -w : unset default FNM_PATHNAME when using fnmatch() to match skipped paths\n"
+" -M <depth>: limit depth (works with -b/m/d)\n"
+" -D : skip dotfiles\n"
;
static void
Usage(void)
@@ -501,70 +535,80 @@
{
vector<string> patterns;
vector<string> paths;
+ int maxdepth = -1;
+
thisprog = argv[0];
argc--; argv++;
-
- while (argc > 0 && **argv == '-') {
- (*argv)++;
- if (!(**argv))
- /* Cas du "adb - core" */
- Usage();
- while (**argv)
- switch (*(*argv)++) {
- case 'b': op_flags |= OPT_b; break;
- case 'c': op_flags |= OPT_c; break;
- case 'd': op_flags |= OPT_d; break;
- case 'L': op_flags |= OPT_L; break;
- case 'm': op_flags |= OPT_m; break;
- case 'p': op_flags |= OPT_p; if (argc < 2) Usage();
- patterns.push_back(*(++argv));
- argc--;
- goto b1;
- case 'P': op_flags |= OPT_P; if (argc < 2) Usage();
- paths.push_back(*(++argv));
- argc--;
- goto b1;
- case 'r': op_flags |= OPT_r; break;
- case 'w': op_flags |= OPT_w; break;
- default: Usage(); break;
- }
- b1: argc--; argv++;
- }
-
- if (argc != 1)
- Usage();
- string topdir = *argv++;argc--;
-
- int opt = 0;
- if (op_flags & OPT_r)
- opt |= FsTreeWalker::FtwNoRecurse;
- if (op_flags & OPT_c)
- opt |= FsTreeWalker::FtwNoCanon;
- if (op_flags & OPT_L)
- opt |= FsTreeWalker::FtwFollow;
-
- if (op_flags & OPT_b)
- opt |= FsTreeWalker::FtwTravBreadth;
- else if (op_flags & OPT_d)
- opt |= FsTreeWalker::FtwTravFilesThenDirs;
- else if (op_flags & OPT_m)
- opt |= FsTreeWalker::FtwTravBreadthThenDepth;
-
- string reason;
- if (!recollinit(0, 0, reason)) {
- fprintf(stderr, "Init failed: %s\n", reason.c_str());
- exit(1);
- }
- if (op_flags & OPT_w) {
- FsTreeWalker::setNoFnmPathname();
- }
- FsTreeWalker walker(opt);
- walker.setSkippedNames(patterns);
- walker.setSkippedPaths(paths);
- myCB cb;
- walker.walk(topdir, cb);
- if (walker.getErrCnt() > 0)
- cout << walker.getReason();
+ while (argc > 0 && **argv == '-') {
+ (*argv)++;
+ if (!(**argv))
+ /* Cas du "adb - core" */
+ Usage();
+ while (**argv)
+ switch (*(*argv)++) {
+ case 'b': op_flags |= OPT_b; break;
+ case 'c': op_flags |= OPT_c; break;
+ case 'd': op_flags |= OPT_d; break;
+ case 'D': op_flags |= OPT_D; break;
+ case 'L': op_flags |= OPT_L; break;
+ case 'm': op_flags |= OPT_m; break;
+ case 'M': op_flags |= OPT_M; if (argc < 2) Usage();
+ maxdepth = atoi(*(++argv));
+ argc--;
+ goto b1;
+ case 'p': op_flags |= OPT_p; if (argc < 2) Usage();
+ patterns.push_back(*(++argv));
+ argc--;
+ goto b1;
+ case 'P': op_flags |= OPT_P; if (argc < 2) Usage();
+ paths.push_back(*(++argv));
+ argc--;
+ goto b1;
+ case 'r': op_flags |= OPT_r; break;
+ case 'w': op_flags |= OPT_w; break;
+ default: Usage(); break;
+ }
+ b1: argc--; argv++;
+ }
+
+ if (argc != 1)
+ Usage();
+ string topdir = *argv++;argc--;
+
+ int opt = 0;
+ if (op_flags & OPT_r)
+ opt |= FsTreeWalker::FtwNoRecurse;
+ if (op_flags & OPT_c)
+ opt |= FsTreeWalker::FtwNoCanon;
+ if (op_flags & OPT_L)
+ opt |= FsTreeWalker::FtwFollow;
+ if (op_flags & OPT_D)
+ opt |= FsTreeWalker::FtwSkipDotFiles;
+
+ if (op_flags & OPT_b)
+ opt |= FsTreeWalker::FtwTravBreadth;
+ else if (op_flags & OPT_d)
+ opt |= FsTreeWalker::FtwTravFilesThenDirs;
+ else if (op_flags & OPT_m)
+ opt |= FsTreeWalker::FtwTravBreadthThenDepth;
+
+ string reason;
+ if (!recollinit(0, 0, reason)) {
+ fprintf(stderr, "Init failed: %s\n", reason.c_str());
+ exit(1);
+ }
+ if (op_flags & OPT_w) {
+ FsTreeWalker::setNoFnmPathname();
+ }
+ FsTreeWalker walker;
+ walker.setOpts(opt);
+ walker.setMaxDepth(maxdepth);
+ walker.setSkippedNames(patterns);
+ walker.setSkippedPaths(paths);
+ myCB cb;
+ walker.walk(topdir, cb);
+ if (walker.getErrCnt() > 0)
+ cout << walker.getReason();
}
#endif // TEST_FSTREEWALK