summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2010-05-13 15:40:35 -0700
committerH. Peter Anvin <hpa@linux.intel.com>2010-05-13 15:40:35 -0700
commit922b714122d23fb06e3c11cc65cab094507465c1 (patch)
tree2fb8da512c4676fd077d0da1e3c8eccd1ac2021f
parentf71c8fb531f6db841248c66f814af859eb48f469 (diff)
downloadsyslinux-922b714122d23fb06e3c11cc65cab094507465c1.tar.gz
FAT: need to track the current position past discontinuitiessyslinux-4.00-pre44
When we have a discontiguous file (broken extent), then we need to keep track of where the next extent starts, not where the current extent ends. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--core/fs/fat/fat.c39
1 files changed, 14 insertions, 25 deletions
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index e2fcc14c..a21f4312 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -33,7 +33,6 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num)
uint32_t next_cluster = 0;
sector_t fat_sector;
uint32_t offset;
- int lo, hi;
uint32_t sector_mask = SECTOR_SIZE(fs) - 1;
const uint8_t *data;
@@ -50,10 +49,9 @@ static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num)
* so store the low part, then read the next fat
* sector, read the high part, then combine it.
*/
- lo = data[offset];
+ next_cluster = data[offset];
data = get_fat_sector(fs, fat_sector + 1);
- hi = data[0];
- next_cluster = (hi << 8) + lo;
+ next_cluster += data[0] << 8;
} else {
next_cluster = *(const uint16_t *)(data + offset);
}
@@ -93,6 +91,7 @@ static int fat_next_extent(struct inode *inode, uint32_t lstart)
uint32_t lcluster;
uint32_t pcluster;
uint32_t tcluster;
+ uint32_t xcluster;
const uint32_t cluster_bytes = UINT32_C(1) << sbi->clust_byte_shift;
const uint32_t cluster_secs = UINT32_C(1) << sbi->clust_shift;
sector_t data_area = sbi->data;
@@ -101,22 +100,10 @@ static int fat_next_extent(struct inode *inode, uint32_t lstart)
if (mcluster >= tcluster)
goto err; /* Requested cluster beyond end of file */
- dprintf("Getting next cluster, inode = %p, lstart = %u, mcluster = %u, tcluster = %u\n",
- inode, lstart, mcluster, tcluster);
+ lcluster = PVT(inode)->offset >> sbi->clust_shift;
+ pcluster = ((PVT(inode)->here - data_area) >> sbi->clust_shift) + 2;
- if (inode->next_extent.len) {
- if (inode->next_extent.pstart < data_area)
- goto err; /* Root directory has only one extent */
- lcluster = (inode->next_extent.lstart + inode->next_extent.len)
- >> sbi->clust_shift;
- pcluster = ((inode->next_extent.pstart + inode->next_extent.len
- - data_area) >> sbi->clust_shift) + 2;
-
- if (lcluster > mcluster) {
- lcluster = 0;
- pcluster = PVT(inode)->start_cluster;
- }
- } else {
+ if (lcluster > mcluster || PVT(inode)->here < data_area) {
lcluster = 0;
pcluster = PVT(inode)->start_cluster;
}
@@ -137,17 +124,19 @@ static int fat_next_extent(struct inode *inode, uint32_t lstart)
inode->next_extent.pstart =
((sector_t)(pcluster-2) << sbi->clust_shift) + data_area;
inode->next_extent.len = cluster_secs;
- lcluster++;
+ xcluster = 0; /* Nonsense */
- while (lcluster < tcluster) {
- uint32_t xcluster;
+ while (++lcluster < tcluster) {
xcluster = get_next_cluster(fs, pcluster);
- if (xcluster != pcluster+1)
+ if (xcluster != ++pcluster)
break; /* Not contiguous */
- pcluster = xcluster;
inode->next_extent.len += cluster_secs;
- lcluster++;
}
+
+ /* Note: ->here is bogus if ->offset >= EOF, but that's okay */
+ PVT(inode)->offset = lcluster << sbi->clust_shift;
+ PVT(inode)->here = ((xcluster-2) << sbi->clust_shift) + data_area;
+
return 0;
err: