[e16e8f2] | 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 | } |
---|