"Fossies" - the Fresh Open Source Software Archive

Member "dvdisaster-0.79.5/rs03-verify.c" (15 Oct 2015, 45201 Bytes) of package /linux/misc/dvdisaster-0.79.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rs03-verify.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.79.3_vs_0.79.5.

    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 #include "rs03-includes.h"
   26 
   27 #define EXIT_CODE_SIZE_MISMATCH 1
   28 #define EXIT_CODE_VERSION_MISMATCH 2
   29 
   30 #define EXIT_CODE_UNEXPECTED_EOF 10
   31 #define EXIT_CODE_MISSING_SECTOR 11
   32 #define EXIT_CODE_CHECKSUM_ERROR 12
   33 #define EXIT_CODE_SYNDROME_ERROR 13
   34 
   35 /***
   36  *** Reset the verify output window
   37  ***/
   38 
   39 void ResetRS03VerifyWindow(Method *self)
   40 {  RS03Widgets *wl = (RS03Widgets*)self->widgetList;
   41 
   42    SetLabelText(GTK_LABEL(wl->cmpImageSectors), "");
   43    SetLabelText(GTK_LABEL(wl->cmpImageMd5Sum), "");
   44    SetLabelText(GTK_LABEL(wl->cmpDataSection), "");
   45    SetLabelText(GTK_LABEL(wl->cmpCrcSection), "");
   46    SetLabelText(GTK_LABEL(wl->cmpEccSection), "");
   47    SetLabelText(GTK_LABEL(wl->cmpImageErasure), "");
   48    SetLabelText(GTK_LABEL(wl->cmpImagePrognosis), "");
   49    SetLabelText(GTK_LABEL(wl->cmpImageErasureCnt), "");
   50    SetLabelText(GTK_LABEL(wl->cmpImagePrognosisMsg), "");
   51    SetLabelText(GTK_LABEL(wl->cmpImageResult), "");
   52    SwitchAndSetFootline(wl->cmpImageNotebook, 1, NULL, NULL);
   53 
   54    SetLabelText(GTK_LABEL(wl->cmpEccCreatedBy), "dvdisaster");
   55    SetLabelText(GTK_LABEL(wl->cmpEccMethod), "");
   56    SetLabelText(GTK_LABEL(wl->cmpEccType), "");
   57    SetLabelText(GTK_LABEL(wl->cmpEccRequires), "");
   58    SetLabelText(GTK_LABEL(wl->cmpEccDataCrc), _("Data checksum:"));
   59    SetLabelText(GTK_LABEL(wl->cmpEccDataCrcVal), "");
   60    SetLabelText(GTK_LABEL(wl->cmpEccFingerprint), _("n/a"));
   61    SetLabelText(GTK_LABEL(wl->cmpEccResult), "");
   62    SetLabelText(GTK_LABEL(wl->cmpEccSynLabel), "");
   63    SetLabelText(GTK_LABEL(wl->cmpEccSyndromes), "");
   64 
   65    wl->lastPercent = 0;
   66 
   67    FillSpiral(wl->cmpSpiral, Closure->background);
   68    DrawSpiral(wl->cmpSpiral);
   69 }
   70 
   71 /***
   72  *** Manage the image spiral
   73  ***/
   74 
   75 /*
   76  * Update part of the spiral
   77  */
   78 
   79 typedef struct _spiral_idle_info
   80 {  Spiral *cmpSpiral;
   81    GdkColor *segColor;
   82    int from, to;
   83 } spiral_idle_info;
   84 
   85 static gboolean spiral_idle_func(gpointer data)
   86 {  spiral_idle_info *sii = (spiral_idle_info*)data;
   87    int i;
   88 
   89    for(i=sii->from; i<=sii->to; i++)
   90      DrawSpiralSegment(sii->cmpSpiral, sii->segColor, i-1);
   91 
   92    g_free(sii);
   93    return FALSE;
   94 }
   95 
   96 static void add_verify_values(Method *method, int percent, 
   97                    gint64 newMissing, gint64 newCrcErrors)
   98 {  RS03Widgets *wl = (RS03Widgets*)method->widgetList;
   99    spiral_idle_info *sii = g_malloc(sizeof(spiral_idle_info));
  100 
  101    if(percent < 0 || percent > VERIFY_IMAGE_SEGMENTS)
  102      return;
  103 
  104    sii->cmpSpiral = wl->cmpSpiral;
  105 
  106    sii->segColor = Closure->greenSector;
  107    if(newCrcErrors) sii->segColor = Closure->yellowSector;
  108    if(newMissing) sii->segColor = Closure->redSector;
  109 
  110    sii->from = wl->lastPercent+1;
  111    sii->to   = percent;
  112 
  113    wl->lastPercent = percent;
  114 
  115    g_idle_add(spiral_idle_func, sii);
  116 }
  117 
  118 /*
  119  * Redraw whole spiral
  120  */
  121 
  122 static void redraw_spiral(RS03Widgets *wl)
  123 {  int x = wl->cmpSpiral->mx - wl->cmpSpiral->diameter/2 + 10;
  124 
  125    DrawSpiralLabel(wl->cmpSpiral, wl->cmpLayout,
  126            _("Good sectors"), Closure->greenSector, x, 1);
  127 
  128    DrawSpiralLabel(wl->cmpSpiral, wl->cmpLayout,
  129            _("Sectors with CRC errors"), Closure->yellowSector, x, 2);
  130 
  131    DrawSpiralLabel(wl->cmpSpiral, wl->cmpLayout,
  132            _("Missing sectors"), Closure->redSector, x, 3);
  133 
  134    DrawSpiral(wl->cmpSpiral);
  135 }
  136 
  137 /*
  138  * expose event handler for the spiral
  139  */
  140 
  141 static gboolean expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data)
  142 {  RS03Widgets *wl = (RS03Widgets*)data;
  143    GtkAllocation *a = &widget->allocation;
  144    int w,h,size;
  145 
  146    /* Finish spiral initialization */
  147 
  148    if(!wl->cmpLayout)
  149    {  SetSpiralWidget(wl->cmpSpiral, widget);
  150       wl->cmpLayout = gtk_widget_create_pango_layout(widget, NULL);
  151    }
  152 
  153    SetText(wl->cmpLayout, _("Missing sectors"), &w, &h);
  154    size = wl->cmpSpiral->diameter + 20 + 3*(10+h);  /* approx. size of spiral + labels */
  155 
  156    wl->cmpSpiral->mx = a->width / 2;
  157    wl->cmpSpiral->my = (wl->cmpSpiral->diameter + a->height - size)/2;
  158 
  159    if(!event->count)      /* Exposure compression */
  160      redraw_spiral(wl);   /* Redraw the spiral */
  161 
  162    return TRUE;
  163 }
  164 
  165 /***
  166  *** Create the notebook contents for the verify output
  167  ***/
  168 
  169 void CreateRS03VerifyWindow(Method *self, GtkWidget *parent)
  170 {  RS03Widgets *wl = (RS03Widgets*)self->widgetList;
  171    GtkWidget *sep,*notebook,*ignore,*table,*table2,*lab,*frame,*d_area;
  172    int y1,y2;
  173 
  174    wl->cmpHeadline = gtk_label_new(NULL);
  175    gtk_misc_set_alignment(GTK_MISC(wl->cmpHeadline), 0.0, 0.0); 
  176    gtk_misc_set_padding(GTK_MISC(wl->cmpHeadline), 5, 0);
  177    gtk_box_pack_start(GTK_BOX(parent), wl->cmpHeadline, FALSE, FALSE, 3);
  178 
  179    sep = gtk_hseparator_new();
  180    gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
  181 
  182    sep = gtk_hseparator_new();
  183    gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
  184 
  185    table = gtk_table_new(2, 2, FALSE);
  186    gtk_container_set_border_width(GTK_CONTAINER(table), 5);
  187    gtk_box_pack_start(GTK_BOX(parent), table, TRUE, TRUE, 0);
  188 
  189 
  190    /*** Ecc data info */
  191 
  192    frame = gtk_frame_new(_utf("Error correction properties"));
  193    gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 5);
  194 
  195    table2 = gtk_table_new(2, 7, FALSE);
  196    ignore = gtk_label_new("ecc info");
  197    gtk_container_set_border_width(GTK_CONTAINER(table2), 5);
  198    gtk_container_add(GTK_CONTAINER(frame), table2);
  199    y1=0; y2=1;
  200 
  201    lab = gtk_label_new(NULL);
  202    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  203    SetLabelText(GTK_LABEL(lab), _("Type:"));
  204    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  205    lab = wl->cmpEccType = gtk_label_new(NULL);
  206    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  207    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  208    y1++; y2++;
  209 
  210    lab = gtk_label_new(NULL);
  211    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  212    SetLabelText(GTK_LABEL(lab), _("Method:"));
  213    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  214    lab = wl->cmpEccMethod = gtk_label_new(NULL);
  215    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  216    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  217    y1++; y2++;
  218 
  219    lab = gtk_label_new(NULL);
  220    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  221    SetLabelText(GTK_LABEL(lab), _("Created by:"));
  222    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  223    lab = wl->cmpEccCreatedBy = gtk_label_new(NULL);
  224    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  225    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  226    y1++; y2++;
  227 
  228    lab = gtk_label_new(NULL);
  229    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  230    SetLabelText(GTK_LABEL(lab), _("Requires:"));
  231    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  232    lab = wl->cmpEccRequires = gtk_label_new(NULL);
  233    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  234    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  235    y1++; y2++;
  236 
  237    lab = wl->cmpEccDataCrc = gtk_label_new(NULL);
  238    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  239    SetLabelText(GTK_LABEL(lab), _("Data checksum:"));
  240    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  241    lab = wl->cmpEccDataCrcVal = gtk_label_new(NULL);
  242    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  243    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  244    y1++; y2++;
  245 
  246    lab = gtk_label_new(NULL);
  247    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  248    SetLabelText(GTK_LABEL(lab), _("Fingerprint:"));
  249    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  250    lab = wl->cmpEccFingerprint = gtk_label_new(NULL);
  251    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  252    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  253    y1++; y2++;
  254 
  255    lab = wl->cmpEccResult = gtk_label_new(NULL);
  256    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0);
  257    gtk_table_attach(GTK_TABLE(table2), lab, 0, 2, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 4);
  258 
  259    /*** Image spiral */
  260 
  261    frame = gtk_frame_new(_utf("Image state"));
  262    gtk_table_attach(GTK_TABLE(table), frame, 1, 2, 0, 2, GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_FILL, 5, 5);
  263 
  264    wl->cmpSpiral = CreateSpiral(Closure->grid, Closure->background, 10, 5, VERIFY_IMAGE_SEGMENTS);
  265    d_area = wl->cmpDrawingArea = gtk_drawing_area_new();
  266    gtk_widget_set_size_request(d_area, wl->cmpSpiral->diameter+20, -1);
  267    gtk_container_add(GTK_CONTAINER(frame), d_area);
  268    g_signal_connect(G_OBJECT(d_area), "expose_event", G_CALLBACK(expose_cb), (gpointer)wl);
  269 
  270    /*** Image info */
  271 
  272    frame = gtk_frame_new(_utf("Data integrity"));
  273    gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 5, 5);
  274 
  275    notebook = wl->cmpImageNotebook = gtk_notebook_new();
  276    gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
  277    gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
  278    gtk_container_add(GTK_CONTAINER(frame), notebook);
  279 
  280    ignore = gtk_label_new("no image");
  281    lab = gtk_label_new(_utf("No image present."));
  282    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), lab, ignore);
  283 
  284    table2 = gtk_table_new(2, 9, FALSE);
  285    ignore = gtk_label_new("image info");
  286    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table2, ignore);
  287    gtk_container_set_border_width(GTK_CONTAINER(table2), 5);
  288    y1=0; y2=1;
  289 
  290    lab = gtk_label_new(NULL);
  291    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  292    SetLabelText(GTK_LABEL(lab), _("Medium sectors:"));
  293    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  294    lab = wl->cmpImageSectors = gtk_label_new("0");
  295    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  296    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  297    y1++; y2++;
  298 
  299    lab = gtk_label_new(NULL);
  300    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  301    SetLabelText(GTK_LABEL(lab), _("Data checksum:"));
  302    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  303    lab = wl->cmpImageMd5Sum = gtk_label_new("0");
  304    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  305    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  306    y1++; y2++;
  307 
  308    lab = gtk_label_new(NULL);
  309    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  310    SetLabelText(GTK_LABEL(lab), _("Data section:"));
  311    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  312    lab = wl->cmpDataSection = gtk_label_new(".");
  313    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  314    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  315    y1++; y2++;
  316 
  317    lab = gtk_label_new(NULL);
  318    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  319    SetLabelText(GTK_LABEL(lab), _("Crc section:"));
  320    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  321    lab = wl->cmpCrcSection = gtk_label_new(".");
  322    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  323    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  324    y1++; y2++;
  325 
  326    lab = gtk_label_new(NULL);
  327    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  328    SetLabelText(GTK_LABEL(lab), _("Ecc section:"));
  329    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  330    lab = wl->cmpEccSection= gtk_label_new(".");
  331    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  332    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  333    y1++; y2++;
  334 
  335    lab = wl->cmpEccSynLabel = gtk_label_new(NULL);
  336    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0);
  337    SetLabelText(GTK_LABEL(lab), _("Ecc block test:")); 
  338    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  339    lab = wl->cmpEccSyndromes = gtk_label_new(NULL);
  340    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  341    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  342    y1++; y2++;
  343 
  344    lab = wl->cmpImageErasure = gtk_label_new(NULL);
  345    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  346    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  347    lab = wl->cmpImageErasureCnt = gtk_label_new(NULL);
  348    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  349    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  350    y1++; y2++;
  351 
  352    lab = wl->cmpImagePrognosis = gtk_label_new(NULL);
  353    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  354    gtk_table_attach(GTK_TABLE(table2), lab, 0, 1, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 2 );
  355    lab = wl->cmpImagePrognosisMsg = gtk_label_new(NULL);
  356    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0); 
  357    gtk_table_attach(GTK_TABLE(table2), lab, 1, 2, y1, y2, GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
  358    y1++; y2++;
  359 
  360    lab = wl->cmpImageResult = gtk_label_new(NULL);
  361    gtk_misc_set_alignment(GTK_MISC(lab), 0.0, 0.0);
  362    gtk_table_attach(GTK_TABLE(table2), lab, 0, 2, y1, y2, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 5, 4);
  363 }
  364 
  365 /***
  366  *** Check the consistency of the augmented image
  367  ***/
  368 
  369 /* 
  370  * housekeeping
  371  */
  372 
  373 typedef struct
  374 {  Image *image;
  375    EccHeader *eh;
  376    RS03Layout *lay;
  377    RS03Widgets *wl;
  378    CrcBuf *crcBuf;
  379    Bitmap *map;
  380    unsigned char crcSum[16];
  381    unsigned char *eccBlock[256];
  382    GaloisTables *gt;
  383    ReedSolomonTables *rt;
  384 } verify_closure;
  385 
  386 static void cleanup(gpointer data)
  387 {  verify_closure *vc = (verify_closure*)data;
  388    int i;
  389 
  390    UnregisterCleanup();
  391 
  392    if(Closure->guiMode)
  393       AllowActions(TRUE);
  394 
  395    if(vc->image) CloseImage(vc->image);
  396    if(vc->lay) 
  397    {  g_free(vc->lay);
  398    }
  399    if(vc->map) FreeBitmap(vc->map);
  400    if(vc->crcBuf) FreeCrcBuf(vc->crcBuf);
  401 
  402    for(i=0; i<255; i++)
  403       if(vc->eccBlock[i])
  404      g_free(vc->eccBlock[i]);
  405 
  406    if(vc->gt) FreeGaloisTables(vc->gt);
  407    if(vc->rt) FreeReedSolomonTables(vc->rt);
  408 
  409    g_free(vc);
  410 
  411    if(Closure->guiMode)
  412      g_thread_exit(0);
  413 }
  414 
  415 /***
  416  *** Prognosis for correctability
  417  ***/
  418 
  419 static int prognosis(verify_closure *vc, gint64 missing, gint64 expected)
  420 {  int j,eccblock;
  421    int worst_ecc = 0;
  422    gint64 damaged_sectors = 0, damaged_eccsecs = 0;
  423    gint64 correctable = 0;
  424    gint64 recoverable;
  425 
  426    for(eccblock=0; eccblock<vc->lay->sectorsPerLayer; eccblock++)
  427    {  int count = 255;
  428 
  429       /* Note: ecc file sectors are virtually mapped to augmented image sectors */
  430 
  431       for(j=0; j<255; j++)
  432       {  gint64 sector = j*vc->lay->sectorsPerLayer+eccblock;
  433 
  434      if(GetBit(vc->map, sector))
  435           count--;
  436      else damaged_sectors++;
  437       }
  438 
  439       if(count>0)                damaged_eccsecs++;
  440       if(count>worst_ecc)        worst_ecc = count; 
  441       if(count<=vc->lay->nroots) correctable += count;
  442    }
  443 
  444    recoverable = expected - missing + correctable;
  445 
  446    if(damaged_sectors > 0)
  447    {  int percentage  = (1000*recoverable) / expected;
  448 
  449       PrintLog(_("- erasure counts   :  avg =  %.1f; worst = %d per ecc block.\n"),
  450           (double)damaged_sectors/(double)damaged_eccsecs,worst_ecc);
  451 
  452       PrintLog(_("- prognosis        : %lld of %lld sectors recoverable (%d.%d%%)\n"),
  453            recoverable, expected, percentage/10, percentage%10);
  454 
  455       if(Closure->guiMode)
  456       {  SetLabelText(GTK_LABEL(vc->wl->cmpImageErasure), _("Erasure counts:"));
  457      SetLabelText(GTK_LABEL(vc->wl->cmpImagePrognosis), _("Prognosis:"));
  458 
  459      SetLabelText(GTK_LABEL(vc->wl->cmpImageErasureCnt),
  460               _("<span %s>avg =  %.1f; worst = %d per ecc block.</span>"),
  461               worst_ecc <= vc->lay->nroots ? Closure->greenMarkup : Closure->redMarkup,
  462               (double)damaged_sectors/(double)damaged_eccsecs,worst_ecc);
  463 
  464      SetLabelText(GTK_LABEL(vc->wl->cmpImagePrognosisMsg),
  465              _("<span %s>%lld of %lld sectors recoverable (%d.%d%%)</span>"),
  466               recoverable < expected ? Closure->redMarkup : Closure->greenMarkup,
  467              recoverable, expected, percentage/10, percentage%10);
  468       }
  469    }          
  470 
  471    if(damaged_sectors && worst_ecc <= vc->lay->nroots && recoverable >= expected)
  472         return TRUE;
  473    else return FALSE;
  474 }
  475 
  476 /***
  477  *** Error syndrome check
  478  ***/
  479 
  480 static int check_syndromes(verify_closure *vc)
  481 {  RS03Layout *lay = vc->lay;
  482    Image *image = vc->image;
  483    gint64 li,ecc_block;
  484    gint64 cache_idx = Closure->prefetchSectors;
  485    gint64 ecc_good, ecc_bad, ecc_bad_sub;
  486    int percent,last_percent = -1;
  487    int bad_counted;
  488    int layer,i,j;
  489 
  490    if(Closure->guiMode)
  491      SetLabelText(GTK_LABEL(vc->wl->cmpHeadline), "<big>%s</big>\n<i>%s</i>",
  492           _("Checking the image and error correction files."),
  493           _("- Checking ecc blocks (deep verify) -"));
  494 
  495    /* Allocate buffers and initialize layer sector addresses */
  496 
  497    for(i=0, li=0; i<GF_FIELDMAX; i++,li+=lay->sectorsPerLayer)
  498    {  
  499       vc->eccBlock[i] = g_try_malloc(2048*Closure->prefetchSectors);
  500       if(!vc->eccBlock[i])  /* out of memory */
  501       {  int j;
  502 
  503      for(j=0; j<i; j++)
  504         g_free(vc->eccBlock[j]);
  505 
  506      if(Closure->guiMode)
  507        SetLabelText(GTK_LABEL(vc->wl->cmpEccSyndromes),
  508             _("<span %s>Out of memory; try reducing sector prefetch!</span>"),
  509             Closure->redMarkup);
  510      PrintLog(_("* Ecc block test   : out of memory; try reducing sector prefetch!\n"));
  511      return 0;
  512       }
  513    }
  514 
  515    /* Init Reed-Solomon tables */
  516 
  517    vc->gt = CreateGaloisTables(RS_GENERATOR_POLY);
  518    vc->rt = CreateReedSolomonTables(vc->gt, RS_FIRST_ROOT, RS_PRIM_ELEM, lay->nroots);
  519 
  520    /* Check the error syndromes */
  521 
  522    ecc_good = ecc_bad = ecc_bad_sub = 0;
  523 
  524    for(ecc_block=0; ecc_block<lay->sectorsPerLayer; ecc_block++)
  525    {  gint64 num_sectors = 0; 
  526       unsigned char data[GF_FIELDMAX];
  527 
  528       /* Check for user interruption */
  529 
  530       if(Closure->stopActions)   
  531       {  if(Closure->stopActions == STOP_CURRENT_ACTION) /* suppress memleak warning when closing window */
  532         SetLabelText(GTK_LABEL(vc->wl->cmpEccSyndromes), 
  533              _("<span %s>Aborted by user request!</span>"),
  534              Closure->redMarkup); 
  535          return 0;
  536       }
  537 
  538       /* Reload cache? */
  539       
  540       if(cache_idx == Closure->prefetchSectors)
  541       {  
  542      cache_idx = 0;
  543      num_sectors = Closure->prefetchSectors;
  544      if(ecc_block+num_sectors >= lay->sectorsPerLayer)
  545         num_sectors = lay->sectorsPerLayer - ecc_block;
  546 
  547      for(layer=0; layer<GF_FIELDMAX; layer++)
  548        if(layer < lay->ndata-1)
  549          RS03ReadSectors(image, vc->lay, vc->eccBlock[layer], 
  550                 layer, ecc_block, num_sectors, RS03_READ_DATA);
  551        else
  552          RS03ReadSectors(image, vc->lay, vc->eccBlock[layer], 
  553                 layer, ecc_block, num_sectors, RS03_READ_CRC | RS03_READ_ECC);
  554       }
  555 
  556       /* Calculate the error syndromes.
  557      Note that we are only called when the image does not contain
  558      dead sector markers; therefore we can skip this test. */
  559 
  560       bad_counted = FALSE;
  561 
  562       for(i=0; i<2048; i++) 
  563       {  int result;
  564 
  565      for(j=0; j<GF_FIELDMAX; j++)
  566        data[j] = vc->eccBlock[j][2048*cache_idx+i];
  567 
  568      result = TestErrorSyndromes(vc->rt, data);
  569 
  570      if(result)
  571      {  ecc_bad_sub++;
  572         if(!bad_counted)
  573         {  bad_counted++;
  574            ecc_bad++;
  575         }
  576      }
  577       }
  578       cache_idx++;
  579 
  580       if(!bad_counted) ecc_good++;
  581 
  582       /* Advance percentage gauge */
  583 
  584       percent = (100*(ecc_block+1))/lay->sectorsPerLayer;
  585       if(percent != last_percent)
  586       {  last_percent = percent;
  587 
  588      if(!ecc_bad)
  589      {  if(Closure->guiMode)
  590           SetLabelText(GTK_LABEL(vc->wl->cmpEccSyndromes),
  591                _("%d%% tested"),
  592                percent);
  593         PrintProgress(_("- Ecc block test   : %d%% tested"), percent);
  594 
  595      }
  596      else
  597      {  if(Closure->guiMode)
  598           SetLabelText(GTK_LABEL(vc->wl->cmpEccSyndromes),
  599                _("<span %s>%lld good, %lld bad; %d%% tested</span>"),
  600                Closure->redMarkup, ecc_good, ecc_bad, percent);
  601         PrintProgress(_("* Ecc block test   : %lld good, %lld bad; %d%% tested")
  602               , ecc_good, ecc_bad, percent);
  603      }
  604       }
  605    }
  606 
  607    /* Tell user about our findings */
  608 
  609    if(!ecc_bad)
  610    {  if(Closure->guiMode)
  611        SetLabelText(GTK_LABEL(vc->wl->cmpEccSyndromes),_("pass"));
  612       ClearProgress();
  613       PrintLog(_("- Ecc block test   : pass\n"));
  614    }
  615    else
  616    {  if(Closure->guiMode)
  617        SetLabelText(GTK_LABEL(vc->wl->cmpEccSyndromes),
  618             _("<span %s>%lld good, %lld bad; %lld bad sub blocks</span>"),
  619             Closure->redMarkup, ecc_good, ecc_bad, ecc_bad_sub);
  620       PrintLog(_("* Ecc block test   : %lld good, %lld bad; %lld bad sub blocks\n"),
  621            ecc_good, ecc_bad, ecc_bad_sub);
  622 
  623       exitCode = EXIT_CODE_SYNDROME_ERROR;
  624    }
  625    return ecc_bad;
  626 }
  627 
  628 /***
  629  *** The verify action
  630  ***/
  631 
  632 void RS03Verify(Image *image)
  633 {  Method *self = FindMethod("RS03");
  634    verify_closure *vc = g_malloc0(sizeof(verify_closure));
  635    RS03Widgets *wl = self->widgetList;
  636    EccHeader *eh = NULL;
  637    RS03Layout *lay;
  638    RS03CksumClosure *csc;
  639    struct MD5Context image_md5;
  640    unsigned char medium_sum[16];
  641    char data_digest[33], hdr_digest[33];
  642    gint64 s, crc_idx;
  643    int last_percent = 0;
  644    unsigned char buf[2048];
  645    gint64 first_missing, last_missing;
  646    gint64 total_missing,data_missing,crc_missing,ecc_missing;
  647    gint64 new_missing = 0, new_crc_errors = 0;
  648    gint64 data_crc_errors;
  649    gint64 virtual_expected;
  650    gint64 expected_image_sectors;
  651    gint64 eccfile_sectors = 0,expected_eccfile_sectors = 0;
  652    int major,minor,pl;
  653    char method[5];
  654    char *img_advice = NULL;
  655    char *ecc_advice = NULL;
  656    char *version;
  657    int syn_error = 0;
  658    int try_it;
  659    int missing_sector_explained = 0;
  660    int matching_byte_size = TRUE;
  661 
  662    /*** Prepare for early termination */
  663 
  664    RegisterCleanup(_("Check aborted"), cleanup, vc);
  665    vc->image = image;
  666    vc->wl = wl;
  667 
  668    if(image->eccFileHeader && !strncmp((char*)(image->eccFileHeader->method), "RS03", 4)) 
  669    {      eh = image->eccFileHeader;
  670    }
  671    else if(image->eccHeader && !strncmp((char*)(image->eccHeader->method), "RS03", 4)) 
  672    {      eh = image->eccHeader;
  673    }
  674    else Stop("Internal error: RS03Verify() called without suitable image and ecc file");
  675    
  676    vc->eh = eh; 
  677 
  678    /*** Announce type of error correction and what we are going to do */
  679 
  680    if(image->file)
  681    {
  682       PrintLog("\n%s present.\n", Closure->imageName);
  683    }
  684    else  /* may only happen when ecc file is present */
  685    {  PrintLog("\n%s not present.\n", Closure->imageName);
  686 
  687       if(Closure->guiMode)
  688     SwitchAndSetFootline(wl->cmpImageNotebook, 0, NULL, NULL);
  689    }
  690 
  691    if(eh->methodFlags[0] & MFLAG_ECC_FILE)
  692    {
  693       if(Closure->guiMode)
  694     SetLabelText(GTK_LABEL(wl->cmpHeadline), "<big>%s</big>\n<i>%s</i>",
  695              _("Checking the image and error correction files."),
  696              _("- Checking image file -"));
  697 
  698       PrintLog(_("%s present.\n"), Closure->eccName);
  699    }
  700    else 
  701    {  
  702      if(Closure->guiMode)
  703        SetLabelText(GTK_LABEL(wl->cmpHeadline), "<big>%s</big>\n<i>%s</i>",
  704             _("Checking the image file."),
  705             _("- Checking image file -"));
  706    }
  707 
  708    /*** Calculate the layout */
  709 
  710    if(eh->methodFlags[0] & MFLAG_ECC_FILE)
  711         lay = vc->lay = CalcRS03Layout(image, ECC_FILE); 
  712    else lay = vc->lay = CalcRS03Layout(image, ECC_IMAGE); 
  713 
  714    /*** Print information on the ecc portion */
  715 
  716    PrintLog(_("\nError correction properties:\n"));
  717 
  718    /* Check size of error correction file */
  719 
  720    if(lay->target == ECC_FILE)
  721    {  eccfile_sectors = image->eccFile->size / 2048;
  722       expected_eccfile_sectors = 2 + (lay->nroots+1)*lay->sectorsPerLayer;
  723 
  724       if(expected_eccfile_sectors != eccfile_sectors)
  725       {  char *msg;
  726 
  727      if(expected_eccfile_sectors > eccfile_sectors)
  728           msg = g_strdup_printf(_("Ecc file is %lld sectors shorter than expected."),
  729                   expected_eccfile_sectors - eccfile_sectors);
  730      else msg = g_strdup_printf(_("Ecc file is %lld sectors longer than expected."), 
  731                     eccfile_sectors - expected_eccfile_sectors);
  732 
  733      if(Closure->guiMode)
  734         ecc_advice = g_strdup_printf("<span %s>%s</span>", Closure->redMarkup, msg);
  735 
  736      PrintLog(_("* Warning          : %s\n"), msg);
  737      g_free(msg);
  738      exitCode = EXIT_CODE_SIZE_MISMATCH;
  739       }
  740    }
  741    
  742    /* Error correction type */
  743 
  744    if(eh->methodFlags[0] & MFLAG_ECC_FILE)
  745         PrintLog(_("- type             : Error correction file\n"));
  746    else PrintLog(_("- type             : Augmented image\n"));
  747 
  748    if(Closure->guiMode)
  749    {  if(eh->methodFlags[0] & MFLAG_ECC_FILE)
  750        SetLabelText(GTK_LABEL(wl->cmpEccType), _("Error correction file"));
  751       else SetLabelText(GTK_LABEL(wl->cmpEccType), _("Augmented image"));
  752    }
  753 
  754    /* Error correction method */
  755 
  756    memcpy(method, eh->method, 4); method[4] = 0;
  757 
  758    PrintLog(_("- method           : %4s, %d roots, %4.1f%% redundancy.\n"),
  759         method, eh->eccBytes, 
  760         ((double)eh->eccBytes*100.0)/(double)eh->dataBytes);
  761 
  762    if(Closure->guiMode)
  763      SetLabelText(GTK_LABEL(wl->cmpEccMethod), _("%4s, %d roots, %4.1f%% redundancy"),
  764           method, eh->eccBytes, 
  765           ((double)eh->eccBytes*100.0)/(double)eh->dataBytes);
  766 
  767    /* Creator version */
  768 
  769    major = eh->creatorVersion/10000; 
  770    minor = (eh->creatorVersion%10000)/100;
  771    pl    = eh->creatorVersion%100;
  772 
  773    if(eh->creatorVersion%100)        
  774    {  char *format, *color_format = NULL;
  775 
  776       if(eh->methodFlags[3] & MFLAG_DEVEL) 
  777       {  format = "%s-%d.%d (devel-%d)";
  778      color_format = "%s-%d.%d <span %s>(devel-%d)</span>";
  779       }
  780       else if(eh->methodFlags[3] & MFLAG_RC) 
  781       {  format = "%s-%d.%d (rc-%d)";
  782      color_format = "%s-%d.%d <span %s>(rc-%d)</span>";
  783       }
  784       else format = "%s-%d.%d (pl%d)";
  785 
  786       PrintLog(format, _("- created by       : dvdisaster"), major, minor, pl);
  787       PrintLog("\n");
  788 
  789       if(!color_format) color_format = format;
  790       if(Closure->guiMode)
  791       {  if(!color_format)
  792           SetLabelText(GTK_LABEL(wl->cmpEccCreatedBy), color_format, 
  793                "dvdisaster", major, minor, Closure->redMarkup, pl);
  794      else SetLabelText(GTK_LABEL(wl->cmpEccCreatedBy), format, 
  795                "dvdisaster", major, minor, pl);
  796       }
  797    }
  798    else
  799    {  PrintLog(_("- created by       : dvdisaster-%d.%d\n"), 
  800            major, minor);
  801 
  802       if(Closure->guiMode)
  803     SetLabelText(GTK_LABEL(wl->cmpEccCreatedBy), "dvdisaster-%d.%d", major, minor);
  804    }
  805 
  806    /* Required dvdisaster version */
  807 
  808    if(eh->neededVersion%100)        
  809         version = g_strdup_printf("%d.%d (pl%d)",
  810                   eh->neededVersion/10000,
  811                   (eh->neededVersion%10000)/100,
  812                   eh->neededVersion%100);
  813    else version = g_strdup_printf("%d.%d",
  814                   eh->neededVersion/10000,
  815                   (eh->neededVersion%10000)/100);
  816 
  817    if(Closure->version >= eh->neededVersion)
  818    {  PrintLog(_("- requires         : dvdisaster-%s\n"), version);
  819 
  820       if(Closure->guiMode)
  821     SetLabelText(GTK_LABEL(wl->cmpEccRequires), "dvdisaster-%s", version);
  822    }
  823    else 
  824    {  PrintLog(_("* requires         : dvdisaster-%s (BAD)\n"
  825          "* Warning          : The following output might be incorrect.\n"
  826          "*                  : Please visit http://www.dvdisaster.org for an upgrade.\n"),
  827            version);
  828 
  829      if(Closure->guiMode)
  830      {  SetLabelText(GTK_LABEL(wl->cmpEccRequires), 
  831              "<span %s>dvdisaster-%s</span>",
  832              Closure->redMarkup, version);
  833         if(!ecc_advice) 
  834        ecc_advice = g_strdup_printf(_("<span %s>Please upgrade your version of dvdisaster!</span>"), Closure->redMarkup);
  835      }
  836 
  837      exitCode = EXIT_CODE_VERSION_MISMATCH;
  838    }
  839 
  840    g_free(version);
  841 
  842    /* image md5sum as stored in the ecc header */
  843 
  844    if(eh->methodFlags[0] & MFLAG_DATA_MD5)
  845         AsciiDigest(hdr_digest, eh->mediumSum);
  846    else strcpy(hdr_digest, _("none available"));
  847 
  848    PrintLog(_("- data md5sum      : %s\n"),hdr_digest);
  849 
  850    if(Closure->guiMode)
  851      SetLabelText(GTK_LABEL(wl->cmpEccDataCrcVal), "%s", hdr_digest);
  852 
  853    /* compare images in ecc file case */
  854 
  855    if(eh->methodFlags[0] & MFLAG_ECC_FILE)
  856    {  if(image && image->file)
  857       {  if(image->fpState != FP_PRESENT)
  858          {  PrintLog(_("* fingerprint match: NOT POSSIBLE - related sector is missing in image!\n"));
  859 
  860         if(Closure->guiMode)
  861           SetLabelText(GTK_LABEL(wl->cmpEccFingerprint), _("<span %s>missing sector prevents calculation</span>"), Closure->redMarkup);
  862     }
  863     else
  864     { 
  865        if(memcmp(image->imageFP, eh->mediumFP, 16)) 
  866        {  PrintLog(_("* fingerprint match: MISMATCH - .iso and .ecc don't belong together!\n"));
  867 
  868           if(Closure->guiMode)
  869           {  SetLabelText(GTK_LABEL(wl->cmpEccFingerprint), 
  870                   _("<span %s>mismatch</span>"), Closure->redMarkup);
  871 
  872         if(!ecc_advice)
  873           ecc_advice = g_strdup_printf(_("<span %s>Image and error correction files do not belong together!</span>"), Closure->redMarkup);
  874           }
  875        }
  876        else 
  877        {  PrintLog(_("- fingerprint match: good\n"));
  878           if(Closure->guiMode)
  879         SetLabelText(GTK_LABEL(wl->cmpEccFingerprint), _("good"));
  880        }
  881     }
  882       }
  883    }
  884    
  885    /* print advice collected from above tests */
  886 
  887    if(Closure->guiMode)
  888    {  if(ecc_advice) 
  889       {  SetLabelText(GTK_LABEL(wl->cmpEccResult), ecc_advice);
  890          g_free(ecc_advice);
  891       }
  892       else SetLabelText(GTK_LABEL(wl->cmpEccResult),
  893             _("<span %s>Good error correction data.</span>"),
  894             Closure->greenMarkup);
  895    }
  896 
  897    if(!image->file)  /* Ecc file but no image */
  898       goto terminate;
  899 
  900    /*** Print information on image size */
  901 
  902    PrintLog(_("\nData integrity:\n"));
  903 
  904    /* Provide enough bitmap space for all layers */
  905 
  906    vc->map = CreateBitmap0(GF_FIELDMAX*lay->sectorsPerLayer);
  907 
  908    /* Expected and real sectors */
  909 
  910    if(lay->target == ECC_FILE)
  911    {  //expected_sectors = lay->dataSectors + lay->totalSectors;  /* image + ecc file */
  912       virtual_expected = GF_FIELDMAX*lay->sectorsPerLayer;      /* for prognosis map */
  913       expected_image_sectors = lay->dataSectors;                /* just the expected image size */
  914       if(eh->inLast != image->inLast)
  915      matching_byte_size = FALSE;
  916    }
  917    else 
  918    {  virtual_expected = expected_image_sectors = lay->totalSectors;
  919       SetBit(vc->map, lay->eccHeaderPos);
  920       SetBit(vc->map, lay->eccHeaderPos+1);
  921    }
  922 
  923    /* Image size and expected size in ecc file match */
  924    
  925    if(expected_image_sectors == image->sectorSize && matching_byte_size)
  926    {  if(lay->target == ECC_FILE)
  927       {  if(Closure->guiMode)
  928      {  if(image->inLast == 2048)
  929           SetLabelText(GTK_LABEL(wl->cmpImageSectors), _("%lld in image; %lld in ecc file"), 
  930                image->sectorSize, eccfile_sectors);
  931         else
  932           SetLabelText(GTK_LABEL(wl->cmpImageSectors), _("%lld sectors + %d bytes in image; %lld in ecc file"), 
  933                image->sectorSize-1, image->inLast, eccfile_sectors);
  934      }
  935 
  936      if(image->inLast == 2048)
  937           PrintLog(_("- sectors          : %lld in image; "), image->sectorSize);
  938      else PrintLog(_("- sectors          : %lld sectors + %d bytes in image; "), image->sectorSize-1, image->inLast);
  939 
  940      PrintLog(_("%lld in ecc file\n"), eccfile_sectors);
  941       }
  942       else 
  943       {  if(Closure->guiMode)
  944        SetLabelText(GTK_LABEL(wl->cmpImageSectors), _("%lld total / %lld data"), 
  945             image->sectorSize, lay->dataSectors);
  946      PrintLog(_("- medium sectors   : %lld total / %lld data\n"),
  947           image->sectorSize, lay->dataSectors);
  948       }
  949    }
  950    else  /* Mismatch between image size and expected size in ecc file */
  951    {  char *image_size, *expected_size;
  952 
  953       if(image->inLast == 2048)
  954     image_size = g_strdup_printf("%lld", (long long int)image->sectorSize);
  955       else image_size = g_strdup_printf("%lld sectors + %d bytes", (long long int)image->sectorSize-1, image->inLast);
  956 
  957       if(eh->inLast == 2048)
  958            expected_size = g_strdup_printf("%lld", (long long int)expected_image_sectors);
  959       else expected_size = g_strdup_printf("%lld sectors + %d bytes", (long long int)expected_image_sectors-1, eh->inLast);
  960 
  961       if(Closure->guiMode)
  962       {  SetLabelText(GTK_LABEL(wl->cmpImageSectors), _("<span %s>%s (%s expected)</span>"), 
  963               Closure->redMarkup, image_size, expected_size);
  964 
  965      if(image->sectorSize == expected_image_sectors)
  966      {  if(image->inLast < eh->inLast)
  967              img_advice = g_strdup_printf(_("<span %s>Image file is %d bytes shorter than expected.</span>"),
  968                           Closure->redMarkup, eh->inLast-image->inLast);
  969         else img_advice = g_strdup_printf(_("<span %s>Image file is %d bytes longer than expected.</span>"),
  970                           Closure->redMarkup, image->inLast-eh->inLast);
  971      }
  972 
  973      if(expected_image_sectors > image->sectorSize)
  974         img_advice = g_strdup_printf(_("<span %s>Image file is %lld sectors shorter than expected.</span>"),
  975                      Closure->redMarkup, expected_image_sectors - image->sectorSize);
  976      if(expected_image_sectors < image->sectorSize)
  977         img_advice = g_strdup_printf(_("<span %s>Image file is %lld sectors longer than expected.</span>"),
  978                      Closure->redMarkup, image->sectorSize - expected_image_sectors);
  979       }
  980 
  981       if(lay->target == ECC_FILE)
  982     PrintLog(_("* sectors          : %s (%s expected); %lld sectors in ecc file\n"),
  983          image_size, expected_size, eccfile_sectors);
  984       else
  985     PrintLog(_("* medium sectors   : %s (%s expected)\n"),
  986          image_size, expected_size);
  987       g_free(image_size);
  988       g_free(expected_size);
  989    }
  990    
  991    if(Closure->quickVerify)
  992    {  PrintLog(_("* quick mode        : image NOT scanned\n"));
  993       goto terminate;
  994    }
  995 
  996    /*** Read the CRC portion */ 
  997 
  998    vc->crcBuf = self->getCrcBuf(vc->image);
  999    csc = (RS03CksumClosure*)self->ckSumClosure;
 1000 
 1001    /*** Check the data portion of the image file for the
 1002     "dead sector marker" and CRC errors */
 1003    
 1004    if(!LargeSeek(image->file, 0))
 1005      Stop(_("Failed seeking to start of image: %s\n"), strerror(errno));
 1006 
 1007    if(lay->target == ECC_FILE)
 1008      if(!LargeSeek(image->eccFile, 4096))  /* skip the header */
 1009        Stop(_("Failed seeking to start of ecc file: %s\n"), strerror(errno));
 1010 
 1011    MD5Init(&image_md5);
 1012 
 1013    first_missing = last_missing = -1;
 1014    total_missing = data_missing = crc_missing = ecc_missing = 0;
 1015    data_crc_errors = 0;
 1016    crc_idx = 0;
 1017 
 1018    for(s=0; s<virtual_expected; s++)
 1019    {  int percent,current_missing;
 1020       int defective = 0;
 1021 
 1022       /* Check for user interruption */
 1023 
 1024       if(Closure->stopActions)   
 1025       {  if(Closure->stopActions == STOP_CURRENT_ACTION) /* suppress memleak warning when closing window */
 1026         SetLabelText(GTK_LABEL(wl->cmpImageResult), 
 1027              _("<span %s>Aborted by user request!</span>"),
 1028              Closure->redMarkup); 
 1029          goto terminate;
 1030       }
 1031 
 1032       /* Read the next sector */
 1033 
 1034       RS03ReadSectors(image, vc->lay, buf,
 1035               s/vc->lay->sectorsPerLayer,
 1036               s%vc->lay->sectorsPerLayer,
 1037               1,
 1038               RS03_READ_DATA|RS03_READ_CRC|RS03_READ_ECC);
 1039 
 1040       /* update the MD5 sum */
 1041 
 1042       if(s < lay->dataSectors)
 1043       {  if(s < lay->dataSectors - 1)
 1044           MD5Update(&image_md5, buf, 2048);
 1045      else MD5Update(&image_md5, buf, eh->inLast);
 1046       }
 1047 
 1048       /* Look for the dead sector marker */
 1049 
 1050       current_missing = CheckForMissingSector(buf, s, eh->mediumFP, eh->fpSector);
 1051 
 1052       /* Truncated images and ecc files may create "legal" dead sectors. */
 1053 
 1054       if(current_missing != SECTOR_PRESENT)
 1055       {  int dead_sector_from_truncation = 0;
 1056      guint64 real_sector = s;
 1057     
 1058      if(lay->target == ECC_FILE)
 1059      {   if(s>=lay->dataSectors)
 1060          {  real_sector = s - (lay->ndata-1)*lay->sectorsPerLayer + 2;
 1061             if(real_sector*2048 >= image->eccFile->size)
 1062           dead_sector_from_truncation = 1;
 1063          }
 1064      }
 1065 
 1066      if(!dead_sector_from_truncation)
 1067      {  int source_type = SOURCE_IMAGE;
 1068 
 1069         if(lay->target == ECC_FILE && s>=lay->dataSectors)
 1070           source_type = SOURCE_ECCFILE;
 1071      
 1072         ExplainMissingSector(buf, real_sector, current_missing, source_type, &missing_sector_explained);
 1073      }
 1074       }
 1075 
 1076       if(current_missing)
 1077       {  
 1078      if(first_missing < 0) first_missing = s;
 1079          last_missing = s;
 1080      total_missing++;
 1081      new_missing++;
 1082 
 1083      if(lay->target == ECC_IMAGE)
 1084      {  if(s < lay->firstCrcPos) data_missing++;
 1085         else if(s >= lay->firstCrcPos && s < lay->firstEccPos) crc_missing++;
 1086         else ecc_missing++;
 1087      }
 1088      else  /* ecc file case */
 1089      {  if(s < lay->dataSectors) data_missing++;
 1090         else if(s < lay->ndata*lay->sectorsPerLayer) crc_missing++;
 1091         else ecc_missing++;
 1092      }
 1093      defective = TRUE;
 1094      exitCode = EXIT_CODE_MISSING_SECTOR;
 1095       }
 1096 
 1097       /* Report dead sectors. Combine subsequent missing sectors into one report. */
 1098 
 1099       if(!current_missing || s==virtual_expected-1)
 1100       {  if(first_missing>=0)
 1101     {   gint64 first, last;
 1102         char *ecc_msg;
 1103     
 1104         if(lay->target == ECC_FILE && last_missing >= (lay->ndata-1)*lay->sectorsPerLayer)
 1105         {    first = first_missing - (lay->ndata-1)*lay->sectorsPerLayer + 2;
 1106              last = last_missing - (lay->ndata-1)*lay->sectorsPerLayer + 2;
 1107              ecc_msg = g_strdup(_(" (in ecc file)"));
 1108         }
 1109         else 
 1110         {    first = first_missing;
 1111              last = last_missing;
 1112          ecc_msg = g_strdup(" ");
 1113         }
 1114         if(first_missing == last_missing)
 1115              PrintCLI(_("* missing sector   : %lld%s\n"), first,ecc_msg);
 1116         else PrintCLI(_("* missing sectors  : %lld - %lld%s\n"), first, last, ecc_msg);
 1117         first_missing = -1;
 1118         g_free(ecc_msg);
 1119      }
 1120       }
 1121 
 1122       /* If the image sector is from the data portion and it was readable, 
 1123      test its CRC sum */
 1124 
 1125       if(   !current_missing
 1126      && (   (lay->target == ECC_IMAGE && s < lay->firstCrcPos)
 1127          || (lay->target == ECC_FILE && s < lay->dataSectors)))
 1128       {  guint32 crc = Crc32(buf, 2048);
 1129 
 1130      if(GetBit(vc->crcBuf->valid,crc_idx)
 1131         && crc != vc->crcBuf->crcbuf[crc_idx])
 1132      {  PrintCLI(_("* CRC error, sector: %lld\n"), s);
 1133         data_crc_errors++;
 1134         new_crc_errors++;
 1135         defective = TRUE;
 1136         exitCode = EXIT_CODE_CHECKSUM_ERROR;
 1137      }
 1138       }
 1139       crc_idx++;
 1140 
 1141       if(!defective)
 1142     SetBit(vc->map, s);
 1143 
 1144       if(Closure->guiMode) 
 1145       {   /* data part / spiral animation */
 1146       percent = (VERIFY_IMAGE_SEGMENTS*(s+1))/virtual_expected;
 1147 
 1148       /* percentage is reset / output differently for ecc file part */
 1149       if(lay->target == ECC_FILE && s >= lay->dataSectors) 
 1150         percent = (100*(s+1-lay->dataSectors)/(virtual_expected-lay->dataSectors));
 1151       }  
 1152       else  percent = (100*(s+1))/virtual_expected;
 1153 
 1154       if(last_percent != percent) /* Update sector results */
 1155       {  PrintProgress(_("- testing sectors  : %3d%%") ,percent);
 1156      if(Closure->guiMode)
 1157      {  if(lay->target == ECC_IMAGE)
 1158         {  add_verify_values(self, percent, new_missing, new_crc_errors); 
 1159         }
 1160         else /* do not include ecc file sectors in the spiral! */
 1161         {  if(s<lay->dataSectors)
 1162            {  int image_percent = (VERIFY_IMAGE_SEGMENTS*(s+1))/lay->dataSectors;
 1163               
 1164               add_verify_values(self, image_percent, new_missing, new_crc_errors); 
 1165            }
 1166            else
 1167            {  SetLabelText(GTK_LABEL(wl->cmpEccSyndromes),"%d%% tested",percent);
 1168            }
 1169         }
 1170 
 1171         if(data_missing || data_crc_errors)
 1172           SetLabelText(GTK_LABEL(wl->cmpDataSection), 
 1173                _("<span %s>%lld sectors missing; %lld CRC errors</span>"),
 1174                Closure->redMarkup, data_missing, data_crc_errors);
 1175         if(crc_missing || csc->signatureErrors)
 1176           SetLabelText(GTK_LABEL(wl->cmpCrcSection), 
 1177                _("<span %s>%lld sectors missing; %lld signature errors</span>"),
 1178                Closure->redMarkup, crc_missing, csc->signatureErrors);
 1179         if(ecc_missing)
 1180           SetLabelText(GTK_LABEL(wl->cmpEccSection), 
 1181                _("<span %s>%lld sectors missing</span>"),
 1182                Closure->redMarkup, ecc_missing);
 1183      }
 1184      last_percent = percent;
 1185      new_missing = new_crc_errors = 0;
 1186       }
 1187       
 1188       /* If we have processed the image and are about to switch over
 1189      to the ecc file, do some bookkeeping. */
 1190 
 1191       if(lay->target == ECC_FILE && s == lay->dataSectors-1)
 1192       {  
 1193     if(Closure->guiMode)
 1194     {  /* flush/complete spiral */
 1195        add_verify_values(self, VERIFY_IMAGE_SEGMENTS, new_missing, new_crc_errors); 
 1196 
 1197        SetLabelText(GTK_LABEL(wl->cmpHeadline), "<big>%s</big>\n<i>%s</i>",
 1198             _("Checking the image and error correction files."),
 1199             _("- Checking ecc file -"));
 1200 
 1201        SetLabelText(GTK_LABEL(wl->cmpEccSynLabel), _("Error correction file:"));
 1202        last_percent = 0; /* restart counting for ecc file */
 1203     }
 1204       }
 1205    }
 1206 
 1207    /* Complete damage summary */
 1208 
 1209    if(Closure->guiMode)
 1210    {  if(data_missing || data_crc_errors)
 1211         SetLabelText(GTK_LABEL(wl->cmpDataSection), 
 1212              _("<span %s>%lld sectors missing; %lld CRC errors</span>"),
 1213              Closure->redMarkup, data_missing, data_crc_errors);
 1214       if(crc_missing || csc->signatureErrors)
 1215         SetLabelText(GTK_LABEL(wl->cmpCrcSection), 
 1216              _("<span %s>%lld sectors missing; %lld signature errors</span>"),
 1217              Closure->redMarkup, crc_missing, csc->signatureErrors);
 1218       if(ecc_missing)
 1219     SetLabelText(GTK_LABEL(wl->cmpEccSection), 
 1220              _("<span %s>%lld sectors missing</span>"),
 1221              Closure->redMarkup, ecc_missing);
 1222    }
 1223 
 1224    /* The image md5sum is only useful if all blocks have been successfully read. */
 1225 
 1226    MD5Final(medium_sum, &image_md5);
 1227    AsciiDigest(data_digest, medium_sum);
 1228 
 1229    /* Do a resume of our findings */ 
 1230 
 1231    if(!total_missing && !data_crc_errors && !csc->signatureErrors)
 1232       PrintLog(_("- good image/file  : all sectors present\n"
 1233          "- data md5sum      : %s\n"),data_digest);
 1234    else
 1235    {  if(!data_crc_errors && !csc->signatureErrors)
 1236          PrintLog(_("* BAD image/file   : %lld sectors missing\n"), total_missing);
 1237       if(!total_missing)
 1238      PrintLog(_("* suspicious image : all sectors present, but %lld CRC errors\n"), 
 1239           data_crc_errors);
 1240       if(total_missing && data_crc_errors)
 1241      PrintLog(_("* BAD image        : %lld sectors missing, %lld CRC errors\n"), 
 1242           total_missing, data_crc_errors);
 1243 
 1244       PrintLog(_("  ... data section   : %lld sectors missing; %lld CRC errors\n"), 
 1245            data_missing, data_crc_errors);
 1246       if(!total_missing && !data_crc_errors && !csc->signatureErrors)
 1247     PrintLog(_("  ... data md5sum    : %s\n"), data_digest); 
 1248 
 1249       if(csc->signatureErrors)
 1250      PrintLog(_("  ... crc section    : %lld sectors missing; %lld signature errors\n"), 
 1251           crc_missing, csc->signatureErrors);
 1252       else
 1253      PrintLog(_("  ... crc section    : %lld sectors missing\n"), crc_missing);
 1254 
 1255       PrintLog(_("  ... ecc section    : %lld sectors missing\n"), ecc_missing);
 1256    }
 1257 
 1258    if(Closure->guiMode)
 1259    {  if(!data_missing && !data_crc_errors) 
 1260                         SetLabelText(GTK_LABEL(wl->cmpDataSection), _("complete"));
 1261       if(!crc_missing && !csc->signatureErrors)  
 1262                     SetLabelText(GTK_LABEL(wl->cmpCrcSection), _("complete"));
 1263       if(!ecc_missing)  SetLabelText(GTK_LABEL(wl->cmpEccSection), _("complete"));
 1264      
 1265       SetLabelText(GTK_LABEL(wl->cmpImageMd5Sum), "%s", data_missing ? "-" : data_digest);
 1266    }
 1267 
 1268    /*** Test error syndromes */
 1269 
 1270    if(Closure->guiMode)
 1271    {  SetLabelText(GTK_LABEL(wl->cmpEccSynLabel), _("Ecc block test:"));
 1272       SetLabelText(GTK_LABEL(wl->cmpEccSyndromes), "");
 1273    }
 1274    if(0&&total_missing + data_crc_errors != 0)
 1275    { if(Closure->guiMode) 
 1276         SetLabelText(GTK_LABEL(wl->cmpEccSyndromes),
 1277              _("<span %s>Skipped; not useful on known defective image</span>"),
 1278              Closure->redMarkup);
 1279 
 1280      PrintLog(_("* Ecc block test   : skipped; not useful on defective image\n"));
 1281    }
 1282    else syn_error = check_syndromes(vc);
 1283 
 1284    /*** Print image advice */
 1285 
 1286    if(Closure->guiMode)
 1287    {
 1288       if(img_advice) 
 1289       {  SetLabelText(GTK_LABEL(wl->cmpImageResult), img_advice);
 1290          g_free(img_advice);
 1291       }
 1292       else 
 1293       {  if(!total_missing && !data_crc_errors && !syn_error)
 1294         SetLabelText(GTK_LABEL(wl->cmpImageErasure),  /* avoid two blank lines */
 1295              _("<span %s>Good image.</span>"),
 1296              Closure->greenMarkup);
 1297      else
 1298            SetLabelText(GTK_LABEL(wl->cmpImageResult),
 1299             _("<span %s>Damaged image.</span>"),
 1300             Closure->redMarkup);
 1301       }
 1302    }
 1303 
 1304    /*** Print final results */
 1305 
 1306    try_it = prognosis(vc, total_missing+data_crc_errors, lay->totalSectors); 
 1307 
 1308    if(Closure->guiMode)
 1309    {  if(total_missing || data_crc_errors)
 1310       {  if(try_it) SetLabelText(GTK_LABEL(wl->cmpImageResult),
 1311                  _("<span %s>Full data recovery is likely.</span>"),
 1312                  Closure->greenMarkup);
 1313          else       SetLabelText(GTK_LABEL(wl->cmpImageResult),
 1314                  _("<span %s>Full data recovery is NOT possible.</span>"),
 1315                  Closure->redMarkup);
 1316       }
 1317    }
 1318 
 1319    /*** Close and clean up */
 1320 
 1321 terminate:
 1322    cleanup((gpointer)vc);
 1323 }