diff options
Diffstat (limited to 'contrib/syslinux-4.02/libfat/fatchain.c')
-rw-r--r-- | contrib/syslinux-4.02/libfat/fatchain.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/libfat/fatchain.c b/contrib/syslinux-4.02/libfat/fatchain.c new file mode 100644 index 0000000..9853a72 --- /dev/null +++ b/contrib/syslinux-4.02/libfat/fatchain.c @@ -0,0 +1,134 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * + * This program 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, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * fatchain.c + * + * Follow a FAT chain + */ + +#include "libfatint.h" +#include "ulint.h" + +/* + * Convert a cluster number (or 0 for the root directory) to a + * sector number. Return -1 on failure. + */ +libfat_sector_t libfat_clustertosector(const struct libfat_filesystem *fs, + int32_t cluster) +{ + if (cluster == 0) + cluster = fs->rootcluster; + + if (cluster == 0) + return fs->rootdir; + else if (cluster < 2 || cluster >= fs->endcluster) + return -1; + else + return fs->data + ((libfat_sector_t) (cluster - 2) << fs->clustshift); +} + +/* + * Get the next sector of either the root directory or a FAT chain. + * Returns 0 on end of file and -1 on error. + */ + +libfat_sector_t libfat_nextsector(struct libfat_filesystem * fs, + libfat_sector_t s) +{ + int32_t cluster, nextcluster; + uint32_t fatoffset; + libfat_sector_t fatsect; + uint8_t *fsdata; + uint32_t clustmask = fs->clustsize - 1; + libfat_sector_t rs; + + if (s < fs->data) { + if (s < fs->rootdir) + return -1; + + /* Root directory */ + s++; + return (s < fs->data) ? s : 0; + } + + rs = s - fs->data; + + if (~rs & clustmask) + return s + 1; /* Next sector in cluster */ + + cluster = 2 + (rs >> fs->clustshift); + + if (cluster >= fs->endcluster) + return -1; + + switch (fs->fat_type) { + case FAT12: + /* Get first byte */ + fatoffset = cluster + (cluster >> 1); + fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); + fsdata = libfat_get_sector(fs, fatsect); + if (!fsdata) + return -1; + nextcluster = fsdata[fatoffset & LIBFAT_SECTOR_MASK]; + + /* Get second byte */ + fatoffset++; + fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); + fsdata = libfat_get_sector(fs, fatsect); + if (!fsdata) + return -1; + nextcluster |= fsdata[fatoffset & LIBFAT_SECTOR_MASK] << 8; + + /* Extract the FAT entry */ + if (cluster & 1) + nextcluster >>= 4; + else + nextcluster &= 0x0FFF; + + if (nextcluster >= 0x0FF8) + return 0; + break; + + case FAT16: + fatoffset = cluster << 1; + fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); + fsdata = libfat_get_sector(fs, fatsect); + if (!fsdata) + return -1; + nextcluster = + read16((le16_t *) & fsdata[fatoffset & LIBFAT_SECTOR_MASK]); + + if (nextcluster >= 0x0FFF8) + return 0; + break; + + case FAT28: + fatoffset = cluster << 2; + fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); + fsdata = libfat_get_sector(fs, fatsect); + if (!fsdata) + return -1; + nextcluster = + read32((le32_t *) & fsdata[fatoffset & LIBFAT_SECTOR_MASK]); + nextcluster &= 0x0FFFFFFF; + + if (nextcluster >= 0x0FFFFFF8) + return 0; + break; + + default: + return -1; /* WTF? */ + } + + return libfat_clustertosector(fs, nextcluster); +} |