1 /* 2 * Copyright (C) 2003-2009 JNode.org 3 * 2009,2010 Matthias Treydte <mt@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 <epr at jnode.org> 29 * @author Matthias Treydte <waldheinz at gmail.com> 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 ClusterChainDirectory(ClusterChain chain, boolean isRoot)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 readRoot( ClusterChain chain)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 createRoot(Fat fat)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 read(ByteBuffer data)87 protected final void read(ByteBuffer data) throws IOException { 88 this.chain.readData(0, data); 89 } 90 91 @Override write(ByteBuffer data)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 getStorageCluster()113 protected final long getStorageCluster() { 114 return isRoot() ? 0 : chain.getStartCluster(); 115 } 116 delete()117 public final void delete() throws IOException { 118 chain.setChainLength(0); 119 } 120 121 @Override changeSize(int entryCount)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