Disk ARchive  2.4.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
escape.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: escape.hpp,v 1.25 2011/04/17 18:43:39 edrusb Rel $
22 //
23 /*********************************************************************/
24 
40 
41 
42 #ifndef ESCAPE_HPP
43 #define ESCAPE_HPP
44 
45 #include "../my_config.h"
46 
47 extern "C"
48 {
49 #if HAVE_LIMITS_H
50 #include <limits.h>
51 #endif
52 }
53 
54 #include <set>
55 
56 #include "generic_file.hpp"
57 
58 #define ESCAPE_FIXED_SEQUENCE_NORMAL 0xAD
59 #define ESCAPE_FIXED_SEQUENCE_SPARSE_FILE 0xAE
60 
61 #define MAX_BUFFER_SIZE 204800
62 #ifdef SSIZE_MAX
63 #if SSIZE_MAX < MAX_BUFFER_SIZE
64 #undef MAX_BUFFER_SIZE
65 #define MAX_BUFFER_SIZE SSIZE_MAX
66 #endif
67 #endif
68 
69 namespace libdar
70 {
71 
74 
75  class escape : public generic_file
76  {
77  public:
78  enum sequence_type
79  {
80  seqt_undefined, //< not enough data to define the type of the escape sequence
81  seqt_not_a_sequence, //< to escape data corresponding to an escape sequence's fixed byte sequence
82  seqt_file, //< placed before inode information, eventually followed by file data
83  seqt_ea, //< placed before EA data
84  seqt_catalogue, //< placed before the archive's internal catalogue
85  seqt_data_name, //< placed before the archive data_name (at the beginning of the archive)
86  seqt_file_crc, //< placed before the CRC of file's data
87  seqt_ea_crc, //< placed before the CRC of file's EA
88  seqt_changed, //< placed before new copy of file's data if file's data changed while reading it for backup
89  seqt_dirty, //< placed after data CRC if file is dirty
90  seqt_failed_backup //< placed after inode information if the file could not be openned at backup time
91  };
92 
93  // the archive layout of marks is :
94  // ... <seqt_file> <inode> [<file data> [<seqt_changed> <new copy of data> [...] ] <seqt_file_crc> <CRC>[<seqt_dirty>]] [<seqt_ea> <EA> <sqt_ea_crc> <CRC>] ...
95  // this previous sequence that we will call <SEQ> is repeated for each file, then on the overall archive we have :
96  // <seqt_data_name> <data_name> <SEQ> ... <SEQ> <seqt_catalogue> <catalogue> <terminator>
97 
98  // the provided "below" object must exist during the whole live of the escape object, the escape object does not own this "below" object
99  // it must be destroyed by the caller/creator of the escape object.
100 
101 
102  // constructors & destructors
103 
104  escape(generic_file *below, //< "Below" is the generic file that holds the escaped data
105  const std::set<sequence_type> & x_unjumpable); //< a set of marks that can never been jumped over when skipping for the next mark of a any given type.
106  escape(const escape & ref) : generic_file(ref) { copy_from(ref); };
107  const escape & operator = (const escape & ref);
108  ~escape();
109 
110  // escape specific routines
111 
112  void add_mark_at_current_position(sequence_type t);
113 
115 
120  bool skip_to_next_mark(sequence_type t, bool jump);
121  bool next_to_read_is_mark(sequence_type t);
122  bool next_to_read_is_which_mark(sequence_type & t);
123 
124  void add_unjumpable_mark(sequence_type t) { if(is_terminated()) throw SRC_BUG; unjumpable.insert(t); };
125  void remove_unjumpable_mark(sequence_type t);
126  bool is_unjumpable_mark(sequence_type t) const { return unjumpable.find(t) != unjumpable.end(); };
127  void clear_all_unjumpable_marks() { unjumpable.clear(); };
128 
129  // generic_file inherited routines
130  // NOTA: Nothing is done to prevent skip* operation to put the read cursor in the middle of an escape sequence and
131  // thus incorrectly consider it as normal data. Such event should only occure upon archive corruption and will be detected
132  // by checksum mechanisms.
133 
134  bool skip(const infinint & pos);
135  bool skip_to_eof();
136  bool skip_relative(S_I x);
137  infinint get_position();
138 
139  generic_file *get_below() const { return x_below; };
140 
141  protected:
142  U_I inherited_read(char *a, U_I size);
143  void inherited_write(const char *a, U_I size);
144  void inherited_sync_write() { flush_write(); };
145  void inherited_terminate() { flush_or_clean(); };
146 
147  void change_fixed_escape_sequence(unsigned char value) { fixed_sequence[0] = value; };
148  bool has_escaped_data_since_last_skip() const { return escaped_data_count_since_last_skip > 0; };
149 
150  private:
151 
152  //-- constants
153 
155  static const U_I ESCAPE_SEQUENCE_LENGTH = 6;
156  static const U_I WRITE_BUFFER_SIZE = 2*ESCAPE_SEQUENCE_LENGTH;
157  static const U_I READ_BUFFER_SIZE = MAX_BUFFER_SIZE;
158 
160 
166  static const unsigned char usual_fixed_sequence[ESCAPE_SEQUENCE_LENGTH];
167 
168  //-- variables
169 
170  generic_file *x_below; //< the generic_file in which we read/write escaped data from/to the object is not owned by "this"
171  U_I write_buffer_size; //< amount of data in write transit not yet written to "below" (may have to be escaped)
172  char write_buffer[WRITE_BUFFER_SIZE]; //< data in write transit, all data is unescaped, up to the first real mark, after it, data is raw (may be escaped)
173  //< the first real mark is pointed to by escape_seq_offset_in_buffer
174  U_I read_buffer_size; //< amount of data in write transit, read from below, but not yet unescaped and returned to the upper layer
175  U_I already_read; //< data in buffer that has already returned to the upper layer
176  bool read_eof; //< whether we reached a escape sequence while reading data
177  U_I escape_seq_offset_in_buffer; //< location of the first escape sequence which is not a data sequence
178  char read_buffer[READ_BUFFER_SIZE]; //< data in read transit
179  std::set<sequence_type> unjumpable; //< list of mark that cannot be jumped over when searching for the next mark
180  unsigned char fixed_sequence[ESCAPE_SEQUENCE_LENGTH]; // the preambule of an escape sequence to use/search for
181  infinint escaped_data_count_since_last_skip;
182 
183  //-- routines
184 
185  void set_fixed_sequence_for(sequence_type t) { fixed_sequence[ESCAPE_SEQUENCE_LENGTH - 1] = type2char(t); };
186  void check_below() { if(x_below == NULL) throw SRC_BUG; };
187  void clean_data() { read_buffer_size = already_read = escape_seq_offset_in_buffer = 0; }; //< drops all in-transit data
188  void flush_write(); //< write down to "below" all in-transit data
189  void flush_or_clean()
190  {
191  switch(get_mode())
192  {
193  case gf_read_only:
194  clean_data();
195  break;
196  case gf_write_only:
197  flush_write();
198  break;
199  default:
200  throw SRC_BUG;
201  }
202  };
203  void copy_from(const escape & ref);
204  bool mini_read_buffer(); //< returns true if it could end having at least ESCAPE_SEQUENCE_LENGTH bytes in read_buffer, false else (EOF reached).
205 
206  //-- static routine(s)
207 
208  // some convertion routines
209  static char type2char(sequence_type x);
210  static sequence_type char2type(char x);
211 
213 
215 
218  static U_I trouve_amorce(const char *a, U_I size, const unsigned char escape_sequence[ESCAPE_SEQUENCE_LENGTH]);
219 
221 
228  static U_I remove_data_marks_and_stop_at_first_real_mark(char *a, U_I size, U_I & delta, const unsigned char escape_sequence[ESCAPE_SEQUENCE_LENGTH]);
229  };
230 
232 
233 } // end of namespace
234 
235 #endif