Home | History | Annotate | Download | only in fat
      1 /*
      2  * Copyright (C) 2003-2009 JNode.org
      3  *               2009,2010 Matthias Treydte <mt (at) waldheinz.de>
      4  *
      5  * This library is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU Lesser General Public License as published
      7  * by the Free Software Foundation; either version 2.1 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful, but
     11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
     13  * License for more details.
     14  *
     15  * You should have received a copy of the GNU Lesser General Public License
     16  * along with this library; If not, write to the Free Software Foundation, Inc.,
     17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18  */
     19 
     20 package de.waldheinz.fs.fat;
     21 
     22 import de.waldheinz.fs.AbstractFileSystem;
     23 import de.waldheinz.fs.BlockDevice;
     24 import java.io.IOException;
     25 import de.waldheinz.fs.ReadOnlyException;
     26 
     27 /**
     28  * <p>
     29  * Implements the {@code FileSystem} interface for the FAT family of file
     30  * systems. This class always uses the "long file name" specification when
     31  * writing directory entries.
     32  * </p><p>
     33  * For creating (aka "formatting") FAT file systems please refer to the
     34  * {@link SuperFloppyFormatter} class.
     35  * </p>
     36  *
     37  * @author Ewout Prangsma &lt;epr at jnode.org&gt;
     38  * @author Matthias Treydte &lt;waldheinz at gmail.com&gt;
     39  */
     40 public final class FatFileSystem extends AbstractFileSystem {
     41 
     42     private final Fat fat;
     43     private final FsInfoSector fsiSector;
     44     private final BootSector bs;
     45     private final FatLfnDirectory rootDir;
     46     private final AbstractDirectory rootDirStore;
     47     private final FatType fatType;
     48     private final long filesOffset;
     49 
     50     FatFileSystem(BlockDevice api, boolean readOnly) throws IOException {
     51 
     52         this(api, readOnly, false);
     53     }
     54 
     55     /**
     56      * Constructor for FatFileSystem in specified readOnly mode
     57      *
     58      * @param device the {@code BlockDevice} holding the file system
     59      * @param readOnly if this FS should be read-lonly
     60      * @param ignoreFatDifferences
     61      * @throws IOException on read error
     62      */
     63     private FatFileSystem(BlockDevice device, boolean readOnly,
     64             boolean ignoreFatDifferences)
     65             throws IOException {
     66 
     67         super(readOnly);
     68 
     69         this.bs = BootSector.read(device);
     70 
     71         if (bs.getNrFats() <= 0) throw new IOException(
     72                 "boot sector says there are no FATs");
     73 
     74         this.filesOffset = FatUtils.getFilesOffset(bs);
     75         this.fatType = bs.getFatType();
     76         this.fat = Fat.read(bs, 0);
     77 
     78         if (!ignoreFatDifferences) {
     79             for (int i=1; i < bs.getNrFats(); i++) {
     80                 final Fat tmpFat = Fat.read(bs, i);
     81                 if (!fat.equals(tmpFat)) {
     82                     throw new IOException("FAT " + i + " differs from FAT 0");
     83                 }
     84             }
     85         }
     86 
     87         if (fatType == FatType.FAT32) {
     88             final Fat32BootSector f32bs = (Fat32BootSector) bs;
     89             ClusterChain rootDirFile = new ClusterChain(fat,
     90                     f32bs.getRootDirFirstCluster(), isReadOnly());
     91             this.rootDirStore = ClusterChainDirectory.readRoot(rootDirFile);
     92             this.fsiSector = FsInfoSector.read(f32bs);
     93 
     94             if (fsiSector.getFreeClusterCount() != fat.getFreeClusterCount()) {
     95                 throw new IOException("free cluster count mismatch - fat: " +
     96                         fat.getFreeClusterCount() + " - fsinfo: " +
     97                         fsiSector.getFreeClusterCount());
     98             }
     99         } else {
    100             this.rootDirStore =
    101                     Fat16RootDirectory.read((Fat16BootSector) bs,readOnly);
    102             this.fsiSector = null;
    103         }
    104 
    105         this.rootDir = new FatLfnDirectory(rootDirStore, fat, isReadOnly());
    106 
    107     }
    108 
    109     /**
    110      * Reads the file system structure from the specified {@code BlockDevice}
    111      * and returns a fresh {@code FatFileSystem} instance to read or modify
    112      * it.
    113      *
    114      * @param device the {@code BlockDevice} holding the file system
    115      * @param readOnly if the {@code FatFileSystem} should be in read-only mode
    116      * @return the {@code FatFileSystem} instance for the device
    117      * @throws IOException on read error or if the file system structure could
    118      *      not be parsed
    119      */
    120     public static FatFileSystem read(BlockDevice device, boolean readOnly)
    121             throws IOException {
    122 
    123         return new FatFileSystem(device, readOnly);
    124     }
    125 
    126     long getFilesOffset() {
    127         checkClosed();
    128 
    129         return filesOffset;
    130     }
    131 
    132     /**
    133      * Returns the size of the FAT entries of this {@code FatFileSystem}.
    134      *
    135      * @return the exact type of the FAT used by this file system
    136      */
    137     public FatType getFatType() {
    138         checkClosed();
    139 
    140         return this.fatType;
    141     }
    142 
    143     /**
    144      * Returns the volume label of this file system.
    145      *
    146      * @return the volume label
    147      */
    148     public String getVolumeLabel() {
    149         checkClosed();
    150 
    151         final String fromDir = rootDirStore.getLabel();
    152 
    153         if (fromDir == null && fatType != FatType.FAT32) {
    154             return ((Fat16BootSector)bs).getVolumeLabel();
    155         } else {
    156             return fromDir;
    157         }
    158     }
    159 
    160     /**
    161      * Sets the volume label for this file system.
    162      *
    163      * @param label the new volume label, may be {@code null}
    164      * @throws ReadOnlyException if the file system is read-only
    165      * @throws IOException on write error
    166      */
    167     public void setVolumeLabel(String label)
    168             throws ReadOnlyException, IOException {
    169 
    170         checkClosed();
    171         checkReadOnly();
    172 
    173         rootDirStore.setLabel(label);
    174 
    175         if (fatType != FatType.FAT32) {
    176             ((Fat16BootSector)bs).setVolumeLabel(label);
    177         }
    178     }
    179 
    180     AbstractDirectory getRootDirStore() {
    181         checkClosed();
    182 
    183         return rootDirStore;
    184     }
    185 
    186     /**
    187      * Flush all changed structures to the device.
    188      *
    189      * @throws IOException on write error
    190      */
    191     @Override
    192     public void flush() throws IOException {
    193         checkClosed();
    194 
    195         if (bs.isDirty()) {
    196             bs.write();
    197         }
    198 
    199         for (int i = 0; i < bs.getNrFats(); i++) {
    200             fat.writeCopy(FatUtils.getFatOffset(bs, i));
    201         }
    202 
    203         rootDir.flush();
    204 
    205         if (fsiSector != null) {
    206             fsiSector.setFreeClusterCount(fat.getFreeClusterCount());
    207             fsiSector.setLastAllocatedCluster(fat.getLastAllocatedCluster());
    208             fsiSector.write();
    209         }
    210     }
    211 
    212     @Override
    213     public FatLfnDirectory getRoot() {
    214         checkClosed();
    215 
    216         return rootDir;
    217     }
    218 
    219     /**
    220      * Returns the fat.
    221      *
    222      * @return Fat
    223      */
    224     public Fat getFat() {
    225         return fat;
    226     }
    227 
    228     /**
    229      * Returns the bootsector.
    230      *
    231      * @return BootSector
    232      */
    233     public BootSector getBootSector() {
    234         checkClosed();
    235 
    236         return bs;
    237     }
    238 
    239     /**
    240      * <p>
    241      * {@inheritDoc}
    242      * </p><p>
    243      * This method shows the free space in terms of available clusters.
    244      * </p>
    245      *
    246      * @return always -1
    247      */
    248     @Override
    249     public long getFreeSpace() {
    250     	return this.fat.getFreeClusterCount() * this.bs.getBytesPerCluster();
    251     }
    252 
    253     /**
    254      * <p>
    255      * {@inheritDoc}
    256      * </p><p>
    257      * This method is currently not implemented for {@code FatFileSystem} and
    258      * always returns -1.
    259      * </p>
    260      *
    261      * @return always -1
    262      */
    263     @Override
    264     public long getTotalSpace() {
    265     	return this.bs.getDataClusterCount() * this.bs.getBytesPerCluster();
    266     }
    267 
    268     /**
    269      * <p>
    270      * {@inheritDoc}
    271      * </p><p>
    272      * This method is currently not implemented for {@code FatFileSystem} and
    273      * always returns -1.
    274      * </p>
    275      *
    276      * @return always -1
    277      */
    278     @Override
    279     public long getUsableSpace() {
    280         // TODO implement me
    281         return -1;
    282     }
    283 }
    284