summaryrefslogtreecommitdiff
path: root/src/recover.c
blob: 5e9e187903e1b2d91bad7d2d6678de354e60ff94 (plain)
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;
}