![]() |
Disk ARchive
2.5.2
Full featured and portable backup and archiving tool
|
00001 /*********************************************************************/ 00002 // dar - disk archive - a backup/restoration program 00003 // Copyright (C) 2002-2052 Denis Corbin 00004 // 00005 // This program is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU General Public License 00007 // as published by the Free Software Foundation; either version 2 00008 // of the License, or (at your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with this program; if not, write to the Free Software 00017 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 // 00019 // to contact the author : http://dar.linux.free.fr/email.html 00020 /*********************************************************************/ 00021 00037 00038 00039 #ifndef ESCAPE_HPP 00040 #define ESCAPE_HPP 00041 00042 #include "../my_config.h" 00043 00044 extern "C" 00045 { 00046 #if HAVE_LIMITS_H 00047 #include <limits.h> 00048 #endif 00049 } 00050 00051 #include <set> 00052 00053 #include "generic_file.hpp" 00054 00055 #define ESCAPE_FIXED_SEQUENCE_NORMAL 0xAD 00056 #define ESCAPE_FIXED_SEQUENCE_SPARSE_FILE 0xAE 00057 00058 #define MAX_BUFFER_SIZE 102400 00059 #ifdef SSIZE_MAX 00060 #if SSIZE_MAX < MAX_BUFFER_SIZE 00061 #undef MAX_BUFFER_SIZE 00062 #define MAX_BUFFER_SIZE SSIZE_MAX 00063 #endif 00064 #endif 00065 00066 namespace libdar 00067 { 00068 00071 00072 class escape : public generic_file 00073 { 00074 public: 00075 enum sequence_type 00076 { 00077 seqt_undefined, //< not enough data to define the type of the escape sequence 00078 seqt_not_a_sequence, //< to escape data corresponding to an escape sequence's fixed byte sequence 00079 seqt_file, //< placed before inode information, eventually followed by file data 00080 seqt_ea, //< placed before EA data 00081 seqt_catalogue, //< placed before the archive's internal catalogue 00082 seqt_data_name, //< placed before the archive data_name (at the beginning of the archive) 00083 seqt_file_crc, //< placed before the CRC of file's data 00084 seqt_ea_crc, //< placed before the CRC of file's EA 00085 seqt_changed, //< placed before new copy of file's data if file's data changed while reading it for backup 00086 seqt_dirty, //< placed after data CRC if file is dirty 00087 seqt_failed_backup, //< placed after inode information if the file could not be openned at backup time 00088 seqt_fsa, //< placed before FSA data 00089 seqt_fsa_crc //< place before the CRC of file's FSA 00090 }; 00091 00092 // the archive layout of marks is for each entry: 00093 // #seqt_file# <inode> [<file data> [#seqt_changed# <new copy of data> [...] ] #seqt_file_crc# <CRC>[#seqt_dirty#]] [#seqt_ea# <EA> #seqt_ea_crc# <CRC>] 00094 // this previous sequence that we will call <SEQ> is repeated for each file, then on the overall archive we have : 00095 // #seqt_data_name# <data_name> <SEQ> ... <SEQ> #seqt_catalogue# <catalogue> <terminator> 00096 00097 // the provided "below" object must exist during the whole live of the escape object, 00098 // the escape object does not own this "below" object 00099 // it must be destroyed by the caller/creator of the escape object. 00100 00101 00102 // constructors & destructors 00103 00104 escape(generic_file *below, //< "Below" is the generic file that holds the escaped data 00105 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. 00106 escape(const escape & ref) : generic_file(ref) { copy_from(ref); }; 00107 const escape & operator = (const escape & ref); 00108 ~escape(); 00109 00110 // escape specific routines 00111 00112 void add_mark_at_current_position(sequence_type t); 00113 00115 00120 bool skip_to_next_mark(sequence_type t, bool jump); 00121 bool next_to_read_is_mark(sequence_type t); 00122 bool next_to_read_is_which_mark(sequence_type & t); 00123 00124 void add_unjumpable_mark(sequence_type t) { if(is_terminated()) throw SRC_BUG; unjumpable.insert(t); }; 00125 void remove_unjumpable_mark(sequence_type t); 00126 bool is_unjumpable_mark(sequence_type t) const { return unjumpable.find(t) != unjumpable.end(); }; 00127 void clear_all_unjumpable_marks() { unjumpable.clear(); }; 00128 00129 00130 // generic_file inherited routines 00131 // NOTA: Nothing is done to prevent skip* operation to put the read cursor in the middle of an escape sequence and 00132 // thus incorrectly consider it as normal data. Such event should only occure upon archive corruption and will be detected 00133 // by checksum mechanisms. 00134 00135 bool skippable(skippability direction, const infinint & amount); 00136 bool skip(const infinint & pos); 00137 bool skip_to_eof(); 00138 bool skip_relative(S_I x); 00139 infinint get_position() const; 00140 00141 protected: 00142 void inherited_read_ahead(const infinint & amount); 00143 U_I inherited_read(char *a, U_I size); 00144 void inherited_write(const char *a, U_I size); 00145 void inherited_sync_write() { flush_write(); }; 00146 void inherited_flush_read() { flush_write(); clean_read(); }; 00147 void inherited_terminate() { flush_or_clean(); }; 00148 00149 void change_fixed_escape_sequence(unsigned char value) { fixed_sequence[0] = value; }; 00150 bool has_escaped_data_since_last_skip() const { return escaped_data_count_since_last_skip > 0; }; 00151 00152 private: 00153 00154 //-- constants 00155 00157 static const U_I ESCAPE_SEQUENCE_LENGTH = 6; 00158 static const U_I WRITE_BUFFER_SIZE = 2*ESCAPE_SEQUENCE_LENGTH; 00159 static const U_I READ_BUFFER_SIZE = MAX_BUFFER_SIZE; 00160 static const infinint READ_BUFFER_SIZE_INFININT; 00161 00163 00169 static const unsigned char usual_fixed_sequence[ESCAPE_SEQUENCE_LENGTH]; 00170 00171 //-- variables 00172 00173 generic_file *x_below; //< the generic_file in which we read/write escaped data from/to the object is not owned by "this" 00174 U_I write_buffer_size; //< amount of data in write transit not yet written to "below" (may have to be escaped) 00175 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) 00176 //< the first real mark is pointed to by escape_seq_offset_in_buffer 00177 U_I read_buffer_size; //< amount of data in transit, read from below, but possibly not yet unescaped and returned to the upper layer 00178 U_I already_read; //< data in buffer that has already been returned to the upper layer 00179 bool read_eof; //< whether we reached a escape sequence while reading data 00180 U_I escape_seq_offset_in_buffer; //< location of the first escape sequence which is not a data sequence 00181 char read_buffer[READ_BUFFER_SIZE]; //< data in read transit 00182 std::set<sequence_type> unjumpable; //< list of mark that cannot be jumped over when searching for the next mark 00183 unsigned char fixed_sequence[ESCAPE_SEQUENCE_LENGTH]; //< the preambule of an escape sequence to use/search for 00184 infinint escaped_data_count_since_last_skip; 00185 infinint below_position; //< remember the position of object pointed to by x_below 00186 00187 //-- routines 00188 00189 void set_fixed_sequence_for(sequence_type t) { fixed_sequence[ESCAPE_SEQUENCE_LENGTH - 1] = type2char(t); }; 00190 void check_below() const { if(x_below == nullptr) throw SRC_BUG; }; 00191 void clean_read(); //< drops all in-transit data 00192 void flush_write(); //< write down to "below" all in-transit data 00193 void flush_or_clean() 00194 { 00195 switch(get_mode()) 00196 { 00197 case gf_read_only: 00198 clean_read(); 00199 break; 00200 case gf_write_only: 00201 case gf_read_write: 00202 flush_write(); 00203 break; 00204 default: 00205 throw SRC_BUG; 00206 } 00207 }; 00208 void copy_from(const escape & ref); 00209 bool mini_read_buffer(); //< returns true if it could end having at least ESCAPE_SEQUENCE_LENGTH bytes in read_buffer, false else (EOF reached). 00210 00211 //-- static routine(s) 00212 00213 // some convertion routines 00214 static char type2char(sequence_type x); 00215 static sequence_type char2type(char x); 00216 00218 00220 00223 static U_I trouve_amorce(const char *a, U_I size, const unsigned char escape_sequence[ESCAPE_SEQUENCE_LENGTH]); 00224 00226 00233 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]); 00234 }; 00235 00237 00238 } // end of namespace 00239 00240 #endif