#include #include #include "recover.h" extern unsigned long c; void recover(slices_evt_t *slicesEvt, char *src, char *dst, char *ddOpts) { slice_t *sliceToRead; address_t firstError=0, median, foundMax=0; int res; sliceToRead=slicesEvt->data->first; while (!end) { // try to recover sliceToRead and split it if read error switch ( tryRecoverUntilError(sliceToRead, &firstError, src, dst, ddOpts) ) { case 0: // slice recovery has been executed without read error sliceToRead->status=S_RECOVERED; break; case EIO: // slice recovery has encountered a readerror res=sliceSplitEvt(slicesEvt, sliceToRead, firstError, S_RECOVERED, S_UNREADABLE, S_UNKNOWN); if (res<1) { //TODO printf("sliceSplit return %d\n", res); exit(5); } break; default: exit(2); //TODO } /* Now, search the largest S_UNKNOWN zone split it in two parts */ //sliceToRead=slicesFindLargest(slices, S_UNKNOWN); sliceToRead=slicesFindLargestFast(slicesEvt->data, &foundMax, S_UNKNOWN, foundMax, sliceToRead->next); if ( sliceToRead == NULL ) { // There is nothing more to recover, bailout end=1; continue; } median=(sliceToRead->begin+sliceToRead->end)/2; res=sliceSplitEvt(slicesEvt, sliceToRead, median, S_UNKNOWN, S_UNKNOWN, S_UNKNOWN); switch (res) { case 1: // No split, try analyse this zone // Should be a slice of length 1 break; case 2: /* After splitting an S_UNKNOWN zone in two parts take the second for further analysis. We already now that this first one is just preceded by a read error, and errors are frequently grouped in zones, so trying to read a sector just after a faulty sector is most likely a waste of time. */ sliceToRead=sliceToRead->next; break; case 3: // Internal error of sliceSlpit because this set of parameters prevent split by 3 exit(5); // TODO break; case -1: // Memory error exit(4); //TODO break; default: // API error, all necessary cases are already listed exit(6); // TODO } } } int tryRecoverUntilError(slice_t *sliceToRead, address_t *firstError, char *src, char *dst, char*ddOpts) { //TODO : implement realy that char ddinvocation[256]; int res; address_t seek, count; c++; //XXX This is a debug counter seek=sliceToRead->begin; count=sliceToRead->end - seek + 1; res=snprintf(ddinvocation, 255, "dd %s %s %s seek=%lld skip=%lld count=%lld", src, dst, ddOpts, seek, seek, count); puts(ddinvocation); /* // Simulate that we have systematically a read error at first sector *firstError=sliceToRead->begin; res=EIO; */ /* // Simulate that we have systematically a read error at last sector *firstError=sliceToRead->end; res=EIO; */ /* // Simulate that we have systematically a read error at first sector // Simulate for each read, tha we have an error just in the middle if read for mor than one sector if ( sliceToRead->begin == sliceToRead->end ) { res=0; } else { *firstError=(sliceToRead->begin + sliceToRead->end)/2; res=EIO; } */ // Simulate for each read a pseudo random error position and generate some cases of full read without error address_t error=sliceToRead->begin + rand()%count; if ( error % 42 == 0 ) { res=0; } else { res=EIO; *firstError=error; } return res; }