Disk ARchive 2.4.2
|
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 // $Id: sparse_file.hpp,v 1.20 2011/05/20 10:23:07 edrusb Rel $ 00022 // 00023 /*********************************************************************/ 00024 00036 00037 #ifndef SPARSE_FILE_HPP 00038 #define SPARSE_FILE_HPP 00039 00040 #include "../my_config.h" 00041 00042 extern "C" 00043 { 00044 #if HAVE_LIMITS_H 00045 #include <limits.h> 00046 #endif 00047 } 00048 00049 #include "generic_file.hpp" 00050 #include "escape.hpp" 00051 00054 00055 00056 #define SPARSE_FIXED_ZEROED_BLOCK 40960 00057 #ifdef SSIZE_MAX 00058 #if SSIZE_MAX < MAX_BUFFER_SIZE 00059 #undef MAX_BUFFER_SIZE 00060 #define SPARSE_FIXED_ZEROED_BLOCK SSIZE_MAX 00061 #endif 00062 #endif 00063 00064 00065 namespace libdar 00066 { 00067 00068 class sparse_file : public escape 00069 { 00070 public: 00072 00075 // this parameter is only used if "below" is in write-only mode 00076 sparse_file(generic_file *below, const infinint & hole_size = 15); 00077 00078 void write_as_escape(bool mode) { escape_write = mode; }; // if set to true, inherited_write() call will not make any lookup for holes, the written data will simply be escaped if it could collide with a mark used to signal the start of a hole 00079 void read_as_escape(bool mode) { escape_read = mode; }; // if set to true, the data will be unescaped or eof will be signaled to the first mark met, instead of interpreting the mark and what follows as a hole data structure. 00080 void copy_to_without_skip(bool mode) { copy_to_no_skip = mode; }; // if set to true, the copy_to() methods, write zeroed data in place of skipping over a hole to restore it into the target generic_file 00081 00082 bool has_seen_hole() const { return seen_hole; }; 00083 bool has_escaped_data() const { return data_escaped; }; 00084 00086 00095 void copy_to(generic_file & ref) { crc value = infinint(1); copy_to(ref, value); }; 00096 00098 void copy_to(generic_file & ref, crc & value); 00099 00100 // indirectly inherited from generic_file 00101 00102 bool skip(const infinint & pos) { if(pos != offset) throw Efeature("skip in sparse_file"); else return true; }; 00103 bool skip_to_eof() { throw Efeature("skip in sparse_file"); }; 00104 bool skip_relative(S_I x) { if(x != 0) throw Efeature("skip in sparse_file"); return true; }; 00105 infinint get_position(); 00106 00107 protected: 00108 00109 // hidden methods from the escape class 00110 00111 void add_mark_at_current_position(sequence_type t) { escape::add_mark_at_current_position(t); }; 00112 bool skip_to_next_mark(sequence_type t, bool jump) { return escape::skip_to_next_mark(t, jump); }; 00113 bool next_to_read_is_mark(sequence_type t) { return escape::next_to_read_is_mark(t); }; 00114 void add_unjumpable_mark(sequence_type t) { escape::add_unjumpable_mark(t); }; 00115 00116 // redefined protected methods from generic_file 00117 00118 U_I inherited_read(char *a, U_I size); 00119 void inherited_write(const char *a, U_I size); 00120 void inherited_sync_write(); 00121 void inherited_terminate() { escape::inherited_terminate(); }; 00122 00123 private: 00124 static bool initialized; 00125 static unsigned char zeroed_field[SPARSE_FIXED_ZEROED_BLOCK]; // read-only, used when the sequence of zeros is too short for a hole 00126 00127 enum { normal, hole } mode; 00128 infinint zero_count; //< number of zeroed byte pending in the current hole 00129 infinint offset; //< current offset in file (as if it was a plain file). 00130 infinint min_hole_size; //< minimum size of hole to consider 00131 U_I UI_min_hole_size; //< if possible store min_hole_size under U_I, if not this field is set to zero which disables the hole lookup inside buffers while writing data 00132 bool escape_write; //< whether to behave like an escape object when writing down data 00133 bool escape_read; //< whether to behave like an escape object when reading out data 00134 bool copy_to_no_skip; //< whether to hide holes by zeored bytes in the copy_to() methods 00135 bool seen_hole; //< whether a hole has been seen or this is a plain file so far 00136 bool data_escaped; //< whether some data has been escaped to not collide with a mark (may occur even when no hole is met) 00137 00140 void dump_pending_zeros(); 00141 00143 void write_hole(const infinint & length); 00144 00146 00154 static bool look_for_hole(const char *a, U_I size, U_I min_hole_size, U_I & start, U_I & length); 00155 00157 00161 static U_I count_initial_zeros(const char *a, U_I size); 00162 }; 00163 00164 00165 } // end of namespace 00166 00168 00169 #endif