1 /*
2
3 File: godmode.c
4
5 Copyright (C) 1998-2008 Christophe GRENIER <grenier@cgsecurity.org>
6
7 This software is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write the Free Software Foundation, Inc., 51
19 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30 #include <assert.h>
31 #include "types.h"
32 #include "common.h"
33 #include "fnctdsk.h"
34 #include "analyse.h"
35 #include "lang.h"
36 #include "godmode.h"
37 #include "intrface.h"
38 #include "ext2.h"
39 #include "intrf.h"
40 #include "intrfn.h"
41 #include "md.h"
42 #include "ntfs.h"
43 #include "next.h"
44 #include "tpartwr.h"
45 #include "log.h"
46 #include "log_part.h"
47 #include "fat32.h"
48 #include "tntfs.h"
49 #include "thfs.h"
50 #include "partgpt.h"
51 #include "partmacn.h"
52
53 #define RO 1
54 #define RW 0
55 #define MAX_SEARCH_LOCATION 1024
56 extern const arch_fnct_t arch_gpt;
57 extern const arch_fnct_t arch_humax;
58 extern const arch_fnct_t arch_i386;
59 extern const arch_fnct_t arch_mac;
60 extern const arch_fnct_t arch_none;
61 extern const arch_fnct_t arch_sun;
62 extern const arch_fnct_t arch_xbox;
63 static int use_backup(disk_t *disk_car, const list_part_t *list_part, const int verbose,const int dump_ind, const unsigned int expert, char**current_cmd);
64 static int interface_part_bad_log(disk_t *disk_car,list_part_t *list_part_bad);
65 #ifdef HAVE_NCURSES
66 static int interface_part_bad_ncurses(disk_t *disk_car, list_part_t *list_part_bad);
67 static void ask_mbr_order_i386(disk_t *disk_car,list_part_t *list_part);
68 #define ANALYSE_X 0
69 #define ANALYSE_Y 5
70 #define INTER_BAD_PART 10
71 #endif
72 static list_part_t *add_ext_part_i386(disk_t *disk_car, list_part_t *list_part, const int max_ext, const int verbose);
73 static void hint_insert(uint64_t *tab, const uint64_t offset, unsigned int *tab_nbr);
74 /* Optimization */
75 static inline uint64_t CHS2offset_inline(const disk_t *disk_car,const CHS_t*CHS);
76 static list_part_t *search_part(disk_t *disk_car, const list_part_t *list_part_org, const int verbose, const int dump_ind, const int fast_mode, char **current_cmd);
77 static inline void offset2CHS_inline(const disk_t *disk_car,const uint64_t offset, CHS_t*CHS);
78
offset2CHS_inline(const disk_t * disk_car,const uint64_t offset,CHS_t * CHS)79 static inline void offset2CHS_inline(const disk_t *disk_car,const uint64_t offset, CHS_t*CHS)
80 {
81 uint64_t pos=offset/disk_car->sector_size;
82 CHS->sector=(pos%disk_car->geom.sectors_per_head)+1;
83 pos/=disk_car->geom.sectors_per_head;
84 CHS->head=pos%disk_car->geom.heads_per_cylinder;
85 CHS->cylinder=pos/disk_car->geom.heads_per_cylinder;
86 }
87
CHS2offset_inline(const disk_t * disk_car,const CHS_t * CHS)88 static inline uint64_t CHS2offset_inline(const disk_t *disk_car,const CHS_t*CHS)
89 {
90 return (((uint64_t)CHS->cylinder*disk_car->geom.heads_per_cylinder+CHS->head)*disk_car->geom.sectors_per_head+CHS->sector-1)*disk_car->sector_size;
91 }
92 /* Optimization end */
93
get_location_boundary(const disk_t * disk)94 static unsigned int get_location_boundary(const disk_t *disk)
95 {
96 if(disk->arch==&arch_mac)
97 return 4096;
98 else if(disk->arch==&arch_sun)
99 return disk->geom.heads_per_cylinder * disk->geom.sectors_per_head * disk->sector_size;
100 return disk->sector_size;
101 }
102
align_structure_aux(const uint64_t offset,const disk_t * disk)103 static unsigned int align_structure_aux(const uint64_t offset, const disk_t *disk)
104 {
105 unsigned int tmp;
106 if(offset % (1024*1024) == 0)
107 return 1024*1024;
108 tmp=disk->geom.heads_per_cylinder * disk->geom.sectors_per_head * disk->sector_size;
109 if(offset % tmp == 0 || offset % tmp == disk->geom.sectors_per_head * disk->sector_size)
110 return tmp;
111 tmp= disk->geom.sectors_per_head * disk->sector_size;
112 if(offset % tmp == 0)
113 return tmp;
114 return disk->sector_size;
115 }
116
align_structure_i386(list_part_t * list_part,const disk_t * disk,const unsigned int align)117 static void align_structure_i386(list_part_t *list_part, const disk_t *disk, const unsigned int align)
118 {
119 list_part_t *element;
120 for(element=list_part; element!=NULL; element=element->next)
121 {
122 uint64_t partition_end;
123 unsigned int location_boundary;
124 const partition_t *part=element->part;
125 if(align==0)
126 location_boundary=disk->sector_size;
127 else
128 location_boundary=align_structure_aux(part->part_offset, disk);
129 partition_end=(part->part_offset+part->part_size-1+location_boundary-1)/location_boundary*location_boundary-1;
130 if(align!=0 && element->next!=NULL)
131 {
132 const partition_t *next_partition=element->next->part;
133 if( next_partition->part_offset > part->part_offset + part->part_size -1 &&
134 next_partition->part_offset <= partition_end)
135 {
136 /* Do not align the partition if it overlaps the next one because of that */
137 location_boundary=disk->sector_size;
138 partition_end=(part->part_offset + part->part_size-1+location_boundary-1)/location_boundary*location_boundary-1;
139 }
140 }
141 element->part->part_size=partition_end - part->part_offset+1;
142 }
143 }
144
align_structure(list_part_t * list_part,const disk_t * disk,const unsigned int align)145 static void align_structure(list_part_t *list_part, const disk_t *disk, const unsigned int align)
146 {
147 if(disk->arch==&arch_i386)
148 {
149 align_structure_i386(list_part, disk, align);
150 return ;
151 }
152 {
153 list_part_t *element;
154 const unsigned int location_boundary=get_location_boundary(disk);
155 for(element=list_part; element!=NULL; element=element->next)
156 {
157 const uint64_t partition_end=(element->part->part_offset+element->part->part_size-1+location_boundary-1)/location_boundary*location_boundary-1;
158 element->part->part_size=partition_end-element->part->part_offset+1;
159 }
160 }
161 }
162
only_one_bootable(list_part_t * list_part,list_part_t * part_boot)163 void only_one_bootable( list_part_t *list_part, list_part_t *part_boot)
164 {
165 list_part_t *element;
166 if(part_boot->part->status==STATUS_PRIM_BOOT)
167 for(element=list_part;element!=NULL;element=element->next)
168 {
169 if((element!=part_boot)&&(element->part->status==STATUS_PRIM_BOOT))
170 element->part->status=STATUS_PRIM;
171 }
172 }
173
174 #ifdef HAVE_NCURSES
interface_part_bad_ncurses(disk_t * disk_car,list_part_t * list_part)175 static int interface_part_bad_ncurses(disk_t *disk_car, list_part_t *list_part)
176 {
177 int quit=0;
178 int offset=0;
179 int pos_num=0;
180 uint64_t disk_size=disk_car->disk_size;
181 list_part_t *pos=list_part;
182 if(list_part==NULL)
183 return 1;
184 {
185 list_part_t *parts;
186 for(parts=list_part;parts!=NULL;parts=parts->next)
187 {
188 if(disk_size<parts->part->part_offset+parts->part->part_size-1)
189 disk_size=parts->part->part_offset+parts->part->part_size-1;
190 }
191 }
192 aff_copy(stdscr);
193 wmove(stdscr,4,0);
194 wprintw(stdscr,"%s",disk_car->description(disk_car));
195 wmove(stdscr,6,0);
196 {
197 char buffer_disk_size[100];
198 char buffer_disk_size_found[100];
199 size_to_unit(disk_car->disk_size, buffer_disk_size);
200 size_to_unit(disk_size, buffer_disk_size_found);
201 wprintw(stdscr,"The harddisk (%s) seems too small! (< %s)",
202 buffer_disk_size, buffer_disk_size_found);
203 }
204 wmove(stdscr,7,0);
205 wprintw(stdscr,"Check the harddisk size: HD jumper settings, BIOS detection...");
206 #if defined(__CYGWIN__) || defined(__MINGW32__)
207 if(disk_car->disk_size<=((uint64_t)1<<(28-1)) && disk_size>=((uint64_t)1<<(28-1)))
208 {
209 wmove(stdscr,8,0);
210 wprintw(stdscr,"Hint: update Windows to support LBA48 (minimum: W2K SP4 or XP SP1)");
211 }
212 #endif
213 wmove(stdscr,9,0);
214 if(list_part->next==NULL)
215 {
216 wprintw(stdscr,"The following partition can't be recovered:");
217 } else {
218 wprintw(stdscr,"The following partitions can't be recovered:");
219 }
220 mvwaddstr(stdscr,10,0,msg_PART_HEADER);
221 wmove(stdscr,22,0);
222 wattrset(stdscr, A_REVERSE);
223 wprintw(stdscr,"[ Continue ]");
224 wattroff(stdscr, A_REVERSE);
225 do
226 {
227 int i;
228 int car;
229 list_part_t *parts;
230 for(i=0,parts=list_part;(parts!=NULL) && (i<offset);parts=parts->next,i++);
231 for(i=offset;(parts!=NULL) &&((i-offset)<INTER_BAD_PART);i++,parts=parts->next)
232 {
233 wmove(stdscr,11+i-offset,0);
234 wclrtoeol(stdscr); /* before addstr for BSD compatibility */
235 if(parts==pos)
236 {
237 char buffer_part_size[100];
238 wattrset(stdscr, A_REVERSE);
239 waddstr(stdscr, ">");
240 aff_part(stdscr, AFF_PART_BASE, disk_car, parts->part);
241 wattroff(stdscr, A_REVERSE);
242 wmove(stdscr,23,0);
243 wclrtoeol(stdscr); /* before addstr for BSD compatibility */
244 if(parts->part->info[0]!='\0')
245 {
246 wprintw(stdscr,"%s, ",parts->part->info);
247 }
248 size_to_unit(parts->part->part_size, buffer_part_size);
249 wprintw(stdscr,"%s", buffer_part_size);
250 } else
251 {
252 waddstr(stdscr, " ");
253 aff_part(stdscr, AFF_PART_BASE, disk_car, parts->part);
254 }
255 }
256 wrefresh(stdscr);
257 car=wgetch(stdscr);
258 switch(car)
259 {
260 case 'q':
261 case '\r':
262 case '\n':
263 case KEY_ENTER:
264 #ifdef PADENTER
265 case PADENTER:
266 #endif
267 case 'M':
268 quit=1;
269 break;
270 case KEY_UP:
271 if(pos->prev!=NULL)
272 {
273 pos=pos->prev;
274 pos_num--;
275 }
276 break;
277 case KEY_DOWN:
278 if(pos->next!=NULL)
279 {
280 pos=pos->next;
281 pos_num++;
282 }
283 break;
284 case KEY_PPAGE:
285 for(i=0; i<INTER_BAD_PART && pos->prev!=NULL; i++)
286 {
287 pos=pos->prev;
288 pos_num--;
289 }
290 break;
291 case KEY_NPAGE:
292 for(i=0; i<INTER_BAD_PART && pos->next!=NULL; i++)
293 {
294 pos=pos->next;
295 pos_num++;
296 }
297 break;
298 default:
299 break;
300 }
301 if(pos_num<offset)
302 offset=pos_num;
303 if(pos_num>=offset+INTER_BAD_PART)
304 offset=pos_num-INTER_BAD_PART+1;
305 } while(quit==0);
306 return 0;
307 }
308 #endif
309
interface_part_bad_log(disk_t * disk_car,list_part_t * list_part)310 static int interface_part_bad_log(disk_t *disk_car, list_part_t *list_part)
311 {
312 uint64_t disk_size=disk_car->disk_size;
313 if(list_part==NULL)
314 return 1;
315 {
316 list_part_t *parts;
317 for(parts=list_part;parts!=NULL;parts=parts->next)
318 {
319 if(disk_size<parts->part->part_offset+parts->part->part_size-1)
320 disk_size=parts->part->part_offset+parts->part->part_size-1;
321 }
322 }
323 log_warning("%s\n",disk_car->description(disk_car));
324 log_warning("Check the harddisk size: HD jumper settings, BIOS detection...\n");
325 #if defined(__CYGWIN__) || defined(__MINGW32__)
326 if(disk_car->disk_size<=((uint64_t)1<<(28-1)) && disk_size>=((uint64_t)1<<(28-1)))
327 {
328 log_warning("Hint: update Windows to support LBA48 (minimum: W2K SP4 or XP SP1)\n");
329 }
330 #endif
331 {
332 char buffer_disk_size[100];
333 char buffer_disk_size_found[100];
334 size_to_unit(disk_car->disk_size, buffer_disk_size);
335 size_to_unit(disk_size, buffer_disk_size_found);
336 log_warning("The harddisk (%s) seems too small! (< %s)\n",
337 buffer_disk_size, buffer_disk_size_found);
338 }
339 if(list_part->next==NULL)
340 {
341 log_warning("The following partition can't be recovered:\n");
342 } else {
343 log_warning("The following partitions can't be recovered:\n");
344 }
345 {
346 list_part_t *parts;
347 for(parts=list_part;parts!=NULL;parts=parts->next)
348 log_partition(disk_car,parts->part);
349 }
350 return 0;
351 }
352
353 #ifdef HAVE_NCURSES
warning_geometry_ncurses(disk_t * disk_car,const unsigned int recommanded_heads_per_cylinder)354 static void warning_geometry_ncurses(disk_t *disk_car, const unsigned int recommanded_heads_per_cylinder)
355 {
356 aff_copy(stdscr);
357 wmove(stdscr,4,0);
358 wprintw(stdscr,"%s",disk_car->description(disk_car));
359 wmove(stdscr,6,0);
360 wprintw(stdscr, "Warning: the current number of heads per cylinder is %u",
361 disk_car->geom.heads_per_cylinder);
362 wmove(stdscr,7,0);
363 wprintw(stdscr,"but the correct value may be %u.",recommanded_heads_per_cylinder);
364 wmove(stdscr,8,0);
365 wprintw(stdscr,"You can use the Geometry menu to change this value.");
366 wmove(stdscr,9,0);
367 wprintw(stdscr,"It's something to try if");
368 wmove(stdscr,10,0);
369 wprintw(stdscr,"- some partitions are not found by TestDisk");
370 wmove(stdscr,11,0);
371 wprintw(stdscr,"- or the partition table can not be written because partitions overlap.");
372 wmove(stdscr,22,0);
373 wattrset(stdscr, A_REVERSE);
374 wprintw(stdscr,"[ Continue ]");
375 wattroff(stdscr, A_REVERSE);
376 wrefresh(stdscr);
377 while(wgetch(stdscr)==ERR);
378 }
379 #endif
380
hint_insert(uint64_t * tab,const uint64_t offset,unsigned int * tab_nbr)381 static void hint_insert(uint64_t *tab, const uint64_t offset, unsigned int *tab_nbr)
382 {
383 if(*tab_nbr<MAX_SEARCH_LOCATION-1)
384 {
385 unsigned int i,j;
386 for(i=0;i<*tab_nbr && tab[i]<offset;i++);
387 if(i<*tab_nbr && tab[i]==offset)
388 return;
389 (*tab_nbr)++;
390 for(j=*tab_nbr;j>i;j--)
391 tab[j]=tab[j-1];
392 tab[i]=offset;
393 }
394 }
395
search_add_hints(const disk_t * disk,uint64_t * try_offset,unsigned int * try_offset_nbr)396 static void search_add_hints(const disk_t *disk, uint64_t *try_offset, unsigned int *try_offset_nbr)
397 {
398 if(disk->arch==&arch_i386)
399 {
400 /* sometimes users choose Intel instead of GPT */
401 hint_insert(try_offset, 2*disk->sector_size+16384, try_offset_nbr);
402 /* sometimes users don't choose Vista by mistake */
403 hint_insert(try_offset, 2048*512, try_offset_nbr);
404 /* try to deal with incorrect geometry */
405 /* 0/1/1 */
406 hint_insert(try_offset, 32 * disk->sector_size, try_offset_nbr);
407 hint_insert(try_offset, 63 * disk->sector_size, try_offset_nbr);
408 /* 1/[01]/1 CHS x 16 63 */
409 hint_insert(try_offset, 16 * 63 * disk->sector_size, try_offset_nbr);
410 hint_insert(try_offset, 17 * 63 * disk->sector_size, try_offset_nbr);
411 hint_insert(try_offset, 16 * disk->geom.sectors_per_head * disk->sector_size, try_offset_nbr);
412 hint_insert(try_offset, 17 * disk->geom.sectors_per_head * disk->sector_size, try_offset_nbr);
413 /* 1/[01]/1 CHS x 240 63 */
414 hint_insert(try_offset, 240 * 63 * disk->sector_size, try_offset_nbr);
415 hint_insert(try_offset, 241 * 63 * disk->sector_size, try_offset_nbr);
416 hint_insert(try_offset, 240 * disk->geom.sectors_per_head * disk->sector_size, try_offset_nbr);
417 hint_insert(try_offset, 241 * disk->geom.sectors_per_head * disk->sector_size, try_offset_nbr);
418 /* 1/[01]/1 CHS x 255 63 */
419 hint_insert(try_offset, 255 * 63 * disk->sector_size, try_offset_nbr);
420 hint_insert(try_offset, 256 * 63 * disk->sector_size, try_offset_nbr);
421 hint_insert(try_offset, 255 * disk->geom.sectors_per_head * disk->sector_size, try_offset_nbr);
422 hint_insert(try_offset, 256 * disk->geom.sectors_per_head * disk->sector_size, try_offset_nbr);
423 /* Hints for NTFS backup */
424 if(disk->geom.cylinders>1)
425 {
426 CHS_t start;
427 start.cylinder=disk->geom.cylinders-1;
428 start.head=disk->geom.heads_per_cylinder-1;
429 start.sector=disk->geom.sectors_per_head;
430 hint_insert(try_offset, CHS2offset_inline(disk, &start), try_offset_nbr);
431 if(disk->geom.cylinders>2)
432 {
433 start.cylinder--;
434 hint_insert(try_offset, CHS2offset_inline(disk, &start), try_offset_nbr);
435 }
436 }
437 hint_insert(try_offset, (disk->disk_size-disk->sector_size)/(2048*512)*(2048*512)-disk->sector_size, try_offset_nbr);
438 }
439 else if(disk->arch==&arch_gpt)
440 {
441 /* Hint for NTFS backup */
442 const unsigned int gpt_entries_size=128*sizeof(struct gpt_ent);
443 const uint64_t hdr_lba_end=le64((disk->disk_size-1 - gpt_entries_size)/disk->sector_size - 1);
444 const uint64_t ntfs_backup_offset=(hdr_lba_end-1)*disk->sector_size/(2048*512)*(2048*512)-disk->sector_size;
445 hint_insert(try_offset, ntfs_backup_offset, try_offset_nbr);
446 }
447 else if(disk->arch==&arch_mac)
448 {
449 /* sometime users choose Mac instead of GPT for i386 Mac */
450 hint_insert(try_offset, 2*disk->sector_size+16384, try_offset_nbr);
451 }
452 }
453
454 /*
455 Intel
456 - Display CHS
457 - Align: following configuration
458 - MinPartOffset: 512
459 - Geometry: care
460 Mac
461 - Display S
462 - Align to 4k (not required)
463 - MinPartOffset: 512
464 - Geometry: don't care
465 None
466 - Display S
467 - Align: none
468 - MinPartOffset: 0
469 - Geometry: don't care
470 Sun
471 - Display C
472 - Align to C boundaries
473 - MinPartOffset: 512
474 - Partition need to have H=0, S=1
475 - Geometry: required
476 XBox
477 - Display S
478 - Align: none
479 - MinPartOffset: 0x800
480 - Geometry: don't care
481 */
get_min_location(const disk_t * disk)482 static uint64_t get_min_location(const disk_t *disk)
483 {
484 if(disk->arch==&arch_gpt)
485 return 2*disk->sector_size+16384;
486 else if(disk->arch==&arch_i386 || disk->arch==&arch_humax)
487 return disk->sector_size;
488 else if(disk->arch==&arch_mac)
489 return 4096;
490 else if(disk->arch==&arch_sun)
491 return (uint64_t)disk->geom.heads_per_cylinder * disk->geom.sectors_per_head * disk->sector_size;
492 else if(disk->arch==&arch_xbox)
493 return 0x800;
494 /* arch_none */
495 return 0;
496 }
497
search_NTFS_from_backup(disk_t * disk_car,list_part_t * list_part,const int verbose,const int dump_ind,const uint64_t min_location,const uint64_t search_location_max)498 static void search_NTFS_from_backup(disk_t *disk_car, list_part_t *list_part, const int verbose, const int dump_ind, const uint64_t min_location, const uint64_t search_location_max)
499 {
500 unsigned char *buffer_disk;
501 const list_part_t *element;
502 partition_t *partition;
503 buffer_disk=(unsigned char*)MALLOC(16*DEFAULT_SECTOR_SIZE);
504 partition=partition_new(disk_car->arch);
505 for(element=list_part;element!=NULL;element=element->next)
506 {
507 if(element->part->upart_type==UP_NTFS && element->part->sb_offset!=0)
508 {
509 unsigned int i;
510 for(i=32;i>0;i--)
511 {
512 partition->part_size=(uint64_t)0;
513 partition->part_offset=element->part->part_offset - i * disk_car->sector_size;
514 if(disk_car->pread(disk_car, buffer_disk, DEFAULT_SECTOR_SIZE, partition->part_offset)==DEFAULT_SECTOR_SIZE)
515 {
516 if(recover_NTFS(disk_car, (const struct ntfs_boot_sector*)buffer_disk, partition, verbose, dump_ind, 0)==0)
517 {
518 partition->status=STATUS_DELETED;
519 if(disk_car->arch->is_part_known(partition)!=0 && partition->part_size>1 &&
520 partition->part_offset >= min_location &&
521 partition->part_offset+partition->part_size-1 <= search_location_max)
522 {
523 int insert_error=0;
524 partition_t *new_partition=partition_new(NULL);
525 dup_partition_t(new_partition,partition);
526 list_part=insert_new_partition(list_part, new_partition, 0, &insert_error);
527 if(insert_error>0)
528 free(new_partition);
529 }
530 partition_reset(partition, disk_car->arch);
531 }
532 }
533 }
534 }
535 }
536 free(partition);
537 free(buffer_disk);
538 }
539
540 typedef enum { INDSTOP_CONTINUE=0, INDSTOP_STOP=1, INDSTOP_SKIP=2, INDSTOP_QUIT=3 } indstop_t;
541
search_part(disk_t * disk_car,const list_part_t * list_part_org,const int verbose,const int dump_ind,const int fast_mode,char ** current_cmd)542 static list_part_t *search_part(disk_t *disk_car, const list_part_t *list_part_org, const int verbose, const int dump_ind, const int fast_mode, char **current_cmd)
543 {
544 unsigned char *buffer_disk;
545 unsigned char *buffer_disk0;
546 /* TODO use circular buffer for try_offset and try_offset_raid */
547 uint64_t try_offset[MAX_SEARCH_LOCATION];
548 uint64_t try_offset_raid[MAX_SEARCH_LOCATION];
549 const uint64_t min_location=get_min_location(disk_car);
550 uint64_t search_location;
551 unsigned int try_offset_nbr=0;
552 unsigned int try_offset_raid_nbr=0;
553 #ifdef HAVE_NCURSES
554 unsigned int old_cylinder=0;
555 #endif
556 const unsigned int location_boundary=get_location_boundary(disk_car);
557 indstop_t ind_stop=INDSTOP_CONTINUE;
558 list_part_t *list_part=NULL;
559 list_part_t *list_part_bad=NULL;
560 partition_t *partition;
561 /* It's not a problem to read a little bit more than necessary */
562 const uint64_t search_location_max=td_max((disk_car->disk_size /
563 ((uint64_t) disk_car->geom.heads_per_cylinder * disk_car->geom.sectors_per_head * disk_car->sector_size) + 1 ) *
564 ((uint64_t) disk_car->geom.heads_per_cylinder * disk_car->geom.sectors_per_head * disk_car->sector_size),
565 disk_car->disk_real_size);
566 assert(disk_car->sector_size>0);
567 partition=partition_new(disk_car->arch);
568 buffer_disk=(unsigned char*)MALLOC(16*DEFAULT_SECTOR_SIZE);
569 buffer_disk0=(unsigned char*)MALLOC(16*DEFAULT_SECTOR_SIZE);
570 {
571 /* Will search for partition at current known partition location */
572 const list_part_t *element;
573 for(element=list_part_org;element!=NULL;element=element->next)
574 {
575 hint_insert(try_offset, element->part->part_offset, &try_offset_nbr);
576 }
577 }
578
579 #ifdef HAVE_NCURSES
580 wmove(stdscr,22,0);
581 wattrset(stdscr, A_REVERSE);
582 waddstr(stdscr," Stop ");
583 wattroff(stdscr, A_REVERSE);
584 #endif
585 screen_buffer_reset();
586 log_info("\nsearch_part()\n");
587 log_info("%s\n",disk_car->description(disk_car));
588 search_location=min_location;
589 search_add_hints(disk_car, try_offset, &try_offset_nbr);
590 /* Not every sector will be examined */
591 search_location_init(disk_car, location_boundary, fast_mode);
592 /* Scan the disk */
593 while(ind_stop!=INDSTOP_QUIT && search_location < search_location_max)
594 {
595 CHS_t start;
596 offset2CHS_inline(disk_car,search_location,&start);
597 #ifdef HAVE_NCURSES
598 if(disk_car->geom.heads_per_cylinder>1)
599 {
600 if(old_cylinder!=start.cylinder)
601 {
602 old_cylinder=start.cylinder;
603 wmove(stdscr,ANALYSE_Y,ANALYSE_X);
604 wclrtoeol(stdscr);
605 wprintw(stdscr,"Analyse cylinder %5u/%u: %02u%%",
606 start.cylinder, disk_car->geom.cylinders-1,
607 (unsigned int)(search_location*100/disk_car->disk_size));
608 wrefresh(stdscr);
609 switch(check_enter_key_or_s(stdscr))
610 {
611 case 1:
612 ind_stop=INDSTOP_STOP;
613 break;
614 case 2:
615 ind_stop=INDSTOP_SKIP;
616 break;
617 }
618 }
619 }
620 else if((start.cylinder & 0x7FFF)==0)
621 {
622 wmove(stdscr,ANALYSE_Y,ANALYSE_X);
623 wclrtoeol(stdscr);
624 wprintw(stdscr,"Analyse sector %11llu/%llu: %02u%%",
625 (long long unsigned)(search_location / disk_car->sector_size),
626 (long long unsigned)((disk_car->disk_size-1)/disk_car->sector_size),
627 (unsigned int)(search_location*100/disk_car->disk_size));
628 wrefresh(stdscr);
629 switch(check_enter_key_or_s(stdscr))
630 {
631 case 1:
632 ind_stop=INDSTOP_STOP;
633 break;
634 case 2:
635 ind_stop=INDSTOP_SKIP;
636 break;
637 }
638 }
639 #endif
640 {
641 unsigned int sector_inc=0;
642 int test_nbr=0;
643 int search_now=0;
644 int search_now_raid=0;
645 while(try_offset_nbr>0 && try_offset[0]<=search_location)
646 {
647 unsigned int j;
648 if(try_offset[0]==search_location)
649 search_now=1;
650 for(j=0;j<try_offset_nbr-1;j++)
651 try_offset[j]=try_offset[j+1];
652 try_offset_nbr--;
653 }
654 /* PC x/0/1 x/1/1 x/2/1 */
655 /* PC Vista 2048 sectors unit */
656 if(disk_car->arch==&arch_i386)
657 search_now|= (start.sector==1 && fast_mode>1) ||
658 (start.sector==1 && start.head<=2) ||
659 search_location%(2048*512)==0;
660 else
661 search_now|= (search_location%location_boundary==0);
662 while(try_offset_raid_nbr>0 && try_offset_raid[0]<=search_location)
663 {
664 unsigned int j;
665 if(try_offset_raid[0]==search_location)
666 search_now_raid=1;
667 for(j=0;j<try_offset_raid_nbr-1;j++)
668 try_offset_raid[j]=try_offset_raid[j+1];
669 try_offset_raid_nbr--;
670 }
671 do
672 {
673 int res=0;
674 partition->part_size=(uint64_t)0;
675 partition->part_offset=search_location;
676 if(test_nbr==0)
677 {
678 if(search_now_raid>0 || fast_mode>1)
679 { /* Search Linux software RAID */
680 if(disk_car->pread(disk_car, buffer_disk, 8 * DEFAULT_SECTOR_SIZE, search_location) == 8 *DEFAULT_SECTOR_SIZE)
681 {
682 if(recover_MD(disk_car, (const struct mdp_superblock_s*)buffer_disk, partition, verbose, dump_ind)==0)
683 {
684 const struct mdp_superblock_1 *sb1=(const struct mdp_superblock_1 *)buffer_disk;
685 if(le32(sb1->md_magic)==(unsigned int)MD_SB_MAGIC)
686 {
687 if(le32(sb1->major_version)==0)
688 partition->part_offset-=(uint64_t)MD_NEW_SIZE_SECTORS(partition->part_size/512)*512;
689 else
690 partition->part_offset-=le64(sb1->super_offset)*512;
691 }
692 else
693 {
694 if(be32(sb1->major_version)==0)
695 partition->part_offset-=(uint64_t)MD_NEW_SIZE_SECTORS(partition->part_size/512)*512;
696 else
697 partition->part_offset-=be64(sb1->super_offset)*512;
698 }
699 res=1;
700 }
701 else
702 res=0;
703 }
704 }
705 test_nbr++;
706 }
707 if(res<=0 && test_nbr==1)
708 {
709 if((disk_car->arch==&arch_i386 &&
710 ((start.sector==7 && (start.head<=2 || fast_mode>1)) ||
711 search_location%(2048*512)==(7-1)*512)) ||
712 (disk_car->arch!=&arch_i386 && (search_location%location_boundary==(7-1)*512)) ||
713 (disk_car->arch==&arch_gpt&& (search_location%(2048*512)==(7-1)*512)) ||
714 (disk_car->arch==&arch_none && search_location==(7-1)*512))
715 res=search_FAT_backup(buffer_disk,disk_car,partition,verbose,dump_ind);
716 test_nbr++;
717 }
718 if(res<=0 && test_nbr==2)
719 {
720 if((disk_car->arch==&arch_i386 &&
721 ((start.sector==13 && (start.head<=2 || fast_mode>1)) ||
722 search_location%(2048*512)==(13-1)*disk_car->sector_size)) ||
723 (disk_car->arch==&arch_gpt&& (search_location%(2048*512)==(13-1)*512)) ||
724 (disk_car->arch!=&arch_i386 && (search_location%location_boundary==(13-1)*disk_car->sector_size)))
725 res=search_exFAT_backup(buffer_disk, disk_car, partition);
726 test_nbr++;
727 }
728 if(res<=0 && test_nbr==3)
729 {
730 if((disk_car->arch==&arch_i386 &&
731 ((start.sector==disk_car->geom.sectors_per_head &&
732 (start.head==disk_car->geom.heads_per_cylinder-1 || fast_mode>1)) ||
733 search_location%(2048*512)==(2048-1)*512)) ||
734 (disk_car->arch==&arch_gpt&& (search_location%(2048*512)==(2048-1)*512)) ||
735 (disk_car->arch!=&arch_i386 && search_location%location_boundary==(location_boundary-512) &&
736 search_location>0))
737 res=search_NTFS_backup(buffer_disk,disk_car,partition,verbose,dump_ind);
738 test_nbr++;
739 }
740 if(res<=0 && test_nbr==4)
741 {
742 if((disk_car->arch==&arch_i386 &&
743 ((start.sector==disk_car->geom.sectors_per_head &&
744 (start.head==disk_car->geom.heads_per_cylinder-1 || fast_mode>1)) ||
745 search_location%(2048*512)==(2048-1)*512)) ||
746 (disk_car->arch!=&arch_i386 && search_location%location_boundary==(location_boundary-512) &&
747 search_location>0))
748 res=search_HFS_backup(buffer_disk,disk_car,partition,verbose,dump_ind);
749 test_nbr++;
750 }
751 if(res<=0 && test_nbr==5)
752 {
753 int s_log_block_size;
754 /* try backup superblock */
755 /* It must be in fast_mode>0 because it can hide otherwise other partition type */
756 /* Block size: 1024, 2048 or 4096 bytes (8192 bytes on Alpha systems) */
757 /* From e2fsprogs-1.34/lib/ext2fs/initialize.c: set_field(s_first_data_block, super->s_log_block_size ? 0 : 1); */
758 /* Assumes that TestDisk is not running under Alpha and s_blocks_per_group=8 * block size */
759 for(s_log_block_size=0;(s_log_block_size<=2)&&(res<=0);s_log_block_size++)
760 {
761 /* sparse superblock feature: The groups chosen are 0, 1 and powers of 3, 5 and 7. */
762 /* Checking group 3 */
763 const uint64_t hd_offset=3*(EXT2_MIN_BLOCK_SIZE<<s_log_block_size)*8*(EXT2_MIN_BLOCK_SIZE<<s_log_block_size)+(s_log_block_size==0?2*DEFAULT_SECTOR_SIZE:0);
764 if(search_location>=hd_offset)
765 {
766 CHS_t start_ext2;
767 offset2CHS_inline(disk_car,search_location-hd_offset,&start_ext2);
768 if((disk_car->arch==&arch_i386 && start_ext2.sector==1 && (start_ext2.head<=2 || fast_mode>1)) ||
769 (disk_car->arch==&arch_i386 && (search_location-hd_offset)%(2048*512)==0) ||
770 (disk_car->arch!=&arch_i386 && (search_location-hd_offset)%location_boundary==0))
771 {
772 if(disk_car->pread(disk_car, buffer_disk, 1024, search_location)==1024)
773 {
774 const struct ext2_super_block *sb=(const struct ext2_super_block*)buffer_disk;
775 if(le16(sb->s_magic)==EXT2_SUPER_MAGIC && le16(sb->s_block_group_nr)>0 &&
776 recover_EXT2(disk_car, sb, partition, verbose, dump_ind)==0)
777 res=1;
778 }
779 }
780 }
781 }
782 test_nbr++;
783 }
784 if(res<=0 && test_nbr==6)
785 {
786 if(search_now==0)
787 test_nbr=14;
788 else
789 {
790 if(disk_car->pread(disk_car, buffer_disk0, 16 * DEFAULT_SECTOR_SIZE, partition->part_offset) == 16 * DEFAULT_SECTOR_SIZE)
791 res=search_type_2(buffer_disk0,disk_car,partition,verbose,dump_ind);
792 else
793 res=-1;
794 test_nbr++;
795 }
796 }
797 if(res<=0 && test_nbr==7)
798 {
799 if(res==0)
800 res=search_type_1(buffer_disk0, disk_car,partition,verbose,dump_ind);
801 test_nbr++;
802 }
803 if(res<=0 && test_nbr==8)
804 {
805 if(res==0)
806 res=search_type_0(buffer_disk0,disk_car,partition,verbose,dump_ind);
807 test_nbr++;
808 }
809 if(res<=0 && test_nbr==9)
810 {
811 res=search_type_8(buffer_disk,disk_car,partition,verbose,dump_ind);
812 test_nbr++;
813 }
814 if(res<=0 && test_nbr==10)
815 {
816 /* Try to catch disklabel before BSD FFS partition */
817 res=search_type_16(buffer_disk,disk_car,partition,verbose,dump_ind);
818 test_nbr++;
819 }
820 if(res<=0 && test_nbr==11)
821 {
822 res=search_type_64(buffer_disk,disk_car,partition,verbose,dump_ind);
823 test_nbr++;
824 }
825 if(res<=0 && test_nbr==12)
826 {
827 /* read to fill the cache */
828 disk_car->pread(disk_car, buffer_disk, 8 * DEFAULT_SECTOR_SIZE,
829 partition->part_offset + (63 + 16) * 512);
830 /* Try to catch disklabel before BSD FFS partition */
831 res=search_type_128(buffer_disk,disk_car,partition,verbose,dump_ind);
832 test_nbr++;
833 }
834 if(res<=0 && test_nbr==13)
835 {
836 res=search_type_2048(buffer_disk,disk_car,partition,verbose,dump_ind);
837 test_nbr++;
838 }
839 if(test_nbr>=14)
840 {
841 sector_inc=1;
842 test_nbr=0;
843 }
844 if(res<0)
845 {
846 #ifdef HAVE_NCURSES
847 wmove(stdscr,ANALYSE_Y+1,ANALYSE_X);
848 wclrtoeol(stdscr);
849 wprintw(stdscr,msg_READ_ERROR_AT, start.cylinder,start.head,start.sector,(unsigned long)(partition->part_offset/disk_car->sector_size));
850 #endif
851 /* Stop reading after the end of the disk */
852 if(search_location >= disk_car->disk_real_size)
853 search_location = search_location_max;
854 }
855 else if(res>0)
856 {
857 partition->status=STATUS_DELETED;
858 log_partition(disk_car,partition);
859 aff_part_buffer(AFF_PART_BASE, disk_car,partition);
860 #ifdef HAVE_NCURSES
861 screen_buffer_to_interface();
862 #endif
863 if(disk_car->arch->is_part_known(partition)!=0 &&
864 partition->part_size>1 &&
865 partition->part_offset>=min_location)
866 {
867 const uint64_t pos_fin=partition->part_offset+partition->part_size-1;
868 if(partition->upart_type!=UP_MD && partition->upart_type!=UP_MD1 &&
869 ind_stop==INDSTOP_CONTINUE)
870 { /* Detect Linux md 0.9 software raid */
871 unsigned int disk_factor;
872 for(disk_factor=6; disk_factor>=1;disk_factor--)
873 { /* disk_factor=1, detect Raid 0/1 */
874 /* disk_factor>1, detect Raid 5 */
875 unsigned int help_factor;
876 for(help_factor=0; help_factor<=MD_MAX_CHUNK_SIZE/MD_RESERVED_BYTES+3; help_factor++)
877 {
878 const uint64_t offset=(uint64_t)MD_NEW_SIZE_SECTORS((partition->part_size/disk_factor+help_factor*MD_RESERVED_BYTES-1)/MD_RESERVED_BYTES*MD_RESERVED_BYTES/512)*512;
879 hint_insert(try_offset_raid, partition->part_offset+offset, &try_offset_raid_nbr);
880 }
881 }
882 /* TODO: Detect Linux md 1.0 software raid */
883 }
884 /* */
885 if(pos_fin <= search_location_max)
886 {
887 {
888 int insert_error=0;
889 partition_t *new_partition=partition_new(NULL);
890 dup_partition_t(new_partition,partition);
891 list_part=insert_new_partition(list_part, new_partition, 0, &insert_error);
892 if(insert_error>0)
893 free(new_partition);
894 }
895 {
896 const uint64_t next_part_offset=partition->part_offset+partition->part_size-1+1;
897 const uint64_t head_size=(uint64_t)disk_car->geom.sectors_per_head * disk_car->sector_size;
898 hint_insert(try_offset, next_part_offset, &try_offset_nbr);
899 hint_insert(try_offset, next_part_offset+head_size, &try_offset_nbr);
900 if(next_part_offset%head_size!=0)
901 {
902 hint_insert(try_offset, (next_part_offset+head_size-1)/head_size*head_size, &try_offset_nbr);
903 hint_insert(try_offset, (next_part_offset+head_size-1)/head_size*head_size+head_size, &try_offset_nbr);
904 }
905 }
906 if((fast_mode==0) && (partition->part_offset+partition->part_size-disk_car->sector_size > search_location))
907 {
908 search_location=partition->part_offset+partition->part_size-disk_car->sector_size;
909 test_nbr=0;
910 sector_inc=1;
911 }
912 }
913 else
914 {
915 {
916 int insert_error=0;
917 partition_t *new_partition=partition_new(NULL);
918 dup_partition_t(new_partition,partition);
919 list_part_bad=insert_new_partition(list_part_bad, new_partition, 0, &insert_error);
920 if(insert_error>0)
921 free(new_partition);
922 }
923 if(verbose>0)
924 log_warning("This partition ends after the disk limits. (start=%llu, size=%llu, end=%llu, disk end=%llu)\n",
925 (unsigned long long)(partition->part_offset/disk_car->sector_size),
926 (unsigned long long)(partition->part_size/disk_car->sector_size),
927 (unsigned long long)(pos_fin/disk_car->sector_size),
928 (unsigned long long)(disk_car->disk_size/disk_car->sector_size));
929 else
930 log_warning("This partition ends after the disk limits.\n");
931 }
932 }
933 else
934 {
935 if(verbose>0)
936 {
937 log_warning("Partition not added.\n");
938 }
939 }
940 partition_reset(partition, disk_car->arch);
941 }
942 }
943 while(sector_inc==0);
944 }
945 if(ind_stop==INDSTOP_SKIP)
946 {
947 ind_stop=INDSTOP_CONTINUE;
948 if(try_offset_nbr>0 && search_location < try_offset[0])
949 search_location=try_offset[0];
950 }
951 else if(ind_stop==INDSTOP_STOP)
952 {
953 if(try_offset_nbr>0 && search_location < try_offset[0])
954 search_location=try_offset[0];
955 else
956 ind_stop=INDSTOP_QUIT;
957 }
958 else
959 { /* Optimized "search_location+=disk_car->sector_size;" */
960 uint64_t min=search_location_update(search_location);
961 if(try_offset_nbr>0 && min>try_offset[0])
962 min=try_offset[0];
963 if(try_offset_raid_nbr>0 && min>try_offset_raid[0])
964 min=try_offset_raid[0];
965 if(min==(uint64_t)-1 || min<=search_location)
966 search_location+=disk_car->sector_size;
967 else
968 search_location=min;
969 }
970 }
971 /* Search for NTFS partition near the supposed partition beginning
972 given by the NTFS backup boot sector */
973 if(fast_mode>0)
974 search_NTFS_from_backup(disk_car, list_part, verbose, dump_ind, min_location, search_location_max);
975 free(partition);
976 if(ind_stop!=INDSTOP_CONTINUE)
977 log_info("Search for partition aborted\n");
978 if(list_part_bad!=NULL)
979 {
980 interface_part_bad_log(disk_car,list_part_bad);
981 #ifdef HAVE_NCURSES
982 if(*current_cmd==NULL)
983 interface_part_bad_ncurses(disk_car,list_part_bad);
984 #endif
985 }
986 part_free_list(list_part_bad);
987 free(buffer_disk0);
988 free(buffer_disk);
989 return list_part;
990 }
991
992 #ifdef HAVE_NCURSES
ask_mbr_order_i386(disk_t * disk_car,list_part_t * list_part)993 static void ask_mbr_order_i386(disk_t *disk_car,list_part_t *list_part)
994 {
995 partition_t *table[4];
996 int nbr_prim=0;
997 int i,pos=0;
998 int res;
999 int quit=0;
1000 list_part_t *element;
1001 /* Initialisation */
1002 aff_copy(stdscr);
1003 wmove(stdscr,4,0);
1004 wprintw(stdscr,"%s",disk_car->description(disk_car));
1005 mvwaddstr(stdscr,5,0,msg_MBR_ORDER);
1006 mvwaddstr(stdscr,6,0,msg_PART_HEADER_LONG);
1007 for(element=list_part;element!=NULL;element=element->next)
1008 {
1009 if((element->part->order>0) && (element->part->order<5))
1010 table[nbr_prim++]=element->part;
1011 }
1012 /* */
1013 log_info("\nSelect primary partition\n");
1014 for(i=0;i<nbr_prim;i++)
1015 log_partition(disk_car,table[i]);
1016 /* */
1017 do
1018 {
1019 partition_t *table2[4];
1020 int car;
1021 unsigned int order;
1022 /* sort table into table2 */
1023 int part=0;
1024 res=0;
1025 for(order=1;order<=4;order++)
1026 {
1027 int nbr=0;
1028 for(i=0;i<nbr_prim;i++)
1029 if(table[i]->order==order)
1030 {
1031 table2[part++]=table[i];
1032 nbr++;
1033 }
1034 res|=(nbr>1);
1035 }
1036 if(part!=nbr_prim)
1037 {
1038 log_critical("\nBUG part %d, nbr_prim %d\n", part, nbr_prim);
1039 }
1040 for(i=0;i<nbr_prim;i++)
1041 {
1042 wmove(stdscr,5+2+i,0);
1043 wclrtoeol(stdscr);
1044 if(i==pos)
1045 standout();
1046 aff_part(stdscr,AFF_PART_ORDER|AFF_PART_STATUS,disk_car,table2[i]);
1047 if(i==pos)
1048 standend();
1049 }
1050 wmove(stdscr,20,0);
1051 if(res)
1052 wprintw(stdscr,msg_MBR_ORDER_BAD);
1053 else
1054 wprintw(stdscr,msg_MBR_ORDER_GOOD);
1055 wrefresh(stdscr);
1056 car=wgetch(stdscr);
1057 quit=0;
1058 switch(car)
1059 {
1060 case KEY_UP:
1061 if(--pos<0)
1062 pos=nbr_prim-1;
1063 break;
1064 case KEY_DOWN:
1065 if(++pos>=nbr_prim)
1066 pos=0;
1067 break;
1068 case KEY_PPAGE:
1069 pos=0;
1070 break;
1071 case KEY_NPAGE:
1072 pos=nbr_prim-1;
1073 break;
1074 case '1':
1075 case '2':
1076 case '3':
1077 case '4':
1078 table2[pos]->order=car-'0';
1079 break;
1080 case KEY_RIGHT:
1081 case ' ':
1082 case '+':
1083 if(++table2[pos]->order>4)
1084 table2[pos]->order=1;
1085 break;
1086 case KEY_LEFT:
1087 case '-':
1088 if(--table2[pos]->order<1)
1089 table2[pos]->order=4;
1090 break;
1091 case 'q':
1092 case '\r':
1093 case '\n':
1094 case KEY_ENTER:
1095 #ifdef PADENTER
1096 case PADENTER:
1097 #endif
1098 case 'M':
1099 quit=1;
1100 break;
1101 }
1102 wrefresh(stdscr);
1103 } while(res!=0 || quit==0);
1104 }
1105 #endif
1106
reduce_structure(const list_part_t * list_part_org)1107 static list_part_t *reduce_structure(const list_part_t *list_part_org)
1108 {
1109
1110 const list_part_t *element;
1111 list_part_t *list_part=NULL;
1112 for(element=list_part_org; element!=NULL; element=element->next)
1113 {
1114 if(element->part->status!=STATUS_DELETED)
1115 {
1116 int insert_error=0;
1117 partition_t *new_partition=partition_new(NULL);
1118 dup_partition_t(new_partition, element->part);
1119 list_part=insert_new_partition(list_part, new_partition, 0, &insert_error);
1120 if(insert_error>0)
1121 free(new_partition);
1122 }
1123 }
1124 return list_part;
1125 }
1126
add_ext_part_i386(disk_t * disk,list_part_t * list_part,const int max_ext,const int verbose)1127 static list_part_t *add_ext_part_i386(disk_t *disk, list_part_t *list_part, const int max_ext, const int verbose)
1128 {
1129 /* list_part need to be sorted! */
1130 /* All extended partitions of an P_EXTENDX are P_EXTENDED */
1131 int insert_error=0;
1132 list_part_t *element;
1133 list_part_t *deb=NULL;
1134 list_part_t *fin=NULL;
1135 int nbr_entries=0;
1136 partition_t *new_partition;
1137 unsigned int order=0;
1138 uint64_t part_extended_offset=0;
1139 uint64_t part_extended_end=0;
1140 for(element=list_part;element!=NULL;)
1141 {
1142 if(element->part->status==STATUS_EXT)
1143 {
1144 /* remove already existing extended partition */
1145 list_part_t *next=element->next;
1146 if(element->prev!=NULL)
1147 element->prev->next=element->next;
1148 if(element->next!=NULL)
1149 element->next->prev=element->prev;
1150 order=element->part->order;
1151 if(element==list_part)
1152 list_part=next;
1153 free(element->part);
1154 free(element);
1155 element=next;
1156 }
1157 else
1158 {
1159 if(element->part->status==STATUS_LOG)
1160 {
1161 if(deb==NULL)
1162 {
1163 deb=element;
1164 nbr_entries++;
1165 }
1166 fin=element;
1167 }
1168 else
1169 nbr_entries++;
1170 element=element->next;
1171 }
1172 }
1173 if(deb==NULL)
1174 return list_part;
1175 assert(fin!=NULL);
1176 if(nbr_entries==4 || max_ext!=0)
1177 {
1178 if(verbose>0)
1179 {
1180 log_info("add_ext_part_i386: max\n");
1181 }
1182 if(deb->prev==NULL)
1183 {
1184 uint64_t tmp;
1185 part_extended_offset=deb->part->part_offset - disk->sector_size;
1186 if(deb->part->part_offset%(1024*1024)==0)
1187 tmp=1024*1024;
1188 else
1189 tmp=(uint64_t)disk->geom.sectors_per_head * disk->sector_size;
1190 if(tmp < part_extended_offset)
1191 part_extended_offset=tmp;
1192 }
1193 else
1194 {
1195 uint64_t tmp;
1196 part_extended_offset=deb->prev->part->part_offset + deb->prev->part->part_size;
1197 /* round up part_extended_offset */
1198 if(deb->part->part_offset%(1024*1024)==0)
1199 {
1200 tmp=(part_extended_offset+1024*1024-1)/(1024*1024)*(1024*1024);
1201 }
1202 else
1203 {
1204 CHS_t start;
1205 start.cylinder=offset2cylinder(disk, part_extended_offset-1)+1;
1206 start.head=0;
1207 start.sector=1;
1208 tmp=CHS2offset_inline(disk, &start);
1209 }
1210 if(tmp < deb->part->part_offset &&
1211 (deb->prev==NULL || tmp >= deb->prev->part->part_offset + deb->prev->part->part_size))
1212 part_extended_offset=tmp;
1213 }
1214 if(fin->next==NULL)
1215 {
1216 part_extended_end=fin->part->part_offset + fin->part->part_size - disk->sector_size;
1217 /* In some weird cases, a partition may end after the end of the disk */
1218 if(part_extended_end < disk->disk_size - disk->sector_size)
1219 part_extended_end=disk->disk_size - disk->sector_size;
1220 }
1221 else
1222 part_extended_end=fin->next->part->part_offset - disk->sector_size;
1223 /* round down part_extended_end */
1224 if(part_extended_offset%(1024*1024)==0)
1225 {
1226 const uint64_t tmp=part_extended_end/(1024*1024)*(1024*1024) - disk->sector_size;
1227 if(fin->part->part_offset + fin->part->part_size - disk->sector_size <= tmp)
1228 part_extended_end=tmp;
1229 }
1230 else
1231 {
1232 uint64_t tmp;
1233 CHS_t end;
1234 end.cylinder=offset2cylinder(disk, part_extended_end)-1;
1235 end.head=disk->geom.heads_per_cylinder-1;
1236 end.sector=disk->geom.sectors_per_head;
1237 tmp=CHS2offset_inline(disk, &end);
1238 if(fin->part->part_offset + fin->part->part_size - disk->sector_size <= tmp)
1239 part_extended_end=tmp;
1240 }
1241 }
1242 else
1243 {
1244 uint64_t tmp;
1245 if(verbose>0)
1246 {
1247 log_info("add_ext_part_i386: min\n");
1248 }
1249 part_extended_offset=deb->part->part_offset - disk->sector_size;
1250 /* round down part_extended_offset */
1251 if(deb->part->part_offset%(1024*1024)==0)
1252 {
1253 tmp=part_extended_offset/(1024*1024)*(1024*1024);
1254 }
1255 else
1256 {
1257 CHS_t start;
1258 start.cylinder=offset2cylinder(disk, part_extended_offset);
1259 if(start.cylinder==0)
1260 start.head=1;
1261 else
1262 start.head=0;
1263 start.sector=1;
1264 tmp=CHS2offset_inline(disk, &start);
1265 }
1266 if(tmp > 0 && tmp < deb->part->part_offset &&
1267 (deb->prev==NULL || tmp >= deb->prev->part->part_offset + deb->prev->part->part_size))
1268 part_extended_offset=tmp;
1269
1270 part_extended_end=fin->part->part_offset + fin->part->part_size - disk->sector_size;
1271 /* round up part_extended_end */
1272 if(part_extended_offset%(1024*1024)==0)
1273 {
1274 tmp=(part_extended_end+1024*1024-1)/(1024*1024)*(1024*1024) - disk->sector_size;
1275 }
1276 else
1277 {
1278 CHS_t end;
1279 offset2CHS_inline(disk, part_extended_end, &end);
1280 end.head=disk->geom.heads_per_cylinder-1;
1281 end.sector=disk->geom.sectors_per_head;
1282 tmp=CHS2offset_inline(disk, &end);
1283 }
1284 if(tmp < disk->disk_size)
1285 part_extended_end=tmp;
1286 }
1287 new_partition=partition_new(disk->arch);
1288 new_partition->order=order;
1289 new_partition->part_type_i386=(offset2cylinder(disk, part_extended_end) > 1023?P_EXTENDX:P_EXTENDED);
1290 new_partition->status=STATUS_EXT;
1291 new_partition->part_offset=part_extended_offset;
1292 new_partition->part_size=part_extended_end - new_partition->part_offset + disk->sector_size;
1293 list_part=insert_new_partition(list_part, new_partition, 0, &insert_error);
1294 if(insert_error>0)
1295 free(new_partition);
1296 return list_part;
1297 }
1298
use_backup(disk_t * disk_car,const list_part_t * list_part,const int verbose,const int dump_ind,const unsigned int expert,char ** current_cmd)1299 static int use_backup(disk_t *disk_car, const list_part_t *list_part, const int verbose,const int dump_ind, const unsigned int expert, char**current_cmd)
1300 {
1301 const list_part_t *element;
1302 if(verbose>1)
1303 {
1304 log_trace("use_backup\n");
1305 }
1306 for(element=list_part;element!=NULL;element=element->next)
1307 {
1308 if(element->part->sb_offset!=0)
1309 {
1310 switch(element->part->upart_type)
1311 {
1312 case UP_FAT32:
1313 fat32_boot_sector(disk_car, element->part, verbose, dump_ind, expert,current_cmd);
1314 break;
1315 case UP_NTFS:
1316 ntfs_boot_sector(disk_car, element->part, verbose, expert, current_cmd);
1317 break;
1318 case UP_HFS:
1319 case UP_HFSP:
1320 case UP_HFSX:
1321 HFS_HFSP_boot_sector(disk_car, element->part, verbose, current_cmd);
1322 break;
1323 default:
1324 log_warning("Need to fix\n");
1325 log_partition(disk_car,element->part);
1326 break;
1327 }
1328 }
1329 }
1330 return 0;
1331 }
1332
warning_geometry(const list_part_t * list_part,disk_t * disk,const int verbose,char ** current_cmd)1333 static void warning_geometry(const list_part_t *list_part, disk_t *disk, const int verbose, char **current_cmd)
1334 {
1335 if(list_part!=NULL && (disk->arch==&arch_i386 || disk->arch==&arch_sun))
1336 { /* Correct disk geometry is necessary for successfull Intel and Sun partition recovery */
1337 const unsigned int heads_per_cylinder=get_geometry_from_list_part(disk, list_part, verbose);
1338 if(disk->geom.heads_per_cylinder!=heads_per_cylinder)
1339 {
1340 log_warning("Warning: the current number of heads per cylinder is %u but the correct value may be %u.\n",
1341 disk->geom.heads_per_cylinder, heads_per_cylinder);
1342 #ifdef HAVE_NCURSES
1343 if(*current_cmd==NULL)
1344 {
1345 warning_geometry_ncurses(disk, heads_per_cylinder);
1346 }
1347 #endif
1348 }
1349 }
1350 }
1351
ask_write_partition_table(const list_part_t * list_part_org,disk_t * disk_car,const int verbose,const int dump_ind,const int ask_part_order,const unsigned int expert,char ** current_cmd,unsigned int * menu,int * fast_mode)1352 static int ask_write_partition_table(const list_part_t *list_part_org, disk_t *disk_car, const int verbose, const int dump_ind, const int ask_part_order, const unsigned int expert, char **current_cmd, unsigned int *menu, int *fast_mode)
1353 {
1354 int res_interface_write;
1355 int do_again=0;
1356 int max_ext=0;
1357 int can_ask_minmax_ext=0;
1358 int no_confirm=0;
1359 list_part_t *list_part;
1360 list_part=reduce_structure(list_part_org);
1361 /* sort list_part */
1362 list_part=sort_partition_list(list_part);
1363 /* Create PC/Intel Extended partition */
1364 /* if(disk_car->arch==&arch_i386) */
1365 {
1366 list_part_t *parts;
1367 uint64_t partext_offset=0;
1368 uint64_t partext_size=0;
1369 list_part=add_ext_part_i386(disk_car, list_part, !max_ext, verbose);
1370 for(parts=list_part;parts!=NULL;parts=parts->next)
1371 if(parts->part->status==STATUS_EXT)
1372 {
1373 partext_offset=parts->part->part_offset;
1374 partext_size=parts->part->part_size;
1375 }
1376 if(partext_offset>0)
1377 {
1378 list_part=add_ext_part_i386(disk_car, list_part, max_ext, verbose);
1379 for(parts=list_part;parts!=NULL;parts=parts->next)
1380 if(parts->part->status==STATUS_EXT)
1381 {
1382 if(partext_offset!=parts->part->part_offset || partext_size!=parts->part->part_size)
1383 can_ask_minmax_ext=1;
1384 }
1385 }
1386 }
1387 list_part=disk_car->arch->init_part_order(disk_car,list_part);
1388 if(ask_part_order!=0)
1389 {
1390 /* Demande l'ordre des entrees dans le MBR */
1391 #ifdef HAVE_NCURSES
1392 ask_mbr_order_i386(disk_car,list_part);
1393 #endif
1394 /* Demande l'ordre des partitions etendues */
1395 }
1396 do
1397 {
1398 do_again=0;
1399 res_interface_write=interface_write(disk_car,list_part,((*fast_mode)<1),can_ask_minmax_ext, &no_confirm, current_cmd, menu);
1400 switch(res_interface_write)
1401 {
1402 case 'W':
1403 if(disk_car->arch == &arch_mac)
1404 {
1405 #ifdef HAVE_NCURSES
1406 write_part_mac_warning_ncurses();
1407 #endif
1408 }
1409 else if(disk_car->arch == &arch_sun)
1410 {
1411 #ifdef HAVE_NCURSES
1412 not_implemented("write_part_sun");
1413 #endif
1414 }
1415 else if(disk_car->arch == &arch_xbox)
1416 {
1417 #ifdef HAVE_NCURSES
1418 not_implemented("write_part_xbox");
1419 #endif
1420 }
1421 else if(disk_car->arch->write_part!=NULL)
1422 {
1423 if(no_confirm!=0
1424 #ifdef HAVE_NCURSES
1425 || ask_confirmation("Write partition table, confirm ? (Y/N)")!=0
1426 #endif
1427 )
1428 {
1429 log_info("write!\n");
1430 if(disk_car->arch->write_part(disk_car, list_part, RW, verbose))
1431 {
1432 display_message(msg_PART_WR_ERR);
1433 }
1434 else
1435 {
1436 use_backup(disk_car,list_part,verbose,dump_ind,expert,current_cmd);
1437 if(no_confirm==0)
1438 display_message("You will have to reboot for the change to take effect.\n");
1439 }
1440 }
1441 else
1442 log_info("Don't write, no confirmation\n");
1443 }
1444 break;
1445 case 0:
1446 if(disk_car->arch->write_part!=NULL)
1447 {
1448 log_info("simulate write!\n");
1449 disk_car->arch->write_part(disk_car, list_part, RO, verbose);
1450 }
1451 break;
1452 case 'S':
1453 if((*fast_mode) < 2)
1454 (*fast_mode)++;
1455 break;
1456 case 'E':
1457 max_ext=!max_ext;
1458 list_part=add_ext_part_i386(disk_car, list_part, max_ext, verbose);
1459 do_again=1;
1460 break;
1461 }
1462 }
1463 while(do_again==1);
1464 part_free_list(list_part);
1465 return res_interface_write;
1466 }
1467
interface_recovery(disk_t * disk_car,const list_part_t * list_part_org,const int verbose,const int dump_ind,const int align,const int ask_part_order,const unsigned int expert,char ** current_cmd)1468 int interface_recovery(disk_t *disk_car, const list_part_t *list_part_org, const int verbose, const int dump_ind, const int align, const int ask_part_order, const unsigned int expert, char **current_cmd)
1469 {
1470 int res_interface_write;
1471 int fast_mode=0;
1472 do
1473 {
1474 list_part_t *list_part;
1475 const list_part_t *element;
1476 unsigned int menu=0;
1477 if(fast_mode==0)
1478 menu=4; /* Search! */
1479 #ifdef HAVE_NCURSES
1480 aff_copy(stdscr);
1481 wmove(stdscr,4,0);
1482 wprintw(stdscr,"%s",disk_car->description(disk_car));
1483 wmove(stdscr,5,0);
1484 #endif
1485 list_part=search_part(disk_car, list_part_org, verbose, dump_ind, fast_mode, current_cmd);
1486 warning_geometry(list_part, disk_car, verbose, current_cmd);
1487 align_structure(list_part, disk_car, align);
1488
1489 disk_car->arch->init_structure(disk_car,list_part,verbose);
1490 if(verbose>0)
1491 {
1492 #ifdef TARGET_LINUX
1493 unsigned int i=0;
1494 #endif
1495 /* Write found partitions in the log file */
1496 log_info("\nResults\n");
1497 for(element=list_part;element!=NULL;element=element->next)
1498 log_partition(disk_car,element->part);
1499 #ifdef TARGET_LINUX
1500 if(list_part!=NULL)
1501 log_info("\nHint for advanced users: dmsetup may be used if you prefer to avoid rewriting the partition table for the moment:\n");
1502 for(element=list_part;element!=NULL;element=element->next)
1503 {
1504 const partition_t *partition=element->part;
1505 log_info("echo \"0 %llu linear %s %llu\" | dmsetup create test%u\n",
1506 (long long unsigned)(partition->part_size/512),
1507 disk_car->device,
1508 (long long unsigned)(partition->part_offset/512),
1509 i++);
1510 }
1511 #endif
1512 }
1513 log_flush();
1514 do
1515 {
1516 list_part=ask_structure(disk_car,list_part,verbose,current_cmd);
1517 if(disk_car->arch->test_structure(list_part)==0)
1518 {
1519 res_interface_write=ask_write_partition_table(list_part, disk_car, verbose, dump_ind, ask_part_order, expert, current_cmd, &menu, &fast_mode);
1520 }
1521 else
1522 {
1523 display_message("Invalid partition structure.\n");
1524 res_interface_write=0;
1525 }
1526 } while(res_interface_write == 'R');
1527 part_free_list(list_part);
1528 } while(res_interface_write=='S');
1529 return 0;
1530 }
1531