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