1 /*
2  * Copyright (C) 2009,2010 Matthias Treydte <[email protected]>
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  * Contains the FAT32 specific parts of the boot sector.
26  *
27  * @author Matthias Treydte &lt;matthias.treydte at meetwise.com&gt;
28  */
29 final class Fat32BootSector extends BootSector {
30 
31     /**
32      * The offset to the entry specifying the first cluster of the FAT32
33      * root directory.
34      */
35     public final static int ROOT_DIR_FIRST_CLUSTER_OFFSET = 0x2c;
36 
37     /**
38      * The offset to the 4 bytes specifying the sectors per FAT value.
39      */
40     public static final int SECTORS_PER_FAT_OFFSET = 0x24;
41 
42     /**
43      * Offset to the file system type label.
44      */
45     public static final int FILE_SYSTEM_TYPE_OFFSET = 0x52;
46 
47     public static final int VERSION_OFFSET = 0x2a;
48     public static final int VERSION = 0;
49 
50     public static final int FS_INFO_SECTOR_OFFSET = 0x30;
51     public static final int BOOT_SECTOR_COPY_OFFSET = 0x32;
52     public static final int EXTENDED_BOOT_SIGNATURE_OFFSET = 0x42;
53 
54     /*
55      * TODO: make this constructor private
56      */
Fat32BootSector(BlockDevice device)57     public Fat32BootSector(BlockDevice device) throws IOException {
58         super(device);
59     }
60 
61     @Override
init()62     public void init() throws IOException {
63         super.init();
64 
65         set16(VERSION_OFFSET, VERSION);
66 
67         setBootSectorCopySector(6); /* as suggested by M$ */
68     }
69 
70     /**
71      * Returns the first cluster in the FAT that contains the root directory.
72      *
73      * @return the root directory's first cluster
74      */
getRootDirFirstCluster()75     public long getRootDirFirstCluster() {
76         return get32(ROOT_DIR_FIRST_CLUSTER_OFFSET);
77     }
78 
79     /**
80      * Sets the first cluster of the root directory.
81      *
82      * @param value the root directory's first cluster
83      */
setRootDirFirstCluster(long value)84     public void setRootDirFirstCluster(long value) {
85         if (getRootDirFirstCluster() == value) return;
86 
87         set32(ROOT_DIR_FIRST_CLUSTER_OFFSET, value);
88     }
89 
90     /**
91      * Sets the sectur number that contains a copy of the boot sector.
92      *
93      * @param sectNr the sector that contains a boot sector copy
94      */
setBootSectorCopySector(int sectNr)95     public void setBootSectorCopySector(int sectNr) {
96         if (getBootSectorCopySector() == sectNr) return;
97         if (sectNr < 0) throw new IllegalArgumentException(
98                 "boot sector copy sector must be >= 0");
99 
100         set16(BOOT_SECTOR_COPY_OFFSET, sectNr);
101     }
102 
103     /**
104      * Returns the sector that contains a copy of the boot sector, or 0 if
105      * there is no copy.
106      *
107      * @return the sector number of the boot sector copy
108      */
getBootSectorCopySector()109     public int getBootSectorCopySector() {
110         return get16(BOOT_SECTOR_COPY_OFFSET);
111     }
112 
113     /**
114      * Sets the 11-byte volume label stored at offset 0x47.
115      *
116      * @param label the new volume label, may be {@code null}
117      */
setVolumeLabel(String label)118     public void setVolumeLabel(String label) {
119         for (int i=0; i < 11; i++) {
120             final byte c =
121                     (label == null) ? 0 :
122                     (label.length() > i) ? (byte) label.charAt(i) : 0x20;
123 
124             set8(0x47 + i, c);
125         }
126     }
127 
getFsInfoSectorNr()128     public int getFsInfoSectorNr() {
129         return get16(FS_INFO_SECTOR_OFFSET);
130     }
131 
setFsInfoSectorNr(int offset)132     public void setFsInfoSectorNr(int offset) {
133         if (getFsInfoSectorNr() == offset) return;
134 
135         set16(FS_INFO_SECTOR_OFFSET, offset);
136     }
137 
138     @Override
setSectorsPerFat(long v)139     public void setSectorsPerFat(long v) {
140         if (getSectorsPerFat() == v) return;
141 
142         set32(SECTORS_PER_FAT_OFFSET, v);
143     }
144 
145     @Override
getSectorsPerFat()146     public long getSectorsPerFat() {
147         return get32(SECTORS_PER_FAT_OFFSET);
148     }
149 
150     @Override
getFatType()151     public FatType getFatType() {
152         return FatType.FAT32;
153     }
154 
155     @Override
setSectorCount(long count)156     public void setSectorCount(long count) {
157         super.setNrTotalSectors(count);
158     }
159 
160     @Override
getSectorCount()161     public long getSectorCount() {
162         return super.getNrTotalSectors();
163     }
164 
165     /**
166      * This is always 0 for FAT32.
167      *
168      * @return always 0
169      */
170     @Override
getRootDirEntryCount()171     public int getRootDirEntryCount() {
172         return 0;
173     }
174 
setFileSystemId(int id)175     public void setFileSystemId(int id) {
176         super.set32(0x43, id);
177     }
178 
getFileSystemId()179     public int getFileSystemId() {
180         return (int) super.get32(0x43);
181     }
182 
183     /**
184      * Writes a copy of this boot sector to the specified device, if a copy
185      * is requested.
186      *
187      * @param device the device to write the boot sector copy to
188      * @throws IOException on write error
189      * @see #getBootSectorCopySector()
190      */
writeCopy(BlockDevice device)191     public void writeCopy(BlockDevice device) throws IOException {
192         if (getBootSectorCopySector() > 0) {
193             final long offset = getBootSectorCopySector() * SIZE;
194             buffer.rewind();
195             buffer.limit(buffer.capacity());
196             device.write(offset, buffer);
197         }
198     }
199 
200     @Override
getFileSystemTypeLabelOffset()201     public int getFileSystemTypeLabelOffset() {
202         return FILE_SYSTEM_TYPE_OFFSET;
203     }
204 
205     @Override
getExtendedBootSignatureOffset()206     public int getExtendedBootSignatureOffset() {
207         return EXTENDED_BOOT_SIGNATURE_OFFSET;
208     }
209 }
210