Disk ARchive  2.4.10
 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 
157  class eod : public entree
158  {
159  public :
160  eod() {};
161  eod(generic_file & f) {};
162  // dump defined by entree
163  unsigned char signature() const { return 'z'; };
164  entree *clone() const { return new (std::nothrow) eod(); };
165 
166 
167 #ifdef LIBDAR_SPECIAL_ALLOC
168  USE_SPECIAL_ALLOC(eod);
169 #endif
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);
287  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
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 (std::nothrow) 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  void change_size(const infinint & s) const { *size = s; };
516  infinint get_storage_size() const { return *storage_size; };
517  void set_storage_size(const infinint & s) { *storage_size = s; };
518  virtual generic_file *get_data(get_data_mode mode) const; // returns a newly allocated object in read_only mode
519  void clean_data(); // partially free memory (but get_data() becomes disabled)
520  void set_offset(const infinint & r);
521  const infinint & get_offset() const;
522  unsigned char signature() const { return mk_signature('f', get_saved_status()); };
523 
524  void set_crc(const crc &c);
525  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
526  bool has_crc() const { return check != NULL; };
527  bool get_crc_size(infinint & val) const; //< returns true if crc is know and puts its width in argument
528  void drop_crc() { if(check != NULL) { delete check; check = NULL; } };
529 
530  // whether the plain file has to detect sparse file
531  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; };
532 
533  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; };
534 
535  // whether the plain file is stored with a sparse_file datastructure in the archive
536  bool get_sparse_file_detection_read() const { return (file_data_status_read & FILE_DATA_WITH_HOLE) != 0; };
537  bool get_sparse_file_detection_write() const { return (file_data_status_write & FILE_DATA_WITH_HOLE) != 0; };
538 
539  entree *clone() const { return new (std::nothrow) file(*this); };
540 
541  compression get_compression_algo_read() const { return algo_read; };
542 
543  compression get_compression_algo_write() const { return algo_write; };
544 
545  // object migration methods (merging)
546  void change_compression_algo_write(compression x) { algo_write = x; };
547  void change_location(generic_file *x) { loc = x; };
548 
549  // dirtiness
550 
551  bool is_dirty() const { return dirty; };
552  void set_dirty(bool value) { dirty = value; };
553 
554 #ifdef LIBDAR_SPECIAL_ALLOC
555  USE_SPECIAL_ALLOC(file);
556 #endif
557 
558  protected:
559  void sub_compare(const inode & other) const;
560  void inherited_dump(generic_file & f, bool small) const;
561  void post_constructor(generic_file & f);
562 
563  enum { empty, from_path, from_cat } status;
564 
565  private:
566  std::string chemin; //< path to the data (when read from filesystem)
567  infinint *offset; //< start location of the data in 'loc'
568  infinint *size; //< size of the data (uncompressed)
569  infinint *storage_size; //< how much data used in archive (after compression)
570  crc *check;
571  bool dirty; //< true when a file has been modified at the time it was saved
572 
573  generic_file *loc; //< where to find data (eventually compressed) at the recorded offset and for storage_size length
574  compression algo_read; //< which compression algorithm to use to read the file's data
575  compression algo_write; //< which compression algorithm to use to write down (merging) the file's data
576  bool furtive_read_mode; // used only when status equals "from_path"
577  char file_data_status_read; // defines the datastructure to use when reading the data
578  char file_data_status_write; // defines the datastructure to apply when writing down the data
579 
580  void detruit();
581  };
582 
584  class door : public file
585  {
586  public:
587  door(const infinint & xuid, const infinint & xgid, U_16 xperm,
588  const infinint & last_access,
589  const infinint & last_modif,
590  const infinint & last_change,
591  const std::string & src,
592  const path & che,
593  const infinint & fs_device) : file(xuid, xgid, xperm, last_access, last_modif,
594  last_change, src, che, 0, fs_device, false) {};
595  door(user_interaction & dialog,
596  generic_file & f,
597  const archive_version & reading_ver,
598  saved_status saved,
599  compression default_algo,
600  generic_file *data_loc,
601  generic_file *ea_loc,
602  escape *ptr) : file(dialog, f, reading_ver, saved, default_algo, data_loc, ea_loc, ptr) {};
603 
604  unsigned char signature() const { return mk_signature('o', get_saved_status()); };
605 
606  generic_file *get_data(get_data_mode mode) const; // inherited from class file
607 
608 #ifdef LIBDAR_SPECIAL_ALLOC
609  USE_SPECIAL_ALLOC(door);
610 #endif
611  };
612 
614  class lien : public inode
615  {
616  public :
617  lien(const infinint & uid, const infinint & gid, U_16 perm,
618  const infinint & last_access,
619  const infinint & last_modif,
620  const infinint & last_change,
621  const std::string & name,
622  const std::string & target,
623  const infinint & fs_device);
624  lien(user_interaction & dialog,
625  generic_file & f,
626  const archive_version & reading_ver,
627  saved_status saved,
628  generic_file *ea_loc,
629  escape *ptr);
630 
631  const std::string & get_target() const;
632  void set_target(std::string x);
633 
634  // using the method is_more_recent_than() from inode
635  // using method has_changed_since() from inode class
636  unsigned char signature() const { return mk_signature('l', get_saved_status()); };
637  entree *clone() const { return new (std::nothrow) lien(*this); };
638 
639 #ifdef LIBDAR_SPECIAL_ALLOC
640  USE_SPECIAL_ALLOC(lien);
641 #endif
642  protected :
643  void sub_compare(const inode & other) const;
644  void inherited_dump(generic_file & f, bool small) const;
645 
646 
647  private :
648  std::string points_to;
649  };
650 
652  class directory : public inode
653  {
654  public :
655  directory(const infinint & xuid, const infinint & xgid, U_16 xperm,
656  const infinint & last_access,
657  const infinint & last_modif,
658  const infinint & last_change,
659  const std::string & xname,
660  const infinint & device);
661  directory(const directory &ref); // only the inode part is build, no children is duplicated (empty dir)
662  const directory & operator = (const directory & ref); // set the inode part *only* no subdirectories/subfiles are copies or removed.
663  directory(user_interaction & dialog,
664  generic_file & f,
665  const archive_version & reading_ver,
666  saved_status saved,
667  entree_stats & stats,
668  std::map <infinint, etoile *> & corres,
669  compression default_algo,
670  generic_file *data_loc,
671  generic_file *ea_loc,
672  bool lax,
673  bool only_detruit, // objects of other class than detruit and directory are not built in memory
674  escape *ptr);
675  ~directory(); // detruit aussi tous les fils et se supprime de son 'parent'
676 
677  void add_children(nomme *r); // when r is a directory, 'parent' is set to 'this'
678  bool has_children() const { return !ordered_fils.empty(); };
679  void reset_read_children() const;
680  void end_read() const;
681  bool read_children(const nomme * &r) const; // read the direct children of the directory, returns false if no more is available
682  // remove all entry not yet read by read_children
683  void tail_to_read_children();
684 
685  void remove(const std::string & name); // remove the given entry from the catalogue
686  // as side effect the reset_read_children() method must be called.
687 
688  directory * get_parent() const { return parent; };
689  bool search_children(const std::string &name, nomme *&ref);
690  bool callback_for_children_of(user_interaction & dialog, const std::string & sdir, bool isolated = false) const;
691 
692  // using is_more_recent_than() from inode class
693  // using method has_changed_since() from inode class
694  unsigned char signature() const { return mk_signature('d', get_saved_status()); };
695 
696  // some data has changed since archive of reference in this directory or subdirectories
697  bool get_recursive_has_changed() const { return recursive_has_changed; };
698  // update the recursive_has_changed field
699  void recursive_has_changed_update() const;
700 
701  // get then number of "nomme" entry contained in this directory and subdirectories (recursive call)
702  infinint get_tree_size() const;
703  // get the number of entry having some EA set in the directory tree (recursive call)
704  infinint get_tree_ea_num() const;
705  // get the number of entry that are hard linked inode (aka mirage in dar implementation) (recursive call)
706  infinint get_tree_mirage_num() const;
707  // for each mirage found (hard link implementation) in the directory tree, add its etiquette to the returned
708  // list with the number of reference that has been found in the tree. (map[etiquette] = number of occurence)
709  // from outside of class directory, the given argument is expected to be an empty map.
710  void get_etiquettes_found_in_tree(std::map<infinint, infinint> & already_found) const;
711 
712  // whether this directory is empty or not
713  bool is_empty() const { return ordered_fils.empty(); };
714 
715  // recursively remove all mirage entries
716  void remove_all_mirages_and_reduce_dirs();
717 
718  entree *clone() const { return new (std::nothrow) directory(*this); };
719 
720 #ifdef LIBDAR_SPECIAL_ALLOC
721  USE_SPECIAL_ALLOC(directory);
722 #endif
723 
724  protected:
725  void inherited_dump(generic_file & f, bool small) const;
726 
727  private :
728  static const eod fin;
729 
730  directory *parent;
731 #ifdef LIBDAR_FAST_DIR
732  std::map<std::string, nomme *> fils; // used for fast lookup
733 #endif
734  std::list<nomme *> ordered_fils;
735  std::list<nomme *>::iterator it;
736  bool recursive_has_changed;
737 
738  void clear();
739  };
740 
742  class device : public inode
743  {
744  public :
745  device(const infinint & uid, const infinint & gid, U_16 perm,
746  const infinint & last_access,
747  const infinint & last_modif,
748  const infinint &last_change,
749  const std::string & name,
750  U_16 major,
751  U_16 minor,
752  const infinint & fs_device);
753  device(user_interaction & dialog,
754  generic_file & f,
755  const archive_version & reading_ver,
756  saved_status saved,
757  generic_file *ea_loc,
758  escape *ptr);
759 
760  int get_major() const { if(get_saved_status() != s_saved) throw SRC_BUG; else return xmajor; };
761  int get_minor() const { if(get_saved_status() != s_saved) throw SRC_BUG; else return xminor; };
762  void set_major(int x) { xmajor = x; };
763  void set_minor(int x) { xminor = x; };
764 
765  // using method is_more_recent_than() from inode class
766  // using method has_changed_since() from inode class
767  // signature is left pure abstract
768 
769 #ifdef LIBDAR_SPECIAL_ALLOC
770  USE_SPECIAL_ALLOC(device);
771 #endif
772 
773  protected :
774  void sub_compare(const inode & other) const;
775  void inherited_dump(generic_file & f, bool small) const;
776 
777  private :
778  U_16 xmajor, xminor;
779  };
780 
782  class chardev : public device
783  {
784  public:
785  chardev(const infinint & uid, const infinint & gid, U_16 perm,
786  const infinint & last_access,
787  const infinint & last_modif,
788  const infinint & last_change,
789  const std::string & name,
790  U_16 major,
791  U_16 minor,
792  const infinint & fs_device) : device(uid, gid, perm,
793  last_access,
794  last_modif,
795  last_change,
796  name,
797  major, minor, fs_device) {};
798  chardev(user_interaction & dialog,
799  generic_file & f,
800  const archive_version & reading_ver,
801  saved_status saved,
802  generic_file *ea_loc,
803  escape *ptr) : device(dialog, f, reading_ver, saved, ea_loc, ptr) {};
804 
805  // using dump from device class
806  // using method is_more_recent_than() from device class
807  // using method has_changed_since() from device class
808  unsigned char signature() const { return mk_signature('c', get_saved_status()); };
809  entree *clone() const { return new (std::nothrow) chardev(*this); };
810 
811 #ifdef LIBDAR_SPECIAL_ALLOC
812  USE_SPECIAL_ALLOC(chardev);
813 #endif
814  };
815 
817  class blockdev : public device
818  {
819  public:
820  blockdev(const infinint & uid, const infinint & gid, U_16 perm,
821  const infinint & last_access,
822  const infinint & last_modif,
823  const infinint & last_change,
824  const std::string & name,
825  U_16 major,
826  U_16 minor,
827  const infinint & fs_device) : device(uid, gid, perm, last_access,
828  last_modif, last_change, name,
829  major, minor, fs_device) {};
830  blockdev(user_interaction & dialog,
831  generic_file & f,
832  const archive_version & reading_ver,
833  saved_status saved,
834  generic_file *ea_loc,
835  escape *ptr) : device(dialog, f, reading_ver, saved, ea_loc, ptr) {};
836 
837  // using dump from device class
838  // using method is_more_recent_than() from device class
839  // using method has_changed_since() from device class
840  unsigned char signature() const { return mk_signature('b', get_saved_status()); };
841  entree *clone() const { return new (std::nothrow) blockdev(*this); };
842 
843 #ifdef LIBDAR_SPECIAL_ALLOC
844  USE_SPECIAL_ALLOC(blockdev);
845 #endif
846  };
847 
849  class tube : public inode
850  {
851  public :
852  tube(const infinint & xuid, const infinint & xgid, U_16 xperm,
853  const infinint & last_access,
854  const infinint & last_modif,
855  const infinint & last_change,
856  const std::string & xname,
857  const infinint & fs_device) : inode(xuid, xgid, xperm, last_access, last_modif, last_change, xname, fs_device) { set_saved_status(s_saved); };
858  tube(user_interaction & dialog,
859  generic_file & f,
860  const archive_version & reading_ver,
861  saved_status saved,
862  generic_file *ea_loc,
863  escape *ptr) : inode(dialog, f, reading_ver, saved, ea_loc, ptr) {};
864 
865  // using dump from inode class
866  // using method is_more_recent_than() from inode class
867  // using method has_changed_since() from inode class
868  unsigned char signature() const { return mk_signature('p', get_saved_status()); };
869  entree *clone() const { return new (std::nothrow) tube(*this); };
870 
871 #ifdef LIBDAR_SPECIAL_ALLOC
872  USE_SPECIAL_ALLOC(tube);
873 #endif
874  };
875 
877  class prise : public inode
878  {
879  public :
880  prise(const infinint & xuid, const infinint & xgid, U_16 xperm,
881  const infinint & last_access,
882  const infinint & last_modif,
883  const infinint & last_change,
884  const std::string & xname,
885  const infinint & fs_device) : inode(xuid, xgid, xperm, last_access, last_modif, last_change, xname, fs_device) { set_saved_status(s_saved); };
886  prise(user_interaction & dialog,
887  generic_file & f,
888  const archive_version & reading_ver,
889  saved_status saved,
890  generic_file *ea_loc,
891  escape *ptr) : inode(dialog, f, reading_ver, saved, ea_loc, ptr) {};
892 
893  // using dump from inode class
894  // using method is_more_recent_than() from inode class
895  // using method has_changed_since() from inode class
896  unsigned char signature() const { return mk_signature('s', get_saved_status()); };
897  entree *clone() const { return new (std::nothrow) prise(*this); };
898 
899 #ifdef LIBDAR_SPECIAL_ALLOC
900  USE_SPECIAL_ALLOC(prise);
901 #endif
902  };
903 
905  class detruit : public nomme
906  {
907  public :
908  detruit(const std::string & name, unsigned char firm, const infinint & date) : nomme(name) , del_date(date) { signe = firm; };
909  detruit(generic_file & f, const archive_version & reading_ver);
910  detruit(const nomme &ref) : nomme(ref.get_name()), del_date(0) { signe = ref.signature(); };
911 
912  unsigned char get_signature() const { return signe; };
913  void set_signature(unsigned char x) { signe = x; };
914  unsigned char signature() const { return 'x'; };
915  entree *clone() const { return new (std::nothrow) detruit(*this); };
916 
917  const infinint & get_date() const { return del_date; };
918  void set_date(const infinint & ref) { del_date = ref; };
919 
920 #ifdef LIBDAR_SPECIAL_ALLOC
921  USE_SPECIAL_ALLOC(detruit);
922 #endif
923  protected:
924  void inherited_dump(generic_file & f, bool small) const;
925 
926  private :
927  unsigned char signe;
928  infinint del_date;
929  };
930 
932  class ignored : public nomme
933  {
934  public :
935  ignored(const std::string & name) : nomme(name) {};
936  ignored(generic_file & f) : nomme(f) { throw SRC_BUG; };
937 
938  unsigned char signature() const { return 'i'; };
939  entree *clone() const { return new (std::nothrow) ignored(*this); };
940 #ifdef LIBDAR_SPECIAL_ALLOC
941  USE_SPECIAL_ALLOC(ignored);
942 #endif
943 
944  protected:
945  void inherited_dump(generic_file & f, bool small) const { throw SRC_BUG; };
946 
947  };
948 
950  class ignored_dir : public inode
951  {
952  public:
953  ignored_dir(const directory &target) : inode(target) {};
954  ignored_dir(user_interaction & dialog,
955  generic_file & f,
956  const archive_version & reading_ver,
957  generic_file *ea_loc,
958  escape *ptr) : inode(dialog, f, reading_ver, s_not_saved, ea_loc, ptr) { throw SRC_BUG; };
959 
960  unsigned char signature() const { return 'j'; };
961  entree *clone() const { return new (std::nothrow) ignored_dir(*this); };
962 #ifdef LIBDAR_SPECIAL_ALLOC
963  USE_SPECIAL_ALLOC(ignored_dir);
964 #endif
965 
966  protected:
967  void inherited_dump(generic_file & f, bool small) const; // behaves like an empty directory
968 
969  };
970 
972  class catalogue : protected mem_ui
973  {
974  public :
975  catalogue(user_interaction & dialog,
976  const infinint & root_last_modif,
977  const label & data_name);
978  catalogue(user_interaction & dialog,
979  generic_file & f,
980  const archive_version & reading_ver,
981  compression default_algo,
982  generic_file *data_loc,
983  generic_file *ea_loc,
984  bool lax,
985  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
986  bool only_detruit = false); //< if set to true, only directories and detruit objects are read from the archive
987  catalogue(const catalogue & ref) : mem_ui(ref), out_compare(ref.out_compare) { partial_copy_from(ref); };
988  const catalogue & operator = (const catalogue &ref);
989  virtual ~catalogue() { detruire(); };
990 
991 
992  // reading methods. The reading is iterative and uses the current_read directory pointer
993 
994  virtual void reset_read() const; // set the reading cursor to the beginning of the catalogue
995  virtual void end_read() const; // set the reading cursor to the end of the catalogue
996  virtual void skip_read_to_parent_dir() const;
997  // skip all items of the current dir and of any subdir, the next call will return
998  // next item of the parent dir (no eod to exit from the current dir !)
999  virtual bool read(const entree * & ref) const;
1000  // sequential read (generates eod) and return false when all files have been read
1001  virtual bool read_if_present(std::string *name, const nomme * & ref) const;
1002  // pseudo-sequential read (reading a directory still
1003  // implies that following read are located in this subdirectory up to the next EOD) but
1004  // it returns false if no entry of this name are present in the current directory
1005  // a call with NULL as first argument means to set the current dir the parent directory
1006  void remove_read_entry(std::string & name);
1007  // in the currently read directory, removes the entry which name is given in argument
1008  const directory & get_current_reading_dir() const { return *current_read; };
1009  // remove from the catalogue all the entries that have not yet been read
1010  // by read().
1011  void tail_catalogue_to_current_read();
1012 
1013 
1014  void reset_sub_read(const path &sub); // initialise sub_read to the given directory
1015  bool sub_read(const entree * &ref); // sequential read of the catalogue, ignoring all that
1016  // is not part of the subdirectory specified with reset_sub_read
1017  // the read include the inode leading to the sub_tree as well as the pending eod
1018 
1019  // return true if the last read entry has already been read
1020  // and has not to be counted again. This is never the case for catalogue but may occure
1021  // with escape_catalogue (where from the 'virtual').
1022  // last this method gives a valid result only if the last read() entry is a directory as
1023  // only directory may be read() twice.
1024  virtual bool read_second_time_dir() const { return false; };
1025 
1026 
1027  // Additions methods. The addition is also iterative but uses its specific current_add directory pointer
1028 
1029  void reset_add();
1030 
1032  // real implementation is only needed in escape_catalogue class, here there nothing to be done
1033  virtual void pre_add(const entree *ref, compressor *compr) const {};
1034  virtual void pre_add_ea(const entree *ref, compressor *compr) const {};
1035  virtual void pre_add_crc(const entree *ref, compressor *compr) const {};
1036  virtual void pre_add_dirty(compressor *compr) const {};
1037  virtual void pre_add_ea_crc(const entree *ref, compressor *compr) const {};
1038  virtual void pre_add_waste_mark(compressor *compr) const {};
1039  virtual void pre_add_failed_mark(compressor *compr) const {};
1040  virtual escape *get_escape_layer() const { return NULL; };
1041 
1042  void add(entree *ref); // add at end of catalogue (sequential point of view)
1043  void re_add_in(const std::string &subdirname); // return into an already existing subdirectory for further addition
1044  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
1045  void add_in_current_read(nomme *ref); // add in currently read directory
1046 
1047 
1048 
1049  // Comparison methods. The comparision is here also iterative and uses its specific current_compare directory pointer
1050 
1051  void reset_compare();
1052  bool compare(const entree * name, const entree * & extracted);
1053  // returns true if the ref exists, and gives it back in second argument as it is in the current catalogue.
1054  // returns false is no entry of that nature exists in the catalogue (in the current directory)
1055  // if ref is a directory, the operation is normaly relative to the directory itself, but
1056  // such a call implies a chdir to that directory. thus, a call with an EOD is necessary to
1057  // change to the parent directory.
1058  // note :
1059  // if a directory is not present, returns false, but records the inexistant subdirectory
1060  // structure defined by the following calls to this routine, this to be able to know when
1061  // the last available directory is back the current one when changing to parent directory,
1062  // and then proceed with normal comparison of inode. In this laps of time, the call will
1063  // always return false, while it temporary stores the missing directory structure
1064 
1065 
1066 
1067  // non interative methods
1068 
1069  bool direct_read(const path & ref, const nomme * &ret);
1070  infinint update_destroyed_with(catalogue & ref);
1071  // ref must have the same root, else the operation generates an exception
1072 
1073  void update_absent_with(catalogue & ref, infinint aborting_next_etoile);
1074  // in case of abortion, completes missing files as if what could not be
1075  // inspected had not changed since the reference was done
1076  // aborting_last_etoile is the highest etoile reference withing "this" current object.
1077 
1078  void dump(generic_file & f) const;
1079  void listing(bool isolated,
1080  const mask &selection,
1081  const mask & subtree,
1082  bool filter_unsaved,
1083  bool list_ea,
1084  std::string marge) const;
1085  void tar_listing(bool isolated,
1086  const mask & selection,
1087  const mask & subtree,
1088  bool filter_unsaved,
1089  bool list_ea,
1090  std::string beginning) const;
1091  void xml_listing(bool isolated,
1092  const mask & selection,
1093  const mask & subtree,
1094  bool filter_unsaved,
1095  bool list_ea,
1096  std::string beginning) const;
1097 
1098  entree_stats get_stats() const { return stats; };
1099 
1101  bool is_empty() const { if(contenu == NULL) throw SRC_BUG; return contenu->is_empty(); };
1102 
1103  const directory *get_contenu() const { return contenu; }; // used by data_tree
1104 
1105  const label & get_data_name() const { return ref_data_name; };
1106  infinint get_root_dir_last_modif() const { return contenu->get_last_modif(); };
1107 
1109  void launch_recursive_has_changed_update() const { contenu->recursive_has_changed_update(); };
1110 
1111  infinint get_root_mtime() const { return contenu->get_last_modif(); };
1112 
1114  void reset_all();
1115 
1116 
1117  protected:
1118  entree_stats & access_stats() { return stats; };
1119  void set_data_name(const label & val) { ref_data_name = val; };
1120  void copy_detruits_from(const catalogue & ref); // needed for escape_catalogue implementation only.
1121 
1122  const eod * get_r_eod_address() const { return & r_eod; }; // eod are never stored in the catalogue
1123  // however it is sometimes required to return such a reference to a valid object
1124  // owned by the catalogue.
1125 
1126 
1129  void swap_stuff(catalogue & ref);
1130 
1131  private :
1132  directory *contenu;
1133  path out_compare;
1134  directory *current_compare;
1135  directory *current_add;
1136  directory *current_read;
1137  path *sub_tree;
1138  signed int sub_count;
1139  entree_stats stats;
1140  label ref_data_name;
1141 
1142  void partial_copy_from(const catalogue &ref);
1143  void detruire();
1144 
1145  static const eod r_eod; // needed to return eod reference, without taking risk of saturating memory
1146  static const U_I CAT_CRC_SIZE;
1147  };
1148 
1149 
1150 
1152 
1153 } // end of namespace
1154 
1155 #endif