9
0
Fork 0

Merge branch 'for-next/fat-detection'

This commit is contained in:
Sascha Hauer 2012-10-03 21:10:37 +02:00
commit 3b02a1ac3a
3 changed files with 77 additions and 30 deletions

View File

@ -26,6 +26,7 @@
#include <fcntl.h>
#include <fs.h>
#include <malloc.h>
#include <errno.h>
static const char *filetype_str[] = {
[filetype_unknown] = "unknown",
@ -42,6 +43,7 @@ static const char *filetype_str[] = {
[filetype_sh] = "Bourne Shell",
[filetype_mips_barebox] = "MIPS barebox image",
[filetype_fat] = "FAT filesytem",
[filetype_mbr] = "MBR sector",
};
const char *file_type_to_string(enum filetype f)
@ -52,26 +54,51 @@ const char *file_type_to_string(enum filetype f)
return NULL;
}
static int is_fat(u8 *buf)
#define MBR_StartSector 8 /* MBR: Offset of Starting Sector in Partition Table Entry */
#define BS_55AA 510 /* Boot sector signature (2) */
#define MBR_Table 446 /* MBR: Partition table offset (2) */
#define BS_FilSysType32 82 /* File system type (1) */
#define BS_FilSysType 54 /* File system type (1) */
enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec)
{
if (get_unaligned_le16(&buf[510]) != 0xAA55)
return 0;
/*
* bootsec can be used to return index of the first sector in the
* first partition
*/
if (bootsec)
*bootsec = 0;
/* FAT */
if ((get_unaligned_le32(&buf[54]) & 0xFFFFFF) == 0x544146)
return 1;
/*
* Check record signature (always placed at offset 510 even if the
* sector size is > 512)
*/
if (get_unaligned_le16(&sector[BS_55AA]) != 0xAA55)
return filetype_unknown;
/* FAT32 */
if ((get_unaligned_le32(&buf[82]) & 0xFFFFFF) == 0x544146)
return 1;
/* Check "FAT" string */
if ((get_unaligned_le32(&sector[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
return filetype_fat;
return 0;
if ((get_unaligned_le32(&sector[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
return filetype_fat;
if (bootsec)
/*
* This must be an MBR, so return the starting sector of the
* first partition so we could check if there is a FAT boot
* sector there
*/
*bootsec = get_unaligned_le16(&sector[MBR_Table + MBR_StartSector]);
return filetype_mbr;
}
enum filetype file_detect_type(void *_buf)
{
u32 *buf = _buf;
u8 *buf8 = _buf;
enum filetype type;
if (strncmp(buf8, "#!/bin/sh", 9) == 0)
return filetype_sh;
@ -99,8 +126,9 @@ enum filetype file_detect_type(void *_buf)
return filetype_aimage;
if (strncmp(buf8 + 0x10, "barebox", 7) == 0)
return filetype_mips_barebox;
if (is_fat(buf8))
return filetype_fat;
type = is_fat_or_mbr(buf8, NULL);
if (type != filetype_unknown)
return type;
return filetype_unknown;
}
@ -110,6 +138,7 @@ enum filetype file_name_detect_type(const char *filename)
int fd, ret;
void *buf;
enum filetype type = filetype_unknown;
unsigned long bootsec;
fd = open(filename, O_RDONLY);
if (fd < 0)
@ -123,6 +152,21 @@ enum filetype file_name_detect_type(const char *filename)
type = file_detect_type(buf);
if (type == filetype_mbr) {
/*
* Get the first partition start sector
* and check for FAT in it
*/
is_fat_or_mbr(buf, &bootsec);
ret = lseek(fd, (bootsec) * 512, SEEK_SET);
if (ret < 0)
goto err_out;
ret = read(fd, buf, 512);
if (ret < 0)
goto err_out;
type = is_fat_or_mbr((u8 *)buf, NULL);
}
err_out:
close(fd);
free(buf);

View File

@ -93,6 +93,7 @@
#include <errno.h>
#include <malloc.h>
#include <linux/ctype.h>
#include <filetype.h>
#include "ff.h" /* FatFs configurations and declarations */
#include "diskio.h" /* Declarations of low level disk I/O functions */
@ -1531,29 +1532,20 @@ int follow_path ( /* 0(0): successful, !=0: error code */
/*
* Load boot record and check if it is an FAT boot record
*/
static int check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
static enum filetype check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
FATFS *fs, /* File system object */
DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
DWORD sect, /* Sector# (lba) to check if it is an FAT boot record or not */
DWORD *bootsec
)
{
int ret;
enum filetype ret;
/* Load boot record */
ret = disk_read(fs, fs->win, sect, 1);
if (ret)
return ret;
/* Check record signature (always placed at offset 510 even if the sector size is>512) */
if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)
return -ENODEV;
return filetype_unknown;
/* Check "FAT" string */
if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
return 0;
if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
return 0;
return -ENODEV;
return is_fat_or_mbr(fs->win, bootsec);
}
/*
@ -1565,8 +1557,10 @@ static int chk_mounted ( /* 0(0): successful, !=0: any error occurred */
)
{
BYTE fmt, b;
DWORD first_boot_sect;
DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
WORD nrsv;
enum filetype type;
INIT_LIST_HEAD(&fs->dirtylist);
@ -1579,9 +1573,16 @@ static int chk_mounted ( /* 0(0): successful, !=0: any error occurred */
return -EIO;
#endif
/* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */
fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */
if (fmt)
return fmt; /* No FAT volume is found */
type = check_fs(fs, bsect = 0, &first_boot_sect); /* Check sector 0 if it is a VBR */
if (type == filetype_mbr) {
/* Sector 0 is an MBR, now check for FAT in the first partition */
type = check_fs(fs, bsect = first_boot_sect, NULL);
if (type != filetype_fat)
return -ENODEV;
}
if (type == filetype_unknown)
return -ENODEV;
/* Following code initializes the file system object */

View File

@ -19,10 +19,12 @@ enum filetype {
filetype_sh,
filetype_mips_barebox,
filetype_fat,
filetype_mbr,
};
const char *file_type_to_string(enum filetype f);
enum filetype file_detect_type(void *_buf);
enum filetype file_name_detect_type(const char *filename);
enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec);
#endif /* __FILE_TYPE_H */