![]() |
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 00033 00034 #ifndef SPARSE_FILE_HPP 00035 #define SPARSE_FILE_HPP 00036 00037 #include "../my_config.h" 00038 00039 extern "C" 00040 { 00041 #if HAVE_LIMITS_H 00042 #include <limits.h> 00043 #endif 00044 } 00045 00046 #include "generic_file.hpp" 00047 #include "escape.hpp" 00048 00051 00052 00053 #define SPARSE_FIXED_ZEROED_BLOCK 40960 00054 #ifdef SSIZE_MAX 00055 #if SSIZE_MAX < MAX_BUFFER_SIZE 00056 #undef MAX_BUFFER_SIZE 00057 #define SPARSE_FIXED_ZEROED_BLOCK SSIZE_MAX 00058 #endif 00059 #endif 00060 00061 00062 namespace libdar 00063 { 00064 00065 class sparse_file : public escape 00066 { 00067 public: 00069 00072 // this parameter is only used if "below" is in write-only mode 00073 sparse_file(generic_file *below, const infinint & hole_size = 15); 00074 00075 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 00076 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. 00077 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 00078 00079 bool has_seen_hole() const { return seen_hole; }; 00080 bool has_escaped_data() const { return data_escaped; }; 00081 00083 00092 void copy_to(generic_file & ref) { crc *tmp = nullptr; copy_to(ref, 0, tmp); if(tmp != nullptr) throw SRC_BUG; }; 00093 00095 void copy_to(generic_file & ref, const infinint & crc_size, crc * & value); 00096 00097 // indirectly inherited from generic_file 00098 bool skippable(skippability direction, const infinint & amount) { return false; }; 00099 bool skip(const infinint & pos) { if(pos != offset) throw Efeature("skip in sparse_file"); else return true; }; 00100 bool skip_to_eof() { throw Efeature("skip in sparse_file"); }; 00101 bool skip_relative(S_I x) { if(x != 0) throw Efeature("skip in sparse_file"); return true; }; 00102 infinint get_position() const; 00103 00104 protected: 00105 00106 // methods from the escape class we hide from the (public) class interface 00107 00108 void add_mark_at_current_position(sequence_type t) { escape::add_mark_at_current_position(t); }; 00109 bool skip_to_next_mark(sequence_type t, bool jump) { return escape::skip_to_next_mark(t, jump); }; 00110 bool next_to_read_is_mark(sequence_type t) { return escape::next_to_read_is_mark(t); }; 00111 void add_unjumpable_mark(sequence_type t) { escape::add_unjumpable_mark(t); }; 00112 00113 // methods from generic_file redefined as protected 00114 00115 U_I inherited_read(char *a, U_I size); 00116 void inherited_write(const char *a, U_I size); 00117 void inherited_sync_write(); 00118 // inherited_flush_read() kept as is from the escape class 00119 // inherited_terminate() kept as is from the escape class 00120 00121 private: 00122 static bool initialized; //< whether static field "zeroed_field" has been initialized 00123 static unsigned char zeroed_field[SPARSE_FIXED_ZEROED_BLOCK]; //< read-only, used when the sequence of zeros is too short for a hole 00124 00125 enum { normal, hole } mode; //< wether we are currently reading/writing a hole or normal data 00126 infinint zero_count; //< number of zeroed byte pending in the current hole 00127 infinint offset; //< current offset in file (as if it was a plain file). 00128 infinint min_hole_size; //< minimum size of hole to consider 00129 U_I UI_min_hole_size; //< if possible store min_hole_size as U_I, if not this field is set to zero which disables the hole lookup inside buffers while writing data 00130 bool escape_write; //< whether to behave like an escape object when writing down data 00131 bool escape_read; //< whether to behave like an escape object when reading out data 00132 bool copy_to_no_skip; //< whether to hide holes by zeored bytes in the copy_to() methods 00133 bool seen_hole; //< whether a hole has been seen or this is a plain file so far 00134 bool data_escaped; //< whether some data has been escaped to not collide with a mark (may occur even when no hole is met) 00135 00138 void dump_pending_zeros(); 00139 00141 void write_hole(const infinint & length); 00142 00146 void reset(); 00147 00148 00150 00158 static bool look_for_hole(const char *a, U_I size, U_I min_hole_size, U_I & start, U_I & length); 00159 00161 00165 static U_I count_initial_zeros(const char *a, U_I size); 00166 }; 00167 00168 00169 } // end of namespace 00170 00172 00173 #endif