1 /* Copyright (C) 2004-2021 J.F.Dockes
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the
14  *   Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 #ifndef _FSTREEWALK_H_INCLUDED_
18 #define _FSTREEWALK_H_INCLUDED_
19 
20 #include <string>
21 #include <vector>
22 
23 struct PathStat;
24 
25 class FsTreeWalkerCB;
26 
27 /**
28  * Class implementing a Unix directory recursive walk.
29  *
30  * A user-defined function object is called for every file or
31  * directory. Patterns to be ignored can be set before starting the
32  * walk. Options control whether we follow symlinks and whether we recurse
33  * on subdirectories.
34  */
35 class FsTreeWalker {
36 public:
37     // Global option to use FNM_PATHNAME when matching paths (for
38     // skippedPaths).
39     // We initially used FNM_PATHNAME, and we can't change it now
40     // (because of all the config files around). So add global option
41     // to not use the flag, which can be set from rclconfig by adding
42     // a value to the config file (skippedPathsNoFnmPathname)
43     static bool o_useFnmPathname;
setNoFnmPathname()44     static void setNoFnmPathname() {
45         o_useFnmPathname = false;
46     }
47 
48     // Global option to observe a "nowalk" file, which makes us treat
49     // directories as if they were in skippedPaths) if the file exists
50     // inside the directory.
51     static std::string o_nowalkfn;
setNoWalkFn(const std::string & nowalkfn)52     static void setNoWalkFn(const std::string& nowalkfn) {
53         o_nowalkfn = nowalkfn;
54     }
55 
56     // Flags for call to processone(). FtwDirEnter is used when
57     // entering a directory. FtwDirReturn is used when returning to it
58     // after processing a subdirectory.
59     enum CbFlag {FtwRegular, FtwDirEnter, FtwDirReturn, FtwSkipped};
60     enum Status {FtwOk=0, FtwError=1, FtwStop=2,
61                  FtwStatAll = FtwError|FtwStop};
62     enum Options {FtwOptNone = 0, FtwNoRecurse = 1, FtwFollow = 2,
63                   FtwNoCanon = 4, FtwSkipDotFiles = 8,
64                   // Only callback for skipped files and directories,
65                   // for getting a list of skipped stuff. We don't
66                   // descend into skipped directories.
67                   // ** The callback will receive a null struct stat pointer.**
68                   FtwOnlySkipped = 0x10,
69                   // Tree walking options.  Natural is close to depth first: process
70                   //   directory entries as we see them, recursing into subdirectories at
71                   //   once
72                   // Breadth means we process all files and dirs at a given directory level
73                   // before going deeper.
74                   //
75                   // FilesThenDirs is close to Natural, except that we process all files in a
76                   //   given directory before going deeper: allows keeping only a single
77                   //   directory open
78                   // We don't do pure depth first (process subdirs before files), this does
79                   // not appear to make any sense.
80                   FtwTravNatural = 0x10000, FtwTravBreadth = 0x20000,
81                   FtwTravFilesThenDirs = 0x40000,
82                   FtwTravBreadthThenDepth = 0x80000
83     };
84     static const int FtwTravMask;
85     FsTreeWalker(int opts = FtwTravNatural);
86     ~FsTreeWalker();
87 
88     void setOpts(int opts);
89     int getOpts();
90     void setDepthSwitch(int);
91     void setMaxDepth(int);
92 
93     /**
94      * Begin file system walk.
95      * @param dir is not checked against the ignored patterns (this is
96      *     a feature and must not change.
97      * @param cb the function object that will be called back for every
98      *    file-system object (called both at entry and exit for directories).
99      */
100     Status walk(const std::string &dir, FsTreeWalkerCB& cb);
101     /** Get explanation for error */
102     std::string getReason();
103     int getErrCnt();
104 
105     /**
106      * Add a pattern (file or dir) to be ignored (ie: #* , *~)
107      */
108     bool addSkippedName(const std::string &pattern);
109     /** Set the ignored patterns set */
110     bool setSkippedNames(const std::vector<std::string> &patterns);
111     /** Set the exclusive patterns set */
112     bool setOnlyNames(const std::vector<std::string> &patterns);
113 
114     /** Same for skipped paths: this are paths, not names, under which we
115         do not descend (ie: /home/me/.recoll) */
116     bool addSkippedPath(const std::string &path);
117     /** Set the ignored paths list */
118     bool setSkippedPaths(const std::vector<std::string> &patterns);
119 
120     /** Test if path/name should be skipped. This can be used independently of
121      * an actual tree walk */
122     bool inSkippedPaths(const std::string& path, bool ckparents = false);
123     bool inSkippedNames(const std::string& name);
124     bool inOnlyNames(const std::string& name);
125 
126 private:
127     Status iwalk(const std::string &dir, struct PathStat *stp,
128                  FsTreeWalkerCB& cb);
129     class Internal;
130     Internal *data;
131 };
132 
133 class FsTreeWalkerCB {
134 public:
~FsTreeWalkerCB()135     virtual ~FsTreeWalkerCB() {}
136     // Only st_mtime, st_ctime, st_size, st_mode (filetype bits: dir/reg/lnk),
137     virtual FsTreeWalker::Status
138     processone(const std::string&, const struct PathStat *,
139                FsTreeWalker::CbFlag) = 0;
140 };
141 
142 // Utility function. Somewhat like du.
143 int64_t fsTreeBytes(const std::string& topdir);
144 
145 #endif /* _FSTREEWALK_H_INCLUDED_ */
146