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 22 #include "../my_config.h" 23 24 extern "C" 25 { 26 #if HAVE_STRING_H 27 #include <string.h> 28 #endif 29 } // end of extern "C" 30 31 32 #include "header_version.hpp" 33 #include "integers.hpp" 34 35 #define LIBDAR_URL_VERSION "http://dar.linux.free.fr/pre-release/doc/Notes.html#Dar_version_naming" 36 37 using namespace std; 38 39 namespace libdar 40 { 41 static const U_I HEADER_CRC_SIZE = 2; //< CRC width (deprecated, now only used when reading old archives) 42 header_version()43 header_version::header_version() 44 { 45 algo_zip = none; 46 cmd_line = ""; 47 initial_offset = 0; 48 sym = crypto_none; 49 crypted_key = nullptr; 50 ref_layout = nullptr; 51 ciphered = false; 52 arch_signed = false; 53 } 54 read(generic_file & f,user_interaction & dialog,bool lax_mode)55 void header_version::read(generic_file & f, user_interaction & dialog, bool lax_mode) 56 { 57 crc *ctrl = nullptr; 58 char tmp; 59 U_I flag; 60 61 f.reset_crc(HEADER_CRC_SIZE); 62 try 63 { 64 edition.read(f); 65 } 66 catch(Egeneric & e) 67 { 68 if(lax_mode) 69 { 70 string answ; 71 U_I equivalent; 72 bool ok = false; 73 74 dialog.warning(gettext("LAX MODE: Failed to read the archive header's format version.")); 75 do 76 { 77 answ = dialog.get_string(tools_printf(gettext("LAX MODE: Please provide the archive format: You can use the table at %s to find the archive format depending on the release version, (for example if this archive has been created using dar release 2.3.4 to 2.3.7 answer \"6\" without the quotes here): "), LIBDAR_URL_VERSION), true); 78 if(tools_my_atoi(answ.c_str(), equivalent)) 79 edition = equivalent; 80 else 81 { 82 dialog.pause(tools_printf(gettext("LAX MODE: \"%S\" is not a valid archive format"), &answ)); 83 continue; 84 } 85 86 try 87 { 88 dialog.pause(tools_printf(gettext("LAX MODE: Using archive format \"%d\"?"), equivalent)); 89 ok = true; 90 } 91 catch(Euser_abort & e) 92 { 93 ok = false; 94 } 95 } 96 while(!ok); 97 } 98 else 99 throw; 100 } 101 102 if(f.read(&tmp, 1) == 1) // compression algo 103 { 104 bool ok = false; 105 do 106 { 107 try 108 { 109 algo_zip = char2compression(tmp); 110 ok = true; 111 } 112 catch(Erange & e) 113 { 114 if(!lax_mode) 115 throw; 116 117 string answ = dialog.get_string(gettext("LAX MODE: Unknown compression algorithm used, assuming data corruption occurred. Please help me, answering with one of the following words \"none\", \"gzip\", \"bzip2\" or \"lzo\" at the next prompt:"), true); 118 if(answ == gettext("none")) 119 tmp = compression2char(none); 120 else if(answ == gettext("gzip")) 121 tmp = compression2char(gzip); 122 else if(answ == gettext("bzip2")) 123 tmp = compression2char(bzip2); 124 else if(answ == gettext("lzo")) 125 tmp = compression2char(lzo); 126 } 127 } 128 while(!ok); 129 } 130 else 131 throw Erange("header_version::read", gettext("Reached End of File while reading archive header_version data structure")); 132 133 tools_read_string(f, cmd_line); 134 135 if(edition > 1) 136 { 137 unsigned char tomp; 138 if(f.read((char *)&tomp, 1) != 1) 139 throw Erange("header_version::read", gettext("Reached End of File while reading archive header_version data structure")); 140 // even in lax mode, because reading further is vain 141 flag = tomp; 142 } 143 else 144 flag = 0; // flag has been at edition 2 145 if((flag & FLAG_HAS_AN_EXTENDED_SIZE) != 0) 146 { 147 unsigned char tomp; 148 149 if(f.read((char *)&tomp, 1) != 1) 150 throw Erange("header_version::read", gettext("Reached End of File while reading archive header_version data structure")); 151 flag <<= 8; 152 flag += tomp; 153 } 154 155 if((flag & FLAG_INITIAL_OFFSET) != 0) 156 { 157 initial_offset.read(f); 158 } 159 else 160 initial_offset = 0; 161 162 if((flag & FLAG_SCRAMBLED) != 0) 163 { 164 ciphered = true; 165 if(edition >= 9) 166 { 167 if(f.read(&tmp, sizeof(tmp)) != 1) 168 throw Erange("header_version::read", gettext("Reached End of File while reading archive header_version data structure")); 169 170 try 171 { 172 sym = char_2_crypto_algo(tmp); 173 } 174 catch(Erange & e) 175 { 176 if(!lax_mode) 177 throw; 178 dialog.printf("Unknown crypto algorithm used in archive, ignoring that field and simply assuming the archive has been encrypted, if not done you will need to specify the crypto algorithm to use in order to read this archive"); 179 sym = crypto_none; 180 } 181 } 182 else 183 // unknown ciphering algorithm used (old archive format) or no encryption 184 // not coherent with flag which has the FLAG_SCRAMBLED bit set 185 // but that this way we record that the crypto algo has 186 // to be provided by the user 187 sym = crypto_none; 188 } 189 else 190 { 191 ciphered = false; 192 sym = crypto_none; // no crypto used, coherent with flag 193 } 194 195 has_tape_marks = (flag & FLAG_SEQUENCE_MARK) != 0; 196 if(edition < 8 && has_tape_marks) 197 { 198 if(lax_mode) 199 has_tape_marks = false; // Escape sequence marks appeared at revision 08 200 else 201 throw Erange("header_version::read", gettext("Corruption met while reading header_version data structure")); 202 } 203 204 if(crypted_key != nullptr) 205 { 206 delete crypted_key; 207 crypted_key = nullptr; 208 } 209 210 if((flag & FLAG_HAS_CRYPTED_KEY) != 0) 211 { 212 infinint key_size = f; 213 214 crypted_key = new (get_pool()) memory_file(); 215 if(crypted_key == nullptr) 216 throw Ememory("header_version::read"); 217 if(f.copy_to(*crypted_key, key_size) != key_size) 218 throw Erange("header_version::read", gettext("Missing data for encrypted symmetrical key")); 219 } 220 221 if((flag & FLAG_HAS_REF_SLICING) != 0) 222 { 223 try 224 { 225 if(ref_layout == nullptr) 226 ref_layout = new (get_pool()) slice_layout(); 227 if(ref_layout == nullptr) 228 throw Ememory("header_version::read"); 229 ref_layout->read(f); 230 } 231 catch(Egeneric & e) 232 { 233 if(lax_mode) 234 { 235 dialog.warning(gettext("Error met while reading archive of reference slicing layout, ignoring this field and continuing")); 236 clear_slice_layout(); 237 } 238 else 239 throw; 240 } 241 } 242 else 243 clear_slice_layout(); 244 245 arch_signed = (flag & FLAG_ARCHIVE_IS_SIGNED) != 0; 246 247 ctrl = f.get_crc(); 248 if(ctrl == nullptr) 249 throw SRC_BUG; 250 251 try 252 { 253 if(edition == empty_archive_version()) 254 { 255 if(lax_mode) 256 dialog.warning(gettext("Consistency check failed for archive header")); 257 else 258 throw Erange("header_version::read", gettext("Consistency check failed for archive header")); 259 } 260 261 if(edition > 7) 262 { 263 crc *coh = create_crc_from_file(f, get_pool()); 264 265 if(coh == nullptr) 266 throw SRC_BUG; 267 try 268 { 269 if(typeid(*coh) != typeid(*ctrl)) 270 { 271 if(coh->get_size() != ctrl->get_size()) 272 throw SRC_BUG; 273 else 274 throw SRC_BUG; // both case lead to a bug, but we need to know which one is met 275 } 276 277 if(*coh != *ctrl) 278 { 279 if(lax_mode) 280 dialog.warning(gettext("Consistency check failed for archive header")); 281 else 282 throw Erange("header_version::read", gettext("Consistency check failed for archive header")); 283 } 284 } 285 catch(...) 286 { 287 if(coh != nullptr) 288 delete coh; 289 throw; 290 } 291 if(coh != nullptr) 292 delete coh; 293 } 294 if(initial_offset.is_zero()) 295 initial_offset = f.get_position(); 296 } 297 catch(...) 298 { 299 if(ctrl != nullptr) 300 delete ctrl; 301 throw; 302 } 303 304 if(ctrl != nullptr) 305 delete ctrl; 306 } 307 write(generic_file & f) const308 void header_version::write(generic_file &f) const 309 { 310 crc *ctrl = nullptr; 311 char tmp; 312 unsigned char flag[2]; 313 314 // preparing the data 315 316 flag[0] = 0; 317 flag[1] = 0; 318 319 if(!initial_offset.is_zero()) 320 flag[0] |= FLAG_INITIAL_OFFSET; // adding it to the flag 321 322 if(crypted_key != nullptr) 323 flag[0] |= FLAG_HAS_CRYPTED_KEY; 324 325 if(ref_layout != nullptr) 326 flag[0] |= FLAG_HAS_REF_SLICING; 327 328 if(has_tape_marks) 329 flag[0] |= FLAG_SEQUENCE_MARK; 330 331 if(sym != crypto_none) 332 flag[0] |= FLAG_SCRAMBLED; 333 // Note: we cannot set this flag (even if ciphered is true) if we do not know the crypto algo 334 // as since version 9 the presence of this flag implies the existence 335 // of the crypto algorithm in the header/trailer and we will always 336 // write down a header/version of the latest known format (thus greater or 337 // equal to 9). 338 339 if(arch_signed) 340 flag[1] |= (FLAG_ARCHIVE_IS_SIGNED >> 8); 341 342 if(flag[1] > 0) 343 flag[1] |= FLAG_HAS_AN_EXTENDED_SIZE; 344 // and we will drop two bytes for the flag 345 346 // writing down the data 347 348 f.reset_crc(HEADER_CRC_SIZE); 349 edition.dump(f); 350 tmp = compression2char(algo_zip); 351 f.write(&tmp, sizeof(tmp)); 352 tools_write_string(f, cmd_line); 353 if(flag[1] != 0) 354 f.write((char *)&(flag[1]), sizeof(unsigned char)); 355 f.write((char *)&(flag[0]), sizeof(unsigned char)); 356 if(initial_offset != 0) 357 initial_offset.dump(f); 358 if(sym != crypto_none) 359 { 360 tmp = crypto_algo_2_char(sym); 361 f.write(&tmp, sizeof(tmp)); 362 } 363 364 if(crypted_key != nullptr) 365 { 366 crypted_key->size().dump(f); 367 crypted_key->skip(0); 368 crypted_key->copy_to(f); 369 } 370 371 if(ref_layout != nullptr) 372 ref_layout->write(f); 373 374 ctrl = f.get_crc(); 375 if(ctrl == nullptr) 376 throw SRC_BUG; 377 try 378 { 379 ctrl->dump(f); 380 } 381 catch(...) 382 { 383 if(ctrl != nullptr) 384 delete ctrl; 385 throw; 386 } 387 if(ctrl != nullptr) 388 delete ctrl; 389 } 390 display(user_interaction & dialog) const391 void header_version::display(user_interaction & dialog) const 392 { 393 string algo = compression2string(get_compression_algo()); 394 string sym = get_edition() >= 9 ? crypto_algo_2_string(get_sym_crypto_algo()) : (is_ciphered() ? gettext("yes") : gettext("no")); 395 string asym = get_edition() >= 9 && (get_crypted_key() != nullptr) ? "gnupg" : gettext("none"); 396 string xsigned = is_signed() ? gettext("yes") : gettext("no"); 397 398 dialog.printf(gettext("Archive version format : %s\n"), get_edition().display().c_str()); 399 dialog.printf(gettext("Compression algorithm used : %S\n"), &algo); 400 dialog.printf(gettext("Symmetric key encryption used : %S\n"), &sym); 401 dialog.printf(gettext("Asymmetric key encryption used : %S\n"), &asym); 402 dialog.printf(gettext("Archive is signed : %S\n"), &xsigned); 403 dialog.printf(gettext("Sequential reading marks : %s\n"), (get_tape_marks() ? gettext("present") : gettext("absent"))); 404 dialog.printf(gettext("User comment : %S\n"), &(get_command_line())); 405 } 406 detruit()407 void header_version::detruit() 408 { 409 clear_crypted_key(); 410 clear_slice_layout(); 411 } 412 copy_from(const header_version & ref)413 void header_version::copy_from(const header_version & ref) 414 { 415 edition = ref.edition; 416 algo_zip = ref.algo_zip; 417 cmd_line = ref.cmd_line; 418 initial_offset = ref.initial_offset; 419 sym = ref.sym; 420 if(ref.crypted_key != nullptr) 421 { 422 crypted_key = new (get_pool()) memory_file(*ref.crypted_key); 423 if(crypted_key == nullptr) 424 throw Ememory("header_version::copy_from"); 425 } 426 else 427 crypted_key = nullptr; 428 if(ref.ref_layout != nullptr) 429 { 430 ref_layout = new (get_pool()) slice_layout(*ref.ref_layout); 431 if(ref_layout == nullptr) 432 throw Ememory("header_version::copy_from"); 433 } 434 else 435 ref_layout = nullptr; 436 has_tape_marks = ref.has_tape_marks; 437 ciphered = ref.ciphered; 438 arch_signed = ref.arch_signed; 439 } 440 441 442 443 } // end of namespace 444