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 : dar.linux@free.fr 00020 /*********************************************************************/ 00021 // $Id$ 00022 // 00023 /*********************************************************************/ 00024 00025 #ifndef CATALOGUE_HPP 00026 #define CATALOGUE_HPP 00027 00028 #pragma interface 00029 00030 #include <unistd.h> 00031 #include <vector> 00032 #include <map> 00033 #include "infinint.hpp" 00034 #include "path.hpp" 00035 #include "generic_file.hpp" 00036 #include "header_version.hpp" 00037 #include "ea.hpp" 00038 #include "compressor.hpp" 00039 #include "integers.hpp" 00040 #include "mask.hpp" 00041 00042 class file_etiquette; 00043 class entree; 00044 00045 enum saved_status { s_saved, s_fake, s_not_saved }; 00046 00047 extern void catalogue_set_reading_version(const version &ver); 00048 extern unsigned char mk_signature(unsigned char base, saved_status state); 00049 00050 struct entree_stats 00051 { 00052 infinint num_x; // number of file referenced as destroyed since last backup 00053 infinint num_d; // number of directories 00054 infinint num_f; // number of plain files (hard link or not, thus file directory entries) 00055 infinint num_c; // number of char devices 00056 infinint num_b; // number of block devices 00057 infinint num_p; // number of named pipes 00058 infinint num_s; // number of unix sockets 00059 infinint num_l; // number of symbolic links 00060 infinint num_hard_linked_inodes; // number of inode that have more than one link (inode with "hard links") 00061 infinint num_hard_link_entries; // total number of hard links (file directory entry pointing to an 00062 // inode already linked in the same or another directory (i.e. hard linked)) 00063 infinint saved; // total number of saved inode (unix inode, not inode class) hard links do not count here 00064 infinint total; // total number of inode in archive (unix inode, not inode class) hard links do not count here 00065 void clear() { num_x = num_d = num_f = num_c = num_b = num_p 00066 = num_s = num_l = num_hard_linked_inodes 00067 = num_hard_link_entries = saved = total = 0; }; 00068 void add(const entree *ref); 00069 void listing(ostream & flux) const; 00070 }; 00071 00072 class entree 00073 { 00074 public : 00075 static void reset_read() { corres.clear(); stats.clear(); }; 00076 static entree *read(generic_file & f); 00077 static entree_stats get_stats() { return stats; }; 00078 static void freemem() { stats.clear(); corres.clear(); }; 00079 00080 virtual ~entree() {}; 00081 virtual void dump(generic_file & f) const; 00082 virtual unsigned char signature() const = 0; 00083 virtual entree *clone() const = 0; 00084 00085 private : 00086 static map <infinint, file_etiquette *> corres; 00087 static entree_stats stats; 00088 }; 00089 00090 extern bool compatible_signature(unsigned char a, unsigned char b); 00091 00092 class eod : public entree 00093 { 00094 public : 00095 eod() {}; 00096 eod(generic_file & f) {}; 00097 // dump defined by entree 00098 unsigned char signature() const { return 'z'; }; 00099 entree *clone() const { return new eod(); }; 00100 }; 00101 00102 class nomme : public entree 00103 { 00104 public : 00105 nomme(const string & name) { xname = name; }; 00106 nomme(generic_file & f); 00107 void dump(generic_file & f) const; 00108 00109 string get_name() const { return xname; }; 00110 void change_name(const string &x) { xname = x; }; 00111 bool same_as(const nomme & ref) const { return xname == ref.xname; }; 00112 // no need to have a virtual method, as signature will differ in inherited classes (argument type changes) 00113 00114 // signature() is kept as an abstract method 00115 // clone() is abstract 00116 00117 private : 00118 string xname; 00119 }; 00120 00121 class inode : public nomme 00122 { 00123 public: 00124 inode(U_16 xuid, U_16 xgid, U_16 xperm, 00125 const infinint & last_access, 00126 const infinint & last_modif, 00127 const string & xname); 00128 inode(generic_file & f, saved_status saved); 00129 inode(const inode & ref); 00130 ~inode() { if(ea != NULL) delete ea; }; 00131 00132 void dump(generic_file & f) const; 00133 U_16 get_uid() const { return uid; }; 00134 U_16 get_gid() const { return gid; }; 00135 U_16 get_perm() const { return perm; }; 00136 infinint get_last_access() const { return last_acc; }; 00137 infinint get_last_modif() const { return last_mod; }; 00138 void set_last_access(const infinint & x_time) { last_acc = x_time; }; 00139 void set_last_modif(const infinint & x_time) { last_mod = x_time; }; 00140 saved_status get_saved_status() const { return xsaved; }; 00141 void set_saved_status(saved_status x) { xsaved = x; }; 00142 00143 bool same_as(const inode & ref) const; 00144 virtual bool is_more_recent_than(const inode & ref) const; 00145 virtual bool has_changed_since(const inode & ref) const; 00146 // signature() left as an abstract method 00147 // clone is abstract 00148 void compare(const inode &other, bool root_ea, bool user_ea) const; 00149 // throw Erange exception if a difference has been detected 00150 // this is not a symetrical comparison, but all what is present 00151 // in the current object is compared against the argument 00152 // which may contain supplementary informations 00153 00154 00155 00157 // EXTENDED ATTRIBUTS Methods 00158 // 00159 00160 enum ea_status { ea_none, ea_partial, ea_full }; 00161 // ea_none : no EA present to this inode in filesystem 00162 // ea_partial : EA present in filesystem but not stored (ctime used to check changes) 00163 // ea_full : EA present in filesystem and attached to this inode 00164 00165 // I : to know whether EA data is present or not for this object 00166 void ea_set_saved_status(ea_status status); 00167 ea_status ea_get_saved_status() const { return ea_saved; }; 00168 00169 // II : to associate EA list to an inode object (mainly for backup operation) #EA_FULL only# 00170 void ea_attach(ea_attributs *ref); 00171 const ea_attributs *get_ea() const; 00172 void ea_detach() const; //discards any future call to get_ea() ! 00173 00174 // III : to record where is dump the EA in the archive #EA_FULL only# 00175 void ea_set_offset(const infinint & pos) { ea_offset = pos; }; 00176 void ea_set_crc(const crc & val) { copy_crc(ea_crc, val); }; 00177 00178 // IV : to know/record if EA have been modified #EA_FULL or EA_PARTIAL# 00179 infinint get_last_change() const; 00180 void set_last_change(const infinint & x_time); 00181 00183 00184 static void set_ignore_owner(bool mode) { ignore_owner = mode; }; 00185 00186 protected: 00187 virtual void sub_compare(const inode & other) const {}; 00188 00189 private : 00190 U_16 uid; 00191 U_16 gid; 00192 U_16 perm; 00193 infinint last_acc, last_mod; 00194 saved_status xsaved; 00195 ea_status ea_saved; 00196 // the following is used only if ea_saved == full 00197 infinint ea_offset; 00198 ea_attributs *ea; 00199 // the following is used if ea_saved == full or ea_saved == partial 00200 infinint last_cha; 00201 crc ea_crc; 00202 00203 static generic_file *storage; // where are stored EA 00204 // this is a static variable (shared amoung all objects) 00205 // because it is not efficient to have many copies of the same value 00206 // if in the future, all inode have their EA stored in their own 00207 // generic_file, this will be changed. 00208 static bool ignore_owner; 00209 }; 00210 00211 class file : public inode 00212 { 00213 public : 00214 file(U_16 xuid, U_16 xgid, U_16 xperm, 00215 const infinint & last_access, 00216 const infinint & last_modif, 00217 const string & src, 00218 const path & che, 00219 const infinint & taille); 00220 file(generic_file & f, saved_status saved); 00221 00222 void dump(generic_file & f) const; 00223 bool is_more_recent_than(const inode & ref) const; 00224 bool has_changed_since(const inode & ref) const; 00225 infinint get_size() const { return size; }; 00226 infinint get_storage_size() const { return storage_size; }; 00227 void set_storage_size(const infinint & s) { storage_size = s; }; 00228 generic_file *get_data() const; // return a newly alocated object in read_only mode 00229 void clean_data(); // partially free memory (but get_data() becomes disabled) 00230 void set_offset(const infinint & r); 00231 unsigned char signature() const { return mk_signature('f', get_saved_status()); }; 00232 00233 void set_crc(const crc &c) { copy_crc(check, c); }; 00234 bool get_crc(crc & c) const; 00235 entree *clone() const { return new file(*this); }; 00236 00237 static void set_compression_algo_used(compression a) { algo = a; }; 00238 static compression get_compression_algo_used() { return algo; }; 00239 static void set_archive_localisation(generic_file *f) { loc = f; }; 00240 00241 protected : 00242 void sub_compare(const inode & other) const; 00243 00244 private : 00245 enum { empty, from_path, from_cat } status; 00246 path chemin; 00247 infinint offset; 00248 infinint size; 00249 infinint storage_size; 00250 crc check; 00251 00252 static generic_file *loc; 00253 static compression algo; 00254 }; 00255 00256 class etiquette 00257 { 00258 public: 00259 virtual infinint get_etiquette() const = 0; 00260 virtual const file *get_inode() const = 0; 00261 }; 00262 00263 class file_etiquette : public file, public etiquette 00264 { 00265 public : 00266 file_etiquette(U_16 xuid, U_16 xgid, U_16 xperm, 00267 const infinint & last_access, 00268 const infinint & last_modif, 00269 const string & src, 00270 const path & che, 00271 const infinint & taille) : file(xuid, xgid, xperm, last_access, last_modif, src, che, taille) 00272 { etiquette = compteur++; }; 00273 file_etiquette(generic_file & f, saved_status saved); 00274 00275 void dump(generic_file &f) const; 00276 unsigned char signature() const { return mk_signature('e', get_saved_status()); }; 00277 entree *clone() const { return new file_etiquette(*this); }; 00278 00279 static void reset_etiquette_counter() { compteur = 0; }; 00280 00281 // inherited from etiquette 00282 infinint get_etiquette() const { return etiquette; }; 00283 void change_etiquette() { etiquette = compteur++; }; 00284 const file *get_inode() const { return this; }; 00285 00286 private : 00287 infinint etiquette; 00288 00289 static infinint compteur; 00290 }; 00291 00292 class hard_link : public nomme, public etiquette 00293 { 00294 public : 00295 hard_link(const string & name, file_etiquette *ref); 00296 hard_link(generic_file & f, infinint & etiquette); // with etiquette, a call to set_reference() follows 00297 00298 void dump(generic_file &f) const; 00299 unsigned char signature() const { return 'h'; }; 00300 entree *clone() const { return new hard_link(*this); }; 00301 void set_reference(file_etiquette *ref); 00302 00303 // inherited from etiquette 00304 infinint get_etiquette() const { return x_ref->get_etiquette(); }; 00305 const file *get_inode() const { return x_ref; }; 00306 00307 private : 00308 file_etiquette *x_ref; 00309 }; 00310 00311 00312 class lien : public inode 00313 { 00314 public : 00315 lien(U_16 uid, U_16 gid, U_16 perm, 00316 const infinint & last_access, 00317 const infinint & last_modif, 00318 const string & name, const string & target); 00319 lien(generic_file & f, saved_status saved); 00320 00321 void dump(generic_file & f) const; 00322 string get_target() const; 00323 void set_target(string x); 00324 00325 // using the method is_more_recent_than() from inode 00326 // using method has_changed_since() from inode class 00327 unsigned char signature() const { return mk_signature('l', get_saved_status()); }; 00328 entree *clone() const { return new lien(*this); }; 00329 00330 protected : 00331 void sub_compare(const inode & other) const; 00332 00333 private : 00334 string points_to; 00335 }; 00336 00337 class directory : public inode 00338 { 00339 public : 00340 directory(U_16 xuid, U_16 xgid, U_16 xperm, 00341 const infinint & last_access, 00342 const infinint & last_modif, 00343 const string & xname); 00344 directory(const directory &ref); // only the inode part is build, no children is duplicated (empty dir) 00345 directory(generic_file & f, saved_status saved); 00346 ~directory(); // detruit aussi tous les fils et se supprime de son 'parent' 00347 00348 void dump(generic_file & f) const; 00349 void add_children(nomme *r); // when r is a directory, 'parent' is set to 'this' 00350 void reset_read_children() const; 00351 bool read_children(const nomme * &r) const; // read the direct children of the directory, returns false if no more is available 00352 void listing(ostream & flux, const mask &m = bool_mask(true), string marge = "") const; 00353 void tar_listing(ostream & flux, const mask &m = bool_mask(true), const string & beginning = "") const; 00354 directory * get_parent() const { return parent; }; 00355 bool search_children(const string &name, nomme *&ref); 00356 00357 // using is_more_recent_than() from inode class 00358 // using method has_changed_since() from inode class 00359 unsigned char signature() const { return mk_signature('d', get_saved_status()); }; 00360 entree *clone() const { return new directory(*this); }; 00361 00362 private : 00363 directory *parent; 00364 vector<nomme *> fils; 00365 vector<nomme *>::iterator it; 00366 00367 void clear(); 00368 }; 00369 00370 class device : public inode 00371 { 00372 public : 00373 device(U_16 uid, U_16 gid, U_16 perm, 00374 const infinint & last_access, 00375 const infinint & last_modif, 00376 const string & name, 00377 U_16 major, 00378 U_16 minor); 00379 device(generic_file & f, saved_status saved); 00380 00381 void dump(generic_file & f) const; 00382 int get_major() const { if(get_saved_status() != s_saved) throw SRC_BUG; else return xmajor; }; 00383 int get_minor() const { if(get_saved_status() != s_saved) throw SRC_BUG; else return xminor; }; 00384 void set_major(int x) { xmajor = x; }; 00385 void set_minor(int x) { xminor = x; }; 00386 00387 // using method is_more_recent_than() from inode class 00388 // using method has_changed_since() from inode class 00389 // signature is left pure abstract 00390 00391 protected : 00392 void sub_compare(const inode & other) const; 00393 00394 private : 00395 U_16 xmajor, xminor; 00396 }; 00397 00398 class chardev : public device 00399 { 00400 public: 00401 chardev(U_16 uid, U_16 gid, U_16 perm, 00402 const infinint & last_access, 00403 const infinint & last_modif, 00404 const string & name, 00405 U_16 major, 00406 U_16 minor) : device(uid, gid, perm, last_access, 00407 last_modif, name, 00408 major, minor) {}; 00409 chardev(generic_file & f, saved_status saved) : device(f, saved) {}; 00410 00411 // using dump from device class 00412 // using method is_more_recent_than() from device class 00413 // using method has_changed_since() from device class 00414 unsigned char signature() const { return mk_signature('c', get_saved_status()); }; 00415 entree *clone() const { return new chardev(*this); }; 00416 }; 00417 00418 class blockdev : public device 00419 { 00420 public: 00421 blockdev(U_16 uid, U_16 gid, U_16 perm, 00422 const infinint & last_access, 00423 const infinint & last_modif, 00424 const string & name, 00425 U_16 major, 00426 U_16 minor) : device(uid, gid, perm, last_access, 00427 last_modif, name, 00428 major, minor) {}; 00429 blockdev(generic_file & f, saved_status saved) : device(f, saved) {}; 00430 00431 // using dump from device class 00432 // using method is_more_recent_than() from device class 00433 // using method has_changed_since() from device class 00434 unsigned char signature() const { return mk_signature('b', get_saved_status()); }; 00435 entree *clone() const { return new blockdev(*this); }; 00436 }; 00437 00438 class tube : public inode 00439 { 00440 public : 00441 tube(U_16 xuid, U_16 xgid, U_16 xperm, 00442 const infinint & last_access, 00443 const infinint & last_modif, 00444 const string & xname) : inode(xuid, xgid, xperm, last_access, last_modif, xname) { set_saved_status(s_saved); }; 00445 tube(generic_file & f, saved_status saved) : inode(f, saved) {}; 00446 00447 // using dump from inode class 00448 // using method is_more_recent_than() from inode class 00449 // using method has_changed_since() from inode class 00450 unsigned char signature() const { return mk_signature('p', get_saved_status()); }; 00451 entree *clone() const { return new tube(*this); }; 00452 }; 00453 00454 class prise : public inode 00455 { 00456 public : 00457 prise(U_16 xuid, U_16 xgid, U_16 xperm, 00458 const infinint & last_access, 00459 const infinint & last_modif, 00460 const string & xname) : inode(xuid, xgid, xperm, last_access, last_modif, xname) { set_saved_status(s_saved); }; 00461 prise(generic_file & f, saved_status saved) : inode(f, saved) {}; 00462 00463 // using dump from inode class 00464 // using method is_more_recent_than() from inode class 00465 // using method has_changed_since() from inode class 00466 unsigned char signature() const { return mk_signature('s', get_saved_status()); }; 00467 entree *clone() const { return new prise(*this); }; 00468 }; 00469 00470 class detruit : public nomme 00471 { 00472 public : 00473 detruit(const string & name, unsigned char firm) : nomme(name) { signe = firm; }; 00474 detruit(generic_file & f) : nomme(f) { if(f.read((char *)&signe, 1) != 1) throw Erange("detruit::detruit", "missing data to buid"); }; 00475 00476 void dump(generic_file & f) const { nomme::dump(f); f.write((char *)&signe, 1); }; 00477 unsigned char get_signature() const { return signe; }; 00478 void set_signature(unsigned char x) { signe = x; }; 00479 unsigned char signature() const { return 'x'; }; 00480 entree *clone() const { return new detruit(*this); }; 00481 00482 private : 00483 unsigned char signe; 00484 }; 00485 00486 class ignored : public nomme 00487 { 00488 public : 00489 ignored(const string & name) : nomme(name) {}; 00490 ignored(generic_file & f) : nomme(f) { throw SRC_BUG; }; 00491 00492 void dump(generic_file & f) const { throw SRC_BUG; }; 00493 unsigned char signature() const { return 'i'; }; 00494 entree *clone() const { return new ignored(*this); }; 00495 }; 00496 00497 class ignored_dir : public inode 00498 { 00499 public: 00500 ignored_dir(const directory &target) : inode(target) {}; 00501 ignored_dir(generic_file & f) : inode(f, s_not_saved) { throw SRC_BUG; }; 00502 00503 void dump(generic_file & f) const; // behaves like an empty directory 00504 unsigned char signature() const { return 'j'; }; 00505 entree *clone() const { return new ignored_dir(*this); }; 00506 }; 00507 00508 class catalogue 00509 { 00510 public : 00511 catalogue(); 00512 catalogue(generic_file & f); 00513 catalogue(const catalogue & ref) : out_compare(ref.out_compare) { partial_copy_from(ref); }; 00514 catalogue & operator = (const catalogue &ref); 00515 ~catalogue() { detruire(); }; 00516 00517 void reset_read(); 00518 void skip_read_to_parent_dir(); 00519 // skip all items of the current dir and of any subdir, the next call will return 00520 // next item of the parent dir (no eod to exit from the current dir !) 00521 bool read(const entree * & ref); 00522 // sequential read (generates eod) and return false when all files have been read 00523 bool read_if_present(string *name, const nomme * & ref); 00524 // pseudo-sequential read (reading a directory still 00525 // implies that following read are located in this subdirectory up to the next EOD) but 00526 // it returns false if no entry of this name are present in the current directory 00527 // a call with NULL as first argument means to set the current dir the parent directory 00528 00529 void reset_sub_read(const path &sub); // return false if the path do not exists in catalogue 00530 bool sub_read(const entree * &ref); // sequential read of the catalogue, ignoring all that 00531 // is not part of the subdirectory specified with reset_sub_read 00532 // the read include the inode leading to the sub_tree as well as the pending eod 00533 00534 void reset_add(); 00535 void add(entree *ref); // add at end of catalogue (sequential point of view) 00536 void add_in_current_read(nomme *ref); // add in currently read directory 00537 00538 void reset_compare(); 00539 bool compare(const entree * name, const entree * & extracted); 00540 // returns true if the ref exists, and gives it back in second argument as it is in the current catalogue. 00541 // returns false is no entry of that nature exists in the catalogue (in the current directory) 00542 // if ref is a directory, the operation is normaly relative to the directory itself, but 00543 // such a call implies a chdir to that directory. thus, a call with an EOD is necessary to 00544 // change to the parent directory. 00545 // note : 00546 // if a directory is not present, returns false, but records the inexistant subdirectory 00547 // structure defined by the following calls to this routine, this to be able to know when 00548 // the last available directory is back the current one when changing to parent directory, 00549 // and then proceed with normal comparison of inode. In this laps of time, the call will 00550 // always return false, while it temporary stores the missing directory structure 00551 00552 bool direct_read(const path & ref, const nomme * &ret); 00553 00554 infinint update_destroyed_with(catalogue & ref); 00555 // ref must have the same root, else the operation generates a exception 00556 00557 void dump(generic_file & ref) const; 00558 void listing(ostream & flux, const mask &m = bool_mask(true), string marge = "") const; 00559 void tar_listing(ostream & flux, const mask & m = bool_mask(true), const string & beginning = "") const; 00560 entree_stats get_stats() const { return stats; }; 00561 00562 const directory *get_contenu() const { return contenu; }; // used by data_tree 00563 00564 private : 00565 directory *contenu; 00566 path out_compare; // stores the missing directory structure, when extracting 00567 directory *current_compare; // points to the current directory when extracting 00568 directory *current_add; // points to the directory where to add the next file with add_file; 00569 directory *current_read; // points to the directory where the next item will be read 00570 path *sub_tree; // path to sub_tree 00571 signed int sub_count; // count the depth in of read routine in the sub_tree 00572 entree_stats stats; // statistics catalogue contents 00573 00574 void partial_copy_from(const catalogue &ref); 00575 void detruire(); 00576 00577 static const eod r_eod; // needed to return eod reference, without taking risk of saturating memory 00578 }; 00579 00580 #endif