diff mbox

[U-Boot,1/3] fs/fat: Fix FAT detection to support non-DOS partition tables

Message ID 1324402874-15400-2-git-send-email-Kyle.D.Moffett@boeing.com
State Superseded
Headers show

Commit Message

Kyle Moffett Dec. 20, 2011, 5:41 p.m. UTC
The FAT filesystem code currently ends up requiring that the partition
table be a DOS MBR, as it checks for the DOS 0x55 0xAA signature on the
partition table (which may be Mac, EFI, ISO9660, etc) before actually
computing the partition offset.

This fixes support for accessing a FAT filesystem in an ISO9660 boot
volume (El-Torito format) by reordering the filesystem checks and
reading the 0x55 0xAA "DOS boot signature" and FAT/FAT32 magic number
from the first sector of the partition instead of from sector 0.

Signed-off-by: Kyle Moffett <Kyle.D.Moffett@boeing.com>
---
 fs/fat/fat.c |  123 ++++++++++++++++++++++++++++-----------------------------
 1 files changed, 60 insertions(+), 63 deletions(-)

Comments

Mike Frysinger Dec. 20, 2011, 6:20 p.m. UTC | #1
On Tuesday 20 December 2011 12:41:12 Kyle Moffett wrote:
> --- a/fs/fat/fat.c
> +++ b/fs/fat/fat.c
> 
> +static disk_partition_t cur_part_info = {
> +	.start = 0,
> +	.size = 0,
> +	.blksz = 512,
> +	.name = "",
> +	.type = "",
> +};

there any way we could delay that initialization of blksz to runtime ?  if 
that wasn't there, cur_part_info would be in .bss instead of .data.
-mike
Kyle Moffett Dec. 20, 2011, 6:23 p.m. UTC | #2
On Dec 20, 2011, at 13:20, Mike Frysinger wrote:
> On Tuesday 20 December 2011 12:41:12 Kyle Moffett wrote:
>> --- a/fs/fat/fat.c
>> +++ b/fs/fat/fat.c
>> 
>> +static disk_partition_t cur_part_info = {
>> +	.start = 0,
>> +	.size = 0,
>> +	.blksz = 512,
>> +	.name = "",
>> +	.type = "",
>> +};
> 
> there any way we could delay that initialization of blksz to runtime ?  if 
> that wasn't there, cur_part_info would be in .bss instead of .data.

I redid this patch several times before I figured out what was going
on and I ended up with both paths fully initializing this struct, so
there's really no need for an initializer at all.

I'll remove it for the next round.

Thanks for the review!

Cheers,
Kyle Moffett

--
Curious about my work on the Debian powerpcspe port?
I'm keeping a blog here: http://pureperl.blogspot.com/
diff mbox

Patch

diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 9a29458..13bab8f 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -44,49 +44,36 @@  static void downcase (char *str)
 }
 
 static block_dev_desc_t *cur_dev = NULL;
-
-static unsigned long part_offset = 0;
-
-static int cur_part = 1;
-
-#define DOS_PART_TBL_OFFSET	0x1be
-#define DOS_PART_MAGIC_OFFSET	0x1fe
+static unsigned int cur_part_nr = 1;
+static disk_partition_t cur_part_info = {
+	.start = 0,
+	.size = 0,
+	.blksz = 512,
+	.name = "",
+	.type = "",
+};
+
+#define DOS_BOOT_MAGIC_OFFSET	0x1fe
 #define DOS_FS_TYPE_OFFSET	0x36
 #define DOS_FS32_TYPE_OFFSET	0x52
 
