Home | History | Annotate | Download | only in libfat
      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 }
    135