• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
libfat_clustertosector(const struct libfat_filesystem * fs,int32_t cluster)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 
libfat_nextsector(struct libfat_filesystem * fs,libfat_sector_t s)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