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 | } |
---|