Disk ARchive  2.4.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
catalogue.hpp
Go to the documentation of this file.
1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21 // $Id: catalogue.hpp,v 1.111 2011/05/27 12:29:18 edrusb Rel $
22 //
23 /*********************************************************************/
24 
28 
29 #ifndef CATALOGUE_HPP
30 #define CATALOGUE_HPP
31 
32 #include "../my_config.h"
33 
34 extern "C"
35 {
36 #if HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 } // end extern "C"
40 
41 #include <vector>
42 #include <map>
43 #include "infinint.hpp"
44 #include "generic_file.hpp"
45 #include "path.hpp"
46 #include "header_version.hpp"
47 #include "ea.hpp"
48 #include "compressor.hpp"
49 #include "integers.hpp"
50 #include "mask.hpp"
51 #include "special_alloc.hpp"
52 #include "user_interaction.hpp"
53 #include "label.hpp"
54 #include "escape.hpp"
55 
56 namespace libdar
57 {
58  class etoile;
59  class entree;
60 
63 
64  enum saved_status
65  {
66  s_saved, //< inode is saved in the archive
67  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.
68  s_not_saved //< inode is not saved in the archive
69  };
70 
72  struct entree_stats
73  {
74  infinint num_x; //< number of file referenced as destroyed since last backup
75  infinint num_d; //< number of directories
76  infinint num_f; //< number of plain files (hard link or not, thus file directory entries)
77  infinint num_c; //< number of char devices
78  infinint num_b; //< number of block devices
79  infinint num_p; //< number of named pipes
80  infinint num_s; //< number of unix sockets
81  infinint num_l; //< number of symbolic links
82  infinint num_D; //< number of Door
83  infinint num_hard_linked_inodes; //< number of inode that have more than one link (inode with "hard links")
84  infinint num_hard_link_entries; //< total number of hard links (file directory entry pointing to \an
85  //< inode already linked in the same or another directory (i.e. hard linked))
86  infinint saved; //< total number of saved inode (unix inode, not inode class) hard links do not count here
87  infinint total; //< total number of inode in archive (unix inode, not inode class) hard links do not count here
88  void clear() { num_x = num_d = num_f = num_c = num_b = num_p
89  = num_s = num_l = num_D = num_hard_linked_inodes
90  = num_hard_link_entries = saved = total = 0; };
91  void add(const entree *ref);
92  void listing(user_interaction & dialog) const;
93  };
94 
96  class entree
97  {
98  public :
99  static entree *read(user_interaction & dialog,
100  generic_file & f, const archive_version & reading_ver,
101  entree_stats & stats,
102  std::map <infinint, etoile *> & corres,
103  compression default_algo,
104  generic_file *data_loc,
105  generic_file *ea_loc,
106  bool lax,
107  bool only_detruit,
108  escape *ptr);
109 
110  virtual ~entree() {};
111 
113 
120  void dump(generic_file & f, bool small) const;
121 
123 
130  void specific_dump(generic_file & f, bool small) const { inherited_dump(f, small); };
131 
133 
136  virtual void post_constructor(generic_file & f) {};
137 
138 
139  virtual unsigned char signature() const = 0;
140  virtual entree *clone() const = 0;
141 
142  // SPECIAL ALLOC not adapted here
143  // because some inherited class object (eod) are
144  // temporary
145 
146  protected:
147  virtual void inherited_dump(generic_file & f, bool small) const;
148 
149 
150  private:
151  static const U_I ENTREE_CRC_SIZE;
152 
153  };
154 
155  extern bool compatible_signature(unsigned char a, unsigned char b);
156  extern unsigned char mk_signature(unsigned char base, saved_status state);
157 
159  class eod : public entree
160  {
161  public :
162  eod() {};
163  eod(generic_file & f) {};
164  // dump defined by entree
165  unsigned char signature() const { return 'z'; };
166  entree *clone() const { return new eod(); };
167 
168  // eod are generally temporary object they are NOT
169  // well adapted to "SPECIAL ALLOC"
170  };
171 
173  class nomme : public entree
174  {
175  public:
176  nomme(const std::string & name) { xname = name; };
177  nomme(generic_file & f);
178  virtual bool operator == (const nomme & ref) const { return xname == ref.xname; };
179  virtual bool operator < (const nomme & ref) const { return xname < ref.xname; };
180 
181  const std::string & get_name() const { return xname; };
182  void change_name(const std::string & x) { xname = x; };
183  bool same_as(const nomme & ref) const { return xname == ref.xname; };
184  // no need to have a virtual method, as signature will differ in inherited classes (argument type changes)
185 
186  // signature() is kept as an abstract method
187  // clone() is abstract
188 
189 #ifdef LIBDAR_SPECIAL_ALLOC
190  USE_SPECIAL_ALLOC(nomme);
191 #endif
192 
193  protected:
194  void inherited_dump(generic_file & f, bool small) const;
195 
196  private:
197  std::string xname;
198  };
199 
200 
202  class inode : public nomme
203  {
204  public:
205 
207 
209  {
210  cf_all, //< consider any available field for comparing inodes
211  cf_ignore_owner, //< consider any available field except ownership fields
212  cf_mtime, //< consider any available field except ownership and permission fields
213  cf_inode_type //< only consider the file type
214  };
215 
216  inode(const infinint & xuid, const infinint & xgid, U_16 xperm,
217  const infinint & last_access,
218  const infinint & last_modif,
219  const infinint & last_change,
220  const std::string & xname, const infinint & device);
221  inode(user_interaction & dialog,
222  generic_file & f,
223  const archive_version & reading_ver,
224  saved_status saved,
225  generic_file *ea_loc,
226  escape *ptr); // if ptr is not NULL, reading a partial dump(), which was done with "small" set to true
227  inode(const inode & ref);
228  const inode & operator = (const inode & ref);
229  ~inode();
230 
231  const infinint & get_uid() const { return uid; };
232  const infinint & get_gid() const { return gid; };
233  U_16 get_perm() const { return perm; };
234  infinint get_last_access() const { return *last_acc; };
235  infinint get_last_modif() const { return *last_mod; };
236  void set_last_access(const infinint & x_time) { *last_acc = x_time; };
237  void set_last_modif(const infinint & x_time) { *last_mod = x_time; };
238  saved_status get_saved_status() const { return xsaved; };
239  void set_saved_status(saved_status x) { xsaved = x; };
240  infinint get_device() const { return *fs_dev; };
241 
242  bool same_as(const inode & ref) const;
243  bool is_more_recent_than(const inode & ref, const infinint & hourshift) const;
244  // used for RESTORATION
245  virtual bool has_changed_since(const inode & ref, const infinint & hourshift, comparison_fields what_to_check) const;
246  // signature() left as an abstract method
247  // clone is abstract too
248  // used for INCREMENTAL BACKUP
249  void compare(const inode &other,
250  const mask & ea_mask,
251  comparison_fields what_to_check,
252  const infinint & hourshift,
253  bool symlink_date) const;
254 
255  // throw Erange exception if a difference has been detected
256  // this is not a symetrical comparison, but all what is present
257  // in the current object is compared against the argument
258  // which may contain supplementary informations
259  // used for DIFFERENCE
260 
261 
262 
264  // EXTENDED ATTRIBUTS Methods
265  //
266 
267  enum ea_status { ea_none, ea_partial, ea_fake, ea_full, ea_removed };
268  // ea_none : no EA present for this inode in filesystem
269  // ea_partial : EA present in filesystem but not stored (ctime used to check changes)
270  // 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.
271  // ea_full : EA present in filesystem and attached to this inode
272  // ea_removed : EA were present in the reference version, but not present anymore
273 
274  // I : to know whether EA data is present or not for this object
275  void ea_set_saved_status(ea_status status);
276  ea_status ea_get_saved_status() const { return ea_saved; };
277 
278  // II : to associate EA list to an inode object (mainly for backup operation) #EA_FULL only#
279  void ea_attach(ea_attributs *ref);
280  const ea_attributs *get_ea() const; // #<-- EA_FULL *and* EA_REMOVED# for this call only
281  void ea_detach() const; //discards any future call to get_ea() !
282  infinint ea_get_size() const; //returns the size of EA (still valid if ea have been detached)
283 
284  // III : to record where is dump the EA in the archive #EA_FULL only#
285  void ea_set_offset(const infinint & pos) { *ea_offset = pos; };
286  void ea_set_crc(const crc & val) { crc::set_crc_pointer(ea_crc, &val); };
287  void ea_get_crc(crc & val) const;
288  bool ea_get_crc_size(infinint & val) const; //< returns true if crc is know and puts its width in argument
289 
290  // IV : to know/record if EA have been modified # any EA status#
291  infinint get_last_change() const;
292  void set_last_change(const infinint & x_time);
293  bool has_last_change() const { return last_cha != NULL; };
294  // old format did provide last_change only when EA were present, since archive
295  // format 8, this field is always present even in absence of EA. Thus it is
296  // still necessary to check if the inode has a last_change() before
297  // using get_last_change() (depends on the version of the archive read).
298 
299 
300  // V : for archive migration (merging)
301  void change_ea_location(generic_file *loc) { storage = loc; };
302 
304 
305 #ifdef LIBDAR_SPECIAL_ALLOC
306  USE_SPECIAL_ALLOC(inode);
307 #endif
308 
309  protected:
310  virtual void sub_compare(const inode & other) const {};
311 
313  escape *get_escape_layer() const { return esc; };
314 
315  void inherited_dump(generic_file & f, bool small) const;
316 
317  private :
318  infinint uid;
319  infinint gid;
320  U_16 perm;
321  infinint *last_acc, *last_mod;
322  saved_status xsaved;
323  ea_status ea_saved;
324  // the following is used only if ea_saved == full
325  infinint *ea_offset;
326  ea_attributs *ea;
327  infinint ea_size;
328  // the following is used if ea_saved == full or ea_saved == partial
329  infinint *last_cha;
330  crc *ea_crc;
331  infinint *fs_dev;
332  generic_file *storage; // where are stored EA
333  archive_version edit; // need to know EA format used in archive file
334 
335  escape *esc; // if not NULL, the object is partially build from archive (at archive generation, dump() was called with small set to true)
336 
337  static const ea_attributs empty_ea;
338  };
339 
341  class etoile
342  {
343  public:
344 
346 
350  etoile(inode *host, const infinint & etiquette_number);
351  etoile(const etoile & ref) { throw SRC_BUG; }; // copy constructor not allowed for this class
352  const etoile & operator = (const etoile & ref) { throw SRC_BUG; }; // assignment not allowed for this class
353  ~etoile() { delete hosted; };
354 
355  void add_ref(void *ref);
356  void drop_ref(void *ref);
357  infinint get_ref_count() const { return refs.size(); };
358  inode *get_inode() const { return hosted; };
359  infinint get_etiquette() const { return etiquette; };
360  void change_etiquette(const infinint & new_val) { etiquette = new_val; };
361 
362 
363  bool is_counted() const { return tags.counted; };
364  bool is_wrote() const { return tags.wrote; };
365  bool is_dumped() const { return tags.dumped; };
366  void set_counted(bool val) { tags.counted = val ? 1 : 0; };
367  void set_wrote(bool val) { tags.wrote = val ? 1 : 0; };
368  void set_dumped(bool val) { tags.dumped = val ? 1 : 0; };
369 
370  // return the address of the first mirage that triggered the creation of this mirage
371  // if this object is destroyed afterward this call returns NULL
372  const void *get_first_ref() const { if(refs.size() == 0) throw SRC_BUG; return refs.front(); };
373 
374 #ifdef LIBDAR_SPECIAL_ALLOC
375  USE_SPECIAL_ALLOC(etoile);
376 #endif
377 
378  private:
379  struct bool_tags
380  {
381  unsigned counted : 1; //< whether the inode has been counted
382  unsigned wrote : 1; //< whether the inode has its data copied to archive
383  unsigned dumped : 1; //< whether the inode information has been dumped in the catalogue
384  unsigned : 5; //< padding to get byte boundary and reserved for future use.
385 
386  bool_tags() { counted = wrote = dumped = 0; };
387  };
388 
389  std::list<void *> refs; //< list of pointers to the mirages objects, in the order of their creation
390  inode *hosted;
391  infinint etiquette;
392  bool_tags tags;
393  };
394 
396 
398  class mirage : public nomme
399  {
400  public:
401  enum mirage_format {fmt_mirage, //< new format
402  fmt_hard_link, //< old dual format
403  fmt_file_etiquette }; //< old dual format
404 
405  mirage(const std::string & name, etoile *ref) : nomme(name) { star_ref = ref; if(ref == NULL) throw SRC_BUG; star_ref->add_ref(this); };
406  mirage(user_interaction & dialog,
407  generic_file & f,
408  const archive_version & reading_ver,
409  saved_status saved,
410  entree_stats & stats,
411  std::map <infinint, etoile *> & corres,
412  compression default_algo,
413  generic_file *data_loc,
414  generic_file *ea_loc,
415  mirage_format fmt,
416  bool lax,
417  escape *ptr);
418  mirage(user_interaction & dialog,
419  generic_file & f,
420  const archive_version & reading_ver,
421  saved_status saved,
422  entree_stats & stats,
423  std::map <infinint, etoile *> & corres,
424  compression default_algo,
425  generic_file *data_loc,
426  generic_file *ea_loc,
427  bool lax,
428  escape *ptr);
429  mirage(const mirage & ref) : nomme (ref) { star_ref = ref.star_ref; if(star_ref == NULL) throw SRC_BUG; star_ref->add_ref(this); };
430  const mirage & operator = (const mirage & ref);
431  ~mirage() { star_ref->drop_ref(this); };
432 
433  unsigned char signature() const { return 'm'; };
434  entree *clone() const { return new mirage(*this); };
435 
436  inode *get_inode() const { if(star_ref == NULL) throw SRC_BUG; return star_ref->get_inode(); };
437  infinint get_etiquette() const { return star_ref->get_etiquette(); };
438  infinint get_etoile_ref_count() const { return star_ref->get_ref_count(); };
439  etoile *get_etoile() const { return star_ref; };
440 
441  bool is_inode_counted() const { return star_ref->is_counted(); };
442  bool is_inode_wrote() const { return star_ref->is_wrote(); };
443  bool is_inode_dumped() const { return star_ref->is_dumped(); };
444  void set_inode_counted(bool val) const { star_ref->set_counted(val); };
445  void set_inode_wrote(bool val) const { star_ref->set_wrote(val); };
446  void set_inode_dumped(bool val) const { star_ref->set_dumped(val); };
447 
448  void post_constructor(generic_file & f);
449 
451  bool is_first_mirage() const { return star_ref->get_first_ref() == this; };
452 
453 #ifdef LIBDAR_SPECIAL_ALLOC
454  USE_SPECIAL_ALLOC(mirage);
455 #endif
456 
457  protected:
458  void inherited_dump(generic_file & f, bool small) const;
459 
460  private:
461  etoile *star_ref;
462 
463  void init(user_interaction & dialog,
464  generic_file & f,
465  const archive_version & reading_ver,
466  saved_status saved,
467  entree_stats & stats,
468  std::map <infinint, etoile *> & corres,
469  compression default_algo,
470  generic_file *data_loc,
471  generic_file *ea_loc,
472  mirage_format fmt,
473  bool lax,
474  escape *ptr);
475  };
476 
477 
479  class file : public inode
480  {
481  public :
482  enum get_data_mode
483  {
484  keep_compressed, //< provide access to compressed data
485  keep_hole, //< provide access to uncompressed data but sparse_file datastructure
486  normal, //< provide access to full data (uncompressed, uses skip() to restore holes)
487  plain //< provide access to plain data, no skip to restore holes, provide instead zeroed bytes
488  };
489 
490  static const U_8 FILE_DATA_WITH_HOLE = 0x01; //< file's data contains hole datastructure
491  static const U_8 FILE_DATA_IS_DIRTY = 0x02; //< data modified while being saved
492 
493  file(const infinint & xuid, const infinint & xgid, U_16 xperm,
494  const infinint & last_access,
495  const infinint & last_modif,
496  const infinint & last_change,
497  const std::string & src,
498  const path & che,
499  const infinint & taille,
500  const infinint & fs_device,
501  bool x_furtive_read_mode);
502  file(const file & ref);
503  file(user_interaction & dialog,
504  generic_file & f,
505  const archive_version & reading_ver,
506  saved_status saved,
507  compression default_algo,
508  generic_file *data_loc,
509  generic_file *ea_loc,
510  escape *ptr);
511  ~file() { detruit(); };
512 
513  bool has_changed_since(const inode & ref, const infinint & hourshift, inode::comparison_fields what_to_check) const;
514  infinint get_size() const { return *size; };
515  infinint get_storage_size() const { return *storage_size; };
516  void set_storage_size(const infinint & s) { *storage_size = s; };
517  virtual generic_file *get_data(get_data_mode mode) const; // returns a newly allocated object in read_only mode
518  void clean_data(); // partially free memory (but get_data() becomes disabled)
519  void set_offset(const infinint & r);
520  const infinint & get_offset() const;
521  unsigned char signature() const { return mk_signature('f', get_saved_status()); };
522 
523  void set_crc(const crc &c) { crc::set_crc_pointer(check, &c); };
524  bool get_crc(crc & c) const;
525  bool has_crc() const { return check != NULL; };
526  bool get_crc_size(infinint & val) const; //< returns true if crc is know and puts its width in argument
527  void drop_crc() { if(check != NULL) { delete check; check = NULL; } };
528 
529  // whether the plain file has to detect sparse file
530  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; };
531 
532  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; };
533 
534  // whether the plain file is stored with a sparse_file datastructure in the archive
535  bool get_sparse_file_detection_read() const { return (file_data_status_read & FILE_DATA_WITH_HOLE) != 0; };
536  bool get_sparse_file_detection_write() const { return (file_data_status_write & FILE_DATA_WITH_HOLE) != 0; };
537 
538  entree *clone() const { return new file(*this); };
539 
540  compression get_compression_algo_read() const { return algo_read; };
541 
542  compression get_compression_algo_write() const { return algo_write; };
543 
544  // object migration methods (merging)
545  void change_compression_algo_write(compression x) { algo_write = x; };
546  void change_location(generic_file *x) { loc = x; };
547 
548  // dirtiness
549 
550  bool is_dirty() const { return dirty; };
551  void set_dirty(bool value) { dirty = value; };
552 
553 #ifdef LIBDAR_SPECIAL_ALLOC
554  USE_SPECIAL_ALLOC(file);
555 #endif
556 
557  protected:
558  void sub_compare(const inode & other) const;
559  void inherited_dump(generic_file & f, bool small) const;
560  void post_constructor(generic_file & f);
561 
562  enum { empty, from_path, from_cat } status;
563 
564  private:
565  std::string chemin; //< path to the data (when read from filesystem)
566  infinint *offset; //< start location of the data in 'loc'
567  infinint *size; //< size of the data (uncompressed)
568  infinint *storage_size; //< how much data used in archive (after compression)
569  crc *check;
570  bool dirty; //< true when a file has been modified at the time it was saved
571 
572  generic_file *loc; //< where to find data (eventually compressed) at the recorded offset and for storage_size length
573  compression algo_read; //< which compression algorithm to use to read the file's data
574  compression algo_write; //< which compression algorithm to use to write down (merging) the file's data
575  bool furtive_read_mode; // used only when status equals "from_path"
576  char file_data_status_read; // defines the datastructure to use when reading the data
577  char file_data_status_write; // defines the datastructure to apply when writing down the data
578 
579  void detruit();
580  };
581 
583  class door : public file
584  {
585  public:
586  door(const infinint & xuid, const infinint & xgid, U_16 xperm,
587  const infinint & last_access,
588  const infinint & last_modif,
589  const infinint & last_change,
590  const std::string & src,
591  const path & che,
592  const infinint & fs_device) : file(xuid, xgid, xperm, last_access, last_modif,
593  last_change, src, che, 0, fs_device, false) {};
594  door(user_interaction & dialog,
595  generic_file & f,
596  const archive_version & reading_ver,
597  saved_status saved,
598  compression default_algo,
599  generic_file *data_loc,
600  generic_file *ea_loc,
601  escape *ptr) : file(dialog, f, reading_ver, saved, default_algo, data_loc, ea_loc, ptr) {};
602 
603  unsigned char signature() const { return mk_signature('o', get_saved_status()); };
604 
605  generic_file *get_data(get_data_mode mode) const; // inherited from class file
606  };
607 
609  class lien : public inode
610  {
611  public :
612  lien(const infinint & uid, const infinint & gid, U_16 perm,
613  const infinint & last_access,
614  const infinint & last_modif,
615  const infinint & last_change,
616  const std::string & name,
617  const std::string & target,
618  const infinint & fs_device);
619  lien(user_interaction & dialog,
620  generic_file & f,
621  const archive_version & reading_ver,
622  saved_status saved,
623  generic_file *ea_loc,
624  escape *ptr);
625 
626  const std::string & get_target() const;
627  void set_target(std::string x);
628 
629  // using the method is_more_recent_than() from inode
630  // using method has_changed_since() from inode class
631  unsigned char signature() const { return mk_signature('l', get_saved_status()); };
632  entree *clone() const { return new lien(*this); };
633 
634 #ifdef LIBDAR_SPECIAL_ALLOC
635  USE_SPECIAL_ALLOC(lien);
636 #endif
637  protected :
638  void sub_compare(const inode & other) const;
639  void inherited_dump(generic_file & f, bool small) const;
640 
641 
642  private :
643  std::string points_to;
644  };
645 
647  class directory : public inode
648  {
649  public :
650  directory(const infinint & xuid, const infinint & xgid, U_16 xperm,
651  const infinint & last_access,
652  const infinint & last_modif,
653  const infinint & last_change,
654  const std::string & xname,
655  const infinint & device);
656  directory(const directory &ref); // only the inode part is build, no children is duplicated (empty dir)
657  const directory & operator = (const directory & ref); // set the inode part *only* no subdirectories/subfiles are copies or removed.
658  directory(user_interaction & dialog,
659  generic_file & f,
660  const archive_version & reading_ver,
661  saved_status saved,
662  entree_stats & stats,
663  std::map <infinint, etoile *> & corres,
664  compression default_algo,
665  generic_file *data_loc,
666  generic_file *ea_loc,
667  bool lax,
668  bool only_detruit, // objects of other class than detruit and directory are not built in memory
669  escape *ptr);
670  ~directory(); // detruit aussi tous les fils et se supprime de son 'parent'
671 
672  void add_children(nomme *r); // when r is a directory, 'parent' is set to 'this'
673  bool has_children() const { return !fils.empty(); };
674  void reset_read_children() const;
675  void end_read() const;
676  bool read_children(const nomme * &r) const; // read the direct children of the directory, returns false if no more is available
677  // remove all entry not yet read by read_children
678  void tail_to_read_children();
679 
680  void remove(const std::string & name); // remove the given entry from the catalogue
681  // as side effect the reset_read_children() method must be called.
682 
683  directory * get_parent() const { return parent; };
684  bool search_children(const std::string &name, nomme *&ref);
685  bool callback_for_children_of(user_interaction & dialog, const std::string & sdir, bool isolated = false) const;
686 
687  // using is_more_recent_than() from inode class
688  // using method has_changed_since() from inode class
689  unsigned char signature() const { return mk_signature('d', get_saved_status()); };
690 
691  // some data has changed since archive of reference in this directory or subdirectories
692  bool get_recursive_has_changed() const { return recursive_has_changed; };
693  // update the recursive_has_changed field
694  void recursive_has_changed_update() const;
695 
696  // get then number of "nomme" entry contained in this directory and subdirectories (recursive call)
697  infinint get_tree_size() const;
698  // get the number of entry having some EA set in the directory tree (recursive call)
699  infinint get_tree_ea_num() const;
700  // get the number of entry that are hard linked inode (aka mirage in dar implementation) (recursive call)
701  infinint get_tree_mirage_num() const;
702  // for each mirage found (hard link implementation) in the directory tree, add its etiquette to the returned
703  // list with the number of reference that has been found in the tree. (map[etiquette] = number of occurence)
704  // from outside of class directory, the given argument is expected to be an empty map.
705  void get_etiquettes_found_in_tree(std::map<infinint, infinint> & already_found) const;
706 
707  // whether this directory is empty or not
708  bool is_empty() const { return fils.empty(); };
709 
710  // recursively remove all mirage entries
711  void remove_all_mirages_and_reduce_dirs();
712 
713  entree *clone() const { return new directory(*this); };
714 
715 #ifdef LIBDAR_SPECIAL_ALLOC
716  USE_SPECIAL_ALLOC(directory);
717 #endif
718 
719  protected:
720  void inherited_dump(generic_file & f, bool small) const;
721 
722  private :
723  static const eod fin;
724 
725  directory *parent;
726  std::map<std::string, nomme *> fils; // used for fast lookup
727  std::list<nomme *> ordered_fils;
728  std::list<nomme *>::iterator it;
729  bool recursive_has_changed;
730 
731  void clear();
732  };
733 
735  class device : public inode
736  {
737  public :
738  device(const infinint & uid, const infinint & gid, U_16 perm,
739  const infinint & last_access,
740  const infinint & last_modif,
741  const infinint &last_change,
742  const std::string & name,
743  U_16 major,
744  U_16 minor,
745  const infinint & fs_device);
746  device(user_interaction & dialog,
747  generic_file & f,
748  const archive_version & reading_ver,
749  saved_status saved,
750  generic_file *ea_loc,
751  escape *ptr);
752 
753  int get_major() const { if(get_saved_status() != s_saved) throw SRC_BUG; else return xmajor; };
754  int get_minor() const { if(get_saved_status() != s_saved) throw SRC_BUG; else return xminor; };
755  void set_major(int x) { xmajor = x; };
756  void set_minor(int x) { xminor = x; };
757 
758  // using method is_more_recent_than() from inode class
759  // using method has_changed_since() from inode class
760  // signature is left pure abstract
761 
762 #ifdef LIBDAR_SPECIAL_ALLOC
763  USE_SPECIAL_ALLOC(device);
764 #endif
765 
766  protected :
767  void sub_compare(const inode & other) const;
768  void inherited_dump(generic_file & f, bool small) const;
769 
770  private :
771  U_16 xmajor, xminor;
772  };
773 
775  class chardev : public device
776  {
777  public:
778  chardev(const infinint & uid, const infinint & gid, U_16 perm,
779  const infinint & last_access,
780  const infinint & last_modif,
781  const infinint & last_change,
782  const std::string & name,
783  U_16 major,
784  U_16 minor,
785  const infinint & fs_device) : device(uid, gid, perm,
786  last_access,
787  last_modif,
788  last_change,
789  name,
790  major, minor, fs_device) {};
791  chardev(user_interaction & dialog,
792  generic_file & f,
793  const archive_version & reading_ver,
794  saved_status saved,
795  generic_file *ea_loc,
796  escape *ptr) : device(dialog, f, reading_ver, saved, ea_loc, ptr) {};
797 
798  // using dump from device class
799  // using method is_more_recent_than() from device class
800  // using method has_changed_since() from device class
801  unsigned char signature() const { return mk_signature('c', get_saved_status()); };
802  entree *clone() const { return new chardev(*this); };
803 
804 #ifdef LIBDAR_SPECIAL_ALLOC
805  USE_SPECIAL_ALLOC(chardev);
806 #endif
807  };
808 
810  class blockdev : public device
811  {
812  public:
813  blockdev(const infinint & uid, const infinint & gid, U_16 perm,
814  const infinint & last_access,
815  const infinint & last_modif,
816  const infinint & last_change,
817  const std::string & name,
818  U_16 major,
819  U_16 minor,
820  const infinint & fs_device) : device(uid, gid, perm, last_access,
821  last_modif, last_change, name,
822  major, minor, fs_device) {};
823  blockdev(user_interaction & dialog,
824  generic_file & f,
825  const archive_version & reading_ver,
826  saved_status saved,
827  generic_file *ea_loc,
828  escape *ptr) : device(dialog, f, reading_ver, saved, ea_loc, ptr) {};
829 
830  // using dump from device class
831  // using method is_more_recent_than() from device class
832  // using method has_changed_since() from device class
833  unsigned char signature() const { return mk_signature('b', get_saved_status()); };
834  entree *clone() const { return new blockdev(*this); };
835 
836 #ifdef LIBDAR_SPECIAL_ALLOC
837  USE_SPECIAL_ALLOC(blockdev);
838 #endif
839  };
840 
842  class tube : public inode
843  {
844  public :
845  tube(const infinint & xuid, const infinint & xgid, U_16 xperm,
846  const infinint & last_access,
847  const infinint & last_modif,
848  const infinint & last_change,
849  const std::string & xname,
850  const infinint & fs_device) : inode(xuid, xgid, xperm, last_access, last_modif, last_change, xname, fs_device) { set_saved_status(s_saved); };
851  tube(user_interaction & dialog,
852  generic_file & f,
853  const archive_version & reading_ver,
854  saved_status saved,
855  generic_file *ea_loc,
856  escape *ptr) : inode(dialog, f, reading_ver, saved, ea_loc, ptr) {};
857 
858  // using dump from inode class
859  // using method is_more_recent_than() from inode class
860  // using method has_changed_since() from inode class
861  unsigned char signature() const { return mk_signature('p', get_saved_status()); };
862  entree *clone() const { return new tube(*this); };
863 
864 #ifdef LIBDAR_SPECIAL_ALLOC
865  USE_SPECIAL_ALLOC(tube);
866 #endif
867  };
868 
870  class prise : public inode
871  {
872  public :
873  prise(const infinint & xuid, const infinint & xgid, U_16 xperm,
874  const infinint & last_access,
875  const infinint & last_modif,
876  const infinint & last_change,
877  const std::string & xname,
878  const infinint & fs_device) : inode(xuid, xgid, xperm, last_access, last_modif, last_change, xname, fs_device) { set_saved_status(s_saved); };
879  prise(user_interaction & dialog,
880  generic_file & f,
881  const archive_version & reading_ver,
882  saved_status saved,
883  generic_file *ea_loc,
884  escape *ptr) : inode(dialog, f, reading_ver, saved, ea_loc, ptr) {};
885 
886  // using dump from inode class
887  // using method is_more_recent_than() from inode class
888  // using method has_changed_since() from inode class
889  unsigned char signature() const { return mk_signature('s', get_saved_status()); };
890  entree *clone() const { return new prise(*this); };
891 
892 #ifdef LIBDAR_SPECIAL_ALLOC
893  USE_SPECIAL_ALLOC(prise);
894 #endif
895  };
896 
898  class detruit : public nomme
899  {
900  public :
901  detruit(const std::string & name, unsigned char firm, const infinint & date) : nomme(name) , del_date(date) { signe = firm; };
902  detruit(generic_file & f, const archive_version & reading_ver);
903  detruit(const nomme &ref) : nomme(ref.get_name()), del_date(0) { signe = ref.signature(); };
904 
905  unsigned char get_signature() const { return signe; };
906  void set_signature(unsigned char x) { signe = x; };
907  unsigned char signature() const { return 'x'; };
908  entree *clone() const { return new detruit(*this); };
909 
910  const infinint & get_date() const { return del_date; };
911  void set_date(const infinint & ref) { del_date = ref; };
912 
913 #ifdef LIBDAR_SPECIAL_ALLOC
914  USE_SPECIAL_ALLOC(detruit);
915 #endif
916  protected:
917  void inherited_dump(generic_file & f, bool small) const;
918 
919  private :
920  unsigned char signe;
921  infinint del_date;
922  };
923 
925  class ignored : public nomme
926  {
927  public :
928  ignored(const std::string & name) : nomme(name) {};
929  ignored(generic_file & f) : nomme(f) { throw SRC_BUG; };
930 
931  unsigned char signature() const { return 'i'; };
932  entree *clone() const { return new ignored(*this); };
933 #ifdef LIBDAR_SPECIAL_ALLOC
934  USE_SPECIAL_ALLOC(ignored);
935 #endif
936 
937  protected:
938  void inherited_dump(generic_file & f, bool small) const { throw SRC_BUG; };
939 
940  };
941 
943  class ignored_dir : public inode
944  {
945  public:
946  ignored_dir(const directory &target) : inode(target) {};
947  ignored_dir(user_interaction & dialog,
948  generic_file & f,
949  const archive_version & reading_ver,
950  generic_file *ea_loc,
951  escape *ptr) : inode(dialog, f, reading_ver, s_not_saved, ea_loc, ptr) { throw SRC_BUG; };
952 
953  unsigned char signature() const { return 'j'; };
954  entree *clone() const { return new ignored_dir(*this); };
955 #ifdef LIBDAR_SPECIAL_ALLOC
956  USE_SPECIAL_ALLOC(ignored_dir);
957 #endif
958 
959  protected:
960  void inherited_dump(generic_file & f, bool small) const; // behaves like an empty directory
961 
962  };
963 
965  class catalogue : protected mem_ui
966  {
967  public :
968  catalogue(user_interaction & dialog,
969  const infinint & root_last_modif,
970  const label & data_name);
971  catalogue(user_interaction & dialog,
972  generic_file & f,
973  const archive_version & reading_ver,
974  compression default_algo,
975  generic_file *data_loc,
976  generic_file *ea_loc,
977  bool lax,
978  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
979  bool only_detruit = false); //< if set to true, only directories and detruit objects are read from the archive
980  catalogue(const catalogue & ref) : mem_ui(ref), out_compare(ref.out_compare) { partial_copy_from(ref); };
981  const catalogue & operator = (const catalogue &ref);
982  virtual ~catalogue() { detruire(); };
983 
984 
985  // reading methods. The reading is iterative and uses the current_read directory pointer
986 
987  virtual void reset_read() const; // set the reading cursor to the beginning of the catalogue
988  virtual void end_read() const; // set the reading cursor to the end of the catalogue
989  virtual void skip_read_to_parent_dir() const;
990  // skip all items of the current dir and of any subdir, the next call will return
991  // next item of the parent dir (no eod to exit from the current dir !)
992  virtual bool read(const entree * & ref) const;
993  // sequential read (generates eod) and return false when all files have been read
994  virtual bool read_if_present(std::string *name, const nomme * & ref) const;
995  // pseudo-sequential read (reading a directory still
996  // implies that following read are located in this subdirectory up to the next EOD) but
997  // it returns false if no entry of this name are present in the current directory
998  // a call with NULL as first argument means to set the current dir the parent directory
999  void remove_read_entry(std::string & name);
1000  // in the currently read directory, removes the entry which name is given in argument
1001  const directory & get_current_reading_dir() const { return *current_read; };
1002  // remove from the catalogue all the entries that have not yet been read
1003  // by read().
1004  void tail_catalogue_to_current_read();
1005 
1006 
1007  void reset_sub_read(const path &sub); // initialise sub_read to the given directory
1008  bool sub_read(const entree * &ref); // sequential read of the catalogue, ignoring all that
1009  // is not part of the subdirectory specified with reset_sub_read
1010  // the read include the inode leading to the sub_tree as well as the pending eod
1011 
1012  // return true if the last read entry has already been read
1013  // and has not to be counted again. This is never the case for catalogue but may occure
1014  // with escape_catalogue (where from the 'virtual').
1015  // last this method gives a valid result only if the last read() entry is a directory as
1016  // only directory may be read() twice.
1017  virtual bool read_second_time_dir() const { return false; };
1018 
1019 
1020  // Additions methods. The addition is also iterative but uses its specific current_add directory pointer
1021 
1022  void reset_add();
1023 
1025  // real implementation is only needed in escape_catalogue class, here there nothing to be done
1026  virtual void pre_add(const entree *ref, compressor *compr) const {};
1027  virtual void pre_add_ea(const entree *ref, compressor *compr) const {};
1028  virtual void pre_add_crc(const entree *ref, compressor *compr) const {};
1029  virtual void pre_add_dirty(compressor *compr) const {};
1030  virtual void pre_add_ea_crc(const entree *ref, compressor *compr) const {};
1031  virtual void pre_add_waste_mark(compressor *compr) const {};
1032  virtual void pre_add_failed_mark(compressor *compr) const {};
1033  virtual escape *get_escape_layer() const { return NULL; };
1034 
1035  void add(entree *ref); // add at end of catalogue (sequential point of view)
1036  void re_add_in(const std::string &subdirname); // return into an already existing subdirectory for further addition
1037  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
1038  void add_in_current_read(nomme *ref); // add in currently read directory
1039 
1040 
1041 
1042  // Comparison methods. The comparision is here also iterative and uses its specific current_compare directory pointer
1043 
1044  void reset_compare();
1045  bool compare(const entree * name, const entree * & extracted);
1046  // returns true if the ref exists, and gives it back in second argument as it is in the current catalogue.
1047  // returns false is no entry of that nature exists in the catalogue (in the current directory)
1048  // if ref is a directory, the operation is normaly relative to the directory itself, but
1049  // such a call implies a chdir to that directory. thus, a call with an EOD is necessary to
1050  // change to the parent directory.
1051  // note :
1052  // if a directory is not present, returns false, but records the inexistant subdirectory
1053  // structure defined by the following calls to this routine, this to be able to know when
1054  // the last available directory is back the current one when changing to parent directory,
1055  // and then proceed with normal comparison of inode. In this laps of time, the call will
1056  // always return false, while it temporary stores the missing directory structure
1057 
1058 
1059 
1060  // non interative methods
1061 
1062  bool direct_read(const path & ref, const nomme * &ret);
1063  infinint update_destroyed_with(catalogue & ref);
1064  // ref must have the same root, else the operation generates an exception
1065 
1066  void update_absent_with(catalogue & ref, infinint aborting_next_etoile);
1067  // in case of abortion, completes missing files as if what could not be
1068  // inspected had not changed since the reference was done
1069  // aborting_last_etoile is the highest etoile reference withing "this" current object.
1070 
1071  void dump(generic_file & f) const;
1072  void listing(bool isolated,
1073  const mask &selection,
1074  const mask & subtree,
1075  bool filter_unsaved,
1076  bool list_ea,
1077  std::string marge) const;
1078  void tar_listing(bool isolated,
1079  const mask & selection,
1080  const mask & subtree,
1081  bool filter_unsaved,
1082  bool list_ea,
1083  std::string beginning) const;
1084  void xml_listing(bool isolated,
1085  const mask & selection,
1086  const mask & subtree,
1087  bool filter_unsaved,
1088  bool list_ea,
1089  std::string beginning) const;
1090 
1091  entree_stats get_stats() const { return stats; };
1092 
1094  bool is_empty() const { if(contenu == NULL) throw SRC_BUG; return contenu->is_empty(); };
1095 
1096  const directory *get_contenu() const { return contenu; }; // used by data_tree
1097 
1098  const label & get_data_name() const { return ref_data_name; };
1099  infinint get_root_dir_last_modif() const { return contenu->get_last_modif(); };
1100 
1102  void launch_recursive_has_changed_update() const { contenu->recursive_has_changed_update(); };
1103 
1104  infinint get_root_mtime() const { return contenu->get_last_modif(); };
1105 
1107  void reset_all();
1108 
1109 #ifdef LIBDAR_SPECIAL_ALLOC
1110  USE_SPECIAL_ALLOC(catalogue);
1111 #endif
1112 
1113  protected:
1114  entree_stats & access_stats() { return stats; };
1115  void set_data_name(const label & val) { ref_data_name = val; };
1116  void copy_detruits_from(const catalogue & ref); // needed for escape_catalogue implementation only.
1117 
1118  const eod * get_r_eod_address() const { return & r_eod; }; // eod are never stored in the catalogue
1119  // however it is sometimes required to return such a reference to a valid object
1120  // owned by the catalogue.
1121 
1122 
1125  void swap_stuff(catalogue & ref);
1126 
1127  private :
1128  directory *contenu;
1129  path out_compare;
1130  directory *current_compare;
1131  directory *current_add;
1132  directory *current_read;
1133  path *sub_tree;
1134  signed int sub_count;
1135  entree_stats stats;
1136  label ref_data_name;
1137 
1138  void partial_copy_from(const catalogue &ref);
1139  void detruire();
1140 
1141  static const eod r_eod; // needed to return eod reference, without taking risk of saturating memory
1142  static const U_I CAT_CRC_SIZE;
1143  };
1144 
1145 
1146 
1148 
1149 } // end of namespace
1150 
1151 #endif