Adding upstream version 3.30~pre4.
[syslinux-debian/hramrach.git] / libfat / fatchain.c
blob34005b19ffb7ae8debf36ccdca3612e562916ec3
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004 H. Peter Anvin - All Rights Reserved
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.
11 * ----------------------------------------------------------------------- */
14 * fatchain.c
16 * Follow a FAT chain
19 #include "libfatint.h"
20 #include "ulint.h"
23 * Convert a cluster number (or 0 for the root directory) to a
24 * sector number. Return -1 on failure.
26 libfat_sector_t libfat_clustertosector(const struct libfat_filesystem *fs,
27 int32_t cluster)
29 if ( cluster == 0 )
30 cluster = fs->rootcluster;
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);
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.
45 libfat_sector_t libfat_nextsector(struct libfat_filesystem *fs,
46 libfat_sector_t s)
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;
55 if ( s < fs->data ) {
56 if ( s < fs->rootdir )
57 return -1;
59 /* Root directory */
60 s++;
61 return ( s < fs->data ) ? s : 0;
64 rs = s - fs->data;
66 if ( ~rs & clustmask )
67 return s+1; /* Next sector in cluster */
69 cluster = 2 + (rs >> fs->clustshift);
71 if ( cluster >= fs->endcluster )
72 return -1;
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];
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;
92 /* Extract the FAT entry */
93 if ( cluster & 1 )
94 nextcluster >>= 4;
95 else
96 nextcluster &= 0x0FFF;
98 if ( nextcluster >= 0x0FF8 )
99 return 0;
100 break;
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 = read16((le16_t *)&fsdata[fatoffset & LIBFAT_SECTOR_MASK]);
110 if ( nextcluster >= 0x0FFF8 )
111 return 0;
112 break;
114 case FAT28:
115 fatoffset = cluster << 2;
116 fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT);
117 fsdata = libfat_get_sector(fs, fatsect);
118 if ( !fsdata )
119 return -1;
120 nextcluster = read32((le32_t *)&fsdata[fatoffset & LIBFAT_SECTOR_MASK]);
121 nextcluster &= 0x0FFFFFFF;
123 if ( nextcluster >= 0x0FFFFFF8 )
124 return 0;
125 break;
127 default:
128 return -1; /* WTF? */
131 return libfat_clustertosector(fs, nextcluster);