1 /* dvdisaster: Additional error correction for optical media. 2 * Copyright (C) 2004-2015 Carsten Gnoerlich. 3 * 4 * Email: carsten@dvdisaster.org -or- cgnoerlich@fsfe.org 5 * Project homepage: http://www.dvdisaster.org 6 * 7 * This file is part of dvdisaster. 8 * 9 * dvdisaster is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation, either version 3 of the License, or 12 * (at your option) any later version. 13 * 14 * dvdisaster is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with dvdisaster. If not, see <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "dvdisaster.h" 24 25 #define DSM_VERSION "1.00" 26 #define PSM_VERSION "1.00" 27 28 /*** 29 *** Create an unique marker for missing sectors 30 ***/ 31 32 static void write_missing_sector(unsigned char *out, guint64 sector, 33 unsigned char *fingerprint, guint64 fingerprint_sector, 34 char *volume_label, char *simulation_hint) 35 { char *buf = (char*)out; 36 char *end_marker; 37 int end_length; 38 39 /* Bytefill requested? */ 40 41 if(Closure->fillUnreadable >= 0) 42 { memset(out, Closure->fillUnreadable, 2048); 43 return; 44 } 45 46 /* historic words ... ;-) */ 47 48 memset(buf, 0, 2048); 49 50 g_sprintf(buf, 51 "dvdisaster dead sector marker\n" 52 "This sector could not be read from the image.\n" 53 "Its contents have been substituted by the dvdisaster read routine.\n"); 54 55 end_marker = "dvdisaster dead sector end marker\n"; 56 end_length = strlen(end_marker); 57 memcpy(buf+2046-end_length, end_marker, end_length); 58 59 /* May we use the new marker features? */ 60 61 if(!Closure->dsmVersion) 62 return; 63 64 /* Yes, add the missing sector attributes */ 65 66 g_sprintf(buf+0x100,"Dead sector marker version"); 67 g_sprintf(buf+0x120,"%s",DSM_VERSION); 68 g_sprintf(buf+0x140,"Dead sector number"); 69 g_sprintf(buf+0x160,"%lld", (long long)sector); 70 g_sprintf(buf+0x180,"Medium fingerprint"); 71 if(fingerprint) memcpy(buf+0x1a0, fingerprint, 16); 72 else memcpy(buf+0x1b0, "none", 4); 73 g_sprintf(buf+0x1c0,"Medium fingerprint sector"); 74 g_sprintf(buf+0x1e0,"%lld", (long long)fingerprint_sector); 75 g_sprintf(buf+0x200,"Volume label (if any)"); 76 g_sprintf(buf+0x220,"%s", volume_label ? volume_label : "none"); 77 78 if(simulation_hint) 79 { g_sprintf(buf+0x240,"Simulation hint"); 80 g_sprintf(buf+0x260,"%s", simulation_hint); 81 } 82 } 83 84 void CreateDebuggingSector(unsigned char *out, guint64 sector, 85 unsigned char *fingerprint, guint64 fingerprint_sector, 86 char *volume_label, char *simulation_hint) 87 { write_missing_sector(out, sector, fingerprint, fingerprint_sector, volume_label, simulation_hint); 88 } 89 90 void CreateMissingSector(unsigned char *out, guint64 sector, 91 unsigned char *fingerprint, guint64 fingerprint_sector, 92 char *volume_label) 93 { write_missing_sector(out, sector, fingerprint, fingerprint_sector, volume_label, NULL); 94 } 95 96 /*** 97 *** Create an unique padding sector 98 ***/ 99 100 void CreatePaddingSector(unsigned char *out, guint64 sector, 101 unsigned char *fingerprint, guint64 fingerprint_sector) 102 { char *buf = (char*)out; 103 char *end_marker; 104 int end_length; 105 106 memset(buf, 0, 2048); 107 108 g_sprintf(buf, 109 "dvdisaster padding sector " 110 "This is a padding sector needed for augmenting the image " 111 "with error correction data."); 112 113 end_marker = "dvdisaster padding sector end marker"; 114 end_length = strlen(end_marker); 115 memcpy(buf+2047-end_length, end_marker, end_length); 116 117 g_sprintf(buf+0x100,"Padding sector marker version"); 118 g_sprintf(buf+0x120,"%s",DSM_VERSION); 119 g_sprintf(buf+0x140,"Padding sector number"); 120 g_sprintf(buf+0x160,"%lld", (long long)sector); 121 g_sprintf(buf+0x180,"Medium fingerprint"); 122 if(fingerprint) memcpy(buf+0x1a0, fingerprint, 16); 123 else memcpy(buf+0x1b0, "none", 4); 124 g_sprintf(buf+0x1c0,"Medium fingerprint sector"); 125 g_sprintf(buf+0x1e0,"%lld", (long long)fingerprint_sector); 126 } 127 128 /*** 129 *** Helper functions 130 ***/ 131 132 static int get_recorded_number(unsigned char *buf, guint64 *number) 133 { 134 if(!strcmp((char*)buf+0x140, "Dead sector number")) 135 { *number = strtoll((char*)buf+0x160, NULL, 10); 136 return TRUE; 137 } 138 139 *number = 0; 140 return FALSE; 141 } 142 143 static char *get_volume_label(unsigned char *buf) 144 { 145 if(!strcmp((char*)buf+0x200, "Volume label (if any)")) 146 { if(!strcmp((char*)buf+0x220, "none")) 147 return NULL; 148 else return g_strdup((char*)buf+0x220); 149 } 150 151 return NULL; 152 } 153 154 /* 155 * Used for simulating specific errors 156 */ 157 158 char *GetSimulationHint(unsigned char *buf) 159 { 160 if(!strcmp((char*)buf+0x240, "Simulation hint")) 161 return g_strdup((char*)buf+0x260); 162 163 return NULL; 164 } 165 166 /*** 167 *** Check whether this is a missing sector 168 ***/ 169 170 int CheckForMissingSector(unsigned char *buf, guint64 sector, 171 unsigned char *fingerprint, guint64 fingerprint_sector) 172 { static char pattern[2048]; 173 static char last_pattern = 0; 174 guint64 recorded_number; 175 char *sim_hint; 176 177 /* Bytefill used as missing sector marker? */ 178 179 if(Closure->fillUnreadable >= 0) 180 { if(Closure->fillUnreadable != last_pattern) /* cache the pattern */ 181 memset(pattern, Closure->fillUnreadable, 2048); 182 183 if(memcmp(buf, pattern, 2048)) 184 return SECTOR_PRESENT; 185 else return SECTOR_MISSING; 186 } 187 188 /* See if it is our dead sector marker */ 189 190 if(strncmp((char*)buf, 191 "dvdisaster dead sector marker\n" 192 "This sector could not be read from the image.\n" 193 "Its contents have been substituted by the dvdisaster read routine.\n", 194 143) 195 || strncmp((char*)buf+2046-34, "dvdisaster dead sector end marker\n", 34)) 196 197 return SECTOR_PRESENT; 198 199 /* New style missing sector marker? */ 200 201 if(strcmp((char*)buf+0x100,"Dead sector marker version")) 202 return SECTOR_MISSING; 203 204 /*** Evaluate new style sector marker */ 205 206 /* Look for hints on simulated images */ 207 208 sim_hint = GetSimulationHint(buf); 209 if(sim_hint) 210 { g_free(sim_hint); 211 return SECTOR_WITH_SIMULATION_HINT; 212 } 213 214 /* Verify sector number */ 215 216 if(get_recorded_number(buf, &recorded_number)) 217 if(recorded_number != sector) 218 return SECTOR_MISSING_DISPLACED; 219 220 /* Verify medium fingerprint. If the dead sector was fingerprinted with 221 a different sector, ignore the test. Retrieving the right fingerprint 222 sector is too expensive. */ 223 224 if(fingerprint 225 && !strcmp((char*)buf+0x1c0, "Medium fingerprint sector") 226 && memcmp((char*)buf+0x1b0, "none", 4)) 227 { gint64 fps_recorded = strtoll((char*)buf+0x1e0, NULL, 10); 228 229 if(fps_recorded == fingerprint_sector) 230 { if(!strcmp((char*)buf+0x180, "Medium fingerprint")) 231 if(memcmp((char*)buf+0x1a0, (char*)fingerprint, 16)) 232 return SECTOR_MISSING_WRONG_FP; 233 } 234 } 235 236 return SECTOR_MISSING; 237 } 238 239 int CheckForMissingSectors(unsigned char *buf, guint64 sector, 240 unsigned char *fingerprint, guint64 fingerprint_sector, 241 int n_sectors, guint64 *first_defect) 242 { int i,result; 243 244 for(i=0; i<n_sectors; i++) 245 { result = CheckForMissingSector(buf, sector, fingerprint, fingerprint_sector); 246 247 if(result != SECTOR_PRESENT) 248 { *first_defect = sector; 249 return result; 250 } 251 252 buf += 2048; 253 sector++; 254 } 255 256 return SECTOR_PRESENT; 257 } 258 259 /*** 260 *** Dialogue for indicating problem with the missing sector 261 ***/ 262 263 static void insert_buttons(GtkDialog *dialog) 264 { 265 gtk_dialog_add_buttons(dialog, 266 _utf("Stop reporting these errors"), 1, 267 _utf("Continue reporting"), 0, NULL); 268 } 269 270 void ExplainMissingSector(unsigned char *buf, guint64 sector, int error, int source_type, int *number) 271 { int answer; 272 guint64 recorded_number; 273 char *vol_label, *label_msg; 274 275 if(Closure->noMissingWarnings) 276 return; 277 278 /* Missing sectors should be reported in the following cases: 279 - In an image, normal missing sectors are to be expected. 280 Only displayced sectors and sectors with wrong fingerprint should be reported. 281 - In a medium, all kinds of missing sectors constitute a problem and must be reported. 282 - Within an ecc file, no missing sectors should appear although these are at least 283 harmless for RS03-type ecc files. Report them all. 284 */ 285 286 if(source_type == SOURCE_IMAGE && error != SECTOR_MISSING_DISPLACED && error != SECTOR_MISSING_WRONG_FP) 287 return; 288 289 /* In CLI mode, only report the first unrecoverable sector unless verbose is given. */ 290 291 if(!Closure->guiMode && !Closure->verbose && *number > 0) 292 { if(*number == 1) 293 PrintLog(_("* ... more unrecoverable sectors found ...\n" 294 "* further messages are suppressed unless the -v option is given.\n")); 295 (*number)++; 296 return; 297 } 298 (*number)++; 299 300 /* Get some meta data from the dsm */ 301 302 get_recorded_number(buf, &recorded_number); 303 304 vol_label = get_volume_label(buf); 305 if(vol_label) 306 { if(Closure->guiMode) 307 label_msg = g_strdup_printf(_("\n\nThe label of the original (defective) medium was:\n%s\n\n"), vol_label); 308 else label_msg = g_strdup_printf(_("\n* \n* The label of the original (defective) medium was:\n* \n* %s\n* "), vol_label); 309 g_free(vol_label); 310 } 311 else label_msg = g_strdup("\n"); 312 313 /* Error was found in an image */ 314 315 if(source_type == SOURCE_IMAGE) 316 { switch(error) 317 { case SECTOR_MISSING_DISPLACED: 318 { char *msg = _("Unrecoverable sector found!\n\n" 319 "Sector %lld is marked unreadable and annotated to be\n" 320 "in a different location (%lld).\n\n" 321 "The image was probably mastered from defective content.\n" 322 "For example it might contain one or more files which came\n" 323 "from a damaged medium which was NOT fully recovered.\n" 324 "This means that some files may have been silently corrupted.%s\n" 325 "Since the image was already created defective it can not be\n" 326 "repaired by dvdisaster. Also it will not be possible to create\n" 327 "error correction data for it. Sorry for the bad news.\n"); 328 329 if(!Closure->guiMode) 330 PrintLogWithAsterisks(msg,sector, recorded_number, label_msg); 331 else 332 { answer = ModalDialog(GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE, insert_buttons, msg, 333 sector, recorded_number, label_msg); 334 335 if(answer) Closure->noMissingWarnings = TRUE; 336 } 337 } 338 break; 339 340 case SECTOR_MISSING_WRONG_FP: 341 { char *msg = _("Unrecoverable sector found!\n\n" 342 "Sector %lld is marked unreadable and seems to come\n" 343 "from a different medium.\n\n" 344 "The image was probably mastered from defective content.\n" 345 "For example it might contain one or more files which came\n" 346 "from a damaged medium which was NOT fully recovered.\n" 347 "This means that some files may have been silently corrupted.%s\n" 348 "Since the image was already created defective it can not be\n" 349 "repaired by dvdisaster. Also it will not be possible to create\n" 350 "error correction data for it. Sorry for the bad news.\n"); 351 352 if(!Closure->guiMode) 353 PrintLogWithAsterisks(msg,sector, label_msg); 354 else 355 { answer = ModalDialog(GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE, insert_buttons, msg, 356 sector, label_msg); 357 if(answer) Closure->noMissingWarnings = TRUE; 358 } 359 } 360 break; 361 } 362 } 363 364 /* Error was found while reading a medium */ 365 366 if(source_type == SOURCE_MEDIUM) 367 { char *msg = _("Unrecoverable sector found!\n\n" 368 "Sector %lld is marked unreadable on the medium.\n\n" 369 "The medium was probably mastered from defective content.\n" 370 "For example it might contain one or more files which came\n" 371 "from a damaged medium which was NOT fully recovered.\n" 372 "This means that some files may have been silently corrupted.\n" 373 "Since the medium was already created defective it can not be\n" 374 "repaired by dvdisaster. Also it will not be possible to create\n" 375 "error correction data for it. Sorry for the bad news.\n"); 376 377 if(!Closure->guiMode) 378 PrintLogWithAsterisks(msg, sector); 379 else 380 { answer = ModalDialog(GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE, insert_buttons, msg, 381 sector); 382 383 if(answer) Closure->noMissingWarnings = TRUE; 384 } 385 } 386 387 /* Error was found while reading an ecc file */ 388 389 if(source_type == SOURCE_ECCFILE) 390 { char *msg = _("Unrecoverable sector found!\n\n" 391 "Sector %lld is marked unreadable in the ecc file.\n\n" 392 "The ecc file was probably taken from a medium which\n" 393 "was NOT fully recovered. That means that some sectors\n" 394 "in the ecc file are missing and its error correction\n" 395 "capacity will be reduced.\n"); 396 397 if(!Closure->guiMode) 398 PrintLogWithAsterisks(msg, sector); 399 else 400 { answer = ModalDialog(GTK_MESSAGE_ERROR, GTK_BUTTONS_NONE, insert_buttons, msg, 401 sector); 402 403 if(answer) Closure->noMissingWarnings = TRUE; 404 } 405 } 406 407 g_free(label_msg); 408 } 409