-static int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr)
+static int disk_read(__u32 block, __u32 nr_blocks, void *buf)
 {
-	if (cur_dev == NULL)
+	if (!cur_dev || !cur_dev->block_read)
 		return -1;
 
-	startblock += part_offset;
-
-	if (cur_dev->block_read) {
-		return cur_dev->block_read(cur_dev->dev, startblock, getsize,
-					   (unsigned long *) bufptr);
-	}
-	return -1;
+	return cur_dev->block_read(cur_dev->dev,
+			cur_part_info.start + block, nr_blocks, buf);
 }
 
 int fat_register_device (block_dev_desc_t * dev_desc, int part_no)
 {
 	unsigned char buffer[dev_desc->blksz];
+	unsigned int found_partition = 0;
 
-	if (!dev_desc->block_read)
-		return -1;
+	/* First close any currently found FAT filesystem */
+	cur_dev = NULL;
 
-	cur_dev = dev_desc;
-	/* check if we have a MBR (on floppies we have only a PBR) */
-	if (dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *)buffer) != 1) {
-		printf("** Can't read from device %d **\n",
-			dev_desc->dev);
-		return -1;
-	}
-	if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
-	    buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
-		/* no signature found */
-		return -1;
-	}
 #if (defined(CONFIG_CMD_IDE) || \
      defined(CONFIG_CMD_MG_DISK) || \
      defined(CONFIG_CMD_SATA) || \
@@ -94,45 +81,55 @@  int fat_register_device (block_dev_desc_t * dev_desc, int part_no)
      defined(CONFIG_CMD_USB) || \
      defined(CONFIG_MMC) || \
      defined(CONFIG_SYSTEMACE) )
-	{
-		disk_partition_t info;
-
-		/* First we assume there is a MBR */
-		if (!get_partition_info(dev_desc, part_no, &info)) {
-			part_offset = info.start;
-			cur_part = part_no;
-		} else if ((strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET],
-				    "FAT", 3) == 0) ||
-			   (strncmp((char *)&buffer[DOS_FS32_TYPE_OFFSET],
-				    "FAT32", 5) == 0)) {
-			/* ok, we assume we are on a PBR only */
-			cur_part = 1;
-			part_offset = 0;
-		} else {
+
+	/* Read the partition table, if present */
+	if (!get_partition_info(dev_desc, part_no, &cur_part_info)) {
+		cur_dev = dev_desc;
+		cur_part_nr = part_no;
+	}
+#endif
+
+	/* Otherwise it might be a superfloppy (whole-disk FAT filesystem) */
+	if (!cur_dev) {
+		if (part_no != 1) {
 			printf("** Partition %d not valid on device %d **\n",
-				part_no, dev_desc->dev);
+					part_no, dev_desc->dev);
 			return -1;
 		}
+
+		found_partition = 1;
+		cur_dev = dev_desc;
+		cur_part_nr = 1;
+		cur_part_info.start = 0;
+		cur_part_info.size = dev_desc->lba;
+		cur_part_info.blksz = dev_desc->blksz;
+		memset(cur_part_info.name, 0, sizeof(cur_part_info.name));
+		memset(cur_part_info.type, 0, sizeof(cur_part_info.type));
 	}
-#else
-	if ((strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], "FAT", 3) == 0) ||
-	    (strncmp((char *)&buffer[DOS_FS32_TYPE_OFFSET], "FAT32", 5) == 0)) {
-		/* ok, we assume we are on a PBR only */
-		cur_part = 1;
-		part_offset = 0;
-	} else {
-		/* FIXME we need to determine the start block of the
-		 * partition where the DOS FS resides. This can be done
-		 * by using the get_partition_info routine. For this
-		 * purpose the libpart must be included.
-		 */
-		part_offset = 32;
-		cur_part = 1;
+
+	/* Make sure it has a valid FAT header */
+	if (disk_read(0, 1, buffer) != 1) {
+		cur_dev = NULL;
+		return -1;
 	}
-#endif
-	return 0;
+
+	/* Check if it's actually a DOS volume */
+	if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) {
+		cur_dev = NULL;
+		return -1;
+	}
+
+	/* Check for FAT12/FAT16/FAT32 filesystem */
+	if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3))
+		return 0;
+	if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5))
+		return 0;
+
+	cur_dev = NULL;
+	return -1;
 }
 
+
 /*
  * Get the first occurence of a directory delimiter ('/' or '\') in a string.
  * Return index into string if found, -1 otherwise.
@@ -1170,7 +1167,7 @@  int file_fat_detectfs (void)
 	vol_label[11] = '\0';
 	volinfo.fs_type[5] = '\0';
 
-	printf("Partition %d: Filesystem: %s \"%s\"\n", cur_part,
+	printf("Partition %d: Filesystem: %s \"%s\"\n", cur_part_nr,
 		volinfo.fs_type, vol_label);
 
 	return 0;