📄 fatfs.java
字号:
}
public long getOffset(Object fd) throws IOException
{
synchronized (lock)
{
return ((FATFSDescriptor)fd).filePointer;
}
}
public long getLength(Object fd) throws IOException
{
synchronized (lock)
{
return ((FATFSDescriptor)fd).length;
}
}
public int available(Object fd) throws IOException
{
FATFSDescriptor fDesc = (FATFSDescriptor)fd;
synchronized (lock)
{
return fDesc.length - fDesc.filePointer;
}
}
public void close(Object fd) throws IOException
{
FATFSDescriptor fDesc = (FATFSDescriptor)fd;
synchronized (lock)
{
if((openWriters != null) && openWriters.contains(fd))
{
synchronized (sector)
{
if(!disk.read((fDesc.fileSector << shiftBytesPerSector) + fDesc.fileOffset, sector, 0, DIR_ENTRY_SIZE))
{
throw new IOException("Unable to read disk");
}
long millis = System.currentTimeMillis();
if(calendar == null)
{
calendar = Calendar.getInstance();
}
calendar.setTime(new Date(millis));
int time = ((calendar.get(Calendar.SECOND) / 2) & 0x01F) |
((calendar.get(Calendar.MINUTE) & 0x03F) << 5) |
((calendar.get(Calendar.HOUR_OF_DAY) & 0x1F) << 11);
int date = (calendar.get(Calendar.DATE) & 0x1F) |
(((calendar.get(Calendar.MONTH) + 1) & 0x0F) << 5) |
(((calendar.get(Calendar.YEAR) - 1980) & 0x7F) << 9);
ArrayUtils.putShort(date, sector, OFFSET_DIR_LAST_ACCESS_DATE);
ArrayUtils.putShort(time, sector, OFFSET_DIR_WRITE_TIME);
ArrayUtils.putShort(date, sector, OFFSET_DIR_WRITE_DATE);
ArrayUtils.putInt(fDesc.length, sector, OFFSET_DIR_FILE_SIZE);
disk.write((fDesc.fileSector << shiftBytesPerSector) + fDesc.fileOffset, sector, 0, DIR_ENTRY_SIZE);
}
openWriters.removeElement(fd);
}
}
}
public void unmount()
{
disk.flush();
return; /*TODO*/
}
public byte[] getContents(String fileName, byte uid) throws IOException {return null; /*TODO*/}
private static final int FAT16_MASK = 0x0FFFF;
private static final int FAT32_MASK = 0x0FFFFFFF;
private static final int FS_TYPE_FAT32 = 0;
private static final int FS_TYPE_FAT16 = 1;
private static final int FS_TYPE_FAT12 = 2;
private static final int CLUST_EOFE = 0xffffffff;
private static final int OFFSET_FAT_SIGNATURE = 510;
private static final int OFFSET_BPB_BYTES_PER_SECTOR = 11;
private static final int OFFSET_BPB_SECTORS_PER_CLUSTER = 13;
private static final int OFFSET_BPB_RESERVED_SECTOR_COUNT = 14;
private static final int OFFSET_BPB_NUM_FATS = 16;
private static final int OFFSET_BPB_ROOT_ENTRY_COUNT = 17;
private static final int OFFSET_BPB_TOTAL_SECTORS_16 = 19;
private static final int OFFSET_BPB_FAT_SIZE_16 = 22;
private static final int OFFSET_BPB_TOTAL_SECTORS_32 = 32;
private static final int OFFSET_BPB_FAT_SIZE_32 = 36;
private static final int ATTR_READ_ONLY = 0x01;
private static final int ATTR_HIDDEN = 0x02;
private static final int ATTR_SYSTEM = 0x04;
private static final int ATTR_VOLUME_ID = 0x08;
private static final int ATTR_DIRECTORY = 0x10;
private static final int ATTR_ARCHIVE = 0x20;
private static final int ATTR_LONG_NAME = ATTR_READ_ONLY |
ATTR_HIDDEN |
ATTR_SYSTEM |
ATTR_VOLUME_ID;
private static final int DIR_ENTRY_SIZE = 32;
private static final int OFFSET_DIR_NAME = 0;
private static final int OFFSET_DIR_ATTRIBUTES = 11;
private static final int OFFSET_DIR_NT_RESERVED = 12;
private static final int OFFSET_DIR_CREATE_TIME_TENTH = 13;
private static final int OFFSET_DIR_CREATE_TIME = 14;
private static final int OFFSET_DIR_CREATE_DATE = 16;
private static final int OFFSET_DIR_LAST_ACCESS_DATE = 18;
private static final int OFFSET_DIR_FIRST_CLUSTER_HIGH = 20;
private static final int OFFSET_DIR_WRITE_TIME = 22;
private static final int OFFSET_DIR_WRITE_DATE = 24;
private static final int OFFSET_DIR_FIRST_CLUSTER_LOW = 26;
private static final int OFFSET_DIR_FILE_SIZE = 28;
private static final int DIR_SLOT_DELETED = 0xE5;
private static final int DIR_LAST_ENTRY = 0x00;
private static final int DIR_NAME_IS_E5 = 0x05;
private DiskInterface disk;
//Buffer we will use for all sector reads and writes. This will save unnecessary memory allocations.
private byte[] sector;
//Secondary buffer we will use for reads and writes to the FAT table. This will save unnecessary memory allocations.
private byte[] sector2;
//Addresses to the start of each File Allocation Table (most FS use two copies, but there could be more)
private int[] tableAddresses;
private int bytesPerSector;
private int shiftBytesPerSector;
private int sectorsPerCluster;
private int shiftSectorsPerCluster;
private int FATType;
private int firstDataSector;
private int firstRootDirSector;
private int maxCluster;
private String[] fileParts = new String[10];
private int filePartsLength = 0;
private int currentFileSector;
private int currentFileOffset;
private Object lock = new Object();
private Vector listVector = null;
private Calendar calendar = null;
private Vector openReaders = null;
private Vector openWriters = null;
private static final byte[] dotBytes = {'.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
private static final byte[] dotdotBytes = {'.', '.', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
private void parseBootSector(byte[] sector) throws FATException
{
if(ArrayUtils.getShort(sector, OFFSET_FAT_SIGNATURE) != 0x0AA55)
{
throw new FATException("Invalid FAT signature");
}
int totalSectors = ArrayUtils.getShort(sector, OFFSET_BPB_TOTAL_SECTORS_16);
if(totalSectors == 0)
{
totalSectors = ArrayUtils.getInt(sector, OFFSET_BPB_TOTAL_SECTORS_32);
}
if((totalSectors << shiftBytesPerSector) > disk.size())
{
throw new FATException("Boot sector shows disk larger than it really is");
}
bytesPerSector = ArrayUtils.getShort(sector, OFFSET_BPB_BYTES_PER_SECTOR);
if(bytesPerSector == 0)
{
throw new FATException("Bytes per sector cannot be 0.");
}
int x = bytesPerSector;
shiftBytesPerSector = 0;
while(x != 1)
{
shiftBytesPerSector++;
x >>= 1;
}
sectorsPerCluster = ArrayUtils.getByte(sector, OFFSET_BPB_SECTORS_PER_CLUSTER);
if(sectorsPerCluster == 0)
{
throw new FATException("Secotrs per cluster cannot be 0.");
}
x = sectorsPerCluster;
shiftSectorsPerCluster = 0;
while(x != 1)
{
shiftSectorsPerCluster++;
x >>= 1;
}
int rootEntCnt = ArrayUtils.getShort(sector, OFFSET_BPB_ROOT_ENTRY_COUNT);
int rootDirSectors = ((rootEntCnt * DIR_ENTRY_SIZE) + (bytesPerSector - 1)) / bytesPerSector;
int fatSize = ArrayUtils.getShort(sector, OFFSET_BPB_FAT_SIZE_16);
if(fatSize == 0)
{
fatSize = ArrayUtils.getInt(sector, OFFSET_BPB_FAT_SIZE_32);
}
int reservedSectorCount = ArrayUtils.getShort(sector, OFFSET_BPB_RESERVED_SECTOR_COUNT);
int numFATs = ArrayUtils.getByte(sector, OFFSET_BPB_NUM_FATS);
firstRootDirSector = reservedSectorCount + (numFATs * fatSize);
firstDataSector = firstRootDirSector + rootDirSectors;
int dataSectors = totalSectors - firstDataSector;
int countOfClusters = dataSectors >> shiftSectorsPerCluster;
maxCluster = countOfClusters + 2;
if(countOfClusters < 4085)
{
FATType = FS_TYPE_FAT12;
throw new FATException("FAT12 is not supported");
}
else if(countOfClusters < 65525)
{
FATType = FS_TYPE_FAT16;
}
else
{
FATType = FS_TYPE_FAT32;
}
tableAddresses = new int[numFATs];
for(int i = 0; i < numFATs; i++)
{
tableAddresses[i] = (reservedSectorCount + (i * fatSize)) * bytesPerSector;
}
}
private int sectorToCluster(int sector)
{
return (((sector - firstDataSector) >> shiftSectorsPerCluster) + 2);
}
private int clusterToSector(int cluster)
{
return ((cluster - 2) << shiftSectorsPerCluster) + firstDataSector;
}
private int nextCluster(int cluster, boolean growFile, boolean clearNew) throws FATException
{
int mask;
// Get the next cluster pointer.
int next = readFATEntry(cluster);
if(FATType == FS_TYPE_FAT32)
{
mask = FAT32_MASK;
}
else if(FATType == FS_TYPE_FAT16)
{
mask = FAT16_MASK;
}
else
{
throw new FATException("Unrecognized FAT Type");
}
if(next == (CLUST_EOFE & mask))
{
// We're at the end of the chain.
if(growFile)
{
boolean emptyClusterFound = false;
// Look for an unused cluster.
for(next = 2; next < maxCluster; next++)
{
int temp = readFATEntry(next);
if(temp == 0)
{
// Found an unused cluster, add it to the end of the chain.
writeFATEntry(cluster, next);
writeFATEntry(next, CLUST_EOFE);
emptyClusterFound = true;
if(clearNew)
{
synchronized (sector2)
{
int newSector = clusterToSector(next);
com.dalsemi.system.ArrayUtils.arrayFill(sector2, 0, bytesPerSector, (byte)0x00);
for(int i = 0; i < sectorsPerCluster; i++)
{
disk.write((newSector + i) << shiftBytesPerSector, sector2, 0, bytesPerSector);
}
}
}
break;
}
}
if(!emptyClusterFound)
{
next = 0;
}
}
else
{
next = 0;
}
}
return next;
}
private int readFATEntry(int cluster) throws FATException
{
int offset = 0;
if(FATType == FS_TYPE_FAT16)
{
// Entries are 2 bytes wide.
offset = cluster << 1;
}
else if(FATType == FS_TYPE_FAT32)
{
// Entries are 4 bytes wide.
offset = cluster << 2;
}
else
{
throw new FATException("Unrecognized FAT Type");
}
// Start of the FAT table plus start address of the sector containing offset.
int sectorAddress = tableAddresses[0] + ((offset >> shiftBytesPerSector) << shiftBytesPerSector);
// Index into the table from the beginning of the sector.
offset = offset & (bytesPerSector - 1);
synchronized(sector2)
{
// Read the relevant sector of the FAT table
if(!disk.read(sectorAddress, sector2, 0, bytesPerSector))
{
throw new FATException("Error reading disk");
}
if(FATType == FS_TYPE_FAT16)
{
return ArrayUtils.getShort(sector2, offset) & FAT16_MASK;
}
else if(FATType == FS_TYPE_FAT32)
{
return ArrayUtils.getInt(sector2, offset) & FAT32_MASK;
}
else
{
throw new FATException("Unrecognized FAT Type");
}
}
}
private void writeFATEntry(int cluster, int value) throws FATException
{
int offset = 0;
if(FATType == FS_TYPE_FAT16)
{
// Entries are 2 bytes wide.
offset = cluster << 1;
}
else if(FATType == FS_TYPE_FAT32)
{
// Entries are 4 bytes wide.
offset = cluster << 2;
}
else
{
throw new FATException("Unrecognized FAT Type");
}
for(int i = 0; i < tableAddresses.length; i++)
{
// Start of the FAT table plus offset into the table.
int sectorAddress = tableAddresses[i] + offset;
synchronized(sector2)
{
if(FATType == FS_TYPE_FAT16)
{
ArrayUtils.putShort(value & FAT16_MASK, sector2, 0);
if(!disk.write(sectorAddress, sector2, 0, 2))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -