diff options
Diffstat (limited to 'src/main/java/de/waldheinz/fs/fat/Fat16BootSector.java')
-rw-r--r-- | src/main/java/de/waldheinz/fs/fat/Fat16BootSector.java | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/main/java/de/waldheinz/fs/fat/Fat16BootSector.java b/src/main/java/de/waldheinz/fs/fat/Fat16BootSector.java new file mode 100644 index 0000000..38bdc2e --- /dev/null +++ b/src/main/java/de/waldheinz/fs/fat/Fat16BootSector.java @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2009,2010 Matthias Treydte <mt@waldheinz.de> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; If not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package de.waldheinz.fs.fat; + +import de.waldheinz.fs.BlockDevice; +import java.io.IOException; + +/** + * The boot sector layout as used by the FAT12 / FAT16 variants. + * + * @author Matthias Treydte <matthias.treydte at meetwise.com> + */ +final class Fat16BootSector extends BootSector { + + /** + * The default number of entries for the root directory. + * + * @see #getRootDirEntryCount() + * @see #setRootDirEntryCount(int) + */ + public static final int DEFAULT_ROOT_DIR_ENTRY_COUNT = 512; + + /** + * The default volume label. + */ + public static final String DEFAULT_VOLUME_LABEL = "NO NAME"; //NOI18N + + /** + * The maximum number of clusters for a FAT12 file system. This is actually + * the number of clusters where mkdosfs stop complaining about a FAT16 + * partition having not enough sectors, so it would be misinterpreted + * as FAT12 without special handling. + * + * @see #getNrLogicalSectors() + */ + public static final int MAX_FAT12_CLUSTERS = 4084; + + public static final int MAX_FAT16_CLUSTERS = 65524; + + /** + * The offset to the sectors per FAT value. + */ + public static final int SECTORS_PER_FAT_OFFSET = 0x16; + + /** + * The offset to the root directory entry count value. + * + * @see #getRootDirEntryCount() + * @see #setRootDirEntryCount(int) + */ + public static final int ROOT_DIR_ENTRIES_OFFSET = 0x11; + + /** + * The offset to the first byte of the volume label. + */ + public static final int VOLUME_LABEL_OFFSET = 0x2b; + + /** + * Offset to the FAT file system type string. + * + * @see #getFileSystemType() + */ + public static final int FILE_SYSTEM_TYPE_OFFSET = 0x36; + + /** + * The maximum length of the volume label. + */ + public static final int MAX_VOLUME_LABEL_LENGTH = 11; + + public static final int EXTENDED_BOOT_SIGNATURE_OFFSET = 0x26; + + /** + * Creates a new {@code Fat16BootSector} for the specified device. + * + * @param device the {@code BlockDevice} holding the boot sector + */ + public Fat16BootSector(BlockDevice device) { + super(device); + } + + /** + * Returns the volume label that is stored in this boot sector. + * + * @return the volume label + */ + public String getVolumeLabel() { + final StringBuilder sb = new StringBuilder(); + + for (int i=0; i < MAX_VOLUME_LABEL_LENGTH; i++) { + final char c = (char) get8(VOLUME_LABEL_OFFSET + i); + + if (c != 0) { + sb.append(c); + } else { + break; + } + } + + return sb.toString(); + } + + /** + * Sets the volume label that is stored in this boot sector. + * + * @param label the new volume label + * @throws IllegalArgumentException if the specified label is longer + * than {@link #MAX_VOLUME_LABEL_LENGTH} + */ + public void setVolumeLabel(String label) throws IllegalArgumentException { + if (label.length() > MAX_VOLUME_LABEL_LENGTH) + throw new IllegalArgumentException("volume label too long"); + + for (int i = 0; i < MAX_VOLUME_LABEL_LENGTH; i++) { + set8(VOLUME_LABEL_OFFSET + i, + i < label.length() ? label.charAt(i) : 0); + } + } + + /** + * Gets the number of sectors/fat for FAT 12/16. + * + * @return int + */ + @Override + public long getSectorsPerFat() { + return get16(SECTORS_PER_FAT_OFFSET); + } + + /** + * Sets the number of sectors/fat + * + * @param v the new number of sectors per fat + */ + @Override + public void setSectorsPerFat(long v) { + if (v == getSectorsPerFat()) return; + if (v > 0x7FFF) throw new IllegalArgumentException( + "too many sectors for a FAT12/16"); + + set16(SECTORS_PER_FAT_OFFSET, (int)v); + } + + @Override + public FatType getFatType() { + final long rootDirSectors = ((getRootDirEntryCount() * 32) + + (getBytesPerSector() - 1)) / getBytesPerSector(); + final long dataSectors = getSectorCount() - + (getNrReservedSectors() + (getNrFats() * getSectorsPerFat()) + + rootDirSectors); + final long clusterCount = dataSectors / getSectorsPerCluster(); + + if (clusterCount > MAX_FAT16_CLUSTERS) throw new IllegalStateException( + "too many clusters for FAT12/16: " + clusterCount); + + return clusterCount > MAX_FAT12_CLUSTERS ? + FatType.FAT16 : FatType.FAT12; + } + + @Override + public void setSectorCount(long count) { + if (count > 65535) { + setNrLogicalSectors(0); + setNrTotalSectors(count); + } else { + setNrLogicalSectors((int) count); + setNrTotalSectors(count); + } + } + + @Override + public long getSectorCount() { + if (getNrLogicalSectors() == 0) return getNrTotalSectors(); + else return getNrLogicalSectors(); + } + + /** + * Gets the number of entries in the root directory. + * + * @return int the root directory entry count + */ + @Override + public int getRootDirEntryCount() { + return get16(ROOT_DIR_ENTRIES_OFFSET); + } + + /** + * Sets the number of entries in the root directory + * + * @param v the new number of entries in the root directory + * @throws IllegalArgumentException for negative values + */ + public void setRootDirEntryCount(int v) throws IllegalArgumentException { + if (v < 0) throw new IllegalArgumentException(); + if (v == getRootDirEntryCount()) return; + + set16(ROOT_DIR_ENTRIES_OFFSET, v); + } + + @Override + public void init() throws IOException { + super.init(); + + setRootDirEntryCount(DEFAULT_ROOT_DIR_ENTRY_COUNT); + setVolumeLabel(DEFAULT_VOLUME_LABEL); + } + + @Override + public int getFileSystemTypeLabelOffset() { + return FILE_SYSTEM_TYPE_OFFSET; + } + + @Override + public int getExtendedBootSignatureOffset() { + return EXTENDED_BOOT_SIGNATURE_OFFSET; + } + +} |