1 /* 2 * Copyright (C) 2009,2010 Matthias Treydte <mt@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 <waldheinz at gmail.com> 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 FsInfoSector(BlockDevice device, long offset)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 */ read(Fat32BootSector bs)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 */ create(Fat32BootSector bs)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 offset(Fat32BootSector bs)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 */ setFreeClusterCount(long value)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 */ getFreeClusterCount()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 */ setLastAllocatedCluster(long value)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 */ getLastAllocatedCluster()140 public long getLastAllocatedCluster() { 141 return super.get32(LAST_ALLOCATED_OFFSET); 142 } 143 init()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 verify()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 toString()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