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 java.io.IOException;
     23 import java.nio.ByteBuffer;
     24 
     25 /**
     26  * A directory that is stored in a cluster chain.
     27  *
     28  * @author Ewout Prangsma &lt;epr at jnode.org&gt;
     29  * @author Matthias Treydte &lt;waldheinz at gmail.com&gt;
     30  */
     31 class ClusterChainDirectory extends AbstractDirectory {
     32 
     33     /**
     34      * According to the FAT specification, this is the maximum size a FAT
     35      * directory may occupy on disk. The {@code ClusterChainDirectory} takes
     36      * care not to grow beyond this limit.
     37      *
     38      * @see #changeSize(int)
     39      */
     40     public final static int MAX_SIZE = 65536 * 32;
     41 
     42     /**
     43      * The {@code ClusterChain} that stores this directory. Package-visible
     44      * for testing.
     45      */
     46     final ClusterChain chain;
     47 
     48     protected ClusterChainDirectory(ClusterChain chain, boolean isRoot) {
     49 
     50         super((int)(chain.getLengthOnDisk() / FatDirectoryEntry.SIZE),
     51                 chain.isReadOnly(), isRoot);
     52 
     53         this.chain = chain;
     54     }
     55 
     56     public static ClusterChainDirectory readRoot(
     57             ClusterChain chain) throws IOException {
     58 
     59         final ClusterChainDirectory result =
     60                 new ClusterChainDirectory(chain, true);
     61 
     62         result.read();
     63         return result;
     64     }
     65 
     66     public static ClusterChainDirectory createRoot(Fat fat) throws IOException {
     67 
     68         if (fat.getFatType() != FatType.FAT32) {
     69             throw new IllegalArgumentException(
     70                     "only FAT32 stores root directory in a cluster chain");
     71         }
     72 
     73         final Fat32BootSector bs = (Fat32BootSector) fat.getBootSector();
     74         final ClusterChain cc = new ClusterChain(fat, false);
     75         cc.setChainLength(1);
     76 
     77         bs.setRootDirFirstCluster(cc.getStartCluster());
     78 
     79         final ClusterChainDirectory result =
     80                 new ClusterChainDirectory(cc, true);
     81 
     82         result.flush();
     83         return result;
     84     }
     85 
     86     @Override
     87     protected final void read(ByteBuffer data) throws IOException {
     88         this.chain.readData(0, data);
     89     }
     90 
     91     @Override
     92     protected final void write(ByteBuffer data) throws IOException {
     93         final int toWrite = data.remaining();
     94         chain.writeData(0, data);
     95         final long trueSize = chain.getLengthOnDisk();
     96 
     97         /* TODO: check if the code below is really needed */
     98         if (trueSize > toWrite) {
     99             final int rest = (int) (trueSize - toWrite);
    100             final ByteBuffer fill = ByteBuffer.allocate(rest);
    101             chain.writeData(toWrite, fill);
    102         }
    103     }
    104 
    105     /**
    106      * Returns the first cluster of the chain that stores this directory for
    107      * non-root instances or 0 if this is the root directory.
    108      *
    109      * @return the first storage cluster of this directory
    110      * @see #isRoot()
    111      */
    112     @Override
    113     protected final long getStorageCluster() {
    114         return isRoot() ? 0 : chain.getStartCluster();
    115     }
    116 
    117     public final void delete() throws IOException {
    118         chain.setChainLength(0);
    119     }
    120 
    121     @Override
    122     protected final void changeSize(int entryCount)
    123             throws IOException, IllegalArgumentException {
    124 
    125         assert (entryCount >= 0);
    126 
    127         final int size = entryCount * FatDirectoryEntry.SIZE;
    128 
    129         if (size > MAX_SIZE) throw new DirectoryFullException(
    130                 "directory would grow beyond " + MAX_SIZE + " bytes",
    131                 getCapacity(), entryCount);
    132 
    133         sizeChanged(chain.setSize(Math.max(size, chain.getClusterSize())));
    134     }
    135 
    136 }
    137