Home | History | Annotate | Download | only in fat
      1 /*
      2  * Copyright (C) 2009,2010 Matthias Treydte <mt (at) waldheinz.de>
      3  *
      4  * This library is free software; you can redistribute it and/or modify it
      5  * under the terms of the GNU Lesser General Public License as published
      6  * by the Free Software Foundation; either version 2.1 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
     12  * License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public License
     15  * along with this library; If not, write to the Free Software Foundation, Inc.,
     16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     17  */
     18 
     19 package de.waldheinz.fs.fat;
     20 
     21 import de.waldheinz.fs.BlockDevice;
     22 import java.io.IOException;
     23 
     24 /**
     25  * The FAT32 File System Information Sector.
     26  *
     27  * @author Matthias Treydte &lt;waldheinz at gmail.com&gt;
     28  * @see http://en.wikipedia.org/wiki/File_Allocation_Table#FS_Information_Sector
     29  */
     30 final class FsInfoSector extends Sector {
     31 
     32     /**
     33      * The offset to the free cluster count value in the FS info sector.
     34      */
     35     public static final int FREE_CLUSTERS_OFFSET = 0x1e8;
     36 
     37     /**
     38      * The offset to the "last allocated cluster" value in this sector.
     39      */
     40     public static final int LAST_ALLOCATED_OFFSET = 0x1ec;
     41 
     42     /**
     43      * The offset to the signature of this sector.
     44      */
     45     public static final int SIGNATURE_OFFSET = 0x1fe;
     46 
     47     private FsInfoSector(BlockDevice device, long offset) {
     48         super(device, offset, BootSector.SIZE);
     49     }
     50 
     51     /**
     52      * Reads a {@code FsInfoSector} as specified by the given
     53      * {@code Fat32BootSector}.
     54      *
     55      * @param bs the boot sector that specifies where the FS info sector is
     56      *      stored
     57      * @return the FS info sector that was read
     58      * @throws IOException on read error
     59      * @see Fat32BootSector#getFsInfoSectorNr()
     60      */
     61     public static FsInfoSector read(Fat32BootSector bs) throws IOException {
     62         final FsInfoSector result =
     63                 new FsInfoSector(bs.getDevice(), offset(bs));
     64 
     65         result.read();
     66         result.verify();
     67         return result;
     68     }
     69 
     70     /**
     71      * Creates an new {@code FsInfoSector} where the specified
     72      * {@code Fat32BootSector} indicates it should be.
     73      *
     74      * @param bs the boot sector specifying the FS info sector storage
     75      * @return the FS info sector instance that was created
     76      * @throws IOException on write error
     77      * @see Fat32BootSector#getFsInfoSectorNr()
     78      */
     79     public static FsInfoSector create(Fat32BootSector bs) throws IOException {
     80         final int offset = offset(bs);
     81 
     82         if (offset == 0) throw new IOException(
     83                 "creating a FS info sector at offset 0 is strange");
     84 
     85         final FsInfoSector result =
     86                 new FsInfoSector(bs.getDevice(), offset(bs));
     87 
     88         result.init();
     89         result.write();
     90         return result;
     91     }
     92 
     93     private static int offset(Fat32BootSector bs) {
     94         return bs.getFsInfoSectorNr() * bs.getBytesPerSector();
     95     }
     96 
     97     /**
     98      * Sets the number of free clusters on the file system stored at
     99      * {@link #FREE_CLUSTERS_OFFSET}.
    100      *
    101      * @param value the new free cluster count
    102      * @see Fat#getFreeClusterCount()
    103      */
    104     public void setFreeClusterCount(long value) {
    105         if (getFreeClusterCount() == value) return;
    106 
    107         set32(FREE_CLUSTERS_OFFSET, value);
    108     }
    109 
    110     /**
    111      * Returns the number of free clusters on the file system as sepcified by
    112      * the 32-bit value at {@link #FREE_CLUSTERS_OFFSET}.
    113      *
    114      * @return the number of free clusters
    115      * @see Fat#getFreeClusterCount()
    116      */
    117     public long getFreeClusterCount() {
    118         return get32(FREE_CLUSTERS_OFFSET);
    119     }
    120 
    121     /**
    122      * Sets the last allocated cluster that was used in the {@link Fat}.
    123      *
    124      * @param value the FAT's last allocated cluster number
    125      * @see Fat#getLastAllocatedCluster()
    126      */
    127     public void setLastAllocatedCluster(long value) {
    128         if (getLastAllocatedCluster() == value) return;
    129 
    130         super.set32(LAST_ALLOCATED_OFFSET, value);
    131     }
    132 
    133     /**
    134      * Returns the last allocated cluster number of the {@link Fat} of the
    135      * file system this FS info sector is part of.
    136      *
    137      * @return the last allocated cluster number
    138      * @see Fat#getLastAllocatedCluster()
    139      */
    140     public long getLastAllocatedCluster() {
    141         return super.get32(LAST_ALLOCATED_OFFSET);
    142     }
    143 
    144     private void init() {
    145         buffer.position(0x00);
    146         buffer.put((byte) 0x52);
    147         buffer.put((byte) 0x52);
    148         buffer.put((byte) 0x61);
    149         buffer.put((byte) 0x41);
    150 
    151         /* 480 reserved bytes */
    152 
    153         buffer.position(0x1e4);
    154         buffer.put((byte) 0x72);
    155         buffer.put((byte) 0x72);
    156         buffer.put((byte) 0x41);
    157         buffer.put((byte) 0x61);
    158 
    159         setFreeClusterCount(-1);
    160         setLastAllocatedCluster(Fat.FIRST_CLUSTER);
    161 
    162         buffer.position(SIGNATURE_OFFSET);
    163         buffer.put((byte) 0x55);
    164         buffer.put((byte) 0xaa);
    165 
    166         markDirty();
    167     }
    168 
    169     private void verify() throws IOException {
    170         if (!(get8(SIGNATURE_OFFSET) == 0x55) ||
    171                 !(get8(SIGNATURE_OFFSET + 1) == 0xaa)) {
    172 
    173             throw new IOException("invalid FS info sector signature");
    174         }
    175     }
    176 
    177     @Override
    178     public String toString() {
    179         return FsInfoSector.class.getSimpleName() +
    180                 " [freeClusterCount=" + getFreeClusterCount() + //NOI18N
    181                 ", lastAllocatedCluster=" + getLastAllocatedCluster() + //NOI18N
    182                 ", offset=" + getOffset() + //NOI18N
    183                 ", dirty=" + isDirty() + //NOI18N
    184                 "]"; //NOI18N
    185     }
    186 
    187 }
    188