1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 8 * Boston MA 02111-1307, USA; either version 2 of the License, or 9 * (at your option) any later version; incorporated herein by reference. 10 * 11 * ----------------------------------------------------------------------- */ 12 13 /* 14 * fatchain.c 15 * 16 * Follow a FAT chain 17 */ 18 19 #include "libfatint.h" 20 #include "ulint.h" 21 22 /* 23 * Convert a cluster number (or 0 for the root directory) to a 24 * sector number. Return -1 on failure. 25 */ 26 libfat_sector_t libfat_clustertosector(const struct libfat_filesystem *fs, 27 int32_t cluster) 28 { 29 if (cluster == 0) 30 cluster = fs->rootcluster; 31 32 if (cluster == 0) 33 return fs->rootdir; 34 else if (cluster < 2 || cluster >= fs->endcluster) 35 return -1; 36 else 37 return fs->data + ((libfat_sector_t) (cluster - 2) << fs->clustshift); 38 } 39 40 /* 41 * Get the next sector of either the root directory or a FAT chain. 42 * Returns 0 on end of file and -1 on error. 43 */ 44 45 libfat_sector_t libfat_nextsector(struct libfat_filesystem * fs, 46 libfat_sector_t s) 47 { 48 int32_t cluster, nextcluster; 49 uint32_t fatoffset; 50 libfat_sector_t fatsect; 51 uint8_t *fsdata; 52 uint32_t clustmask = fs->clustsize - 1; 53 libfat_sector_t rs; 54 55 if (s < fs->data) { 56 if (s < fs->rootdir) 57 return -1; 58 59 /* Root directory */ 60 s++; 61 return (s < fs->data) ? s : 0; 62 } 63 64 rs = s - fs->data; 65 66 if (~rs & clustmask) 67 return s + 1; /* Next sector in cluster */ 68 69 cluster = 2 + (rs >> fs->clustshift); 70 71 if (cluster >= fs->endcluster) 72 return -1; 73 74 switch (fs->fat_type) { 75 case FAT12: 76 /* Get first byte */ 77 fatoffset = cluster + (cluster >> 1); 78 fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); 79 fsdata = libfat_get_sector(fs, fatsect); 80 if (!fsdata) 81 return -1; 82 nextcluster = fsdata[fatoffset & LIBFAT_SECTOR_MASK]; 83 84 /* Get second byte */ 85 fatoffset++; 86 fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); 87 fsdata = libfat_get_sector(fs, fatsect); 88 if (!fsdata) 89 return -1; 90 nextcluster |= fsdata[fatoffset & LIBFAT_SECTOR_MASK] << 8; 91 92 /* Extract the FAT entry */ 93 if (cluster & 1) 94 nextcluster >>= 4; 95 else 96 nextcluster &= 0x0FFF; 97 98 if (nextcluster >= 0x0FF8) 99 return 0; 100 break; 101 102 case FAT16: 103 fatoffset = cluster << 1; 104 fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); 105 fsdata = libfat_get_sector(fs, fatsect); 106 if (!fsdata) 107 return -1; 108 nextcluster = 109 read16((le16_t *) & fsdata[fatoffset & LIBFAT_SECTOR_MASK]); 110 111 if (nextcluster >= 0x0FFF8) 112 return 0; 113 break; 114 115 case FAT28: 116 fatoffset = cluster << 2; 117 fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT); 118 fsdata = libfat_get_sector(fs, fatsect); 119 if (!fsdata) 120 return -1; 121 nextcluster = 122 read32((le32_t *) & fsdata[fatoffset & LIBFAT_SECTOR_MASK]); 123 nextcluster &= 0x0FFFFFFF; 124 125 if (nextcluster >= 0x0FFFFFF8) 126 return 0; 127 break; 128 129 default: 130 return -1; /* WTF? */ 131 } 132 133 return libfat_clustertosector(fs, nextcluster); 134 } 135