summaryrefslogtreecommitdiff
path: root/src/recover.c
blob: 21315424ed6881a42af32fdf54929c03a46dd16b (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
#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;
}