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