• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 boot sector layout as used by the FAT12 / FAT16 variants.
26  *
27  * @author Matthias Treydte &lt;matthias.treydte at meetwise.com&gt;
28  */
29 final class Fat16BootSector extends BootSector {
30 
31     /**
32      * The default number of entries for the root directory.
33      *
34      * @see #getRootDirEntryCount()
35      * @see #setRootDirEntryCount(int)
36      */
37     public static final int DEFAULT_ROOT_DIR_ENTRY_COUNT = 512;
38 
39     /**
40      * The default volume label.
41      */
42     public static final String DEFAULT_VOLUME_LABEL = "NO NAME"; //NOI18N
43 
44     /**
45      * The maximum number of clusters for a FAT12 file system. This is actually
46      * the number of clusters where mkdosfs stop complaining about a FAT16
47      * partition having not enough sectors, so it would be misinterpreted
48      * as FAT12 without special handling.
49      *
50      * @see #getNrLogicalSectors()
51      */
52     public static final int MAX_FAT12_CLUSTERS = 4084;
53 
54     public static final int MAX_FAT16_CLUSTERS = 65524;
55 
56     /**
57      * The offset to the sectors per FAT value.
58      */
59     public static final int SECTORS_PER_FAT_OFFSET = 0x16;
60 
61     /**
62      * The offset to the root directory entry count value.
63      *
64      * @see #getRootDirEntryCount()
65      * @see #setRootDirEntryCount(int)
66      */
67     public static final int ROOT_DIR_ENTRIES_OFFSET = 0x11;
68 
69     /**
70      * The offset to the first byte of the volume label.
71      */
72     public static final int VOLUME_LABEL_OFFSET = 0x2b;
73 
74     /**
75      * Offset to the FAT file system type string.
76      *
77      * @see #getFileSystemType()
78      */
79     public static final int FILE_SYSTEM_TYPE_OFFSET = 0x36;
80 
81     /**
82      * The maximum length of the volume label.
83      */
84     public static final int MAX_VOLUME_LABEL_LENGTH = 11;
85 
86     public static final int EXTENDED_BOOT_SIGNATURE_OFFSET = 0x26;
87 
88     /**
89      * Creates a new {@code Fat16BootSector} for the specified device.
90      *
91      * @param device the {@code BlockDevice} holding the boot sector
92      */
Fat16BootSector(BlockDevice device)93     public Fat16BootSector(BlockDevice device) {
94         super(device);
95     }
96 
97     /**
98      * Returns the volume label that is stored in this boot sector.
99      *
100      * @return the volume label
101      */
getVolumeLabel()102     public String getVolumeLabel() {
103         final StringBuilder sb = new StringBuilder();
104 
105         for (int i=0; i < MAX_VOLUME_LABEL_LENGTH; i++) {
106             final char c = (char) get8(VOLUME_LABEL_OFFSET + i);
107 
108             if (c != 0) {
109                 sb.append(c);
110             } else {
111                 break;
112             }
113         }
114 
115         return sb.toString();
116     }
117 
118     /**
119      * Sets the volume label that is stored in this boot sector.
120      *
121      * @param label the new volume label
122      * @throws IllegalArgumentException if the specified label is longer
123      *      than {@link #MAX_VOLUME_LABEL_LENGTH}
124      */
setVolumeLabel(String label)125     public void setVolumeLabel(String label) throws IllegalArgumentException {
126         if (label.length() > MAX_VOLUME_LABEL_LENGTH)
127             throw new IllegalArgumentException("volume label too long");
128 
129         for (int i = 0; i < MAX_VOLUME_LABEL_LENGTH; i++) {
130             set8(VOLUME_LABEL_OFFSET + i,
131                     i < label.length() ? label.charAt(i) : 0);
132         }
133     }
134 
135     /**
136      * Gets the number of sectors/fat for FAT 12/16.
137      *
138      * @return int
139      */
140     @Override
getSectorsPerFat()141     public long getSectorsPerFat() {
142         return get16(SECTORS_PER_FAT_OFFSET);
143     }
144 
145     /**
146      * Sets the number of sectors/fat
147      *
148      * @param v  the new number of sectors per fat
149      */
150     @Override
setSectorsPerFat(long v)151     public void setSectorsPerFat(long v) {
152         if (v == getSectorsPerFat()) return;
153         if (v > 0x7FFF) throw new IllegalArgumentException(
154                 "too many sectors for a FAT12/16");
155 
156         set16(SECTORS_PER_FAT_OFFSET, (int)v);
157     }
158 
159     @Override
getFatType()160     public FatType getFatType() {
161         final long rootDirSectors = ((getRootDirEntryCount() * 32) +
162                 (getBytesPerSector() - 1)) / getBytesPerSector();
163         final long dataSectors = getSectorCount() -
164                 (getNrReservedSectors() + (getNrFats() * getSectorsPerFat()) +
165                 rootDirSectors);
166         final long clusterCount = dataSectors / getSectorsPerCluster();
167 
168         if (clusterCount > MAX_FAT16_CLUSTERS) throw new IllegalStateException(
169                 "too many clusters for FAT12/16: " + clusterCount);
170 
171         return clusterCount > MAX_FAT12_CLUSTERS ?
172             FatType.FAT16 : FatType.FAT12;
173     }
174 
175     @Override
setSectorCount(long count)176     public void setSectorCount(long count) {
177         if (count > 65535) {
178             setNrLogicalSectors(0);
179             setNrTotalSectors(count);
180         } else {
181             setNrLogicalSectors((int) count);
182             setNrTotalSectors(count);
183         }
184     }
185 
186     @Override
getSectorCount()187     public long getSectorCount() {
188         if (getNrLogicalSectors() == 0) return getNrTotalSectors();
189         else return getNrLogicalSectors();
190     }
191 
192     /**
193      * Gets the number of entries in the root directory.
194      *
195      * @return int the root directory entry count
196      */
197     @Override
getRootDirEntryCount()198     public int getRootDirEntryCount() {
199         return get16(ROOT_DIR_ENTRIES_OFFSET);
200     }
201 
202     /**
203      * Sets the number of entries in the root directory
204      *
205      * @param v the new number of entries in the root directory
206      * @throws IllegalArgumentException for negative values
207      */
setRootDirEntryCount(int v)208     public void setRootDirEntryCount(int v) throws IllegalArgumentException {
209         if (v < 0) throw new IllegalArgumentException();
210         if (v == getRootDirEntryCount()) return;
211 
212         set16(ROOT_DIR_ENTRIES_OFFSET, v);
213     }
214 
215     @Override
init()216     public void init() throws IOException {
217         super.init();
218 
219         setRootDirEntryCount(DEFAULT_ROOT_DIR_ENTRY_COUNT);
220         setVolumeLabel(DEFAULT_VOLUME_LABEL);
221     }
222 
223     @Override
getFileSystemTypeLabelOffset()224     public int getFileSystemTypeLabelOffset() {
225         return FILE_SYSTEM_TYPE_OFFSET;
226     }
227 
228     @Override
getExtendedBootSignatureOffset()229     public int getExtendedBootSignatureOffset() {
230         return EXTENDED_BOOT_SIGNATURE_OFFSET;
231     }
232 
233 }
234