1 /*********************************************************************/ 2 // dar - disk archive - a backup/restoration program 3 // Copyright (C) 2002-2052 Denis Corbin 4 // 5 // This program is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU General Public License 7 // as published by the Free Software Foundation; either version 2 8 // of the License, or (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 // 19 // to contact the author : http://dar.linux.free.fr/email.html 20 /*********************************************************************/ 21 22 /// \file mask.hpp 23 /// \brief here lies a collection of mask classes 24 /// 25 /// The mask classes defined here are to be used to filter files 26 /// in the libdar API calls. 27 /// \ingroup API 28 29 #ifndef MASK_HPP 30 #define MASK_HPP 31 32 #include "../my_config.h" 33 34 extern "C" 35 { 36 #if HAVE_UNISTD_H 37 #include <unistd.h> 38 #endif 39 40 #if HAVE_REGEX_H 41 #include <regex.h> 42 #endif 43 } // end extern "C" 44 45 #include <string> 46 #include <vector> 47 48 #include "path.hpp" 49 #include "on_pool.hpp" 50 #include "tools.hpp" 51 52 namespace libdar 53 { 54 55 /// \addtogroup API 56 /// @{ 57 58 /// the generic class, parent of all masks 59 60 /// this is a pure virtual class that is used in API call 61 /// any of the following mask classes inherit from this class 62 class mask : public on_pool 63 { 64 public : ~mask()65 virtual ~mask() {}; 66 67 /// check wether the given string is covered by the mask 68 69 /// \param[in] expression is the filename to check 70 /// \return true if the given filename is covered by the mask 71 /// \note only libdar internally needs to call this method 72 virtual bool is_covered(const std::string &expression) const = 0; 73 74 /// check whether the given path is covered by the mask 75 76 /// \param[in] chemin is the path to check 77 /// \return true if the given path is covered by the mask 78 /// \note only libdar internally needs to call this method 79 /// \note this is an optional method to the previous one, it can be overwritten is_covered(const path & chemin) const80 virtual bool is_covered(const path & chemin) const { return is_covered(chemin.display()); }; 81 82 /// dump in human readable form the nature of the mask 83 84 /// \param[in] prefix used for indentation withing the output string 85 virtual std::string dump(const std::string & prefix = "") const = 0; 86 87 /// this is to be able to copy a mask without knowing its 88 /// exact class and without loosing its specialized data 89 virtual mask *clone() const = 0; 90 }; 91 92 93 /// boolean mask, either always true or false 94 95 /// it matches all files or no files at all 96 class bool_mask : public mask 97 { 98 public : 99 /// the constructor 100 101 /// \param[in] always is the value that this mask will always return 102 /// when the is_covered method will be used 103 /// \note once initialized an object cannot change its behavior bool_mask(bool always)104 bool_mask(bool always) { val = always; }; 105 106 /// inherited from the mask class is_covered(const std::string & expression) const107 bool is_covered(const std::string & expression) const { return val; }; is_covered(const path & chemin) const108 bool is_covered(const path & chemin) const { return val; }; dump(const std::string & prefix) const109 std::string dump(const std::string & prefix) const { return prefix + (val ? gettext("TRUE") : gettext("FALSE")); }; 110 111 /// inherited from the mask class clone() const112 mask *clone() const { return new (get_pool()) bool_mask(val); }; 113 114 private : 115 bool val; 116 }; 117 118 119 /// matches as done on shell command lines (see "man 7 glob") 120 121 class simple_mask : public mask 122 { 123 public : 124 125 /// the constructor to use by libdar external programs 126 127 /// \param[in] wilde_card_expression is the glob expression that defines the mask 128 /// \param[in] case_sensit whether the mask is case sensitive or not 129 simple_mask(const std::string & wilde_card_expression, bool case_sensit); 130 /// copy constructor simple_mask(const simple_mask & m)131 simple_mask(const simple_mask & m) : mask(m) { copy_from(m); }; 132 /// assignment operator 133 const simple_mask & operator = (const simple_mask & m); 134 135 /// inherited from the mask class 136 bool is_covered(const std::string &expression) const; 137 138 /// inherited from the mask class 139 std::string dump(const std::string & prefix) const; 140 141 /// inherited from the mask class clone() const142 mask *clone() const { return new (get_pool()) simple_mask(*this); }; 143 144 private : 145 std::string the_mask; 146 bool case_s; 147 148 void copy_from(const simple_mask & m); 149 }; 150 151 152 /// matches regular expressions (see "man 7 regex") 153 154 class regular_mask : public mask 155 { 156 public : 157 158 /// the constructor to be used by libdar external programs 159 160 /// \param[in] wilde_card_expression is the regular expression that defines the mask 161 /// \param[in] x_case_sensit whether the mask is case sensitive or not 162 regular_mask(const std::string & wilde_card_expression, 163 bool x_case_sensit); 164 /// the copy constructor 165 regular_mask(const regular_mask & ref); 166 /// the assignment operator 167 regular_mask & operator= (const regular_mask & ref); 168 169 /// destructor ~regular_mask()170 virtual ~regular_mask() { regfree(&preg); }; 171 172 /// inherited from the mask class 173 bool is_covered(const std::string & expression) const; 174 175 /// inherited from the mask class 176 std::string dump(const std::string & prefix) const; 177 178 /// inherited from the mask class clone() const179 mask *clone() const { return new (get_pool()) regular_mask(*this); }; 180 181 private : 182 regex_t preg; 183 std::string mask_exp; //< used only by the copy constructor 184 bool case_sensit; //< used only by the copy constructor 185 186 void set_preg(const std::string & wilde_card_expression, 187 bool x_case_sensit); 188 }; 189 190 191 /// negation of another mask 192 193 /// this is the first mask built over masks 194 /// it realizes the negation of the given mask 195 class not_mask : public mask 196 { 197 public : 198 /// the constructor to be used by libdar external programs 199 200 /// \param[in] m is the mask to negate 201 /// \note the mask used as argument need not to survive the just created not_mask object 202 /// as an internal copy of the mask given in argument has been done. not_mask(const mask & m)203 not_mask(const mask &m) { copy_from(m); }; 204 /// copy constructor not_mask(const not_mask & m)205 not_mask(const not_mask & m) : mask(m) { copy_from(m); }; 206 /// assignment operator 207 const not_mask & operator = (const not_mask & m); 208 /// destructor ~not_mask()209 ~not_mask() { detruit(); }; 210 211 /// inherited from the mask class is_covered(const std::string & expression) const212 bool is_covered(const std::string &expression) const { return !ref->is_covered(expression); }; is_covered(const path & chemin) const213 bool is_covered(const path & chemin) const { return !ref->is_covered(chemin); }; 214 std::string dump(const std::string & prefix) const; 215 216 /// inherited from the mask class clone() const217 mask *clone() const { return new (get_pool()) not_mask(*this); }; 218 219 private : 220 mask *ref; 221 222 void copy_from(const not_mask &m); 223 void copy_from(const mask &m); 224 void detruit(); 225 }; 226 227 228 /// makes an *AND* operator between two or more masks 229 230 class et_mask : public mask 231 { 232 public : 233 234 /// the constructor to be used by libdar external programs 235 236 /// \note at this stage the mask is not usable and will 237 /// throw an exception until some mask are added to the *AND* 238 /// thanks to the add_mask() method et_mask()239 et_mask() {}; 240 /// copy constructor et_mask(const et_mask & m)241 et_mask(const et_mask &m) : mask(m) { copy_from(m); }; 242 /// assignment operator 243 const et_mask & operator = (const et_mask &m); 244 /// destructor ~et_mask()245 ~et_mask() { detruit(); }; 246 247 248 /// add a mask to the operator 249 250 /// \param[in] toadd a mask to add to the *AND* operator 251 /// \note the mask given in argument has not to survive the et_mask to which it has been added 252 /// a internal copy of the mask has been done. 253 void add_mask(const mask & toadd); 254 255 /// inherited from the mask class is_covered(const std::string & expression) const256 bool is_covered(const std::string & expression) const { return t_is_covered(expression); }; is_covered(const path & chemin) const257 bool is_covered(const path & chemin) const { return t_is_covered(chemin); }; dump(const std::string & prefix) const258 std::string dump(const std::string & prefix) const { return dump_logical(prefix, gettext("AND")); }; 259 260 /// inherited from the mask class clone() const261 mask *clone() const { return new (get_pool()) et_mask(*this); }; 262 263 /// the number of mask on which is done the *AND* operator 264 265 /// \return the number of mask that has been added thanks to the add_mask() method 266 /// \note there is no mean to remove a given mask once it has been added (see the clear method) size() const267 U_I size() const { return lst.size(); }; 268 269 /// clear the mask 270 271 /// remove all previously added masks 272 /// \note that after this call the mask is no more usable as the *AND* operator cannot be done 273 /// on any mask clear()274 void clear() { detruit(); }; 275 276 protected : 277 std::vector<mask *> lst; 278 279 std::string dump_logical(const std::string & prefix, const std::string & boolop) const; 280 281 private : 282 void copy_from(const et_mask & m); 283 void detruit(); 284 t_is_covered(const T & expression) const285 template<class T> bool t_is_covered(const T & expression) const 286 { 287 std::vector<mask *>::const_iterator it = lst.begin(); 288 289 if(lst.empty()) 290 throw Erange("et_mask::is_covered", dar_gettext("No mask in the list of mask to operate on")); 291 292 while(it != lst.end() && (*it)->is_covered(expression)) 293 ++it; 294 295 return it == lst.end(); 296 } 297 298 }; 299 300 301 /// makes the *OR* operator between two or more masks 302 303 /// this mask has exactly the same use as the et_mask 304 /// please see the et_mask documentation. The only difference 305 /// is that it makes an *OR* operation rather than an *AND* 306 /// with the masks added thanks to the add_mask method 307 class ou_mask : public et_mask 308 { 309 public: 310 /// inherited from the mask class is_covered(const std::string & expression) const311 bool is_covered(const std::string & expression) const { return t_is_covered(expression); }; is_covered(const path & chemin) const312 bool is_covered(const path & chemin) const { return t_is_covered(chemin); }; dump(const std::string & prefix) const313 std::string dump(const std::string & prefix) const { return dump_logical(prefix, gettext("OR")); }; 314 /// inherited from the mask class clone() const315 mask *clone() const { return new (get_pool()) ou_mask(*this); }; 316 317 private: t_is_covered(const T & expression) const318 template<class T> bool t_is_covered(const T & expression) const 319 { 320 std::vector<mask *>::const_iterator it = lst.begin(); 321 322 if(lst.empty()) 323 throw Erange("et_mask::is_covered", dar_gettext("No mask to operate on in the list of mask")); 324 325 while(it != lst.end() && ! (*it)->is_covered(expression)) 326 it++; 327 328 return it != lst.end(); 329 } 330 331 }; 332 333 334 /// string matches if it is subdir of mask or mask is a subdir of expression 335 336 class simple_path_mask : public mask 337 { 338 public : 339 /// the constructor to be used by libdar external programs 340 341 /// \param[in] p the path the compare with 342 /// \param[in] case_sensit whether the mask is case sensitive or not 343 /// \note p must be a valid path simple_path_mask(const path & p,bool case_sensit)344 simple_path_mask(const path &p, bool case_sensit) : chemin(p) { case_s = case_sensit; }; 345 346 /// inherited from the mask class is_covered(const std::string & expression) const347 bool is_covered(const std::string & expression) const { throw SRC_BUG; }; 348 bool is_covered(const path & chemin) const; 349 std::string dump(const std::string & prefix) const; 350 351 /// inherited from the mask class clone() const352 mask *clone() const { return new (get_pool()) simple_path_mask(*this); }; 353 354 private : 355 path chemin; 356 bool case_s; 357 }; 358 359 360 /// matches if string is exactly the given mask (no wilde card expression) 361 362 class same_path_mask : public mask 363 { 364 public : 365 /// the constructor to be used by libdar external programs 366 367 /// \param[in] p is the path to compare with 368 /// \param[in] case_sensit whether the mask is case sensitive or not same_path_mask(const std::string & p,bool case_sensit)369 same_path_mask(const std::string &p, bool case_sensit) { chemin = p; case_s = case_sensit; }; 370 371 /// inherited from the mask class 372 bool is_covered(const std::string &chemin) const; 373 374 /// inherited from the mask class 375 std::string dump(const std::string & prefix) const; 376 377 /// inherited from the mask class clone() const378 mask *clone() const { return new (get_pool()) same_path_mask(*this); }; 379 380 private : 381 std::string chemin; 382 bool case_s; 383 }; 384 385 386 /// matches if string is the given constructor string or a sub directory of it 387 388 class exclude_dir_mask : public mask 389 { 390 public: 391 /// the constructor to be used by libdar external programs 392 393 /// \param[in] p is the path to compare with 394 /// \param[in] case_sensit whether the mask is case sensitive or not exclude_dir_mask(const std::string & p,bool case_sensit)395 exclude_dir_mask(const std::string &p, bool case_sensit) { chemin = p; case_s = case_sensit;}; 396 397 /// inherited from the mask class is_covered(const std::string & expression) const398 bool is_covered(const std::string &expression) const { throw SRC_BUG; } is_covered(const path & chemin) const399 bool is_covered(const path &chemin) const { return chemin.is_subdir_of(chemin, case_s); }; 400 std::string dump(const std::string & prefix) const; 401 402 /// inherited from the mask class clone() const403 mask *clone() const { return new (get_pool()) exclude_dir_mask(*this); }; 404 405 private: 406 std::string chemin; 407 bool case_s; 408 }; 409 410 /// @} 411 412 } // end of namespace 413 414 #endif 415