www.pudn.com > testdisk-6.6.rar > ADV.C


/*

    File: adv.c

    Copyright (C) 1998-2006 Christophe GRENIER 
  
    This software is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
  
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
  
    You should have received a copy of the GNU General Public License along
    with this program; if not, write the Free Software Foundation, Inc., 51
    Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

 */
#ifdef HAVE_CONFIG_H
#include 
#endif
 
#include 
#ifdef HAVE_STDLIB_H
#include 
#endif
#ifdef HAVE_STRING_H
#include 
#endif
#include 
#include "types.h"
#include "common.h"
#include "lang.h"
#include "intrf.h"
#include "fnctdsk.h"
#include "chgtype.h"
#include "testdisk.h"
#include "dirpart.h"
#include "fat.h"
#include "ntfs.h"
#include "hfsp.h"
#include "adv.h"
#include "analyse.h"
#include "intrface.h"
#include "io_redir.h"

#define INTER_ADV_X	0
#define INTER_ADV_Y	23
#define INTER_ADV	15

static int is_hfsp(const t_partition *partition);
static int is_linux(const t_partition *partition);

static int is_hfsp(const t_partition *partition)
{
  switch(partition->part_type_i386)
  {
    case P_HFSP:
      return 1;
  }
  switch(partition->part_type_mac)
  {
    case PMAC_HFS:
      return 1;
  }
  switch(partition->upart_type)
  {
    case UP_HFSP:
      return 1;
    default:
      break;
  }
  return 0;
}

static int is_linux(const t_partition *partition)
{
  switch(partition->part_type_i386)
  {
    case P_LINUX:
      return 1;
  }
  switch(partition->part_type_sun)
  {
    case PSUN_LINUX:
      return 1;
  }
  switch(partition->part_type_mac)
  {
    case PMAC_LINUX:
      return 1;
  }
  switch(partition->upart_type)
  {
    case UP_CRAMFS:
    case UP_EXT2:
    case UP_EXT3:
    case UP_JFS:
    case UP_RFS:
    case UP_RFS2:
    case UP_RFS3:
    case UP_RFS4:
    case UP_XFS:
    case UP_XFS2:
    case UP_XFS3:
    case UP_XFS4:
      return 1;
    default:
      break;
  }
  return 0;
}

