1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#include <errno.h>
#include <stdio.h>
#include "recover.h"
extern unsigned long c;
slices_t *recover(char *src, char *dst, char *ddOpts, address_t beginSector, address_t endSector/*, int depth*/) {
slices_t *slices;
slice_t *sliceToRead;
address_t firstError=0, median, foundMax=0;
int res;
// Initialization : we want to try to recover the beginning of the whole zone
slices=slicesNew();
sliceToRead=sliceNew(beginSector, endSector, S_UNKNOWN, NULL);
if (sliceToRead==NULL) {
exit(1);//TODO
}
slicesAppend(slices, sliceToRead);
// Main loop
while (!end) { // && slices->count < (endSector-beginSector)/depth) {
// 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=sliceSplit(slices, 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(slices, &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=sliceSplit(slices, 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
}
}
return slices;
}
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
int error=sliceToRead->begin + rand()%count;
if ( error % 42 == 0 ) {
res=0;
} else {
res=EIO;
*firstError=error;
}
*/
return res;
}
|