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