Change fdt-specific loader into a generic setup_data loader
[profile/ivi/syslinux.git] / libfat / fatchain.c
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 }