Disk ARchive  2.4.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
.pc/delete2/catalogue.hpp
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines