Disk ARchive
2.4.5
|
00001 /*********************************************************************/ 00002 // dar - disk archive - a backup/restoration program 00003 // Copyright (C) 2002-2052 Denis Corbin 00004 // 00005 // This program is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU General Public License 00007 // as published by the Free Software Foundation; either version 2 00008 // of the License, or (at your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with this program; if not, write to the Free Software 00017 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 // 00019 // to contact the author : http://dar.linux.free.fr/email.html 00020 /*********************************************************************/ 00021 // $Id$ 00022 // 00023 /*********************************************************************/ 00024 00028 00029 #ifndef CATALOGUE_HPP 00030 #define CATALOGUE_HPP 00031 00032 #include "../my_config.h" 00033 00034 extern "C" 00035 { 00036 #if HAVE_UNISTD_H 00037 #include <unistd.h> 00038 #endif 00039 } // end extern "C" 00040 00041 #include <vector> 00042 #include <map> 00043 #include "infinint.hpp" 00044 #include "generic_file.hpp" 00045 #include "path.hpp" 00046 #include "header_version.hpp" 00047 #include "ea.hpp" 00048 #include "compressor.hpp" 00049 #include "integers.hpp" 00050 #include "mask.hpp" 00051 #include "special_alloc.hpp" 00052 #include "user_interaction.hpp" 00053 #include "label.hpp" 00054 #include "escape.hpp" 00055 00056 namespace libdar 00057 { 00058 class etoile; 00059 class entree; 00060 00063 00064 enum saved_status 00065 { 00066 s_saved, //< inode is saved in the archive 00067 s_fake, //< inode is not saved in the archive but is in the archive of reference (isolation context) s_fake is no more used in archive format "08" and above: isolated catalogue do keep the data pointers and s_saved stays a valid status in isolated catalogues. 00068 s_not_saved //< inode is not saved in the archive 00069 }; 00070 00072 struct entree_stats 00073 { 00074 infinint num_x; //< number of file referenced as destroyed since last backup 00075 infinint num_d; //< number of directories 00076 infinint num_f; //< number of plain files (hard link or not, thus file directory entries) 00077 infinint num_c; //< number of char devices 00078 infinint num_b; //< number of block devices 00079 infinint num_p; //< number of named pipes 00080 infinint num_s; //< number of unix sockets 00081 infinint num_l; //< number of symbolic links 00082 infinint num_D; //< number of Door 00083 infinint num_hard_linked_inodes; //< number of inode that have more than one link (inode with "hard links") 00084 infinint num_hard_link_entries; //< total number of hard links (file directory entry pointing to \an 00085 //< inode already linked in the same or another directory (i.e. hard linked)) 00086 infinint saved; //< total number of saved inode (unix inode, not inode class) hard links do not count here 00087 infinint total; //< total number of inode in archive (unix inode, not inode class) hard links do not count here 00088 void clear() { num_x = num_d = num_f = num_c = num_b = num_p 00089 = num_s = num_l = num_D = num_hard_linked_inodes 00090 = num_hard_link_entries = saved = total = 0; }; 00091 void add(const entree *ref); 00092 void listing(user_interaction & dialog) const; 00093 }; 00094 00096 class entree 00097 { 00098 public : 00099 static entree *read(user_interaction & dialog, 00100 generic_file & f, const archive_version & reading_ver, 00101 entree_stats & stats, 00102 std::map <infinint, etoile *> & corres, 00103 compression default_algo, 00104 generic_file *data_loc, 00105 generic_file *ea_loc, 00106 bool lax, 00107 bool only_detruit, 00108 escape *ptr); 00109 00110 virtual ~entree() {}; 00111 00113 00120 void dump(generic_file & f, bool small) const; 00121 00123 00130 void specific_dump(generic_file & f, bool small) const { inherited_dump(f, small); }; 00131 00133 00136 virtual void post_constructor(generic_file & f) {}; 00137 00138 00139 virtual unsigned char signature() const = 0; 00140 virtual entree *clone() const = 0; 00141 00142 #ifdef LIBDAR_SPECIAL_ALLOC 00143 USE_SPECIAL_ALLOC(entree); 00144 #endif 00145 00146 protected: 00147 virtual void inherited_dump(generic_file & f, bool small) const; 00148 00149 00150 private: 00151 static const U_I ENTREE_CRC_SIZE; 00152 00153 }; 00154 00155 extern bool compatible_signature(unsigned char a, unsigned char b); 00156 extern unsigned char mk_signature(unsigned char base, saved_status state); 00157 00159 class eod : public entree 00160 { 00161 public : 00162 eod() {}; 00163 eod(generic_file & f) {}; 00164 // dump defined by entree 00165 unsigned char signature() const { return 'z'; }; 00166 entree *clone() const { return new eod(); }; 00167 00168 00169 #ifdef LIBDAR_SPECIAL_ALLOC 00170 USE_SPECIAL_ALLOC(eod); 00171 #endif 00172 }; 00173 00175 class nomme : public entree 00176 { 00177 public: 00178 nomme(const std::string & name) { xname = name; }; 00179 nomme(generic_file & f); 00180 virtual bool operator == (const nomme & ref) const { return xname == ref.xname; }; 00181 virtual bool operator < (const nomme & ref) const { return xname < ref.xname; }; 00182 00183 const std::string & get_name() const { return xname; }; 00184 void change_name(const std::string & x) { xname = x; }; 00185 bool same_as(const nomme & ref) const { return xname == ref.xname; }; 00186 // no need to have a virtual method, as signature will differ in inherited classes (argument type changes) 00187 00188 // signature() is kept as an abstract method 00189 // clone() is abstract 00190 00191 #ifdef LIBDAR_SPECIAL_ALLOC 00192 USE_SPECIAL_ALLOC(nomme); 00193 #endif 00194 00195 protected: 00196 void inherited_dump(generic_file & f, bool small) const; 00197 00198 private: 00199 std::string xname; 00200 }; 00201 00202 00204 class inode : public nomme 00205 { 00206 public: 00207 00209 00210 enum comparison_fields 00211 { 00212 cf_all, //< consider any available field for comparing inodes 00213 cf_ignore_owner, //< consider any available field except ownership fields 00214 cf_mtime, //< consider any available field except ownership and permission fields 00215 cf_inode_type //< only consider the file type 00216 }; 00217 00218 inode(const infinint & xuid, const infinint & xgid, U_16 xperm, 00219 const infinint & last_access, 00220 const infinint & last_modif, 00221 const infinint & last_change, 00222 const std::string & xname, const infinint & device); 00223 inode(user_interaction & dialog, 00224 generic_file & f, 00225 const archive_version & reading_ver, 00226 saved_status saved, 00227 generic_file *ea_loc, 00228 escape *ptr); // if ptr is not NULL, reading a partial dump(), which was done with "small" set to true 00229 inode(const inode & ref); 00230 const inode & operator = (const inode & ref); 00231 ~inode(); 00232 00233 const infinint & get_uid() const { return uid; }; 00234 const infinint & get_gid() const { return gid; }; 00235 U_16 get_perm() const { return perm; }; 00236 infinint get_last_access() const { return *last_acc; }; 00237 infinint get_last_modif() const { return *last_mod; }; 00238 void set_last_access(const infinint & x_time) { *last_acc = x_time; }; 00239 void set_last_modif(const infinint & x_time) { *last_mod = x_time; }; 00240 saved_status get_saved_status() const { return xsaved; }; 00241 void set_saved_status(saved_status x) { xsaved = x; }; 00242 infinint get_device() const { return *fs_dev; }; 00243 00244 bool same_as(const inode & ref) const; 00245 bool is_more_recent_than(const inode & ref, const infinint & hourshift) const; 00246 // used for RESTORATION 00247 virtual bool has_changed_since(const inode & ref, const infinint & hourshift, comparison_fields what_to_check) const; 00248 // signature() left as an abstract method 00249 // clone is abstract too 00250 // used for INCREMENTAL BACKUP 00251 void compare(const inode &other, 00252 const mask & ea_mask, 00253 comparison_fields what_to_check, 00254 const infinint & hourshift, 00255 bool symlink_date) const; 00256 00257 // throw Erange exception if a difference has been detected 00258 // this is not a symetrical comparison, but all what is present 00259 // in the current object is compared against the argument 00260 // which may contain supplementary informations 00261 // used for DIFFERENCE 00262 00263 00264 00266 // EXTENDED ATTRIBUTS Methods 00267 // 00268 00269 enum ea_status { ea_none, ea_partial, ea_fake, ea_full, ea_removed }; 00270 // ea_none : no EA present for this inode in filesystem 00271 // ea_partial : EA present in filesystem but not stored (ctime used to check changes) 00272 // ea_fake : EA present in filesystem but not attached to this inode (isolation context) no more used in archive version "08" and above, ea_partial or ea_full stays a valid status in isolated catalogue because pointers to EA and data are no more removed during isolation process. 00273 // ea_full : EA present in filesystem and attached to this inode 00274 // ea_removed : EA were present in the reference version, but not present anymore 00275 00276 // I : to know whether EA data is present or not for this object 00277 void ea_set_saved_status(ea_status status); 00278 ea_status ea_get_saved_status() const { return ea_saved; }; 00279 00280 // II : to associate EA list to an inode object (mainly for backup operation) #EA_FULL only# 00281 void ea_attach(ea_attributs *ref); 00282 const ea_attributs *get_ea() const; // #<-- EA_FULL *and* EA_REMOVED# for this call only 00283 void ea_detach() const; //discards any future call to get_ea() ! 00284 infinint ea_get_size() const; //returns the size of EA (still valid if ea have been detached) 00285 00286 // III : to record where is dump the EA in the archive #EA_FULL only# 00287 void ea_set_offset(const infinint & pos) { *ea_offset = pos; }; 00288 void ea_set_crc(const crc & val); 00289 void ea_get_crc(const crc * & ptr) const; //< the argument is set the an allocated crc object owned by this "inode" object, this reference stays valid while the "inode" object exists and MUST NOT be deleted by the caller in any case 00290 bool ea_get_crc_size(infinint & val) const; //< returns true if crc is know and puts its width in argument 00291 00292 // IV : to know/record if EA have been modified # any EA status# 00293 infinint get_last_change() const; 00294 void set_last_change(const infinint & x_time); 00295 bool has_last_change() const { return last_cha != NULL; }; 00296 // old format did provide last_change only when EA were present, since archive 00297 // format 8, this field is always present even in absence of EA. Thus it is 00298 // still necessary to check if the inode has a last_change() before 00299 // using get_last_change() (depends on the version of the archive read). 00300 00301 00302 // V : for archive migration (merging) 00303 void change_ea_location(generic_file *loc) { storage = loc; }; 00304 00306 00307 #ifdef LIBDAR_SPECIAL_ALLOC 00308 USE_SPECIAL_ALLOC(inode); 00309 #endif 00310 00311 protected: 00312 virtual void sub_compare(const inode & other) const {}; 00313 00315 escape *get_escape_layer() const { return esc; }; 00316 00317 void inherited_dump(generic_file & f, bool small) const; 00318 00319 private : 00320 infinint uid; 00321 infinint gid; 00322 U_16 perm; 00323 infinint *last_acc, *last_mod; 00324 saved_status xsaved; 00325 ea_status ea_saved; 00326 // the following is used only if ea_saved == full 00327 infinint *ea_offset; 00328 ea_attributs *ea; 00329 infinint ea_size; 00330 // the following is used if ea_saved == full or ea_saved == partial 00331 infinint *last_cha; 00332 crc *ea_crc; 00333 infinint *fs_dev; 00334 generic_file *storage; // where are stored EA 00335 archive_version edit; // need to know EA format used in archive file 00336 00337 escape *esc; // if not NULL, the object is partially build from archive (at archive generation, dump() was called with small set to true) 00338 00339 static const ea_attributs empty_ea; 00340 }; 00341 00343 class etoile 00344 { 00345 public: 00346 00348 00352 etoile(inode *host, const infinint & etiquette_number); 00353 etoile(const etoile & ref) { throw SRC_BUG; }; // copy constructor not allowed for this class 00354 const etoile & operator = (const etoile & ref) { throw SRC_BUG; }; // assignment not allowed for this class 00355 ~etoile() { delete hosted; }; 00356 00357 void add_ref(void *ref); 00358 void drop_ref(void *ref); 00359 infinint get_ref_count() const { return refs.size(); }; 00360 inode *get_inode() const { return hosted; }; 00361 infinint get_etiquette() const { return etiquette; }; 00362 void change_etiquette(const infinint & new_val) { etiquette = new_val; }; 00363 00364 00365 bool is_counted() const { return tags.counted; }; 00366 bool is_wrote() const { return tags.wrote; }; 00367 bool is_dumped() const { return tags.dumped; }; 00368 void set_counted(bool val) { tags.counted = val ? 1 : 0; }; 00369 void set_wrote(bool val) { tags.wrote = val ? 1 : 0; }; 00370 void set_dumped(bool val) { tags.dumped = val ? 1 : 0; }; 00371 00372 // return the address of the first mirage that triggered the creation of this mirage 00373 // if this object is destroyed afterward this call returns NULL 00374 const void *get_first_ref() const { if(refs.size() == 0) throw SRC_BUG; return refs.front(); }; 00375 00376 #ifdef LIBDAR_SPECIAL_ALLOC 00377 USE_SPECIAL_ALLOC(etoile); 00378 #endif 00379 00380 private: 00381 struct bool_tags 00382 { 00383 unsigned counted : 1; //< whether the inode has been counted 00384 unsigned wrote : 1; //< whether the inode has its data copied to archive 00385 unsigned dumped : 1; //< whether the inode information has been dumped in the catalogue 00386 unsigned : 5; //< padding to get byte boundary and reserved for future use. 00387 00388 bool_tags() { counted = wrote = dumped = 0; }; 00389 }; 00390 00391 std::list<void *> refs; //< list of pointers to the mirages objects, in the order of their creation 00392 inode *hosted; 00393 infinint etiquette; 00394 bool_tags tags; 00395 }; 00396 00398 00400 class mirage : public nomme 00401 { 00402 public: 00403 enum mirage_format {fmt_mirage, //< new format 00404 fmt_hard_link, //< old dual format 00405 fmt_file_etiquette }; //< old dual format 00406 00407 mirage(const std::string & name, etoile *ref) : nomme(name) { star_ref = ref; if(ref == NULL) throw SRC_BUG; star_ref->add_ref(this); }; 00408 mirage(user_interaction & dialog, 00409 generic_file & f, 00410 const archive_version & reading_ver, 00411 saved_status saved, 00412 entree_stats & stats, 00413 std::map <infinint, etoile *> & corres, 00414 compression default_algo, 00415 generic_file *data_loc, 00416 generic_file *ea_loc, 00417 mirage_format fmt, 00418 bool lax, 00419 escape *ptr); 00420 mirage(user_interaction & dialog, 00421 generic_file & f, 00422 const archive_version & reading_ver, 00423 saved_status saved, 00424 entree_stats & stats, 00425 std::map <infinint, etoile *> & corres, 00426 compression default_algo, 00427 generic_file *data_loc, 00428 generic_file *ea_loc, 00429 bool lax, 00430 escape *ptr); 00431 mirage(const mirage & ref) : nomme (ref) { star_ref = ref.star_ref; if(star_ref == NULL) throw SRC_BUG; star_ref->add_ref(this); }; 00432 const mirage & operator = (const mirage & ref); 00433 ~mirage() { star_ref->drop_ref(this); }; 00434 00435 unsigned char signature() const { return 'm'; }; 00436 entree *clone() const { return new mirage(*this); }; 00437 00438 inode *get_inode() const { if(star_ref == NULL) throw SRC_BUG; return star_ref->get_inode(); }; 00439 infinint get_etiquette() const { return star_ref->get_etiquette(); }; 00440 infinint get_etoile_ref_count() const { return star_ref->get_ref_count(); }; 00441 etoile *get_etoile() const { return star_ref; }; 00442 00443 bool is_inode_counted() const { return star_ref->is_counted(); }; 00444 bool is_inode_wrote() const { return star_ref->is_wrote(); }; 00445 bool is_inode_dumped() const { return star_ref->is_dumped(); }; 00446 void set_inode_counted(bool val) const { star_ref->set_counted(val); }; 00447 void set_inode_wrote(bool val) const { star_ref->set_wrote(val); }; 00448 void set_inode_dumped(bool val) const { star_ref->set_dumped(val); }; 00449 00450 void post_constructor(generic_file & f); 00451 00453 bool is_first_mirage() const { return star_ref->get_first_ref() == this; }; 00454 00455 #ifdef LIBDAR_SPECIAL_ALLOC 00456 USE_SPECIAL_ALLOC(mirage); 00457 #endif 00458 00459 protected: 00460 void inherited_dump(generic_file & f, bool small) const; 00461 00462 private: 00463 etoile *star_ref; 00464 00465 void init(user_interaction & dialog, 00466 generic_file & f, 00467 const archive_version & reading_ver, 00468 saved_status saved, 00469 entree_stats & stats, 00470 std::map <infinint, etoile *> & corres, 00471 compression default_algo, 00472 generic_file *data_loc, 00473 generic_file *ea_loc, 00474 mirage_format fmt, 00475 bool lax, 00476 escape *ptr); 00477 }; 00478 00479 00481 class file : public inode 00482 { 00483 public : 00484 enum get_data_mode 00485 { 00486 keep_compressed, //< provide access to compressed data 00487 keep_hole, //< provide access to uncompressed data but sparse_file datastructure 00488 normal, //< provide access to full data (uncompressed, uses skip() to restore holes) 00489 plain //< provide access to plain data, no skip to restore holes, provide instead zeroed bytes 00490 }; 00491 00492 static const U_8 FILE_DATA_WITH_HOLE = 0x01; //< file's data contains hole datastructure 00493 static const U_8 FILE_DATA_IS_DIRTY = 0x02; //< data modified while being saved 00494 00495 file(const infinint & xuid, const infinint & xgid, U_16 xperm, 00496 const infinint & last_access, 00497 const infinint & last_modif, 00498 const infinint & last_change, 00499 const std::string & src, 00500 const path & che, 00501 const infinint & taille, 00502 const infinint & fs_device, 00503 bool x_furtive_read_mode); 00504 file(const file & ref); 00505 file(user_interaction & dialog, 00506 generic_file & f, 00507 const archive_version & reading_ver, 00508 saved_status saved, 00509 compression default_algo, 00510 generic_file *data_loc, 00511 generic_file *ea_loc, 00512 escape *ptr); 00513 ~file() { detruit(); }; 00514 00515 bool has_changed_since(const inode & ref, const infinint & hourshift, inode::comparison_fields what_to_check) const; 00516 infinint get_size() const { return *size; }; 00517 infinint get_storage_size() const { return *storage_size; }; 00518 void set_storage_size(const infinint & s) { *storage_size = s; }; 00519 virtual generic_file *get_data(get_data_mode mode) const; // returns a newly allocated object in read_only mode 00520 void clean_data(); // partially free memory (but get_data() becomes disabled) 00521 void set_offset(const infinint & r); 00522 const infinint & get_offset() const; 00523 unsigned char signature() const { return mk_signature('f', get_saved_status()); }; 00524 00525 void set_crc(const crc &c); 00526 bool get_crc(const crc * & c) const; //< the argument is set the an allocated crc object the owned by the "file" object, its stay valid while this "file" object exists and MUST NOT be deleted by the caller in any case 00527 bool has_crc() const { return check != NULL; }; 00528 bool get_crc_size(infinint & val) const; //< returns true if crc is know and puts its width in argument 00529 void drop_crc() { if(check != NULL) { delete check; check = NULL; } }; 00530 00531 // whether the plain file has to detect sparse file 00532 void set_sparse_file_detection_read(bool val) { if(status == from_cat) throw SRC_BUG; if(val) file_data_status_read |= FILE_DATA_WITH_HOLE; else file_data_status_read &= ~FILE_DATA_WITH_HOLE; }; 00533 00534 void set_sparse_file_detection_write(bool val) { if(val) file_data_status_write |= FILE_DATA_WITH_HOLE; else file_data_status_write &= ~FILE_DATA_WITH_HOLE; }; 00535 00536 // whether the plain file is stored with a sparse_file datastructure in the archive 00537 bool get_sparse_file_detection_read() const { return (file_data_status_read & FILE_DATA_WITH_HOLE) != 0; }; 00538 bool get_sparse_file_detection_write() const { return (file_data_status_write & FILE_DATA_WITH_HOLE) != 0; }; 00539 00540 entree *clone() const { return new file(*this); }; 00541 00542 compression get_compression_algo_read() const { return algo_read; }; 00543 00544 compression get_compression_algo_write() const { return algo_write; }; 00545 00546 // object migration methods (merging) 00547 void change_compression_algo_write(compression x) { algo_write = x; }; 00548 void change_location(generic_file *x) { loc = x; }; 00549 00550 // dirtiness 00551 00552 bool is_dirty() const { return dirty; }; 00553 void set_dirty(bool value) { dirty = value; }; 00554 00555 #ifdef LIBDAR_SPECIAL_ALLOC 00556 USE_SPECIAL_ALLOC(file); 00557 #endif 00558 00559 protected: 00560 void sub_compare(const inode & other) const; 00561 void inherited_dump(generic_file & f, bool small) const; 00562 void post_constructor(generic_file & f); 00563 00564 enum { empty, from_path, from_cat } status; 00565 00566 private: 00567 std::string chemin; //< path to the data (when read from filesystem) 00568 infinint *offset; //< start location of the data in 'loc' 00569 infinint *size; //< size of the data (uncompressed) 00570 infinint *storage_size; //< how much data used in archive (after compression) 00571 crc *check; 00572 bool dirty; //< true when a file has been modified at the time it was saved 00573 00574 generic_file *loc; //< where to find data (eventually compressed) at the recorded offset and for storage_size length 00575 compression algo_read; //< which compression algorithm to use to read the file's data 00576 compression algo_write; //< which compression algorithm to use to write down (merging) the file's data 00577 bool furtive_read_mode; // used only when status equals "from_path" 00578 char file_data_status_read; // defines the datastructure to use when reading the data 00579 char file_data_status_write; // defines the datastructure to apply when writing down the data 00580 00581 void detruit(); 00582 }; 00583 00585 class door : public file 00586 { 00587 public: 00588 door(const infinint & xuid, const infinint & xgid, U_16 xperm, 00589 const infinint & last_access, 00590 const infinint & last_modif, 00591 const infinint & last_change, 00592 const std::string & src, 00593 const path & che, 00594 const infinint & fs_device) : file(xuid, xgid, xperm, last_access, last_modif, 00595 last_change, src, che, 0, fs_device, false) {}; 00596 door(user_interaction & dialog, 00597 generic_file & f, 00598 const archive_version & reading_ver, 00599 saved_status saved, 00600 compression default_algo, 00601 generic_file *data_loc, 00602 generic_file *ea_loc, 00603 escape *ptr) : file(dialog, f, reading_ver, saved, default_algo, data_loc, ea_loc, ptr) {}; 00604 00605 unsigned char signature() const { return mk_signature('o', get_saved_status()); }; 00606 00607 generic_file *get_data(get_data_mode mode) const; // inherited from class file 00608 00609 #ifdef LIBDAR_SPECIAL_ALLOC 00610 USE_SPECIAL_ALLOC(door); 00611 #endif 00612 }; 00613 00615 class lien : public inode 00616 { 00617 public : 00618 lien(const infinint & uid, const infinint & gid, U_16 perm, 00619 const infinint & last_access, 00620 const infinint & last_modif, 00621 const infinint & last_change, 00622 const std::string & name, 00623 const std::string & target, 00624 const infinint & fs_device); 00625 lien(user_interaction & dialog, 00626 generic_file & f, 00627 const archive_version & reading_ver, 00628 saved_status saved, 00629 generic_file *ea_loc, 00630 escape *ptr); 00631 00632 const std::string & get_target() const; 00633 void set_target(std::string x); 00634 00635 // using the method is_more_recent_than() from inode 00636 // using method has_changed_since() from inode class 00637 unsigned char signature() const { return mk_signature('l', get_saved_status()); }; 00638 entree *clone() const { return new lien(*this); }; 00639 00640 #ifdef LIBDAR_SPECIAL_ALLOC 00641 USE_SPECIAL_ALLOC(lien); 00642 #endif 00643 protected : 00644 void sub_compare(const inode & other) const; 00645 void inherited_dump(generic_file & f, bool small) const; 00646 00647 00648 private : 00649 std::string points_to; 00650 }; 00651 00653 class directory : public inode 00654 { 00655 public : 00656 directory(const infinint & xuid, const infinint & xgid, U_16 xperm, 00657 const infinint & last_access, 00658 const infinint & last_modif, 00659 const infinint & last_change, 00660 const std::string & xname, 00661 const infinint & device); 00662 directory(const directory &ref); // only the inode part is build, no children is duplicated (empty dir) 00663 const directory & operator = (const directory & ref); // set the inode part *only* no subdirectories/subfiles are copies or removed. 00664 directory(user_interaction & dialog, 00665 generic_file & f, 00666 const archive_version & reading_ver, 00667 saved_status saved, 00668 entree_stats & stats, 00669 std::map <infinint, etoile *> & corres, 00670 compression default_algo, 00671 generic_file *data_loc, 00672 generic_file *ea_loc, 00673 bool lax, 00674 bool only_detruit, // objects of other class than detruit and directory are not built in memory 00675 escape *ptr); 00676 ~directory(); // detruit aussi tous les fils et se supprime de son 'parent' 00677 00678 void add_children(nomme *r); // when r is a directory, 'parent' is set to 'this' 00679 bool has_children() const { return !ordered_fils.empty(); }; 00680 void reset_read_children() const; 00681 void end_read() const; 00682 bool read_children(const nomme * &r) const; // read the direct children of the directory, returns false if no more is available 00683 // remove all entry not yet read by read_children 00684 void tail_to_read_children(); 00685 00686 void remove(const std::string & name); // remove the given entry from the catalogue 00687 // as side effect the reset_read_children() method must be called. 00688 00689 directory * get_parent() const { return parent; }; 00690 bool search_children(const std::string &name, nomme *&ref); 00691 bool callback_for_children_of(user_interaction & dialog, const std::string & sdir, bool isolated = false) const; 00692 00693 // using is_more_recent_than() from inode class 00694 // using method has_changed_since() from inode class 00695 unsigned char signature() const { return mk_signature('d', get_saved_status()); }; 00696 00697 // some data has changed since archive of reference in this directory or subdirectories 00698 bool get_recursive_has_changed() const { return recursive_has_changed; }; 00699 // update the recursive_has_changed field 00700 void recursive_has_changed_update() const; 00701 00702 // get then number of "nomme" entry contained in this directory and subdirectories (recursive call) 00703 infinint get_tree_size() const; 00704 // get the number of entry having some EA set in the directory tree (recursive call) 00705 infinint get_tree_ea_num() const; 00706 // get the number of entry that are hard linked inode (aka mirage in dar implementation) (recursive call) 00707 infinint get_tree_mirage_num() const; 00708 // for each mirage found (hard link implementation) in the directory tree, add its etiquette to the returned 00709 // list with the number of reference that has been found in the tree. (map[etiquette] = number of occurence) 00710 // from outside of class directory, the given argument is expected to be an empty map. 00711 void get_etiquettes_found_in_tree(std::map<infinint, infinint> & already_found) const; 00712 00713 // whether this directory is empty or not 00714 bool is_empty() const { return ordered_fils.empty(); }; 00715 00716 // recursively remove all mirage entries 00717 void remove_all_mirages_and_reduce_dirs(); 00718 00719 entree *clone() const { return new directory(*this); }; 00720 00721 #ifdef LIBDAR_SPECIAL_ALLOC 00722 USE_SPECIAL_ALLOC(directory); 00723 #endif 00724 00725 protected: 00726 void inherited_dump(generic_file & f, bool small) const; 00727 00728 private : 00729 static const eod fin; 00730 00731 directory *parent; 00732 #ifdef LIBDAR_FAST_DIR 00733 std::map<std::string, nomme *> fils; // used for fast lookup 00734 #endif 00735 std::list<nomme *> ordered_fils; 00736 std::list<nomme *>::iterator it; 00737 bool recursive_has_changed; 00738 00739 void clear(); 00740 }; 00741 00743 class device : public inode 00744 { 00745 public : 00746 device(const infinint & uid, const infinint & gid, U_16 perm, 00747 const infinint & last_access, 00748 const infinint & last_modif, 00749 const infinint &last_change, 00750 const std::string & name, 00751 U_16 major, 00752 U_16 minor, 00753 const infinint & fs_device); 00754 device(user_interaction & dialog, 00755 generic_file & f, 00756 const archive_version & reading_ver, 00757 saved_status saved, 00758 generic_file *ea_loc, 00759 escape *ptr); 00760 00761 int get_major() const { if(get_saved_status() != s_saved) throw SRC_BUG; else return xmajor; }; 00762 int get_minor() const { if(get_saved_status() != s_saved) throw SRC_BUG; else return xminor; }; 00763 void set_major(int x) { xmajor = x; }; 00764 void set_minor(int x) { xminor = x; }; 00765 00766 // using method is_more_recent_than() from inode class 00767 // using method has_changed_since() from inode class 00768 // signature is left pure abstract 00769 00770 #ifdef LIBDAR_SPECIAL_ALLOC 00771 USE_SPECIAL_ALLOC(device); 00772 #endif 00773 00774 protected : 00775 void sub_compare(const inode & other) const; 00776 void inherited_dump(generic_file & f, bool small) const; 00777 00778 private : 00779 U_16 xmajor, xminor; 00780 }; 00781 00783 class chardev : public device 00784 { 00785 public: 00786 chardev(const infinint & uid, const infinint & gid, U_16 perm, 00787 const infinint & last_access, 00788 const infinint & last_modif, 00789 const infinint & last_change, 00790 const std::string & name, 00791 U_16 major, 00792 U_16 minor, 00793 const infinint & fs_device) : device(uid, gid, perm, 00794 last_access, 00795 last_modif, 00796 last_change, 00797 name, 00798 major, minor, fs_device) {}; 00799 chardev(user_interaction & dialog, 00800 generic_file & f, 00801 const archive_version & reading_ver, 00802 saved_status saved, 00803 generic_file *ea_loc, 00804 escape *ptr) : device(dialog, f, reading_ver, saved, ea_loc, ptr) {}; 00805 00806 // using dump from device class 00807 // using method is_more_recent_than() from device class 00808 // using method has_changed_since() from device class 00809 unsigned char signature() const { return mk_signature('c', get_saved_status()); }; 00810 entree *clone() const { return new chardev(*this); }; 00811 00812 #ifdef LIBDAR_SPECIAL_ALLOC 00813 USE_SPECIAL_ALLOC(chardev); 00814 #endif 00815 }; 00816 00818 class blockdev : public device 00819 { 00820 public: 00821 blockdev(const infinint & uid, const infinint & gid, U_16 perm, 00822 const infinint & last_access, 00823 const infinint & last_modif, 00824 const infinint & last_change, 00825 const std::string & name, 00826 U_16 major, 00827 U_16 minor, 00828 const infinint & fs_device) : device(uid, gid, perm, last_access, 00829 last_modif, last_change, name, 00830 major, minor, fs_device) {}; 00831 blockdev(user_interaction & dialog, 00832 generic_file & f, 00833 const archive_version & reading_ver, 00834 saved_status saved, 00835 generic_file *ea_loc, 00836 escape *ptr) : device(dialog, f, reading_ver, saved, ea_loc, ptr) {}; 00837 00838 // using dump from device class 00839 // using method is_more_recent_than() from device class 00840 // using method has_changed_since() from device class 00841 unsigned char signature() const { return mk_signature('b', get_saved_status()); }; 00842 entree *clone() const { return new blockdev(*this); }; 00843 00844 #ifdef LIBDAR_SPECIAL_ALLOC 00845 USE_SPECIAL_ALLOC(blockdev); 00846 #endif 00847 }; 00848 00850 class tube : public inode 00851 { 00852 public : 00853 tube(const infinint & xuid, const infinint & xgid, U_16 xperm, 00854 const infinint & last_access, 00855 const infinint & last_modif, 00856 const infinint & last_change, 00857 const std::string & xname, 00858 const infinint & fs_device) : inode(xuid, xgid, xperm, last_access, last_modif, last_change, xname, fs_device) { set_saved_status(s_saved); }; 00859 tube(user_interaction & dialog, 00860 generic_file & f, 00861 const archive_version & reading_ver, 00862 saved_status saved, 00863 generic_file *ea_loc, 00864 escape *ptr) : inode(dialog, f, reading_ver, saved, ea_loc, ptr) {}; 00865 00866 // using dump from inode class 00867 // using method is_more_recent_than() from inode class 00868 // using method has_changed_since() from inode class 00869 unsigned char signature() const { return mk_signature('p', get_saved_status()); }; 00870 entree *clone() const { return new tube(*this); }; 00871 00872 #ifdef LIBDAR_SPECIAL_ALLOC 00873 USE_SPECIAL_ALLOC(tube); 00874 #endif 00875 }; 00876 00878 class prise : public inode 00879 { 00880 public : 00881 prise(const infinint & xuid, const infinint & xgid, U_16 xperm, 00882 const infinint & last_access, 00883 const infinint & last_modif, 00884 const infinint & last_change, 00885 const std::string & xname, 00886 const infinint & fs_device) : inode(xuid, xgid, xperm, last_access, last_modif, last_change, xname, fs_device) { set_saved_status(s_saved); }; 00887 prise(user_interaction & dialog, 00888 generic_file & f, 00889 const archive_version & reading_ver, 00890 saved_status saved, 00891 generic_file *ea_loc, 00892 escape *ptr) : inode(dialog, f, reading_ver, saved, ea_loc, ptr) {}; 00893 00894 // using dump from inode class 00895 // using method is_more_recent_than() from inode class 00896 // using method has_changed_since() from inode class 00897 unsigned char signature() const { return mk_signature('s', get_saved_status()); }; 00898 entree *clone() const { return new prise(*this); }; 00899 00900 #ifdef LIBDAR_SPECIAL_ALLOC 00901 USE_SPECIAL_ALLOC(prise); 00902 #endif 00903 }; 00904 00906 class detruit : public nomme 00907 { 00908 public : 00909 detruit(const std::string & name, unsigned char firm, const infinint & date) : nomme(name) , del_date(date) { signe = firm; }; 00910 detruit(generic_file & f, const archive_version & reading_ver); 00911 detruit(const nomme &ref) : nomme(ref.get_name()), del_date(0) { signe = ref.signature(); }; 00912 00913 unsigned char get_signature() const { return signe; }; 00914 void set_signature(unsigned char x) { signe = x; }; 00915 unsigned char signature() const { return 'x'; }; 00916 entree *clone() const { return new detruit(*this); }; 00917 00918 const infinint & get_date() const { return del_date; }; 00919 void set_date(const infinint & ref) { del_date = ref; }; 00920 00921 #ifdef LIBDAR_SPECIAL_ALLOC 00922 USE_SPECIAL_ALLOC(detruit); 00923 #endif 00924 protected: 00925 void inherited_dump(generic_file & f, bool small) const; 00926 00927 private : 00928 unsigned char signe; 00929 infinint del_date; 00930 }; 00931 00933 class ignored : public nomme 00934 { 00935 public : 00936 ignored(const std::string & name) : nomme(name) {}; 00937 ignored(generic_file & f) : nomme(f) { throw SRC_BUG; }; 00938 00939 unsigned char signature() const { return 'i'; }; 00940 entree *clone() const { return new ignored(*this); }; 00941 #ifdef LIBDAR_SPECIAL_ALLOC 00942 USE_SPECIAL_ALLOC(ignored); 00943 #endif 00944 00945 protected: 00946 void inherited_dump(generic_file & f, bool small) const { throw SRC_BUG; }; 00947 00948 }; 00949 00951 class ignored_dir : public inode 00952 { 00953 public: 00954 ignored_dir(const directory &target) : inode(target) {}; 00955 ignored_dir(user_interaction & dialog, 00956 generic_file & f, 00957 const archive_version & reading_ver, 00958 generic_file *ea_loc, 00959 escape *ptr) : inode(dialog, f, reading_ver, s_not_saved, ea_loc, ptr) { throw SRC_BUG; }; 00960 00961 unsigned char signature() const { return 'j'; }; 00962 entree *clone() const { return new ignored_dir(*this); }; 00963 #ifdef LIBDAR_SPECIAL_ALLOC 00964 USE_SPECIAL_ALLOC(ignored_dir); 00965 #endif 00966 00967 protected: 00968 void inherited_dump(generic_file & f, bool small) const; // behaves like an empty directory 00969 00970 }; 00971 00973 class catalogue : protected mem_ui 00974 { 00975 public : 00976 catalogue(user_interaction & dialog, 00977 const infinint & root_last_modif, 00978 const label & data_name); 00979 catalogue(user_interaction & dialog, 00980 generic_file & f, 00981 const archive_version & reading_ver, 00982 compression default_algo, 00983 generic_file *data_loc, 00984 generic_file *ea_loc, 00985 bool lax, 00986 const label & lax_layer1_data_name, //< ignored unless in lax mode, in lax mode unless it is a cleared label, forces the catalogue label to be equal to the lax_layer1_data_name for it be considered a plain internal catalogue, even in case of corruption 00987 bool only_detruit = false); //< if set to true, only directories and detruit objects are read from the archive 00988 catalogue(const catalogue & ref) : mem_ui(ref), out_compare(ref.out_compare) { partial_copy_from(ref); }; 00989 const catalogue & operator = (const catalogue &ref); 00990 virtual ~catalogue() { detruire(); }; 00991 00992 00993 // reading methods. The reading is iterative and uses the current_read directory pointer 00994 00995 virtual void reset_read() const; // set the reading cursor to the beginning of the catalogue 00996 virtual void end_read() const; // set the reading cursor to the end of the catalogue 00997 virtual void skip_read_to_parent_dir() const; 00998 // skip all items of the current dir and of any subdir, the next call will return 00999 // next item of the parent dir (no eod to exit from the current dir !) 01000 virtual bool read(const entree * & ref) const; 01001 // sequential read (generates eod) and return false when all files have been read 01002 virtual bool read_if_present(std::string *name, const nomme * & ref) const; 01003 // pseudo-sequential read (reading a directory still 01004 // implies that following read are located in this subdirectory up to the next EOD) but 01005 // it returns false if no entry of this name are present in the current directory 01006 // a call with NULL as first argument means to set the current dir the parent directory 01007 void remove_read_entry(std::string & name); 01008 // in the currently read directory, removes the entry which name is given in argument 01009 const directory & get_current_reading_dir() const { return *current_read; }; 01010 // remove from the catalogue all the entries that have not yet been read 01011 // by read(). 01012 void tail_catalogue_to_current_read(); 01013 01014 01015 void reset_sub_read(const path &sub); // initialise sub_read to the given directory 01016 bool sub_read(const entree * &ref); // sequential read of the catalogue, ignoring all that 01017 // is not part of the subdirectory specified with reset_sub_read 01018 // the read include the inode leading to the sub_tree as well as the pending eod 01019 01020 // return true if the last read entry has already been read 01021 // and has not to be counted again. This is never the case for catalogue but may occure 01022 // with escape_catalogue (where from the 'virtual'). 01023 // last this method gives a valid result only if the last read() entry is a directory as 01024 // only directory may be read() twice. 01025 virtual bool read_second_time_dir() const { return false; }; 01026 01027 01028 // Additions methods. The addition is also iterative but uses its specific current_add directory pointer 01029 01030 void reset_add(); 01031 01033 // real implementation is only needed in escape_catalogue class, here there nothing to be done 01034 virtual void pre_add(const entree *ref, compressor *compr) const {}; 01035 virtual void pre_add_ea(const entree *ref, compressor *compr) const {}; 01036 virtual void pre_add_crc(const entree *ref, compressor *compr) const {}; 01037 virtual void pre_add_dirty(compressor *compr) const {}; 01038 virtual void pre_add_ea_crc(const entree *ref, compressor *compr) const {}; 01039 virtual void pre_add_waste_mark(compressor *compr) const {}; 01040 virtual void pre_add_failed_mark(compressor *compr) const {}; 01041 virtual escape *get_escape_layer() const { return NULL; }; 01042 01043 void add(entree *ref); // add at end of catalogue (sequential point of view) 01044 void re_add_in(const std::string &subdirname); // return into an already existing subdirectory for further addition 01045 void re_add_in_replace(const directory &dir); // same as re_add_in but also set the properties of the existing directory to those of the given argument 01046 void add_in_current_read(nomme *ref); // add in currently read directory 01047 01048 01049 01050 // Comparison methods. The comparision is here also iterative and uses its specific current_compare directory pointer 01051 01052 void reset_compare(); 01053 bool compare(const entree * name, const entree * & extracted); 01054 // returns true if the ref exists, and gives it back in second argument as it is in the current catalogue. 01055 // returns false is no entry of that nature exists in the catalogue (in the current directory) 01056 // if ref is a directory, the operation is normaly relative to the directory itself, but 01057 // such a call implies a chdir to that directory. thus, a call with an EOD is necessary to 01058 // change to the parent directory. 01059 // note : 01060 // if a directory is not present, returns false, but records the inexistant subdirectory 01061 // structure defined by the following calls to this routine, this to be able to know when 01062 // the last available directory is back the current one when changing to parent directory, 01063 // and then proceed with normal comparison of inode. In this laps of time, the call will 01064 // always return false, while it temporary stores the missing directory structure 01065 01066 01067 01068 // non interative methods 01069 01070 bool direct_read(const path & ref, const nomme * &ret); 01071 infinint update_destroyed_with(catalogue & ref); 01072 // ref must have the same root, else the operation generates an exception 01073 01074 void update_absent_with(catalogue & ref, infinint aborting_next_etoile); 01075 // in case of abortion, completes missing files as if what could not be 01076 // inspected had not changed since the reference was done 01077 // aborting_last_etoile is the highest etoile reference withing "this" current object. 01078 01079 void dump(generic_file & f) const; 01080 void listing(bool isolated, 01081 const mask &selection, 01082 const mask & subtree, 01083 bool filter_unsaved, 01084 bool list_ea, 01085 std::string marge) const; 01086 void tar_listing(bool isolated, 01087 const mask & selection, 01088 const mask & subtree, 01089 bool filter_unsaved, 01090 bool list_ea, 01091 std::string beginning) const; 01092 void xml_listing(bool isolated, 01093 const mask & selection, 01094 const mask & subtree, 01095 bool filter_unsaved, 01096 bool list_ea, 01097 std::string beginning) const; 01098 01099 entree_stats get_stats() const { return stats; }; 01100 01102 bool is_empty() const { if(contenu == NULL) throw SRC_BUG; return contenu->is_empty(); }; 01103 01104 const directory *get_contenu() const { return contenu; }; // used by data_tree 01105 01106 const label & get_data_name() const { return ref_data_name; }; 01107 infinint get_root_dir_last_modif() const { return contenu->get_last_modif(); }; 01108 01110 void launch_recursive_has_changed_update() const { contenu->recursive_has_changed_update(); }; 01111 01112 infinint get_root_mtime() const { return contenu->get_last_modif(); }; 01113 01115 void reset_all(); 01116 01117 01118 protected: 01119 entree_stats & access_stats() { return stats; }; 01120 void set_data_name(const label & val) { ref_data_name = val; }; 01121 void copy_detruits_from(const catalogue & ref); // needed for escape_catalogue implementation only. 01122 01123 const eod * get_r_eod_address() const { return & r_eod; }; // eod are never stored in the catalogue 01124 // however it is sometimes required to return such a reference to a valid object 01125 // owned by the catalogue. 01126 01127 01130 void swap_stuff(catalogue & ref); 01131 01132 private : 01133 directory *contenu; 01134 path out_compare; 01135 directory *current_compare; 01136 directory *current_add; 01137 directory *current_read; 01138 path *sub_tree; 01139 signed int sub_count; 01140 entree_stats stats; 01141 label ref_data_name; 01142 01143 void partial_copy_from(const catalogue &ref); 01144 void detruire(); 01145 01146 static const eod r_eod; // needed to return eod reference, without taking risk of saturating memory 01147 static const U_I CAT_CRC_SIZE; 01148 }; 01149 01150 01151 01153 01154 } // end of namespace 01155 01156 #endif