fstreewalk: add option to only call back for skipped names/paths (diags)
This commit is contained in:
parent
ad9e721fab
commit
291b0c32d4
@ -44,6 +44,7 @@ static int op_flags;
|
|||||||
#define OPT_k 0x1000
|
#define OPT_k 0x1000
|
||||||
#define OPT_y 0x2000
|
#define OPT_y 0x2000
|
||||||
#define OPT_s 0x4000
|
#define OPT_s 0x4000
|
||||||
|
#define OPT_S 0x8000
|
||||||
|
|
||||||
class myCB : public FsTreeWalkerCB {
|
class myCB : public FsTreeWalkerCB {
|
||||||
public:
|
public:
|
||||||
@ -64,6 +65,8 @@ public:
|
|||||||
}
|
}
|
||||||
} else if (flg == FsTreeWalker::FtwRegular) {
|
} else if (flg == FsTreeWalker::FtwRegular) {
|
||||||
cout << path << endl;
|
cout << path << endl;
|
||||||
|
} else if (flg == FsTreeWalker::FtwSkipped) {
|
||||||
|
cout << "SKIPPED: " << path << endl;
|
||||||
}
|
}
|
||||||
return FsTreeWalker::FtwOk;
|
return FsTreeWalker::FtwOk;
|
||||||
}
|
}
|
||||||
@ -105,6 +108,7 @@ static char usage [] =
|
|||||||
" -s : don't print dir change info\n"
|
" -s : don't print dir change info\n"
|
||||||
" -w : unset default FNM_PATHNAME when using fnmatch() to match skipped paths\n"
|
" -w : unset default FNM_PATHNAME when using fnmatch() to match skipped paths\n"
|
||||||
" -y <pattern> : add onlyNames entry\n"
|
" -y <pattern> : add onlyNames entry\n"
|
||||||
|
" -S : only print skipped files and directories\n";
|
||||||
;
|
;
|
||||||
static void
|
static void
|
||||||
Usage(void)
|
Usage(void)
|
||||||
@ -150,6 +154,7 @@ int main(int argc, const char **argv)
|
|||||||
goto b1;
|
goto b1;
|
||||||
case 'r': op_flags |= OPT_r; break;
|
case 'r': op_flags |= OPT_r; break;
|
||||||
case 's': op_flags |= OPT_s; break;
|
case 's': op_flags |= OPT_s; break;
|
||||||
|
case 'S': op_flags |= OPT_S; break;
|
||||||
case 'w': op_flags |= OPT_w; break;
|
case 'w': op_flags |= OPT_w; break;
|
||||||
case 'y': op_flags |= OPT_y; if (argc < 2) Usage();
|
case 'y': op_flags |= OPT_y; if (argc < 2) Usage();
|
||||||
onlynames.push_back(*(++argv));
|
onlynames.push_back(*(++argv));
|
||||||
@ -184,6 +189,8 @@ int main(int argc, const char **argv)
|
|||||||
opt |= FsTreeWalker::FtwFollow;
|
opt |= FsTreeWalker::FtwFollow;
|
||||||
if (op_flags & OPT_D)
|
if (op_flags & OPT_D)
|
||||||
opt |= FsTreeWalker::FtwSkipDotFiles;
|
opt |= FsTreeWalker::FtwSkipDotFiles;
|
||||||
|
if (op_flags & OPT_S)
|
||||||
|
opt |= FsTreeWalker::FtwOnlySkipped;
|
||||||
|
|
||||||
if (op_flags & OPT_b)
|
if (op_flags & OPT_b)
|
||||||
opt |= FsTreeWalker::FtwTravBreadth;
|
opt |= FsTreeWalker::FtwTravBreadth;
|
||||||
@ -192,6 +199,7 @@ int main(int argc, const char **argv)
|
|||||||
else if (op_flags & OPT_m)
|
else if (op_flags & OPT_m)
|
||||||
opt |= FsTreeWalker::FtwTravBreadthThenDepth;
|
opt |= FsTreeWalker::FtwTravBreadthThenDepth;
|
||||||
|
|
||||||
|
|
||||||
string reason;
|
string reason;
|
||||||
if (!recollinit(0, 0, 0, reason)) {
|
if (!recollinit(0, 0, 0, reason)) {
|
||||||
fprintf(stderr, "Init failed: %s\n", reason.c_str());
|
fprintf(stderr, "Init failed: %s\n", reason.c_str());
|
||||||
|
|||||||
@ -218,11 +218,7 @@ bool FsTreeWalker::inSkippedPaths(const string& path, bool ckparents)
|
|||||||
|
|
||||||
static inline int slashcount(const string& p)
|
static inline int slashcount(const string& p)
|
||||||
{
|
{
|
||||||
int n = 0;
|
return std::count(p.begin(), p.end(), '/');
|
||||||
for (unsigned int i = 0; i < p.size(); i++)
|
|
||||||
if (p[i] == '/')
|
|
||||||
n++;
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FsTreeWalker::Status FsTreeWalker::walk(const string& _top, FsTreeWalkerCB& cb)
|
FsTreeWalker::Status FsTreeWalker::walk(const string& _top, FsTreeWalkerCB& cb)
|
||||||
@ -302,9 +298,11 @@ FsTreeWalker::Status FsTreeWalker::walk(const string& _top, FsTreeWalkerCB& cb)
|
|||||||
data->logsyserr("stat", nfather);
|
data->logsyserr("stat", nfather);
|
||||||
return errno == ENOENT ? FtwOk : FtwError;
|
return errno == ENOENT ? FtwOk : FtwError;
|
||||||
}
|
}
|
||||||
if ((status = cb.processone(nfather, &st, FtwDirReturn)) &
|
if (!(data->options & FtwOnlySkipped)) {
|
||||||
(FtwStop|FtwError)) {
|
if ((status = cb.processone(nfather, &st, FtwDirReturn)) &
|
||||||
return status;
|
(FtwStop|FtwError)) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,12 +331,18 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
|||||||
|
|
||||||
// Tell user to process the top entry itself
|
// Tell user to process the top entry itself
|
||||||
if (stp->pst_type == PathStat::PST_DIR) {
|
if (stp->pst_type == PathStat::PST_DIR) {
|
||||||
if ((status = cb.processone(top, stp, FtwDirEnter)) &
|
if (!(data->options & FtwOnlySkipped)) {
|
||||||
(FtwStop|FtwError)) {
|
if ((status = cb.processone(top, stp, FtwDirEnter)) &
|
||||||
return status;
|
(FtwStop|FtwError)) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (stp->pst_type == PathStat::PST_REGULAR) {
|
} else if (stp->pst_type == PathStat::PST_REGULAR) {
|
||||||
return cb.processone(top, stp, FtwRegular);
|
if (!(data->options & FtwOnlySkipped)) {
|
||||||
|
return cb.processone(top, stp, FtwRegular);
|
||||||
|
} else {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -406,10 +410,31 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
|||||||
|
|
||||||
// Skipped file names match ?
|
// Skipped file names match ?
|
||||||
if (!data->skippedNames.empty()) {
|
if (!data->skippedNames.empty()) {
|
||||||
if (inSkippedNames(dname))
|
if (inSkippedNames(dname)) {
|
||||||
|
if (data->options & FtwOnlySkipped) {
|
||||||
|
cb.processone(path_cat(top, dname), nullptr, FtwSkipped);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn = path_cat(top, dname);
|
fn = path_cat(top, dname);
|
||||||
|
|
||||||
|
// Skipped file paths match ?
|
||||||
|
if (!data->skippedPaths.empty()) {
|
||||||
|
// We do not check the ancestors. This means that you can have
|
||||||
|
// a topdirs member under a skippedPath, to index a portion of
|
||||||
|
// an ignored area. This is the way it had always worked, but
|
||||||
|
// this was broken by 1.13.00 and the systematic use of
|
||||||
|
// FNM_LEADING_DIR
|
||||||
|
if (inSkippedPaths(fn, false)) {
|
||||||
|
if (data->options & FtwOnlySkipped) {
|
||||||
|
cb.processone(fn, nullptr, FtwSkipped);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int statret = path_fileprops(fn.c_str(), &st, data->options&FtwFollow);
|
int statret = path_fileprops(fn.c_str(), &st, data->options&FtwFollow);
|
||||||
if (statret == -1) {
|
if (statret == -1) {
|
||||||
data->logsyserr("stat", fn);
|
data->logsyserr("stat", fn);
|
||||||
@ -424,22 +449,17 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data->skippedPaths.empty()) {
|
|
||||||
// We do not check the ancestors. This means that you can have
|
|
||||||
// a topdirs member under a skippedPath, to index a portion of
|
|
||||||
// an ignored area. This is the way it had always worked, but
|
|
||||||
// this was broken by 1.13.00 and the systematic use of
|
|
||||||
// FNM_LEADING_DIR
|
|
||||||
if (inSkippedPaths(fn, false))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st.pst_type == PathStat::PST_DIR) {
|
if (st.pst_type == PathStat::PST_DIR) {
|
||||||
if (!o_nowalkfn.empty() && path_exists(path_cat(fn, o_nowalkfn))) {
|
if (!o_nowalkfn.empty() && path_exists(path_cat(fn, o_nowalkfn))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (data->options & FtwNoRecurse) {
|
if (data->options & FtwNoRecurse) {
|
||||||
status = cb.processone(fn, &st, FtwDirEnter);
|
if (!(data->options & FtwOnlySkipped)) {
|
||||||
|
status = cb.processone(fn, &st, FtwDirEnter);
|
||||||
|
} else {
|
||||||
|
status = FtwOk;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (data->options & FtwTravNatural) {
|
if (data->options & FtwTravNatural) {
|
||||||
status = iwalk(fn, &st, cb);
|
status = iwalk(fn, &st, cb);
|
||||||
@ -461,9 +481,11 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
|||||||
if (status & (FtwStop|FtwError))
|
if (status & (FtwStop|FtwError))
|
||||||
goto out;
|
goto out;
|
||||||
if (!(data->options & FtwNoRecurse))
|
if (!(data->options & FtwNoRecurse))
|
||||||
if ((status = cb.processone(top, &st, FtwDirReturn))
|
if (!(data->options & FtwOnlySkipped)) {
|
||||||
& (FtwStop|FtwError))
|
if ((status = cb.processone(top, &st, FtwDirReturn))
|
||||||
goto out;
|
& (FtwStop|FtwError))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
} else if (st.pst_type == PathStat::PST_REGULAR ||
|
} else if (st.pst_type == PathStat::PST_REGULAR ||
|
||||||
st.pst_type == PathStat::PST_SYMLINK) {
|
st.pst_type == PathStat::PST_SYMLINK) {
|
||||||
// Filtering patterns match ?
|
// Filtering patterns match ?
|
||||||
@ -471,9 +493,11 @@ FsTreeWalker::Status FsTreeWalker::iwalk(const string &top,
|
|||||||
if (!inOnlyNames(dname))
|
if (!inOnlyNames(dname))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((status = cb.processone(fn, &st, FtwRegular)) &
|
if (!(data->options & FtwOnlySkipped)) {
|
||||||
(FtwStop|FtwError)) {
|
if ((status = cb.processone(fn, &st, FtwRegular)) &
|
||||||
goto out;
|
(FtwStop|FtwError)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We ignore other file types (devices etc...)
|
// We ignore other file types (devices etc...)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2004 J.F.Dockes
|
/* Copyright (C) 2004-2021 J.F.Dockes
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
@ -25,7 +25,7 @@ struct PathStat;
|
|||||||
class FsTreeWalkerCB;
|
class FsTreeWalkerCB;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class implementing a unix directory recursive walk.
|
* Class implementing a Unix directory recursive walk.
|
||||||
*
|
*
|
||||||
* A user-defined function object is called for every file or
|
* A user-defined function object is called for every file or
|
||||||
* directory. Patterns to be ignored can be set before starting the
|
* directory. Patterns to be ignored can be set before starting the
|
||||||
@ -33,7 +33,7 @@ class FsTreeWalkerCB;
|
|||||||
* on subdirectories.
|
* on subdirectories.
|
||||||
*/
|
*/
|
||||||
class FsTreeWalker {
|
class FsTreeWalker {
|
||||||
public:
|
public:
|
||||||
// Global option to use FNM_PATHNAME when matching paths (for
|
// Global option to use FNM_PATHNAME when matching paths (for
|
||||||
// skippedPaths).
|
// skippedPaths).
|
||||||
// We initially used FNM_PATHNAME, and we can't change it now
|
// We initially used FNM_PATHNAME, and we can't change it now
|
||||||
@ -42,7 +42,7 @@ class FsTreeWalker {
|
|||||||
// a value to the config file (skippedPathsNoFnmPathname)
|
// a value to the config file (skippedPathsNoFnmPathname)
|
||||||
static bool o_useFnmPathname;
|
static bool o_useFnmPathname;
|
||||||
static void setNoFnmPathname() {
|
static void setNoFnmPathname() {
|
||||||
o_useFnmPathname = false;
|
o_useFnmPathname = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global option to observe a "nowalk" file, which makes us treat
|
// Global option to observe a "nowalk" file, which makes us treat
|
||||||
@ -56,22 +56,27 @@ class FsTreeWalker {
|
|||||||
// Flags for call to processone(). FtwDirEnter is used when
|
// Flags for call to processone(). FtwDirEnter is used when
|
||||||
// entering a directory. FtwDirReturn is used when returning to it
|
// entering a directory. FtwDirReturn is used when returning to it
|
||||||
// after processing a subdirectory.
|
// after processing a subdirectory.
|
||||||
enum CbFlag {FtwRegular, FtwDirEnter, FtwDirReturn};
|
enum CbFlag {FtwRegular, FtwDirEnter, FtwDirReturn, FtwSkipped};
|
||||||
enum Status {FtwOk=0, FtwError=1, FtwStop=2,
|
enum Status {FtwOk=0, FtwError=1, FtwStop=2,
|
||||||
FtwStatAll = FtwError|FtwStop};
|
FtwStatAll = FtwError|FtwStop};
|
||||||
enum Options {FtwOptNone = 0, FtwNoRecurse = 1, FtwFollow = 2,
|
enum Options {FtwOptNone = 0, FtwNoRecurse = 1, FtwFollow = 2,
|
||||||
FtwNoCanon = 4, FtwSkipDotFiles = 8,
|
FtwNoCanon = 4, FtwSkipDotFiles = 8,
|
||||||
// Tree walking options. Natural is close to depth first: process
|
// Only callback for skipped files and directories,
|
||||||
// directory entries as we see them, recursing into subdirectories at
|
// for getting a list of skipped stuff. We don't
|
||||||
// once
|
// descend into skipped directories.
|
||||||
// Breadth means we process all files and dirs at a given directory level
|
// ** The callback will receive a null struct stat pointer.**
|
||||||
// before going deeper.
|
FtwOnlySkipped = 0x10,
|
||||||
//
|
// Tree walking options. Natural is close to depth first: process
|
||||||
// FilesThenDirs is close to Natural, except that we process all files in a
|
// directory entries as we see them, recursing into subdirectories at
|
||||||
// given directory before going deeper: allows keeping only a single
|
// once
|
||||||
// directory open
|
// Breadth means we process all files and dirs at a given directory level
|
||||||
// We don't do pure depth first (process subdirs before files), this does
|
// before going deeper.
|
||||||
// not appear to make any sense.
|
//
|
||||||
|
// FilesThenDirs is close to Natural, except that we process all files in a
|
||||||
|
// given directory before going deeper: allows keeping only a single
|
||||||
|
// directory open
|
||||||
|
// We don't do pure depth first (process subdirs before files), this does
|
||||||
|
// not appear to make any sense.
|
||||||
FtwTravNatural = 0x10000, FtwTravBreadth = 0x20000,
|
FtwTravNatural = 0x10000, FtwTravBreadth = 0x20000,
|
||||||
FtwTravFilesThenDirs = 0x40000,
|
FtwTravFilesThenDirs = 0x40000,
|
||||||
FtwTravBreadthThenDepth = 0x80000
|
FtwTravBreadthThenDepth = 0x80000
|
||||||
@ -107,26 +112,26 @@ class FsTreeWalker {
|
|||||||
bool setOnlyNames(const std::vector<std::string> &patterns);
|
bool setOnlyNames(const std::vector<std::string> &patterns);
|
||||||
|
|
||||||
/** Same for skipped paths: this are paths, not names, under which we
|
/** Same for skipped paths: this are paths, not names, under which we
|
||||||
do not descend (ie: /home/me/.recoll) */
|
do not descend (ie: /home/me/.recoll) */
|
||||||
bool addSkippedPath(const std::string &path);
|
bool addSkippedPath(const std::string &path);
|
||||||
/** Set the ignored paths list */
|
/** Set the ignored paths list */
|
||||||
bool setSkippedPaths(const std::vector<std::string> &patterns);
|
bool setSkippedPaths(const std::vector<std::string> &patterns);
|
||||||
|
|
||||||
/** Test if path/name should be skipped. This can be used independently of
|
/** Test if path/name should be skipped. This can be used independently of
|
||||||
* an actual tree walk */
|
* an actual tree walk */
|
||||||
bool inSkippedPaths(const std::string& path, bool ckparents = false);
|
bool inSkippedPaths(const std::string& path, bool ckparents = false);
|
||||||
bool inSkippedNames(const std::string& name);
|
bool inSkippedNames(const std::string& name);
|
||||||
bool inOnlyNames(const std::string& name);
|
bool inOnlyNames(const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Status iwalk(const std::string &dir, struct PathStat *stp,
|
Status iwalk(const std::string &dir, struct PathStat *stp,
|
||||||
FsTreeWalkerCB& cb);
|
FsTreeWalkerCB& cb);
|
||||||
class Internal;
|
class Internal;
|
||||||
Internal *data;
|
Internal *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FsTreeWalkerCB {
|
class FsTreeWalkerCB {
|
||||||
public:
|
public:
|
||||||
virtual ~FsTreeWalkerCB() {}
|
virtual ~FsTreeWalkerCB() {}
|
||||||
// Only st_mtime, st_ctime, st_size, st_mode (filetype bits: dir/reg/lnk),
|
// Only st_mtime, st_ctime, st_size, st_mode (filetype bits: dir/reg/lnk),
|
||||||
virtual FsTreeWalker::Status
|
virtual FsTreeWalker::Status
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user