fat32lib

16:35:48.828 INFO  jd.cli.Main - Decompiling fat32lib.jar
package de.waldheinz.fs;

import java.util.Comparator;

final class FsDirectoryEntry$1
  implements Comparator<FsDirectoryEntry>
{
  public int compare(FsDirectoryEntry e1, FsDirectoryEntry e2)
  {
    if (e2.isDirectory() == e1.isDirectory()) {
      return e1.getName().compareTo(e2.getName());
    }
    if (e2.isDirectory()) {
      return 1;
    }
    return -1;
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.FsDirectoryEntry.1
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

import java.io.IOException;

public abstract interface FileSystem
{
  public abstract FsDirectory getRoot()
    throws IOException;
  
  public abstract boolean isReadOnly();
  
  public abstract void close()
    throws IOException;
  
  public abstract boolean isClosed();
  
  public abstract long getTotalSpace()
    throws IOException;
  
  public abstract long getFreeSpace()
    throws IOException;
  
  public abstract long getUsableSpace()
    throws IOException;
  
  public abstract void flush()
    throws IOException;
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.FileSystem
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

import java.io.IOException;
import java.util.Iterator;

public abstract interface FsDirectory
  extends Iterable<FsDirectoryEntry>, FsObject
{
  public abstract Iterator<FsDirectoryEntry> iterator();
  
  public abstract FsDirectoryEntry getEntry(String paramString)
    throws IOException;
  
  public abstract FsDirectoryEntry addFile(String paramString)
    throws IOException;
  
  public abstract FsDirectoryEntry addDirectory(String paramString)
    throws IOException;
  
  public abstract void remove(String paramString)
    throws IOException;
  
  public abstract void flush()
    throws IOException;
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.FsDirectory
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

public final class ReadOnlyException
  extends RuntimeException
{
  private static final long serialVersionUID = 1L;
  
  public ReadOnlyException()
  {
    super("read-only");
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.ReadOnlyException
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

import java.io.IOException;
import java.nio.ByteBuffer;

public abstract interface FsFile
  extends FsObject
{
  public abstract long getLength();
  
  public abstract void setLength(long paramLong)
    throws IOException;
  
  public abstract void read(long paramLong, ByteBuffer paramByteBuffer)
    throws IOException;
  
  public abstract void write(long paramLong, ByteBuffer paramByteBuffer)
    throws ReadOnlyException, IOException;
  
  public abstract void flush()
    throws IOException;
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.FsFile
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

public abstract interface FsObject
{
  public abstract boolean isValid();
  
  public abstract boolean isReadOnly();
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.FsObject
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

import java.io.IOException;
import java.nio.ByteBuffer;

public abstract interface BlockDevice
{
  public abstract long getSize()
    throws IOException;
  
  public abstract void read(long paramLong, ByteBuffer paramByteBuffer)
    throws IOException;
  
  public abstract void write(long paramLong, ByteBuffer paramByteBuffer)
    throws ReadOnlyException, IOException, IllegalArgumentException;
  
  public abstract void flush()
    throws IOException;
  
  public abstract int getSectorSize()
    throws IOException;
  
  public abstract void close()
    throws IOException;
  
  public abstract boolean isClosed();
  
  public abstract boolean isReadOnly();
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.BlockDevice
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

import java.io.IOException;

public final class UnknownFileSystemException
  extends IOException
{
  private static final long serialVersionUID = 1L;
  private final BlockDevice device;
  
  public UnknownFileSystemException(BlockDevice device)
  {
    super("can not determin file system type");
    this.device = device;
  }
  
  public BlockDevice getDevice()
  {
    return device;
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.UnknownFileSystemException
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

public class AbstractFsObject
  implements FsObject
{
  private final boolean readOnly;
  private boolean valid;
  
  protected AbstractFsObject(boolean readOnly)
  {
    valid = true;
    this.readOnly = readOnly;
  }
  
  public final boolean isValid()
  {
    return valid;
  }
  
  protected final void invalidate()
  {
    valid = false;
  }
  
  protected final void checkValid()
    throws IllegalStateException
  {
    if (!isValid()) {
      throw new IllegalStateException(this + " is not valid");
    }
  }
  
  protected final void checkWritable()
    throws IllegalStateException, ReadOnlyException
  {
    checkValid();
    if (isReadOnly()) {
      throw new ReadOnlyException();
    }
  }
  
  public final boolean isReadOnly()
  {
    return readOnly;
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.AbstractFsObject
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

import de.waldheinz.fs.fat.FatFileSystem;
import java.io.IOException;

public class FileSystemFactory
{
  public static FileSystem create(BlockDevice device, boolean readOnly)
    throws UnknownFileSystemException, IOException
  {
    return FatFileSystem.read(device, readOnly);
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.FileSystemFactory
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

import java.io.IOException;

public abstract class AbstractFileSystem
  implements FileSystem
{
  private final boolean readOnly;
  private boolean closed;
  
  public AbstractFileSystem(boolean readOnly)
  {
    closed = false;
    this.readOnly = readOnly;
  }
  
  public void close()
    throws IOException
  {
    if (!isClosed())
    {
      if (!isReadOnly()) {
        flush();
      }
      closed = true;
    }
  }
  
  public final boolean isClosed()
  {
    return closed;
  }
  
  public final boolean isReadOnly()
  {
    return readOnly;
  }
  
  protected final void checkClosed()
    throws IllegalStateException
  {
    if (isClosed()) {
      throw new IllegalStateException("file system was already closed");
    }
  }
  
  protected final void checkReadOnly()
    throws ReadOnlyException
  {
    if (isReadOnly()) {
      throw new ReadOnlyException();
    }
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.AbstractFileSystem
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs;

import java.io.IOException;
import java.util.Comparator;

public abstract interface FsDirectoryEntry
  extends FsObject
{
  public static final Comparator<FsDirectoryEntry> DIRECTORY_ENTRY_COMPARATOR = new Comparator()
  {
    public int compare(FsDirectoryEntry e1, FsDirectoryEntry e2)
    {
      if (e2.isDirectory() == e1.isDirectory()) {
        return e1.getName().compareTo(e2.getName());
      }
      if (e2.isDirectory()) {
        return 1;
      }
      return -1;
    }
  };
  
  public abstract String getName();
  
  public abstract long getLastModified()
    throws IOException;
  
  public abstract long getCreated()
    throws IOException;
  
  public abstract long getLastAccessed()
    throws IOException;
  
  public abstract boolean isFile();
  
  public abstract boolean isDirectory();
  
  public abstract void setName(String paramString)
    throws IOException;
  
  public abstract void setLastModified(long paramLong)
    throws IOException;
  
  public abstract FsFile getFile()
    throws IOException, UnsupportedOperationException;
  
  public abstract FsDirectory getDirectory()
    throws IOException, UnsupportedOperationException;
  
  public abstract boolean isDirty();
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.FsDirectoryEntry
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

import de.waldheinz.fs.BlockDevice;
import java.io.IOException;

final class Fat16BootSector
  extends BootSector
{
  public static final int DEFAULT_ROOT_DIR_ENTRY_COUNT = 512;
  public static final String DEFAULT_VOLUME_LABEL = "NO NAME";
  public static final int MAX_FAT12_CLUSTERS = 4084;
  public static final int MAX_FAT16_CLUSTERS = 65524;
  public static final int SECTORS_PER_FAT_OFFSET = 22;
  public static final int ROOT_DIR_ENTRIES_OFFSET = 17;
  public static final int VOLUME_LABEL_OFFSET = 43;
  public static final int FILE_SYSTEM_TYPE_OFFSET = 54;
  public static final int MAX_VOLUME_LABEL_LENGTH = 11;
  public static final int EXTENDED_BOOT_SIGNATURE_OFFSET = 38;
  
  public Fat16BootSector(BlockDevice device)
  {
    super(device);
  }
  
  public String getVolumeLabel()
  {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 11; i++)
    {
      char c = (char)get8(43 + i);
      if (c == 0) {
        break;
      }
      sb.append(c);
    }
    return sb.toString();
  }
  
  public void setVolumeLabel(String label)
    throws IllegalArgumentException
  {
    if (label.length() > 11) {
      throw new IllegalArgumentException("volume label too long");
    }
    for (int i = 0; i < 11; i++) {
      set8(43 + i, i < label.length() ? label.charAt(i) : 0);
    }
  }
  
  public long getSectorsPerFat()
  {
    return get16(22);
  }
  
  public void setSectorsPerFat(long v)
  {
    if (v == getSectorsPerFat()) {
      return;
    }
    if (v > 32767L) {
      throw new IllegalArgumentException("too many sectors for a FAT12/16");
    }
    set16(22, (int)v);
  }
  
  public FatType getFatType()
  {
    long rootDirSectors = (getRootDirEntryCount() * 32 + (getBytesPerSector() - 1)) / getBytesPerSector();
    
    long dataSectors = getSectorCount() - (getNrReservedSectors() + getNrFats() * getSectorsPerFat() + rootDirSectors);
    
    long clusterCount = dataSectors / getSectorsPerCluster();
    if (clusterCount > 65524L) {
      throw new IllegalStateException("too many clusters for FAT12/16: " + clusterCount);
    }
    return clusterCount > 4084L ? FatType.FAT16 : FatType.FAT12;
  }
  
  public void setSectorCount(long count)
  {
    if (count > 65535L)
    {
      setNrLogicalSectors(0);
      setNrTotalSectors(count);
    }
    else
    {
      setNrLogicalSectors((int)count);
      setNrTotalSectors(count);
    }
  }
  
  public long getSectorCount()
  {
    if (getNrLogicalSectors() == 0) {
      return getNrTotalSectors();
    }
    return getNrLogicalSectors();
  }
  
  public int getRootDirEntryCount()
  {
    return get16(17);
  }
  
  public void setRootDirEntryCount(int v)
    throws IllegalArgumentException
  {
    if (v < 0) {
      throw new IllegalArgumentException();
    }
    if (v == getRootDirEntryCount()) {
      return;
    }
    set16(17, v);
  }
  
  public void init()
    throws IOException
  {
    super.init();
    
    setRootDirEntryCount(512);
    setVolumeLabel("NO NAME");
  }
  
  public int getFileSystemTypeLabelOffset()
  {
    return 54;
  }
  
  public int getExtendedBootSignatureOffset()
  {
    return 38;
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.Fat16BootSector
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

import de.waldheinz.fs.BlockDevice;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

class Sector
{
  private final BlockDevice device;
  private final long offset;
  protected final ByteBuffer buffer;
  private boolean dirty;
  
  protected Sector(BlockDevice device, long offset, int size)
  {
    this.offset = offset;
    this.device = device;
    buffer = ByteBuffer.allocate(size);
    buffer.order(ByteOrder.LITTLE_ENDIAN);
    dirty = true;
  }
  
  protected void read()
    throws IOException
  {
    buffer.rewind();
    buffer.limit(buffer.capacity());
    device.read(offset, buffer);
    dirty = false;
  }
  
  public final boolean isDirty()
  {
    return dirty;
  }
  
  protected final void markDirty()
  {
    dirty = true;
  }
  
  public BlockDevice getDevice()
  {
    return device;
  }
  
  public final void write()
    throws IOException
  {
    if (!isDirty()) {
      return;
    }
    buffer.position(0);
    buffer.limit(buffer.capacity());
    device.write(offset, buffer);
    dirty = false;
  }
  
  protected int get16(int offset)
  {
    return buffer.getShort(offset) & 0xFFFF;
  }
  
  protected long get32(int offset)
  {
    return buffer.getInt(offset) & 0xFFFFFFFF;
  }
  
  protected int get8(int offset)
  {
    return buffer.get(offset) & 0xFF;
  }
  
  protected void set16(int offset, int value)
  {
    buffer.putShort(offset, (short)(value & 0xFFFF));
    dirty = true;
  }
  
  protected void set32(int offset, long value)
  {
    buffer.putInt(offset, (int)(value & 0xFFFFFFFFFFFFFFFF));
    dirty = true;
  }
  
  protected void set8(int offset, int value)
  {
    if ((value & 0xFF) != value) {
      throw new IllegalArgumentException(value + " too big to be stored in a single octet");
    }
    buffer.put(offset, (byte)(value & 0xFF));
    dirty = true;
  }
  
  protected long getOffset()
  {
    return offset;
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.Sector
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

class SuperFloppyFormatter$1 {}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.SuperFloppyFormatter.1
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

import de.waldheinz.fs.AbstractFileSystem;
import de.waldheinz.fs.BlockDevice;
import de.waldheinz.fs.ReadOnlyException;
import java.io.IOException;

public final class FatFileSystem
  extends AbstractFileSystem
{
  private final Fat fat;
  private final FsInfoSector fsiSector;
  private final BootSector bs;
  private final FatLfnDirectory rootDir;
  private final AbstractDirectory rootDirStore;
  private final FatType fatType;
  private final long filesOffset;
  
  FatFileSystem(BlockDevice api, boolean readOnly)
    throws IOException
  {
    this(api, readOnly, false);
  }
  
  private FatFileSystem(BlockDevice device, boolean readOnly, boolean ignoreFatDifferences)
    throws IOException
  {
    super(readOnly);
    
    bs = BootSector.read(device);
    if (bs.getNrFats() <= 0) {
      throw new IOException("boot sector says there are no FATs");
    }
    filesOffset = FatUtils.getFilesOffset(bs);
    fatType = bs.getFatType();
    fat = Fat.read(bs, 0);
    if (!ignoreFatDifferences) {
      for (int i = 1; i < bs.getNrFats(); i++)
      {
        Fat tmpFat = Fat.read(bs, i);
        if (!fat.equals(tmpFat)) {
          throw new IOException("FAT " + i + " differs from FAT 0");
        }
      }
    }
    if (fatType == FatType.FAT32)
    {
      Fat32BootSector f32bs = (Fat32BootSector)bs;
      ClusterChain rootDirFile = new ClusterChain(fat, f32bs.getRootDirFirstCluster(), isReadOnly());
      
      rootDirStore = ClusterChainDirectory.readRoot(rootDirFile);
      fsiSector = FsInfoSector.read(f32bs);
      if (fsiSector.getFreeClusterCount() != fat.getFreeClusterCount()) {
        throw new IOException("free cluster count mismatch - fat: " + fat.getFreeClusterCount() + " - fsinfo: " + fsiSector.getFreeClusterCount());
      }
    }
    else
    {
      rootDirStore = Fat16RootDirectory.read((Fat16BootSector)bs, readOnly);
      
      fsiSector = null;
    }
    rootDir = new FatLfnDirectory(rootDirStore, fat, isReadOnly());
  }
  
  public static FatFileSystem read(BlockDevice device, boolean readOnly)
    throws IOException
  {
    return new FatFileSystem(device, readOnly);
  }
  
  long getFilesOffset()
  {
    checkClosed();
    
    return filesOffset;
  }
  
  public FatType getFatType()
  {
    checkClosed();
    
    return fatType;
  }
  
  public String getVolumeLabel()
  {
    checkClosed();
    
    String fromDir = rootDirStore.getLabel();
    if ((fromDir == null) && (fatType != FatType.FAT32)) {
      return ((Fat16BootSector)bs).getVolumeLabel();
    }
    return fromDir;
  }
  
  public void setVolumeLabel(String label)
    throws ReadOnlyException, IOException
  {
    checkClosed();
    checkReadOnly();
    
    rootDirStore.setLabel(label);
    if (fatType != FatType.FAT32) {
      ((Fat16BootSector)bs).setVolumeLabel(label);
    }
  }
  
  AbstractDirectory getRootDirStore()
  {
    checkClosed();
    
    return rootDirStore;
  }
  
  public void flush()
    throws IOException
  {
    checkClosed();
    if (bs.isDirty()) {
      bs.write();
    }
    for (int i = 0; i < bs.getNrFats(); i++) {
      fat.writeCopy(FatUtils.getFatOffset(bs, i));
    }
    rootDir.flush();
    if (fsiSector != null)
    {
      fsiSector.setFreeClusterCount(fat.getFreeClusterCount());
      fsiSector.setLastAllocatedCluster(fat.getLastAllocatedCluster());
      fsiSector.write();
    }
  }
  
  public FatLfnDirectory getRoot()
  {
    checkClosed();
    
    return rootDir;
  }
  
  public Fat getFat()
  {
    return fat;
  }
  
  public BootSector getBootSector()
  {
    checkClosed();
    
    return bs;
  }
  
  public long getFreeSpace()
  {
    return fat.getFreeClusterCount() * bs.getBytesPerCluster();
  }
  
  public long getTotalSpace()
  {
    return bs.getDataClusterCount() * bs.getBytesPerCluster();
  }
  
  public long getUsableSpace()
  {
    return -1L;
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.FatFileSystem
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

import de.waldheinz.fs.BlockDevice;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;

public final class Fat
{
  public static final int FIRST_CLUSTER = 2;
  private final long[] entries;
  private final FatType fatType;
  private final int sectorCount;
  private final int sectorSize;
  private final BlockDevice device;
  private final BootSector bs;
  private final long offset;
  private final int lastClusterIndex;
  private int lastAllocatedCluster;
  
  public static Fat read(BootSector bs, int fatNr)
    throws IOException, IllegalArgumentException
  {
    if (fatNr > bs.getNrFats()) {
      throw new IllegalArgumentException("boot sector says there are only " + bs.getNrFats() + " FATs when reading FAT #" + fatNr);
    }
    long fatOffset = FatUtils.getFatOffset(bs, fatNr);
    Fat result = new Fat(bs, fatOffset);
    result.read();
    return result;
  }
  
  public static Fat create(BootSector bs, int fatNr)
    throws IOException, IllegalArgumentException
  {
    if (fatNr > bs.getNrFats()) {
      throw new IllegalArgumentException("boot sector says there are only " + bs.getNrFats() + " FATs when creating FAT #" + fatNr);
    }
    long fatOffset = FatUtils.getFatOffset(bs, fatNr);
    Fat result = new Fat(bs, fatOffset);
    if (bs.getDataClusterCount() > entries.length) {
      throw new IOException("FAT too small for device");
    }
    result.init(bs.getMediumDescriptor());
    result.write();
    return result;
  }
  
  private Fat(BootSector bs, long offset)
    throws IOException
  {
    this.bs = bs;
    fatType = bs.getFatType();
    if (bs.getSectorsPerFat() > 2147483647L) {
      throw new IllegalArgumentException("FAT too large");
    }
    if (bs.getSectorsPerFat() <= 0L) {
      throw new IOException("boot sector says there are " + bs.getSectorsPerFat() + " sectors per FAT");
    }
    if (bs.getBytesPerSector() <= 0) {
      throw new IOException("boot sector says there are " + bs.getBytesPerSector() + " bytes per sector");
    }
    sectorCount = ((int)bs.getSectorsPerFat());
    sectorSize = bs.getBytesPerSector();
    device = bs.getDevice();
    this.offset = offset;
    lastAllocatedCluster = 2;
    if (bs.getDataClusterCount() > 2147483647L) {
      throw new IOException("too many data clusters");
    }
    if (bs.getDataClusterCount() == 0L) {
      throw new IOException("no data clusters");
    }
    lastClusterIndex = ((int)bs.getDataClusterCount() + 2);
    
    entries = new long[(int)(sectorCount * sectorSize / fatType.getEntrySize())];
    if (lastClusterIndex > entries.length) {
      throw new IOException("file system has " + lastClusterIndex + "clusters but only " + entries.length + " FAT entries");
    }
  }
  
  public FatType getFatType()
  {
    return fatType;
  }
  
  public BootSector getBootSector()
  {
    return bs;
  }
  
  public BlockDevice getDevice()
  {
    return device;
  }
  
  private void init(int mediumDescriptor)
  {
    entries[0] = (mediumDescriptor & 0xFF | 0xFFFFF00 & fatType.getBitMask());
    
    entries[1] = fatType.getEofMarker();
  }
  
  private void read()
    throws IOException
  {
    byte[] data = new byte[sectorCount * sectorSize];
    device.read(offset, ByteBuffer.wrap(data));
    for (int i = 0; i < entries.length; i++) {
      entries[i] = fatType.readEntry(data, i);
    }
  }
  
  public void write()
    throws IOException
  {
    writeCopy(offset);
  }
  
  public void writeCopy(long offset)
    throws IOException
  {
    byte[] data = new byte[sectorCount * sectorSize];
    for (int index = 0; index < entries.length; index++) {
      fatType.writeEntry(data, index, entries[index]);
    }
    device.write(offset, ByteBuffer.wrap(data));
  }
  
  public int getMediumDescriptor()
  {
    return (int)(entries[0] & 0xFF);
  }
  
  public long getEntry(int index)
  {
    return entries[index];
  }
  
  public int getLastFreeCluster()
  {
    return lastAllocatedCluster;
  }
  
  public long[] getChain(long startCluster)
  {
    testCluster(startCluster);
    
    int count = 1;
    long cluster = startCluster;
    while (!isEofCluster(entries[((int)cluster)]))
    {
      count++;
      cluster = entries[((int)cluster)];
    }
    long[] chain = new long[count];
    chain[0] = startCluster;
    cluster = startCluster;
    int i = 0;
    while (!isEofCluster(entries[((int)cluster)]))
    {
      cluster = entries[((int)cluster)];
      chain[(++i)] = cluster;
    }
    return chain;
  }
  
  public long getNextCluster(long cluster)
  {
    testCluster(cluster);
    long entry = entries[((int)cluster)];
    if (isEofCluster(entry)) {
      return -1L;
    }
    return entry;
  }
  
  public long allocNew()
    throws IOException
  {
    int entryIndex = -1;
    for (int i = lastAllocatedCluster; i < lastClusterIndex; i++) {
      if (isFreeCluster(i))
      {
        entryIndex = i;
        break;
      }
    }
    if (entryIndex < 0) {
      for (i = 2; i < lastAllocatedCluster; i++) {
        if (isFreeCluster(i))
        {
          entryIndex = i;
          break;
        }
      }
    }
    if (entryIndex < 0) {
      throw new IOException("FAT Full (" + (lastClusterIndex - 2) + ", " + i + ")");
    }
    entries[entryIndex] = fatType.getEofMarker();
    lastAllocatedCluster = (entryIndex % lastClusterIndex);
    if (lastAllocatedCluster < 2) {
      lastAllocatedCluster = 2;
    }
    return entryIndex;
  }
  
  public int getFreeClusterCount()
  {
    int result = 0;
    for (int i = 2; i < lastClusterIndex; i++) {
      if (isFreeCluster(i)) {
        result++;
      }
    }
    return result;
  }
  
  public int getLastAllocatedCluster()
  {
    return lastAllocatedCluster;
  }
  
  public long[] allocNew(int nrClusters)
    throws IOException
  {
    long[] rc = new long[nrClusters];
    
    rc[0] = allocNew();
    for (int i = 1; i < nrClusters; i++) {
      rc[i] = allocAppend(rc[(i - 1)]);
    }
    return rc;
  }
  
  public long allocAppend(long cluster)
    throws IOException
  {
    testCluster(cluster);
    while (!isEofCluster(entries[((int)cluster)])) {
      cluster = entries[((int)cluster)];
    }
    long newCluster = allocNew();
    entries[((int)cluster)] = newCluster;
    
    return newCluster;
  }
  
  public void setEof(long cluster)
  {
    testCluster(cluster);
    entries[((int)cluster)] = fatType.getEofMarker();
  }
  
  public void setFree(long cluster)
  {
    testCluster(cluster);
    entries[((int)cluster)] = 0L;
  }
  
  public boolean equals(Object obj)
  {
    if (!(obj instanceof Fat)) {
      return false;
    }
    Fat other = (Fat)obj;
    if (fatType != fatType) {
      return false;
    }
    if (sectorCount != sectorCount) {
      return false;
    }
    if (sectorSize != sectorSize) {
      return false;
    }
    if (lastClusterIndex != lastClusterIndex) {
      return false;
    }
    if (!Arrays.equals(entries, entries)) {
      return false;
    }
    if (getMediumDescriptor() != other.getMediumDescriptor()) {
      return false;
    }
    return true;
  }
  
  public int hashCode()
  {
    int hash = 7;
    hash = 23 * hash + Arrays.hashCode(entries);
    hash = 23 * hash + fatType.hashCode();
    hash = 23 * hash + sectorCount;
    hash = 23 * hash + sectorSize;
    hash = 23 * hash + lastClusterIndex;
    return hash;
  }
  
  protected boolean isFreeCluster(long entry)
  {
    if (entry > 2147483647L) {
      throw new IllegalArgumentException();
    }
    return entries[((int)entry)] == 0L;
  }
  
  protected boolean isReservedCluster(long entry)
  {
    return fatType.isReservedCluster(entry);
  }
  
  protected boolean isEofCluster(long entry)
  {
    return fatType.isEofCluster(entry);
  }
  
  protected void testCluster(long cluster)
    throws IllegalArgumentException
  {
    if ((cluster < 2L) || (cluster >= entries.length)) {
      throw new IllegalArgumentException("invalid cluster value " + cluster);
    }
  }
  
  public String toString()
  {
    StringBuilder sb = new StringBuilder();
    
    sb.append(getClass().getSimpleName());
    sb.append("[type=");
    sb.append(fatType);
    sb.append(", mediumDescriptor=0x");
    sb.append(Integer.toHexString(getMediumDescriptor()));
    sb.append(", sectorCount=");
    sb.append(sectorCount);
    sb.append(", sectorSize=");
    sb.append(sectorSize);
    sb.append(", freeClusters=");
    sb.append(getFreeClusterCount());
    sb.append("]");
    
    return sb.toString();
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.Fat
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

 enum FatType$2
{
  FatType$2(int x0, long x1, float x2, String x3)
  {
    super(paramString, paramInt, x0, x1, x2, x3, null);
  }
  
  long readEntry(byte[] data, int index)
  {
    int idx = index << 1;
    int b1 = data[idx] & 0xFF;
    int b2 = data[(idx + 1)] & 0xFF;
    return b2 << 8 | b1;
  }
  
  void writeEntry(byte[] data, int index, long entry)
  {
    int idx = index << 1;
    data[idx] = ((byte)(int)(entry & 0xFF));
    data[(idx + 1)] = ((byte)(int)(entry >> 8 & 0xFF));
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.FatType.2
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

import de.waldheinz.fs.BlockDevice;
import java.io.IOException;
import java.util.Random;

public final class SuperFloppyFormatter
{
  public static final int MEDIUM_DESCRIPTOR_HD = 248;
  public static final int DEFAULT_FAT_COUNT = 2;
  public static final int DEFAULT_SECTORS_PER_TRACK = 32;
  public static final int DEFAULT_HEADS = 64;
  @Deprecated
  public static final int DEFULT_HEADS = 64;
  public static final String DEFAULT_OEM_NAME = "fat32lib";
  private static final int MAX_DIRECTORY = 512;
  private final BlockDevice device;
  private String label;
  private String oemName;
  private FatType fatType;
  private int sectorsPerCluster;
  private int reservedSectors;
  private int fatCount;
  
  private SuperFloppyFormatter(BlockDevice device)
    throws IOException
  {
    this.device = device;
    oemName = "fat32lib";
    fatCount = 2;
    setFatType(fatTypeFromDevice());
  }
  
  public static SuperFloppyFormatter get(BlockDevice dev)
    throws IOException
  {
    return new SuperFloppyFormatter(dev);
  }
  
  public String getOemName()
  {
    return oemName;
  }
  
  public SuperFloppyFormatter setOemName(String oemName)
  {
    this.oemName = oemName;
    return this;
  }
  
  public SuperFloppyFormatter setVolumeLabel(String label)
  {
    this.label = label;
    return this;
  }
  
  public String getVolumeLabel()
  {
    return label;
  }
  
  private void initBootSector(BootSector bs)
    throws IOException
  {
    bs.init();
    bs.setFileSystemTypeLabel(fatType.getLabel());
    bs.setNrReservedSectors(reservedSectors);
    bs.setNrFats(fatCount);
    bs.setSectorsPerCluster(sectorsPerCluster);
    bs.setMediumDescriptor(248);
    bs.setSectorsPerTrack(32);
    bs.setNrHeads(64);
    bs.setOemName(oemName);
  }
  
  public FatFileSystem format()
    throws IOException
  {
    int sectorSize = device.getSectorSize();
    int totalSectors = (int)(device.getSize() / sectorSize);
    if (sectorsPerCluster == 0) {
      throw new AssertionError();
    }
    FsInfoSector fsi;
    BootSector bs;
    FsInfoSector fsi;
    if (fatType == FatType.FAT32)
    {
      BootSector bs = new Fat32BootSector(device);
      initBootSector(bs);
      
      Fat32BootSector f32bs = (Fat32BootSector)bs;
      
      f32bs.setFsInfoSectorNr(1);
      
      f32bs.setSectorsPerFat(sectorsPerFat(0, totalSectors));
      Random rnd = new Random(System.currentTimeMillis());
      f32bs.setFileSystemId(rnd.nextInt());
      
      f32bs.setVolumeLabel(label);
      
      fsi = FsInfoSector.create(f32bs);
    }
    else
    {
      bs = new Fat16BootSector(device);
      initBootSector(bs);
      
      Fat16BootSector f16bs = (Fat16BootSector)bs;
      
      int rootDirEntries = rootDirectorySize(device.getSectorSize(), totalSectors);
      
      f16bs.setRootDirEntryCount(rootDirEntries);
      f16bs.setSectorsPerFat(sectorsPerFat(rootDirEntries, totalSectors));
      if (label != null) {
        f16bs.setVolumeLabel(label);
      }
      fsi = null;
    }
    if (fatType == FatType.FAT32)
    {
      Fat32BootSector f32bs = (Fat32BootSector)bs;
      
      f32bs.writeCopy(device);
    }
    Fat fat = Fat.create(bs, 0);
    AbstractDirectory rootDirStore;
    if (fatType == FatType.FAT32)
    {
      AbstractDirectory rootDirStore = ClusterChainDirectory.createRoot(fat);
      fsi.setFreeClusterCount(fat.getFreeClusterCount());
      fsi.setLastAllocatedCluster(fat.getLastAllocatedCluster());
      fsi.write();
    }
    else
    {
      rootDirStore = Fat16RootDirectory.create((Fat16BootSector)bs);
    }
    FatLfnDirectory rootDir = new FatLfnDirectory(rootDirStore, fat, false);
    
    rootDir.flush();
    for (int i = 0; i < bs.getNrFats(); i++) {
      fat.writeCopy(FatUtils.getFatOffset(bs, i));
    }
    bs.write();
    
    FatFileSystem fs = FatFileSystem.read(device, false);
    if (label != null) {
      fs.setVolumeLabel(label);
    }
    fs.flush();
    return fs;
  }
  
  private int sectorsPerFat(int rootDirEntries, int totalSectors)
    throws IOException
  {
    int bps = device.getSectorSize();
    int rootDirSectors = (rootDirEntries * 32 + (bps - 1)) / bps;
    
    long tmp1 = totalSectors - (reservedSectors + rootDirSectors);
    
    int tmp2 = 256 * sectorsPerCluster + fatCount;
    if (fatType == FatType.FAT32) {
      tmp2 /= 2;
    }
    int result = (int)((tmp1 + (tmp2 - 1)) / tmp2);
    
    return result;
  }
  
  private FatType fatTypeFromDevice()
    throws IOException
  {
    return fatTypeFromSize(device.getSize());
  }
  
  public static FatType fatTypeFromSize(long sizeInBytes)
  {
    long sizeInMb = sizeInBytes / 1048576L;
    if (sizeInMb < 4L) {
      return FatType.FAT12;
    }
    if (sizeInMb < 512L) {
      return FatType.FAT16;
    }
    return FatType.FAT32;
  }
  
  public static int clusterSizeFromSize(long sizeInBytes, int sectorSize)
  {
    switch (fatTypeFromSize(sizeInBytes))
    {
    case FAT12: 
      return sectorsPerCluster12(sizeInBytes, sectorSize);
    case FAT16: 
      return sectorsPerCluster16FromSize(sizeInBytes, sectorSize);
    case FAT32: 
      return sectorsPerCluster32FromSize(sizeInBytes, sectorSize);
    }
    throw new AssertionError();
  }
  
  public FatType getFatType()
  {
    return fatType;
  }
  
  public SuperFloppyFormatter setFatType(FatType fatType)
    throws IOException, IllegalArgumentException
  {
    if (fatType == null) {
      throw new NullPointerException();
    }
    switch (fatType)
    {
    case FAT12: 
    case FAT16: 
      reservedSectors = 1;
      break;
    case FAT32: 
      reservedSectors = 32;
    }
    sectorsPerCluster = defaultSectorsPerCluster(fatType);
    this.fatType = fatType;
    
    return this;
  }
  
  private static int rootDirectorySize(int bps, int nbTotalSectors)
  {
    int totalSize = bps * nbTotalSectors;
    if (totalSize >= 81920) {
      return 512;
    }
    return totalSize / 160;
  }
  
  private static int MAX_FAT32_CLUSTERS = 268435445;
  
  private static int sectorsPerCluster32FromSize(long size, int sectorSize)
  {
    long sectors = size / sectorSize;
    if (sectors <= 66600L) {
      throw new IllegalArgumentException("disk too small for FAT32");
    }
    return sectors > 532480L ? 8 : sectors > 16777216L ? 16 : sectors > 33554432L ? 32 : sectors > 67108864L ? 64 : 1;
  }
  
  private int sectorsPerCluster32()
    throws IOException
  {
    if (reservedSectors != 32) {
      throw new IllegalStateException("number of reserved sectors must be 32");
    }
    if (fatCount != 2) {
      throw new IllegalStateException("number of FATs must be 2");
    }
    long sectors = device.getSize() / device.getSectorSize();
    if (sectors <= 66600L) {
      throw new IllegalArgumentException("disk too small for FAT32");
    }
    return sectorsPerCluster32FromSize(device.getSize(), device.getSectorSize());
  }
  
  private static int MAX_FAT16_CLUSTERS = 65524;
  
  private static int sectorsPerCluster16FromSize(long size, int sectorSize)
  {
    long sectors = size / sectorSize;
    if (sectors <= 8400L) {
      throw new IllegalArgumentException("disk too small for FAT16");
    }
    if (sectors > 4194304L) {
      throw new IllegalArgumentException("disk too large for FAT16");
    }
    return sectors > 32680L ? 4 : sectors > 262144L ? 8 : sectors > 524288L ? 16 : sectors > 1048576L ? 32 : sectors > 2097152L ? 64 : 2;
  }
  
  private int sectorsPerCluster16()
    throws IOException
  {
    if (reservedSectors != 1) {
      throw new IllegalStateException("number of reserved sectors must be 1");
    }
    if (fatCount != 2) {
      throw new IllegalStateException("number of FATs must be 2");
    }
    long size = device.getSize();
    int sectorSize = device.getSectorSize();
    return sectorsPerCluster16FromSize(size, sectorSize);
  }
  
  private int defaultSectorsPerCluster(FatType fatType)
    throws IOException
  {
    long size = device.getSize();
    int sectorSize = device.getSectorSize();
    switch (fatType)
    {
    case FAT12: 
      return sectorsPerCluster12(size, sectorSize);
    case FAT16: 
      return sectorsPerCluster16();
    case FAT32: 
      return sectorsPerCluster32();
    }
    throw new AssertionError();
  }
  
  private static int sectorsPerCluster12(long size, int sectorSize)
  {
    int result = 1;
    
    long sectors = size / sectorSize;
    while (sectors / result > 4084L)
    {
      result *= 2;
      if (result * size > 4096L) {
        throw new IllegalArgumentException("disk too large for FAT12");
      }
    }
    return result;
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.SuperFloppyFormatter
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

 enum FatType$3
{
  FatType$3(int x0, long x1, float x2, String x3)
  {
    super(paramString, paramInt, x0, x1, x2, x3, null);
  }
  
  long readEntry(byte[] data, int index)
  {
    int idx = index * 4;
    long l1 = data[idx] & 0xFF;
    long l2 = data[(idx + 1)] & 0xFF;
    long l3 = data[(idx + 2)] & 0xFF;
    long l4 = data[(idx + 3)] & 0xFF;
    return l4 << 24 | l3 << 16 | l2 << 8 | l1;
  }
  
  void writeEntry(byte[] data, int index, long entry)
  {
    int idx = index << 2;
    data[idx] = ((byte)(int)(entry & 0xFF));
    data[(idx + 1)] = ((byte)(int)(entry >> 8 & 0xFF));
    data[(idx + 2)] = ((byte)(int)(entry >> 16 & 0xFF));
    data[(idx + 3)] = ((byte)(int)(entry >> 24 & 0xFF));
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.FatType.3
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

import de.waldheinz.fs.BlockDevice;
import java.io.IOException;
import java.nio.ByteBuffer;

final class FsInfoSector
  extends Sector
{
  public static final int FREE_CLUSTERS_OFFSET = 488;
  public static final int LAST_ALLOCATED_OFFSET = 492;
  public static final int SIGNATURE_OFFSET = 510;
  
  private FsInfoSector(BlockDevice device, long offset)
  {
    super(device, offset, 512);
  }
  
  public static FsInfoSector read(Fat32BootSector bs)
    throws IOException
  {
    FsInfoSector result = new FsInfoSector(bs.getDevice(), offset(bs));
    
    result.read();
    result.verify();
    return result;
  }
  
  public static FsInfoSector create(Fat32BootSector bs)
    throws IOException
  {
    int offset = offset(bs);
    if (offset == 0) {
      throw new IOException("creating a FS info sector at offset 0 is strange");
    }
    FsInfoSector result = new FsInfoSector(bs.getDevice(), offset(bs));
    
    result.init();
    result.write();
    return result;
  }
  
  private static int offset(Fat32BootSector bs)
  {
    return bs.getFsInfoSectorNr() * bs.getBytesPerSector();
  }
  
  public void setFreeClusterCount(long value)
  {
    if (getFreeClusterCount() == value) {
      return;
    }
    set32(488, value);
  }
  
  public long getFreeClusterCount()
  {
    return get32(488);
  }
  
  public void setLastAllocatedCluster(long value)
  {
    if (getLastAllocatedCluster() == value) {
      return;
    }
    super.set32(492, value);
  }
  
  public long getLastAllocatedCluster()
  {
    return super.get32(492);
  }
  
  private void init()
  {
    buffer.position(0);
    buffer.put((byte)82);
    buffer.put((byte)82);
    buffer.put((byte)97);
    buffer.put((byte)65);
    
    buffer.position(484);
    buffer.put((byte)114);
    buffer.put((byte)114);
    buffer.put((byte)65);
    buffer.put((byte)97);
    
    setFreeClusterCount(-1L);
    setLastAllocatedCluster(2L);
    
    buffer.position(510);
    buffer.put((byte)85);
    buffer.put((byte)-86);
    
    markDirty();
  }
  
  private void verify()
    throws IOException
  {
    if ((get8(510) != 85) || (get8(511) != 170)) {
      throw new IOException("invalid FS info sector signature");
    }
  }
  
  public String toString()
  {
    return FsInfoSector.class.getSimpleName() + " [freeClusterCount=" + getFreeClusterCount() + ", lastAllocatedCluster=" + getLastAllocatedCluster() + ", offset=" + getOffset() + ", dirty=" + isDirty() + "]";
  }
}

/* Location:
 * Qualified Name:     de.waldheinz.fs.fat.FsInfoSector
 * Java Class Version: 6 (50.0)
 * JD-Core Version:    0.7.1
 */
package de.waldheinz.fs.fat;

import de.waldheinz.fs.BlockDevice;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public abstract class BootSector
  extends Sector
{
  public static final int FAT_COUNT_OFFSET = 16;
  public static final int RESERVED_SECTORS_OFFSET = 14;
  public static final int TOTAL_SECTORS_16_OFFSET = 19;
  public static final int TOTAL_
1 2 3

Further reading...

For more information on Java 1.5 Tiger, you may find Java 1.5 Tiger, A developer's Notebook by D. Flanagan and B. McLaughlin from O'Reilly of interest.

New!JAR listings


Copyright 2006-2017. Infinite Loop Ltd