Disk ARchive  2.4.5
 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.2.6 2012/02/19 22:15:05 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 #ifdef LIBDAR_SPECIAL_ALLOC
143  USE_SPECIAL_ALLOC(entree);
144 #endif
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 
169 #ifdef LIBDAR_SPECIAL_ALLOC
170  USE_SPECIAL_ALLOC(eod);
171 #endif
172  };
173 
175  class nomme : public entree
176  {
177  public:
178  nomme(const std::string & name) { xname = name; };
179  nomme(generic_file & f);
180  virtual bool operator == (const nomme & ref) const { return xname == ref.xname; };
181  virtual bool operator < (const nomme & ref) const { return xname < ref.xname; };
182 
183  const std::string & get_name() const { return xname; };
184  void change_name(const std::string & x) { xname = x; };
185  bool same_as(const nomme & ref) const { return xname == ref.xname; };
186  // no need to have a virtual method, as signature will differ in inherited classes (argument type changes)
187 
188  // signature() is kept as an abstract method
189  // clone() is abstract
190 
191 #ifdef LIBDAR_SPECIAL_ALLOC
192  USE_SPECIAL_ALLOC(nomme);
193 #endif
194 
195  protected:
196  void inherited_dump(generic_file & f, bool small) const;
197 
198  private:
199  std::string xname;
200  };
201 
202 
204  class inode : public nomme
205  {
206  public:
207 
209 
211  {
212  cf_all, //< consider any available field for comparing inodes
213  cf_ignore_owner, //< consider any available field except ownership fields
214  cf_mtime, //< consider any available field except ownership and permission fields
215  cf_inode_type //< only consider the file type
216  };
217 
218  inode(const infinint & xuid, const infinint & xgid, U_16 xperm,
219  const infinint & last_access,
220  const infinint & last_modif,
221  const infinint & last_change,
222  const std::string & xname, const infinint & device);
223  inode(user_interaction & dialog,
224  generic_file & f,
225  const archive_version & reading_ver,
226  saved_status saved,
227  generic_file *ea_loc,
228  escape *ptr); // if ptr is not NULL, reading a partial dump(), which was done with "small" set to true
229  inode(const inode & ref);
230  const inode & operator = (const inode & ref);
231  ~inode();
232 
233  const infinint & get_uid() const { return uid; };
234  const infinint & get_gid() const { return gid; };
235  U_16 get_perm() const { return perm; };
236  infinint get_last_access() const { return *last_acc; };
237  infinint get_last_modif() const { return *last_mod; };
238  void set_last_access(const infinint & x_time) { *last_acc = x_time; };
239  void set_last_modif(const infinint & x_time) { *last_mod = x_time; };
240  saved_status get_saved_status() const { return xsaved; };
241  void set_saved_status(saved_status x) { xsaved = x; };
242  infinint get_device() const { return *fs_dev; };
243 
244  bool same_as(const inode & ref) const;
245  bool is_more_recent_than(const inode & ref, const infinint & hourshift) const;
246  // used for RESTORATION
247  virtual bool has_changed_since(const inode & ref, const infinint & hourshift, comparison_fields what_to_check) const;
248  // signature() left as an abstract method
249  // clone is abstract too
250  // used for INCREMENTAL BACKUP
251  void compare(const inode &other,
252  const mask & ea_mask,
253  comparison_fields what_to_check,
254  const infinint & hourshift,
255  bool symlink_date) const;
256 
257  // throw Erange exception if a difference has been detected
258  // this is not a symetrical comparison, but all what is present
259  // in the current object is compared against the argument
260  // which may contain supplementary informations
261  // used for DIFFERENCE
262 
263 
264 
266  // EXTENDED ATTRIBUTS Methods
267  //
268 
269  enum ea_status { ea_none, ea_partial, ea_fake, ea_full, ea_removed };
270  // ea_none : no EA present for this inode in filesystem
271  // ea_partial : EA present in filesystem but not stored (ctime used to check changes)
272  // 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.
273  // ea_full : EA present in filesystem and attached to this inode
274  // ea_removed : EA were present in the reference version, but not present anymore
275 
276  // I : to know whether EA data is present or not for this object
277  void ea_set_saved_status(ea_status status);
278  ea_status ea_get_saved_status() const { return ea_saved; };
279 
280  // II : to associate EA list to an inode object (mainly for backup operation) #EA_FULL only#
281  void ea_attach(ea_attributs *ref);
282  const ea_attributs *get_ea() const; // #<-- EA_FULL *and* EA_REMOVED# for this call only
283  void ea_detach() const; //discards any future call to get_ea() !
284  infinint ea_get_size() const; //returns the size of EA (still valid if ea have been detached)
285 
286  // III : to record where is dump the EA in the archive #EA_FULL only#
287  void ea_set_offset(const infinint & pos) { *ea_offset = pos; };
288  void ea_set_crc(const crc & val);
289  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
290  bool ea_get_crc_size(infinint & val) const; //< returns true if crc is know and puts its width in argument
291 
292  // IV : to know/record if EA have been modified # any EA status#
293  infinint get_last_change() const;
294  void set_last_change(const infinint & x_time);
295  bool has_last_change() const { return last_cha != NULL; };
296  // old format did provide last_change only when EA were present, since archive
297  // format 8, this field is always present even in absence of EA. Thus it is
298  // still necessary to check if the inode has a last_change() before
299  // using get_last_change() (depends on the version of the archive read).
300 
301 
302  // V : for archive migration (merging)
303  void change_ea_location(generic_file *loc) { storage = loc; };
304 
306 
307 #ifdef LIBDAR_SPECIAL_ALLOC
308  USE_SPECIAL_ALLOC(inode);
309 #endif
310 
311  protected:
312  virtual void sub_compare(const inode & other) const {};
313 
315  escape *get_escape_layer() const { return esc; };
316 
317  void inherited_dump(generic_file & f, bool small) const;
318 
319  private :
320  infinint uid;
321  infinint gid;
322  U_16 perm;
323  infinint *last_acc, *last_mod;
324  saved_status xsaved;
325  ea_status ea_saved;
326  // the following is used only if ea_saved == full
327  infinint *ea_offset;
328  ea_attributs *ea;
329  infinint ea_size;
330  // the following is used if ea_saved == full or ea_saved == partial
331  infinint *last_cha;
332  crc *ea_crc;
333  infinint *fs_dev;
334  generic_file *storage; // where are stored EA
335  archive_version edit; // need to know EA format used in archive file
336 
337  escape *esc; // if not NULL, the object is partially build from archive (at archive generation, dump() was called with small set to true)
338 
339  static const ea_attributs empty_ea;
340  };
341 
343  class etoile
344  {
345  public:
346 
348 
352  etoile(inode *host, const infinint & etiquette_number);
353  etoile(const etoile & ref) { throw SRC_BUG; }; // copy constructor not allowed for this class
354  const etoile & operator = (const etoile & ref) { throw SRC_BUG; }; // assignment not allowed for this class
355  ~etoile() { delete hosted; };
356 
357  void add_ref(void *ref);
358  void drop_ref(void *ref);
359  infinint get_ref_count() const { return refs.size(); };
360  inode *get_inode() const { return hosted; };
361  infinint get_etiquette() const { return etiquette; };
362  void change_etiquette(const infinint & new_val) { etiquette = new_val; };
363 
364 
365  bool is_counted() const { return tags.counted; };
366  bool is_wrote() const { return tags.wrote; };
367  bool is_dumped() const { return tags.dumped; };
368  void set_counted(bool val) { tags.counted = val ? 1 : 0; };
369  void set_wrote(bool val) { tags.wrote = val ? 1 : 0; };
370  void set_dumped(bool val) { tags.dumped = val ? 1 : 0; };
371 
372  // return the address of the first mirage that triggered the creation of this mirage
373  // if this object is destroyed afterward this call returns NULL
374  const void *get_first_ref() const { if(refs.size() == 0) throw SRC_BUG; return refs.front(); };
375 
376 #ifdef LIBDAR_SPECIAL_ALLOC
377  USE_SPECIAL_ALLOC(etoile);
378 #endif
379 
380  private:
381  struct bool_tags
382  {
383  unsigned counted : 1; //< whether the inode has been counted
384  unsigned wrote : 1; //< whether the inode has its data copied to archive
385  unsigned dumped : 1; //< whether the inode information has been dumped in the catalogue
386  unsigned : 5; //< padding to get byte boundary and reserved for future use.
387 
388  bool_tags() { counted = wrote = dumped = 0; };
389  };
390 
391  std::list<void *> refs; //< list of pointers to the mirages objects, in the order of their creation
392  inode *hosted;
393  infinint etiquette;
394  bool_tags tags;
395  };
396 
398 
400  class mirage : public nomme
401  {
402  public:
403  enum mirage_format {fmt_mirage, //< new format
404  fmt_hard_link, //< old dual format
405  fmt_file_etiquette }; //< old dual format
406 
407  mirage(const std::string & name, etoile *ref) : nomme(name) { star_ref = ref; if(ref == NULL) throw SRC_BUG; star_ref->add_ref(this); };
408  mirage(user_interaction & dialog,
409  generic_file & f,
410  const archive_version & reading_ver,
411  saved_status saved,
412  entree_stats & stats,
413  std::map <infinint, etoile *> & corres,
414  compression default_algo,
415  generic_file *data_loc,
416  generic_file *ea_loc,
417  mirage_format fmt,
418  bool lax,
419  escape *ptr);
420  mirage(user_interaction & dialog,
421  generic_file & f,
422  const archive_version & reading_ver,
423  saved_status saved,
424  entree_stats & stats,
425  std::map <infinint, etoile *> & corres,
426  compression default_algo,
427  generic_file *data_loc,
428  generic_file *ea_loc,
429  bool lax,
430  escape *ptr);
431  mirage(const mirage & ref) : nomme (ref) { star_ref = ref.star_ref; if(star_ref == NULL) throw SRC_BUG; star_ref->add_ref(this); };
432  const mirage & operator = (const mirage & ref);
433  ~mirage() { star_ref->drop_ref(this); };
434 
435  unsigned char signature() const { return 'm'; };
436  entree *clone() const { return new mirage(*this); };
437 
438  inode *get_inode() const { if(star_ref == NULL) throw SRC_BUG; return star_ref->get_inode(); };
439  infinint get_etiquette() const { return star_ref->get_etiquette(); };
440  infinint get_etoile_ref_count() const { return star_ref->get_ref_count(); };
441  etoile *get_etoile() const { return star_ref; };
442 
443  bool is_inode_counted() const { return star_ref->is_counted(); };
444  bool is_inode_wrote() const { return star_ref->is_wrote(); };
445  bool is_inode_dumped() const { return star_ref->is_dumped(); };
446  void set_inode_counted(bool val) const { star_ref->set_counted(val); };
447  void set_inode_wrote(bool val) const { star_ref->set_wrote(val); };
448  void set_inode_dumped(bool val) const { star_ref->set_dumped(val); };
449 
450  void post_constructor(generic_file & f);
451 
453  bool is_first_mirage() const { return star_ref->get_first_ref() == this; };
454 
455 #ifdef LIBDAR_SPECIAL_ALLOC
456  USE_SPECIAL_ALLOC(mirage);
457 #endif
458 
459  protected:
460  void inherited_dump(generic_file & f, bool small) const;
461 
462  private:
463  etoile *star_ref;
464 
465  void init(user_interaction & dialog,
466  generic_file & f,
467  const archive_version & reading_ver,
468  saved_status saved,
469  entree_stats & stats,
470  std::map <infinint, etoile *> & corres,
471  compression default_algo,
472  generic_file *data_loc,
473  generic_file *ea_loc,
474  mirage_format fmt,
475  bool lax,
476  escape *ptr);
477  };
478 
479 
481  class file : public inode
482  {
483  public :
484  enum get_data_mode
485  {
486  keep_compressed, //< provide access to compressed data
487  keep_hole, //< provide access to uncompressed data but sparse_file datastructure
488  normal, //< provide access to full data (uncompressed, uses skip() to restore holes)
489  plain //< provide access to plain data, no skip to restore holes, provide instead zeroed bytes
490  };
491 
492  static const U_8 FILE_DATA_WITH_HOLE = 0x01; //< file's data contains hole datastructure
493  static const U_8 FILE_DATA_IS_DIRTY = 0x02; //< data modified while being saved
494 
495  file(const infinint & xuid, const infinint & xgid, U_16 xperm,
496  const infinint & last_access,
497  const infinint & last_modif,
498  const infinint & last_change,
499  const std::string & src,
500  const path & che,
501  const infinint & taille,
502  const infinint & fs_device,
503  bool x_furtive_read_mode);
504  file(const file & ref);
505  file(user_interaction & dialog,
506  generic_file & f,
507  const archive_version & reading_ver,
508  saved_status saved,
509  compression default_algo,
510  generic_file *data_loc,
511  generic_file *ea_loc,
512  escape *ptr);
513  ~file() { detruit(); };
514 
515  bool has_changed_since(const inode & ref, const infinint & hourshift, inode::comparison_fields what_to_check) const;
516  infinint get_size() const { return *size; };
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 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 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 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 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 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 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 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 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 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 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