Disk ARchive  2.5.2
Full featured and portable backup and archiving tool
escape.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines