diff options
Diffstat (limited to 'src/recover.c')
-rw-r--r-- | src/recover.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/recover.c b/src/recover.c new file mode 100644 index 0000000..2131542 --- /dev/null +++ b/src/recover.c @@ -0,0 +1,128 @@ +#include "recover.h" + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> /* for usleep - to be removed */ + +// Main algorithm for recover datas +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; + sliceToRead=slicesFindLargest(slicesEvt->data, S_UNKNOWN); + 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=sliceEvtSplit(slicesEvt, sliceToRead, firstError, S_RECOVERED, S_UNREADABLE, S_UNKNOWN); + if (res<1) { + //TODO + printf("sliceEvtSplit 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=sliceEvtSplit(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(6); // TODO + break; + case -1: + // Memory error + exit(5); //TODO + break; + default: + // API error, all necessary cases are already listed + exit(7); // TODO + } + } +} + +// Method tha read source (and clone to dest) until the first read error +int tryRecoverUntilError(slice_t *sliceToRead, address_t *firstError, char *src, char *dst, char*ddOpts) { + //TODO : implement realy that + //TODO : bail out hardly if WRITE error (on dest) + +// char ddinvocation[256]; + int res; + address_t seek, count; + + 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); +//TODO : listener to put that info on the interface 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); + address_t error=sliceToRead->begin + rand()%(count/3); + if ( error % 42 == 0 ) { + res=0; + } else { + res=EIO; + *firstError=error; + } + + // Keep things humanly understandable (to be removed when real reads will be done) + //usleep(10000); + + return res; +} + |