#include "fat16.h" uint32_t FAT16FileReadWriter::offsetBytesToCluster(uint32_t offset) { uint32_t cluster = this->firstCluster; uint32_t remaining = offset; while (remaining > this->clusterSize) { cluster = this->backingFS->FAT1[this->firstCluster]; remaining -= this->clusterSize; } return cluster; } FAT16FileReadWriter::FAT16FileReadWriter(uint32_t firstCluster, uint32_t sizeBytes, FAT16FS* backingFS) { this->firstCluster = firstCluster; this->sizeBytes = sizeBytes; this->currentPosition = 0; this->backingFS = backingFS; this->clusterSize = 512 * (uint32_t)(*this->backingFS->sectorsPerCluster); } uint32_t FAT16FileReadWriter::read(uint32_t count, uint8_t* buffer) { //uint8_t* clusterBuffer = new uint8_t[this->clusterSize]; uint8_t clusterBuffer[this->clusterSize]; uint32_t clusterToRead = offsetBytesToCluster(this->currentPosition); uint32_t sectorToRead = this->backingFS->clusterToSector(clusterToRead); this->backingFS->backingDevice->seek(sectorToRead * this->clusterSize); this->backingFS->backingDevice->read(this->clusterSize, clusterBuffer); uint32_t currentClusterIndex = this->currentPosition % this->clusterSize; if (this->currentPosition >= this->sizeBytes) return 0; uint32_t remaining = count; uint32_t index = 0; while (remaining) { if (currentClusterIndex == this->clusterSize) { clusterToRead = this->backingFS->FAT1[clusterToRead]; if (clusterToRead == 0xffff) break; sectorToRead = this->backingFS->clusterToSector(clusterToRead); this->backingFS->backingDevice->seek(sectorToRead * this->clusterSize); this->backingFS->backingDevice->read(this->clusterSize, clusterBuffer); currentClusterIndex = 0; } buffer[index++] = clusterBuffer[currentClusterIndex++]; remaining--; this->currentPosition++; } //delete[] clusterBuffer; return index; } uint32_t FAT16FileReadWriter::write(uint32_t count, uint8_t* buffer) {return;} uint32_t FAT16FileReadWriter::size() { return this->sizeBytes; } uint32_t FAT16FileReadWriter::seek(uint32_t position) { if (position < this->sizeBytes) { this->currentPosition = position; return position; } return 0; } char safeUppercase(char c) { switch (c) { case 'a'...'z': return c & ~32; default: return c; } } void FAT16FS::pathEntryTo83(PathEntry pe, char* buffer) { uint32_t maxSize = pe.length; uint8_t* data = pe.path; uint32_t readIndex=0; uint32_t writeIndex=0; while (writeIndex<11 && readIndex < maxSize) { char c; if ((c=data[readIndex++]) == '.') { writeIndex = 8; continue; } buffer[writeIndex++] = safeUppercase(c); } } uint32_t FAT16FS::clusterToSector(uint32_t cluster) { return (cluster * (uint32_t)(*this->sectorsPerCluster)) + (*sectorsPerFAT * *countFATs) + (*countRDEs / 16) + (*countReserved - 1) - 1; } void FAT16FS::load_file(uint32_t location, uint8_t* destination) { int offset = 0; bool loaded = false; while (!loaded) { uint16_t fromSector = clusterToSector(location); this->backingDevice->seek(fromSector * 512 * *this->sectorsPerCluster); this->backingDevice->read(512 * *this->sectorsPerCluster, destination+offset); offset += 512 * *this->sectorsPerCluster; location = FAT1[location++]; if (location == 0xffff) loaded = true; } } uint32_t FAT16FS::calc_size(uint32_t location) { int offset = 0; bool loaded = false; while (!loaded) { uint16_t fromSector = clusterToSector(location); offset += 512 * *this->sectorsPerCluster; location = FAT1[location++]; if (location == 0xffff) loaded = true; } return offset; } xnoe::tuple FAT16FS::getDirectoryEntry(Path p) { PathElement* current = p.start; DirectoryEntry* currentDirectory = new DirectoryEntry[*countRDEs]; for (int i=0; i < *countRDEs; i++) currentDirectory[i] = rootDirEntries[i]; uint32_t count = *countRDEs; if (!current) return xnoe::tuple(currentDirectory, count, true); escape_for: while (current != p.end) { char name83[12] = " "; pathEntryTo83(current->elem, name83); for (int i=0; i < count; i++) { if (strcmp(currentDirectory[i].name, name83, 11)) { DirectoryEntry found = currentDirectory[i]; if (!(found.directory)) return xnoe::tuple(currentDirectory, count, true); delete currentDirectory; uint32_t sizeBytes = calc_size(found.firstClusterLow); currentDirectory = (DirectoryEntry*)(new uint8_t[sizeBytes]); load_file(found.firstClusterLow, (uint8_t*)currentDirectory); i=0; count = sizeBytes / sizeof(DirectoryEntry); current = current->next; goto escape_for; } } return xnoe::tuple(currentDirectory, 0, false); } return xnoe::tuple(currentDirectory, count, true); } xnoe::tuple FAT16FS::getDirectoryEntryFull(Path p) { PathElement* current = p.start; DirectoryEntry* currentDirectory = new DirectoryEntry[*countRDEs]; for (int i=0; i < *countRDEs; i++) currentDirectory[i] = rootDirEntries[i]; uint32_t count = *countRDEs; if (!current) return xnoe::tuple(currentDirectory, count, true); escape_for: while (current) { char name83[12] = " "; pathEntryTo83(current->elem, name83); for (int i=0; i < count; i++) { if (strcmp(currentDirectory[i].name, name83, 11)) { DirectoryEntry found = currentDirectory[i]; if (!(found.directory)) return xnoe::tuple(currentDirectory, count, true); delete currentDirectory; uint32_t sizeBytes = calc_size(found.firstClusterLow); currentDirectory = (DirectoryEntry*)(new uint8_t[sizeBytes]); load_file(found.firstClusterLow, (uint8_t*)currentDirectory); i=0; count = sizeBytes / sizeof(DirectoryEntry); current = current->next; goto escape_for; } } return xnoe::tuple(currentDirectory, 0, false); } return xnoe::tuple(currentDirectory, count, true); } FAT16FS::FAT16FS(ReadWriter* disk) { this->backingDevice = disk; this->backingDevice->seek(0); this->backingDevice->read(512, sectorOne); this->rootDirEntries = new DirectoryEntry[*countRDEs]; this->backingDevice->seek(((*sectorsPerFAT) * (*countFATs) + (*countReserved)) * 512); this->backingDevice->read((*countRDEs) * sizeof(DirectoryEntry), (uint8_t*)this->rootDirEntries); this->FAT1 = new uint16_t[(*sectorsPerFAT) * 256]; this->backingDevice->seek((*countReserved) * 512); this->backingDevice->read((*sectorsPerFAT) * 512, (uint8_t*)FAT1); } bool FAT16FS::exists(Path p) { xnoe::tuple directory = getDirectoryEntry(p); if (!xnoe::get<2>(directory)) return false; bool found = false; DirectoryEntry* directoryEntries = xnoe::get<0>(directory); uint32_t count = xnoe::get<1>(directory); PathElement* end = p.end; if (!end) return false; char name83[12] = " "; name83[11] = 0; pathEntryTo83(end->elem, name83); for (int i=0; i directory = getDirectoryEntry(p); if (!xnoe::get<2>(directory)) return NoExist; FSType found = NoExist; DirectoryEntry* directoryEntries = xnoe::get<0>(directory); uint32_t count = xnoe::get<1>(directory); PathElement* end = p.end; if (!end) return NoExist; char name83[12] = " "; pathEntryTo83(end->elem, name83); for (int i=0; i directory = getDirectoryEntry(p); if (!xnoe::get<2>(directory)) return 0; DirectoryEntry* directoryEntries = xnoe::get<0>(directory); uint32_t count = xnoe::get<1>(directory); PathElement* end = p.end; if (!end) return 0; uint32_t written=0; char name83[12] = " "; name83[11] = 0; pathEntryTo83(end->elem, name83); for (int i=0; i 7) extLength--; memcpy(text, name83, mainLength); if (name83[8] != ' ') { text[mainLength] = '.'; memcpy(text+mainLength+1, name83+8, extLength); } text[mainLength+extLength+1] = 0; return PathEntry{mainLength+extLength+1, text}; } uint32_t getRealCount(DirectoryEntry* directoryEntries, uint32_t c) { uint32_t r = 0; for (int i = 0; i < c; i++) { if (directoryEntries[i].name[0] != 0 && directoryEntries[i].name[0] != 0xE5 && !directoryEntries[i].volumeid) r++; } return r; } uint32_t FAT16FS::getDentsSize(Path p) { xnoe::tuple directory = getDirectoryEntryFull(p); DirectoryEntry* directoryEntries = xnoe::get<0>(directory); if (!xnoe::get<2>(directory)) { delete directoryEntries; return 0; } uint32_t found = 0; uint32_t count = xnoe::get<1>(directory); found += sizeof(FSDirectoryListing); for (int i=0; i directory = getDirectoryEntryFull(p); DirectoryEntry* directoryEntries = xnoe::get<0>(directory); if (!xnoe::get<2>(directory)) { delete directoryEntries; return 0; } uint32_t count = xnoe::get<1>(directory); uint32_t written=0; buffer->count = getRealCount(directoryEntries, count); buffer->stringsLength = 0; char* nameBuffer = ((char*)buffer); nameBuffer += sizeof(FSDirectoryEntry)*buffer->count + sizeof(FSDirectoryListing); for (int i=0; ientries[written] = FSDirectoryEntry { name83ToPathEntry(directoryEntries[i].name, nameBuffer + 13*written), directoryEntries[i].directory ? Directory : File, directoryEntries[i].size }; written++; buffer->stringsLength += 13; } } delete directoryEntries; }