/*
File: fat_adv.c
Copyright (C) 1998-2009 Christophe GRENIER <grenier@cgsecurity.org>
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 <config.h>
#endif
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include "types.h"
#include "common.h"
#include "fat.h"
#include "lang.h"
#include "fnctdsk.h"
#include "intrf.h"
#include "intrfn.h"
#include "dir.h"
#include "dirpart.h"
#include "fat_dir.h"
#include "io_redir.h"
#include "log.h"
#include "log_part.h"
#include "fat_adv.h"
#include "fat_cluster.h"
#ifdef HAVE_NCURSES
#include "fatn.h"
#endif
#define INTER_FAT_ASK_X 0
#define INTER_FAT_ASK_Y 23
#define INTER_FATBS_X 0
#define INTER_FATBS_Y 22
extern const char *monstr[];
typedef struct info_offset_struct info_offset_t;
struct info_offset_struct
{
unsigned long int offset;
unsigned int nbr;
unsigned int fat_type;
};
static upart_type_t fat_find_info(disk_t *disk_car,unsigned int*reserved, unsigned int*fat_length, const partition_t *partition,const uint64_t max_offset,const int p_fat12,const int p_fat16,const int p_fat32,const int verbose,const int dump_ind,const int interface, const unsigned int expert, unsigned int *fats);
static int fat_find_type(disk_t *disk_car,const partition_t *partition,const uint64_t max_offset,const int p_fat12,const int p_fat16,const int p_fat32,const int verbose,const int dump_ind,const int interface,unsigned int *nbr_offset,info_offset_t *info_offset, const unsigned int max_nbr_offset);
static unsigned int fat_find_fat_start(const unsigned char *buffer,const int p_fat12, const int p_fat16, const int p_fat32,unsigned long int*fat_offset, const unsigned int sector_size);
static void create_fat_boot_sector(disk_t *disk_car, partition_t *partition, const unsigned int reserved, const int verbose, const unsigned int dir_entries, const unsigned long int root_cluster, const unsigned int sectors_per_cluster, const unsigned int fat_length,const int interface, const upart_type_t upart_type, const unsigned int fats, char **current_cmd);
static unsigned int fat32_find_root_cluster(disk_t *disk_car,const partition_t *partition,const unsigned int sectors_per_cluster, const unsigned long int no_of_cluster, const unsigned int reserved, const unsigned int fat_length, const int interface, const int verbose, const unsigned int expert, const unsigned int first_free_cluster, const unsigned int fats);
static int write_FAT_boot_code_aux(unsigned char *buffer);
static int find_dir_entries(disk_t *disk_car,const partition_t *partition, const unsigned int offset,const int verbose);
static int analyse_dir_entries(disk_t *disk_car,const partition_t *partition, const unsigned int offset, const int verbose);
static int analyse_dir_entries2(disk_t *disk_car,const partition_t *partition, const unsigned int reserved, const unsigned int fat_length,const int verbose, unsigned int root_size_max,const upart_type_t upart_type, const unsigned int fats);
static int calcul_sectors_per_cluster(const upart_type_t upart_type, const unsigned long int data_size, const unsigned int fat_length, const unsigned int sector_size);
static int check_FAT_dir_entry(const unsigned char *entry, const unsigned int entry_nr);
static unsigned long int get_subdirectory(disk_t *disk_car,const uint64_t hd_offset, const unsigned long int i);
#ifdef HAVE_NCURSES
static void fat_date_unix2dos(int unix_date,unsigned short *mstime, unsigned short *msdate);
static int fat32_create_rootdir(disk_t *disk_car,const partition_t *partition, const unsigned int reserved, const unsigned int fat_length, const unsigned int root_cluster, const unsigned int sectors_per_cluster, const int verbose, file_data_t *rootdir_list, const unsigned int fats);
static upart_type_t select_fat_info(const info_offset_t *info_offset, const unsigned int nbr_offset,unsigned int*reserved, unsigned int*fat_length, const unsigned long int max_sector_offset, unsigned int *fats);
#endif
/*
* 0 entry is free
* 1 entry is used
* 2 not an entry
* */
static int check_FAT_dir_entry(const unsigned char *entry, const unsigned int entry_nr)
{
int i;
if((entry[0xB]&ATTR_EXT_MASK)==ATTR_EXT)
return 1;
/* log_trace("check_FAT_dir_entry %02x\n",*(entry+0)); */
if(entry[0]==0)
{
for(i=0;i<0x20;i++)
if(entry[i]!='\0')
return 2;
return 0;
}
if(entry[0]==0x20)
return 2;
if(entry[0]==0xE5)
return 1;
if(entry_nr<10 && (entry[0xB]&ATTR_VOLUME)==ATTR_VOLUME)
return 1;
for(i=0;i<8+3;i++)
{
const unsigned char car=entry[i];
if((car>=0x06 && car<=0x1f)||
(car>=0x3a && car<=0x3f)||
(car>='a' && car<='z'))
return 2;
switch(car)
{
case 0x1:
case 0x2:
case 0x3:
case 0x4:
case '"':
case '*':
case '+':
case ',':
case '.':
case '/':
case '[':
case '\\':
case ']':
case '|':
/*log_trace("check_FAT_dir_entry bad %c (%02x)\n",car,car); */
return 2;
default:
/*log_trace("check_FAT_dir_entry good %c (%02x)\n",car,car); */
break;
}
}
return 1;
}
/* */
static unsigned long int get_subdirectory(disk_t *disk_car,const uint64_t hd_offset,const unsigned long int i)
{
unsigned char buffer[DEFAULT_SECTOR_SIZE];
if(disk_car->pread(disk_car, &buffer, sizeof(buffer), hd_offset) != sizeof(buffer))
{
log_error("fat_dir, get_subdirectory(), can't read directory\n");
return 1;
}
/* dump_ncurses(buffer,DEFAULT_SECTOR_SIZE); */
/* 12345678123*/
if(memcmp(&buffer[0],". ",8+3)!=0)
return 1;
if((unsigned)((buffer[0x15]<<24)|(buffer[0x14]<<16)|(buffer[0x1B]<<8)|buffer[0x1A])!=i)
return 1;
/* 12345678123*/
if(memcmp(&buffer[0x20],".. ",8+3)!=0)
return 1;
return (buffer[0x35]<<24)+(buffer[0x34]<<16)+(buffer[0x3B]<<8)+buffer[0x3A];
}
#ifdef HAVE_NCURSES
#define INTER_DIR 16
static int ask_root_directory(disk_t *disk_car, const partition_t *partition, const file_data_t*dir_list, const unsigned long int cluster)
{
/* Return value
* -1: quit
* 1: back
* other: new cluster
* */
int car='A';
int quit=0;
int offset=0;
int pos_num=0;
const file_data_t *current_file;
const file_data_t *pos=dir_list;
WINDOW *window;
window=newwin(LINES, COLS, 0, 0); /* full screen */
aff_copy(window);
wmove(window,4,0);
aff_part(window,AFF_PART_ORDER|AFF_PART_STATUS,disk_car,partition);
wmove(window,6,0);
wprintw(window,"Answer Y(es), N(o), Q(uit) or A(bort interactive mode). N or A if not sure.");
curs_set(1);
do
{
int i;
for(i=0,current_file=dir_list;(current_file!=NULL) && (i<offset);current_file=current_file->next,i++);
for(i=offset;(current_file!=NULL) &&((i-offset)<INTER_DIR);i++,current_file=current_file->next)
{
struct tm *tm_p;
char str[11];
char datestr[80];
wmove(window,8+i-offset,0);
wclrtoeol(window); /* before addstr for BSD compatibility */
if(current_file==pos)
{
wattrset(window, A_REVERSE);
waddstr(window, ">");
}
else
waddstr(window, " ");
if(current_file->stat.st_mtime!=0