void interface_adv(t_param_disk *disk_car, const int debug,const int dump_ind, const unsigned int expert, char**current_cmd)
{
  int quit;
  int offset=0;
  int current_element_num=0;
  int rewrite=1;
  const char *options;
  t_list_part *element;
  t_list_part *list_part;
  t_list_part *current_element;
  ecrit_rapport("\nInterface Advanced\n");
  list_part=disk_car->arch->read_part(disk_car,debug,0);
  current_element=list_part;
  for(element=list_part;element!=NULL;element=element->next)
  {
    aff_part_rapport(disk_car,element->part);
  }
  do
  {
    static struct MenuItem menuAdv[]=
    {
      {'t',"Type","Change type, this setting will not be saved on disk"},
      {'b',"Boot","Boot sector recovery"},
      {'s',"Superblock",NULL},
      {'q',"Quit","Return to main menu"},
      {0,NULL,NULL}
    };
    int menu=0;
    int i;
    int command;
    if(rewrite!=0)
    {
      aff_copy(stdscr);
      wmove(stdscr,4,0);
      wdoprintf(stdscr,"%s",disk_car->description(disk_car));
      if(list_part!=NULL)
	mvwaddstr(stdscr,6,0,msg_PART_HEADER_LONG);
      rewrite=0;
    }
    for(i=0,element=list_part;(element!=NULL) && (inext,i++);
    for(i=offset;(element!=NULL) && ((i-offset)next,i++)
    {
      wmove(stdscr,5+2+i-offset,0);
      wclrtoeol(stdscr);	/* before addstr for BSD compatibility */
      if(element==current_element)
      {
	wattrset(stdscr,A_STANDOUT);
	aff_part(stdscr,AFF_PART_ORDER,disk_car,element->part);
	wattroff(stdscr,A_STANDOUT);
      } else
      {
	aff_part(stdscr,AFF_PART_ORDER,disk_car,element->part);
      }
    }
    menu=0;
    if(current_element==NULL)
    {
      options="q";
      wmove(stdscr,5+2,0);
      wattrset(stdscr,A_STANDOUT);
      wdoprintf(stdscr,"No partition available.");
      wattroff(stdscr,A_STANDOUT);
    }
    else
    {
      if(is_fat(current_element->part) ||
	  is_ntfs(current_element->part))
      {
	options="tbq";
	menu=1;
      }
      else if(is_linux(current_element->part))
      {
	options="tsq";
	menuAdv[2].desc="Locate EXT2/EXT3 backup superblock";
	menu=1;
      }
      else if(is_hfsp(current_element->part))
      {
	options="tsq";
	menuAdv[2].desc="Locate HFS+ backup superblock";
	menu=1;
      }
      else
	options="tq";
    }
    quit=0;
    if(*current_cmd!=NULL)
    {
      int keep_asking;
      command='q';
      do
      {
	keep_asking=0;
	while(*current_cmd[0]==',')
	  (*current_cmd)++;
	if(strncmp(*current_cmd,"type",4)==0)
	{
	  (*current_cmd)+=4;
	  command='t';
	}
	else if(strncmp(*current_cmd,"boot",4)==0)
	{
	  (*current_cmd)+=4;
	  command='b';
	}
	else if(strncmp(*current_cmd,"superblock",10)==0)
	{
	  (*current_cmd)+=10;
	  command='s';
	}
	else
	{
	  unsigned int order;
	  order= atoi(*current_cmd);
	  while(*current_cmd[0]!=',' && *current_cmd[0]!='\0')
	    (*current_cmd)++;
	  for(element=list_part;element!=NULL && element->part->order!=order;element=element->next);
	  if(element!=NULL)
	  {
	    current_element=element;
	    keep_asking=1;
	  }
	}
      } while(keep_asking>0);
    }
    else
      command = wmenuSelect(stdscr,INTER_ADV_Y, INTER_ADV_X, menuAdv, 8, options,
	  MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, menu);
    switch(command)
    {
      case KEY_UP:
	if(current_element!=NULL)
	{
	  if(current_element->prev!=NULL)
	  {
	    current_element=current_element->prev;
	    current_element_num--;
	  }
	  if(current_element_numnext!=NULL)
	  {
	    current_element=current_element->next;
	    current_element_num++;
	  }
	  if(current_element_num>=offset+INTER_ADV)
	    offset++;
	}
	break;
      case 'q':
      case 'Q':
	quit=1;
	break;
      case 'b':
      case 'B':
	if(current_element!=NULL)
	{
	  if(is_fat32(current_element->part))
	  {
	    fat32_boot_sector(disk_car, current_element->part, debug, dump_ind, expert,current_cmd);
	    rewrite=1;
	  }
	  else if(is_fat(current_element->part))
	  {
	    fat1x_boot_sector(disk_car, current_element->part, debug, dump_ind,expert,current_cmd);
	    rewrite=1;
	  }
	  else if(is_ntfs(current_element->part))
	  {
	    ntfs_boot_sector(disk_car, current_element->part, debug, dump_ind, expert, current_cmd);
	    rewrite=1;
	  }
	}
	break;
      case 's':
      case 'S':
	if(current_element!=NULL)
	{
	  if(is_linux(current_element->part))
	  {
	    t_list_part *list_sb=search_superblock(disk_car,current_element->part,debug,dump_ind,1);
	    interface_superblock(disk_car,list_sb,current_cmd);
	    delete_list_part(list_sb);
	  }
	  if(is_hfsp(current_element->part))
	  {
	    HFSP_boot_sector(disk_car, current_element->part, debug, dump_ind, expert, current_cmd);
	  }
	  rewrite=1;
	}
	break;
      case 't':
      case 'T':
	if(current_element!=NULL)
	{
	  change_part_type(disk_car,current_element->part, current_cmd);
	  rewrite=1;
	}
	break;
    }
  } while(quit==0);
  delete_list_part(list_part);
}

int fat1x_boot_sector(t_param_disk *disk_car, t_partition *partition, const int debug, const int dump_ind, const unsigned int expert, char **current_cmd)
{
  unsigned char *buffer_bs;
  const char *options="DR";
  int rescan=1;
  struct MenuItem menu_fat1x[]=
  {
    { 'P', "Previous",""},
    { 'N', "Next","" },
    { 'Q', "Quit","Return to Advanced menu"},
    { 'R', "Rebuild BS","Rebuild boot sector"},
    { 'D', "Dump","Dump boot sector and backup boot sector"},
    { 'C', "Repair FAT","Very Dangerous! Expert only"},
    { 'I', "Init Root","Init root directory: Very Dangerous! Expert only"},
    { 0, NULL, NULL }
  };
  buffer_bs=(unsigned char*)MALLOC(FAT1x_BOOT_SECTOR_SIZE);
  while(1)
  {
    int command;
    aff_buffer(BUFFER_RESET,"Q");
    if(rescan==1)
    {
      aff_copy(stdscr);
      wmove(stdscr,4,0);
      wdoprintf(stdscr,"%s",disk_car->description(disk_car));
      mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
      wmove(stdscr,6,0);
      aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
      ecrit_rapport("\nfat1x_boot_sector\n");
      aff_part_rapport(disk_car,partition);
      if(expert==0)
	options="DRC";
      else
	options="DRCI";
      aff_buffer(BUFFER_ADD,"Boot sector\n");
      if(disk_car->read(disk_car,FAT1x_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset)!=0)
      {
	aff_buffer(BUFFER_ADD,"fat1x_boot_sector: Can't read boot sector.\n");
	memset(buffer_bs,0,FAT1x_BOOT_SECTOR_SIZE);
      }
      if(test_FAT(disk_car,(const struct fat_boot_sector *)buffer_bs,partition,debug,0)==0)
      {
	aff_buffer(BUFFER_ADD,"OK\n");
      }
      aff_buffer(BUFFER_ADD,"\n");
      aff_buffer(BUFFER_ADD,"A valid FAT Boot sector must be present in order to access\n");
      aff_buffer(BUFFER_ADD,"any data; even if the partition is not bootable.\n");
      rescan=0;
    }
    if(*current_cmd!=NULL)
    {
      command=0;
      while(*current_cmd[0]==',')
	(*current_cmd)++;
      if(strncmp(*current_cmd,"rebuildbs",9)==0)
      {
	(*current_cmd)+=9;
	command='R';
      }
      else if(strncmp(*current_cmd,"dump",4)==0)
      {
	(*current_cmd)+=4;
	command='D';
      }
      else if(strncmp(*current_cmd,"repairfat",8)==0)
      {
	(*current_cmd)+=8;
	if(strchr(options,'C')!=NULL)
	  command='C';
      }
      else if(strncmp(*current_cmd,"initroot",8)==0)
      {
	(*current_cmd)+=8;
	if(strchr(options,'I')!=NULL)
	    command='I';
      }
      screen_buffer_to_log();
    }
    else
      command=screen_buffer_display(stdscr,options,menu_fat1x);
    switch(command)
    {
      case 0:
	free(buffer_bs);
	return 0;
      case 'R': /* R : rebuild boot sector */
	rebuild_FAT_BS(disk_car,partition,debug,dump_ind,1,expert,current_cmd);
	rescan=1;
	break;
      case 'D':
	{
	  WINDOW *window=newwin(0,0,0,0);	/* full screen */
	  keypad(window, TRUE); /* Need it to get arrow key */
	  aff_copy(window);
	  wmove(window,4,0);
	  wdoprintf(window,"%s",disk_car->description(disk_car));
	  wmove(window,5,0);
	  aff_part(window,AFF_PART_ORDER,disk_car,partition);
	  ecrit_rapport("Boot sector\n");
	  mvwaddstr(window,6,0, "Boot sector");
	  dump(window,buffer_bs,FAT1x_BOOT_SECTOR_SIZE);
	  delwin(window);
	  (void) clearok(stdscr, TRUE);
#ifdef HAVE_TOUCHWIN
	  touchwin(stdscr);
#endif
	}
	break;
      case 'C':
	repair_FAT_table(disk_car,partition,debug);
	break;
      case 'I':
	FAT_init_rootdir(disk_car,partition,debug);
	break;
    }
  }
}

int fat32_boot_sector(t_param_disk *disk_car, t_partition *partition, const int debug, const int dump_ind, const unsigned int expert, char **current_cmd)
{
  unsigned char *buffer_bs;
  unsigned char *buffer_backup_bs;
  const char *options="DRC";
  int rescan=1;
  struct MenuItem menu_fat32[]=
  {
    { 'P', "Previous",""},
    { 'N', "Next","" },
    { 'Q', "Quit","Return to Advanced menu"},
    { 'O', "Org. BS","Copy boot sector over backup sector"},
    { 'B', "Backup BS","Copy backup boot sector over boot sector"},
    { 'R', "Rebuild BS","Rebuild boot sector"},
    { 'D', "Dump","Dump boot sector and backup boot sector"},
    { 'C', "Repair FAT","Very Dangerous! Expert only"},
    { 0, NULL, NULL }
  };
  buffer_bs=(unsigned char*)MALLOC(3*disk_car->sector_size);
  buffer_backup_bs=(unsigned char*)MALLOC(3*disk_car->sector_size);
  while(1)
  {
    int command;
    aff_buffer(BUFFER_RESET,"Q");
    if(rescan==1)
    {
      int opt_over=0;
      int opt_B=0;
      int opt_O=0;
      options="DRC";
      aff_copy(stdscr);
      wmove(stdscr,4,0);
      wdoprintf(stdscr,"%s",disk_car->description(disk_car));
      mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
      wmove(stdscr,6,0);
      aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
      ecrit_rapport("\nfat32_boot_sector\n");
      aff_part_rapport(disk_car,partition);
      aff_buffer(BUFFER_ADD,"Boot sector\n");
      if(disk_car->read(disk_car,3*disk_car->sector_size, buffer_bs, partition->part_offset)!=0)
      {
	aff_buffer(BUFFER_ADD,"fat32_boot_sector: Can't read boot sector.\n");
	memset(buffer_bs,0,3*disk_car->sector_size);
      }
      if(test_FAT(disk_car,(struct fat_boot_sector *)buffer_bs,partition,debug,0)==0)
      {
	aff_buffer(BUFFER_ADD,"OK\n");
	if(partition->upart_type==UP_FAT32)
	{
	  opt_O=1;
	  opt_over=1;
	}
	else
	{
	  aff_buffer(BUFFER_ADD,"Warning: valid FAT bootsector but not a FAT32 one!");
	}
      }
      aff_buffer(BUFFER_ADD,"\nBackup boot sector\n");
      if(disk_car->read(disk_car,3*disk_car->sector_size, buffer_backup_bs, partition->part_offset+6*disk_car->sector_size)!=0)
      {
	aff_buffer(BUFFER_ADD,"fat32_boot_sector: Can't read backup boot sector.\n");
	memset(buffer_backup_bs,0,3*disk_car->sector_size);
      }
      if(test_FAT(disk_car,(struct fat_boot_sector *)buffer_backup_bs,partition,debug,0)==0)
      {
	aff_buffer(BUFFER_ADD,"OK\n");
	if(partition->upart_type==UP_FAT32)
	{
	  opt_B=1;
	  opt_over=1;
	}
	else
	{
	  aff_buffer(BUFFER_ADD,"Warning: valid FAT backup bootsector but not a FAT32 one!");
	}
      }
      aff_buffer(BUFFER_ADD,"\n");
      if((memcmp(buffer_bs,buffer_backup_bs,0x3E8)==0)&&(memcmp(buffer_bs+0x3F0,buffer_backup_bs+0x3F0,0x600-0x3F0))==0)
      {
	aff_buffer(BUFFER_ADD,"Sectors are identical.\n");
	opt_over=0;
      }
      else
      {
	if(memcmp(buffer_bs,buffer_backup_bs,0x200)!=0)
	  aff_buffer(BUFFER_ADD,"First sectors (Boot code and partition information) are not identical.\n");
	if((memcmp(buffer_bs+disk_car->sector_size, buffer_backup_bs+disk_car->sector_size,0x1E8)!=0)||
	    (memcmp(buffer_bs+disk_car->sector_size+0x1F0, buffer_backup_bs+disk_car->sector_size+0x1F0,0x200-0x1F0)!=0))
	  aff_buffer(BUFFER_ADD,"Second sectors (cluster information) are not identical.\n");
	if(memcmp(buffer_bs+2*disk_car->sector_size, buffer_backup_bs+2*disk_car->sector_size,0x200)!=0)
	  aff_buffer(BUFFER_ADD,"Third sectors (Second part of boot code) are not identical.\n");
      }
      aff_buffer(BUFFER_ADD,"\n");
      aff_buffer(BUFFER_ADD,"A valid FAT Boot sector must be present in order to access\n");
      aff_buffer(BUFFER_ADD,"any data; even if the partition is not bootable.\n");
      if(opt_over!=0)
      {
	if(opt_B!=0 && opt_O!=0)
	  options="DOBR";
	else if(opt_B!=0)
	  options="DBR";
	else if(opt_O!=0)
	  options="DOR";
      }
      rescan=0;
    }
    if(*current_cmd!=NULL)
    {
      command=0;
      while(*current_cmd[0]==',')
	(*current_cmd)++;
      if(strncmp(*current_cmd,"rebuildbs",9)==0)
      {
	(*current_cmd)+=9;
	command='R';
      }
      else if(strncmp(*current_cmd,"dump",4)==0)
      {
	(*current_cmd)+=4;
	command='D';
      }
      else if(strncmp(*current_cmd,"repairfat",8)==0)
      {
	(*current_cmd)+=8;
	if(strchr(options,'C')!=NULL)
	  command='C';
      }
      else if(strncmp(*current_cmd,"originalfat",11)==0)
      {
	(*current_cmd)+=11;
	if(strchr(options,'O')!=NULL)
	    command='O';
      }
      else if(strncmp(*current_cmd,"backupfat",9)==0)
      {
	(*current_cmd)+=9;
	if(strchr(options,'B')!=NULL)
	    command='B';
      }
      screen_buffer_to_log();
    }
    else
      command=screen_buffer_display(stdscr,options,menu_fat32);
    switch(command)
    {
      case 0:
	free(buffer_bs);
	free(buffer_backup_bs);
	return 0;
      case 'O': /* O : copy original boot sector over backup boot */
	if(ask_confirmation("Copy original FAT32 boot sector over backup boot, confirm ? (Y/N)")!=0)
	{
	  ecrit_rapport("copy original boot sector over backup boot\n");
	  if(disk_car->write(disk_car,3*disk_car->sector_size, buffer_bs, partition->part_offset+6*disk_car->sector_size)!=0)
	  {
	    display_message("Write error: Can't overwrite FAT32 backup boot sector\n");
	  }
	  rescan=1;
	}
	break;
      case 'B': /* B : copy backup boot sector over boot sector */
	if(ask_confirmation("Copy backup FAT32 boot sector over boot sector, confirm ? (Y/N)")!=0)
	{
	  ecrit_rapport("copy backup boot sector over boot sector\n");
	  if(disk_car->write(disk_car,3*disk_car->sector_size, buffer_backup_bs, partition->part_offset)!=0)
	  {
	    display_message("Write error: Can't overwrite FAT32 boot sector\n");
	  }
	  rescan=1;
	}
	break;
      case 'R': /* R : rebuild boot sector */
	rebuild_FAT_BS(disk_car,partition,debug,dump_ind,1,expert,current_cmd);
	rescan=1;
	break;
      case 'D':
	{
	  WINDOW *window=newwin(0,0,0,0);	/* full screen */
	  keypad(window, TRUE); /* Need it to get arrow key */
	  aff_copy(window);
	  wmove(window,4,0);
	  wdoprintf(window,"%s",disk_car->description(disk_car));
	  wmove(window,5,0);
	  aff_part(window,AFF_PART_ORDER,disk_car,partition);
	  ecrit_rapport("Boot sector                        Backup boot sector\n");
	  mvwaddstr(window,6,0, "Boot sector                        Backup boot sector");
	  dump2(window,buffer_bs,buffer_backup_bs,3*disk_car->sector_size);
	  delwin(window);
	  (void) clearok(stdscr, TRUE);
#ifdef HAVE_TOUCHWIN
	  touchwin(stdscr);
#endif
	  dump_2fat_rapport((const struct fat_boot_sector*)buffer_bs,(const struct fat_boot_sector*)buffer_backup_bs,UP_FAT32,disk_car->sector_size);
	}
	break;
      case 'C':
	repair_FAT_table(disk_car,partition,debug);
	break;
    }
  }
}

int ntfs_boot_sector(t_param_disk *disk_car, t_partition *partition, const int debug, const int dump_ind, const unsigned int expert, char **current_cmd)
{
  unsigned char *buffer_bs;
  unsigned char *buffer_backup_bs;
  const char *options="";
  int rescan=1;
  struct MenuItem menu_ntfs[]=
  {
    { 'P', "Previous",""},
    { 'N', "Next","" },
    { 'Q', "Quit","Return to Advanced menu"},
    { 'L', "List", "List directories and files" },
    { 'O', "Org. BS","Copy boot sector over backup sector"},
    { 'B', "Backup BS","Copy backup boot sector over boot sector"},
    { 'R', "Rebuild BS","Rebuild boot sector"},
    { 'M', "Repair MFT","Check MFT"},
    { 'D', "Dump","Dump boot sector and backup boot sector"},
    { 0, NULL, NULL }
  };
  buffer_bs=(unsigned char*)MALLOC(NTFS_BOOT_SECTOR_SIZE);
  buffer_backup_bs=(unsigned char*)MALLOC(NTFS_BOOT_SECTOR_SIZE);

  while(1)
  {
    int command;
    aff_buffer(BUFFER_RESET,"Q");
    if(rescan==1)
    {
      int opt_over=0;
      int opt_B=0;
      int opt_O=0;
      options="DRML";
      aff_copy(stdscr);
      wmove(stdscr,4,0);
      wdoprintf(stdscr,"%s",disk_car->description(disk_car));
      mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
      wmove(stdscr,6,0);
      aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
      ecrit_rapport("\nntfs_boot_sector\n");
      aff_part_rapport(disk_car,partition);
      aff_buffer(BUFFER_ADD,"Boot sector\n");
      if(disk_car->read(disk_car,NTFS_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset)!=0)
      {
	aff_buffer(BUFFER_ADD,"ntfs_boot_sector: Can't read boot sector.\n");
	memset(buffer_bs,0,NTFS_BOOT_SECTOR_SIZE);
      }
      if(test_NTFS(disk_car,(struct ntfs_boot_sector*)buffer_bs,partition,debug,0)==0)
      {
	aff_buffer(BUFFER_ADD,"Status: OK\n");
	opt_O=1;
	opt_over=1;
      }
      else
      {
	aff_buffer(BUFFER_ADD,"Status: Bad\n");
      }
      aff_buffer(BUFFER_ADD,"\nBackup boot sector\n");
      if(disk_car->read(disk_car,NTFS_BOOT_SECTOR_SIZE, buffer_backup_bs, partition->part_offset+partition->part_size-disk_car->sector_size)!=0)
      {
	aff_buffer(BUFFER_ADD,"ntfs_boot_sector: Can't read backup boot sector.\n");
	memset(buffer_backup_bs,0,NTFS_BOOT_SECTOR_SIZE);
      }
      if(test_NTFS(disk_car,(struct ntfs_boot_sector*)buffer_backup_bs,partition,debug,0)==0)
      {
	aff_buffer(BUFFER_ADD,"Status: OK\n");
	opt_B=1;
	opt_over=1;
      }
      else
      {
	aff_buffer(BUFFER_ADD,"Status: Bad\n");
      }
      aff_buffer(BUFFER_ADD,"\n");
      if(memcmp(buffer_bs,buffer_backup_bs,NTFS_BOOT_SECTOR_SIZE)==0)
      {
	dump_ntfs_rapport((const struct ntfs_boot_sector *)buffer_bs);
	aff_buffer(BUFFER_ADD,"Sectors are identical.\n");
	opt_over=0;
      }
      else
      {
	dump_2ntfs_rapport((const struct ntfs_boot_sector *)buffer_bs, (const struct ntfs_boot_sector *)buffer_backup_bs);
	aff_buffer(BUFFER_ADD,"Sectors are not identical.\n");
      }
      aff_buffer(BUFFER_ADD,"\n");
      aff_buffer(BUFFER_ADD,"A valid NTFS Boot sector must be present in order to access\n");
      aff_buffer(BUFFER_ADD,"any data; even if the partition is not bootable.\n");
      if(opt_over!=0)
      {
	if(opt_B!=0 && opt_O!=0)
	  options="DOBRL";
	else if(opt_B!=0)
	  options="DBRL";
	else if(opt_O!=0)
	  options="DORL";
      }
      rescan=0;
    }
    if(*current_cmd!=NULL)
    {
      command=0;
      while(*current_cmd[0]==',')
	(*current_cmd)++;
      if(strncmp(*current_cmd,"rebuildbs",9)==0)
      {
	(*current_cmd)+=9;
	command='R';
      }
      else if(strncmp(*current_cmd,"dump",4)==0)
      {
	(*current_cmd)+=4;
	command='D';
      }
      else if(strncmp(*current_cmd,"list",4)==0)
      {
	(*current_cmd)+=4;
	command='L';
      }
      else if(strncmp(*current_cmd,"originalntfs",11)==0)
      {
	(*current_cmd)+=11;
	if(strchr(options,'O')!=NULL)
	    command='O';
      }
      else if(strncmp(*current_cmd,"backupntfs",9)==0)
      {
	(*current_cmd)+=9;
	if(strchr(options,'B')!=NULL)
	    command='B';
      }
      screen_buffer_to_log();
    }
    else
      command=screen_buffer_display(stdscr,options,menu_ntfs);
    switch(command)
    {
      case 0:
        free(buffer_bs);
        free(buffer_backup_bs);
	return 0;
      case 'O': /* O : copy original boot sector over backup boot */
	if(ask_confirmation("Copy original NTFS boot sector over backup boot, confirm ? (Y/N)")!=0)
	{
	  ecrit_rapport("copy original boot sector over backup boot\n");
	  if(disk_car->write(disk_car,NTFS_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset+partition->part_size-disk_car->sector_size)!=0)
	  {
	    display_message("Write error: Can't overwrite NTFS backup boot sector\n");
	  }
	  rescan=1;
	}
	break;
      case 'B': /* B : copy backup boot sector over boot sector */
	if(ask_confirmation("Copy backup NTFS boot sector over boot sector, confirm ? (Y/N)")!=0)
	{
	  ecrit_rapport("copy backup boot sector over boot sector\n");
	  if(disk_car->write(disk_car,NTFS_BOOT_SECTOR_SIZE, buffer_backup_bs, partition->part_offset)!=0)
	  {
	    display_message("Write error: Can't overwrite NTFS boot sector\n");
	  }
	  rescan=1;
	}
	break;
      case 'L':
	if(strchr(options,'O')==NULL && strchr(options,'B')!=NULL)
	{
	  io_redir_add_redir(disk_car,partition->part_offset,sizeof(buffer_backup_bs),0,buffer_backup_bs);
	  dir_partition(disk_car, partition, 0,current_cmd);
	  io_redir_del_redir(disk_car,partition->part_offset);
	}
	else
	  dir_partition(disk_car, partition, 0,current_cmd);
	break;
      case 'M':
        repair_MFT(disk_car, partition, debug);
	break;
      case 'R': /* R : rebuild boot sector */
	rebuild_NTFS_BS(disk_car,partition,debug,dump_ind,1,expert,current_cmd);
	rescan=1;
	break;
      case 'D':
	{
	  WINDOW *window=newwin(0,0,0,0);	/* full screen */
	  keypad(window, TRUE); /* Need it to get arrow key */
	  aff_copy(window);
	  wmove(window,4,0);
	  wdoprintf(window,"%s",disk_car->description(disk_car));
	  wmove(window,5,0);
	  aff_part(window,AFF_PART_ORDER,disk_car,partition);
	  ecrit_rapport("Boot sector                        Backup boot sector\n");
	  mvwaddstr(window,6,0, "Boot sector                        Backup boot sector");
	  dump2(window,buffer_bs,buffer_backup_bs,NTFS_BOOT_SECTOR_SIZE);
	  delwin(window);
	  (void) clearok(stdscr, TRUE);
#ifdef HAVE_TOUCHWIN
	  touchwin(stdscr);
#endif
	}
	break;
    }
  }
}

int HFSP_boot_sector(t_param_disk *disk_car, t_partition *partition, const int debug, const int dump_ind, const unsigned int expert, char **current_cmd)
{
  unsigned char *buffer_bs;
  unsigned char *buffer_backup_bs;
  const char *options="";
  int rescan=1;
  struct MenuItem menu_hfsp[]=
  {
    { 'P', "Previous",""},
    { 'N', "Next","" },
    { 'Q', "Quit","Return to Advanced menu"},
    { 'O', "Org. BS","Copy superblock over backup sector"},
    { 'B', "Backup BS","Copy backup superblock over superblock"},
    { 'D', "Dump","Dump superblock and backup superblock"},
    { 0, NULL, NULL }
  };
  buffer_bs=(unsigned char*)MALLOC(HFSP_BOOT_SECTOR_SIZE);
  buffer_backup_bs=(unsigned char*)MALLOC(HFSP_BOOT_SECTOR_SIZE);

  while(1)
  {
    int command;
    aff_buffer(BUFFER_RESET,"Q");
    if(rescan==1)
    {
      int opt_over=0;
      int opt_B=0;
      int opt_O=0;
      options="D";
      aff_copy(stdscr);
      wmove(stdscr,4,0);
      wdoprintf(stdscr,"%s",disk_car->description(disk_car));
      mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
      wmove(stdscr,6,0);
      aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
      ecrit_rapport("\nHFSP_boot_sector\n");
      aff_part_rapport(disk_car,partition);
      aff_buffer(BUFFER_ADD,"Superblock\n");
      if(disk_car->read(disk_car,HFSP_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset+0x400)!=0)
      {
	aff_buffer(BUFFER_ADD,"HFSP_boot_sector: Can't read superblock.\n");
	memset(buffer_bs,0,HFSP_BOOT_SECTOR_SIZE);
      }
      if(test_HFSP(disk_car,(struct hfsp_vh*)buffer_bs,partition,debug,0)==0)
      {
	aff_buffer(BUFFER_ADD,"OK\n");
	opt_O=1;
	opt_over=1;
      }
      else
      {
	aff_buffer(BUFFER_ADD,"Bad\n");
      }
      aff_buffer(BUFFER_ADD,"\nBackup superblock\n");
      if(disk_car->read(disk_car,HFSP_BOOT_SECTOR_SIZE, buffer_backup_bs, partition->part_offset+partition->part_size-0x400)!=0)
      {
	aff_buffer(BUFFER_ADD,"HFSP_boot_sector: Can't read backup superblock.\n");
	memset(buffer_backup_bs,0,HFSP_BOOT_SECTOR_SIZE);
      }
      if(test_HFSP(disk_car,(struct hfsp_vh*)buffer_backup_bs,partition,debug,0)==0)
      {
	aff_buffer(BUFFER_ADD,"OK\n");
	opt_B=1;
	opt_over=1;
      }
      else
      {
	aff_buffer(BUFFER_ADD,"Bad\n");
      }
      aff_buffer(BUFFER_ADD,"\n");
      if(memcmp(buffer_bs,buffer_backup_bs,HFSP_BOOT_SECTOR_SIZE)==0)
      {
	aff_buffer(BUFFER_ADD,"Sectors are identical.\n");
	opt_over=0;
      }
      else
      {
	aff_buffer(BUFFER_ADD,"Sectors are not identical.\n");
      }
      if(opt_over!=0)
      {
	if(opt_B!=0 && opt_O!=0)
	  options="DOB";
	else if(opt_B!=0)
	  options="DB";
	else if(opt_O!=0)
	  options="DO";
      }
      rescan=0;
    }
    if(*current_cmd!=NULL)
    {
      command=0;
      while(*current_cmd[0]==',')
	(*current_cmd)++;
      if(strncmp(*current_cmd,"dump",4)==0)
      {
	(*current_cmd)+=4;
	command='D';
      }
      else if(strncmp(*current_cmd,"originalhfsp",11)==0)
      {
	(*current_cmd)+=11;
	if(strchr(options,'O')!=NULL)
	    command='O';
      }
      else if(strncmp(*current_cmd,"backuphfsp",9)==0)
      {
	(*current_cmd)+=9;
	if(strchr(options,'B')!=NULL)
	    command='B';
      }
      screen_buffer_to_log();
    }
    else
      command=screen_buffer_display(stdscr,options,menu_hfsp);
    switch(command)
    {
      case 0:
        free(buffer_bs);
        free(buffer_backup_bs);
	return 0;
      case 'O': /* O : copy original superblock over backup boot */
	if(ask_confirmation("Copy original HFSP superblock over backup boot, confirm ? (Y/N)")!=0)
	{
	  ecrit_rapport("copy original superblock over backup boot\n");
	  if(disk_car->write(disk_car,HFSP_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset+partition->part_size-0x400)!=0)
	  {
	    display_message("Write error: Can't overwrite HFSP backup superblock\n");
	  }
	  rescan=1;
	}
	break;
      case 'B': /* B : copy backup superblock over main superblock */
	if(ask_confirmation("Copy backup HFSP superblock over main superblock, confirm ? (Y/N)")!=0)
	{
	  ecrit_rapport("copy backup superblock over main superblock\n");
	  if(disk_car->write(disk_car,HFSP_BOOT_SECTOR_SIZE, buffer_backup_bs, partition->part_offset+0x400)!=0)
	  {
	    display_message("Write error: Can't overwrite HFSP main superblock\n");
	  }
	  rescan=1;
	}
	break;
      case 'D':
	{
	  WINDOW *window=newwin(0,0,0,0);	/* full screen */
	  keypad(window, TRUE); /* Need it to get arrow key */
	  aff_copy(window);
	  wmove(window,4,0);
	  wdoprintf(window,"%s",disk_car->description(disk_car));
	  wmove(window,5,0);
	  aff_part(window,AFF_PART_ORDER,disk_car,partition);
	  ecrit_rapport("Superblock                        Backup superblock\n");
	  mvwaddstr(window,6,0, "Superblock                        Backup superblock");
	  dump2(window,buffer_bs,buffer_backup_bs,HFSP_BOOT_SECTOR_SIZE);
	  delwin(window);
	  (void) clearok(stdscr, TRUE);
#ifdef HAVE_TOUCHWIN
	  touchwin(stdscr);
#endif
	}
	break;
    }
  }
}