[syslinux:fsc] FAT: fix FAT16/32 next cluster calculation, make more similar to FAT12

syslinux-bot for H. Peter Anvin hpa at zytor.com
Sun Jan 31 20:21:06 PST 2010


Commit-ID:  7e123c64f0d338a34148e428bac45468e362da78
Gitweb:     http://syslinux.zytor.com/commit/7e123c64f0d338a34148e428bac45468e362da78
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Sun, 31 Jan 2010 20:16:14 -0800
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Sun, 31 Jan 2010 20:17:47 -0800

FAT: fix FAT16/32 next cluster calculation, make more similar to FAT12

The FAT16/32 next cluster calculations were changed to be somewhat
more like the FAT12 one, but that was done incorrectly: we would end
up reading off the end of the FAT sector we were looking at.  Make it
structurally more similar to the FAT12 calculation, and actually make
it compute correctly.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 core/fs/fat/fat.c |   26 ++++++++++++++++----------
 1 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index 79439e0..23a5512 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -70,17 +70,20 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num)
 	break;
 	
     case FAT16:
-	fat_sector = clust_num >> (SECTOR_SHIFT(fs) - 1);
-	offset = clust_num & sector_mask;
+	offset = clust_num << 1;
+	fat_sector = offset >> SECTOR_SHIFT(fs);
+	offset &= sector_mask;
 	cs = get_fat_sector(fs, fat_sector);
-	next_cluster = ((uint16_t *)cs->data)[offset];
+	next_cluster = *(uint16_t *)(cs->data + offset);
 	break;
 	
     case FAT32:
-	fat_sector = clust_num >> (SECTOR_SHIFT(fs) - 2);
-	offset = clust_num & sector_mask;
+	offset = clust_num << 2;
+	fat_sector = offset >> SECTOR_SHIFT(fs);
+	offset &= sector_mask;
 	cs = get_fat_sector(fs, fat_sector);
-	next_cluster = ((uint32_t *)cs->data)[offset] & 0x0fffffff;
+	next_cluster = *(uint32_t *)(cs->data + offset);
+	next_cluster &= 0x0fffffff;
 	break;
     }
     
@@ -99,24 +102,27 @@ static sector_t get_next_sector(struct fs_info* fs, uint32_t sector)
     if (sector < data_area) {
 	/* Root directory sector... */
 	sector++;
-	if (sector == data_area)
+	if (sector >= data_area)
 	    sector = 0; /* Ran out of root directory, return EOF */
 	return sector;
     }
     
     data_sector = sector - data_area;
     if ((data_sector + 1) & sbi->clust_mask)  /* Still in the same cluster */
-	return sector+1;		      /* Next sector inside cluster */
+	return sector + 1;		      /* Next sector inside cluster */
 
     /* get a new cluster */
     cluster = data_sector >> clust_shift;
     cluster = get_next_cluster(fs, cluster + 2) - 2;
 
-    if (cluster >= sbi->clusters)
+    if (cluster >= sbi->clusters) {
+	printf("Logical cluster = 0x%x, total clusters = 0x%x\n",
+	       cluster + 2, sbi->clusters);
 	return 0;
+    }
     
     /* return the start of the new cluster */
-    sector = (cluster << sbi->clust_shift) + data_area;
+    sector = (cluster << clust_shift) + data_area;
     return sector;
 }
 



More information about the Syslinux-commits mailing list