29 #include <PropWare/c++allocate.h>
37 extern uint8_t HALF_K_DATA_BUFFER1[];
38 extern uint8_t HALF_K_DATA_BUFFER2[];
93 if (NULL != this->m_fat)
103 PropWare::ErrorCode
mount (uint8_t buffer[] = HALF_K_DATA_BUFFER2,
const uint8_t partition = 0) {
104 PropWare::ErrorCode err;
108 else if (3 < partition)
112 check_errors(this->m_driver->start());
113 this->m_fatMod =
false;
114 this->m_nextFileId = 0;
116 this->m_dirMeta.name =
"Current working directory";
121 check_errors(this->read_boot_sector(partition, buffer));
122 check_errors(this->common_boot_sector_parser(buffer));
123 this->partition_info_parser(buffer);
124 check_errors(this->determine_fat_type());
125 this->store_root_info(buffer);
126 check_errors(this->read_fat_and_root_sectors(buffer));
128 this->m_mounted =
true;
138 return this->flush_fat();
150 return this->m_filesystem;
155 static const uint8_t FAT_16 = 2;
156 static const uint8_t FAT_32 = 4;
157 static const uint8_t BOOT_SECTOR_ID = 0xEB;
158 static const uint8_t BOOT_SECTOR_ID_ADDR = 0;
159 static const uint16_t PARTITION_TABLE_START = 0x1BE;
160 static const uint8_t PARTITION_ID_OFFSET = 0x04;
161 static const uint8_t PARTITION_START_OFFSET = 0x08;
162 static const uint8_t CLUSTER_SIZE_ADDR = 0x0D;
163 static const uint8_t RSVD_SCTR_CNT_ADDR = 0x0E;
164 static const uint8_t NUM_FATS_ADDR = 0x10;
165 static const uint8_t ROOT_ENTRY_CNT_ADDR = 0x11;
166 static const uint8_t LABEL_ADDR = 0x47;
167 static const uint8_t SEC_PER_CLSTR_ADDR = 0x0D;
168 static const uint8_t TOT_SCTR_16_ADDR = 0x13;
169 static const uint8_t FAT_SIZE_16_ADDR = 0x16;
170 static const uint8_t TOT_SCTR_32_ADDR = 0x20;
171 static const uint8_t FAT_SIZE_32_ADDR = 0x24;
172 static const uint8_t ROOT_CLUSTER_ADDR = 0x2c;
173 static const uint16_t FAT12_CLSTR_CNT = 4085;
174 static const uint16_t FAT16_CLSTR_CNT = UINT16_MAX - 10;
176 static const int8_t FREE_CLUSTER = 0;
177 static const int8_t RESERVED_CLUSTER = 1;
178 static const int8_t RSVD_CLSTR_VAL_BEG = -15;
179 static const int8_t RSVD_CLSTR_VAL_END = -10;
180 static const int8_t BAD_CLUSTER = -9;
181 static const int32_t EOC_BEG = -8;
182 static const int32_t EOC_END = -1;
183 static const uint32_t EOC_MASK = 0x0fffffff;
188 uint32_t rootEntryCount;
189 uint32_t rootDirSectors;
190 uint32_t rsvdSectorCount;
191 uint32_t totalSectors;
193 uint32_t dataSectors;
195 uint32_t clusterCount;
207 inline PropWare::ErrorCode read_boot_sector (
const uint8_t partition, uint8_t buffer[]) {
208 PropWare::ErrorCode err;
211 check_errors(this->m_driver->read_data_block(0, buffer));
212 const uint8_t bootSectorId = this->m_driver->get_byte(BOOT_SECTOR_ID_ADDR, buffer);
215 if (BOOT_SECTOR_ID == bootSectorId) {
218 this->m_initFatInfo.bootSector = 0;
225 const uint16_t partitionRow = PARTITION_TABLE_START + (partition << 4);
226 check_errors(this->is_fat_volume(buffer[partitionRow + PARTITION_ID_OFFSET]));
227 this->m_initFatInfo.bootSector = this->m_driver->get_long(partitionRow + PARTITION_START_OFFSET, buffer);
228 check_errors(this->m_driver->read_data_block(this->m_initFatInfo.bootSector, buffer));
234 inline PropWare::ErrorCode is_fat_volume (
const uint8_t partitionId)
const {
235 const static uint8_t PARTITION_IDS[54] = {0x01, 0x04, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x11, 0x12, 0x14,
236 0x16, 0x17, 0x1B, 0x1C, 0x1E, 0x24, 0x27, 0x28, 0x56, 0x84, 0x86,
237 0x8B, 0x8D, 0x90, 0x92, 0x97, 0x98, 0x9A, 0xAA, 0xB6, 0xBB, 0xBC,
238 0xC0, 0xC1, 0xC6, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCE, 0xD0, 0xD1,
239 0xD4, 0xD6, 0xDB, 0xDE, 0xE1, 0xE4, 0xE5, 0xEF, 0xF2, 0xFE};
240 for (
auto id : PARTITION_IDS)
241 if (
id == partitionId)
246 inline PropWare::ErrorCode common_boot_sector_parser (uint8_t buffer[]) {
248 InitFATInfo *i = &this->m_initFatInfo;
251 i->rootEntryCount = this->m_driver->get_short(ROOT_ENTRY_CNT_ADDR, buffer);
254 i->rootDirSectors = (i->rootEntryCount * 32 + this->m_driver->get_sector_size() - 1) >>
255 this->m_driver->get_sector_size_shift();
258 i->rsvdSectorCount = this->m_driver->get_short(RSVD_SCTR_CNT_ADDR, buffer);
261 i->numFATs = this->m_driver->get_byte(NUM_FATS_ADDR, buffer);
265 memcpy(this->m_label, &buffer[LABEL_ADDR], 8);
266 this->m_label[8] =
'\0';
268 uint8_t sectorsPerCluster = this->m_driver->get_byte(SEC_PER_CLSTR_ADDR, buffer);
269 switch (sectorsPerCluster) {
271 this->m_tier1sPerTier2Shift = 0;
274 this->m_tier1sPerTier2Shift = 1;
277 this->m_tier1sPerTier2Shift = 2;
280 this->m_tier1sPerTier2Shift = 3;
283 this->m_tier1sPerTier2Shift = 4;
286 this->m_tier1sPerTier2Shift = 5;
289 this->m_tier1sPerTier2Shift = 6;
292 this->m_tier1sPerTier2Shift = 7;
295 pwOut.
printf(
"Sectors per cluster (bad) = %u\n", sectorsPerCluster);
302 inline void partition_info_parser (uint8_t buffer[]) {
304 InitFATInfo *i = &this->m_initFatInfo;
307 uint32_t fatSize = this->m_driver->get_short(FAT_SIZE_16_ADDR, buffer);
309 fatSize = this->m_driver->get_long(FAT_SIZE_32_ADDR, buffer);
310 i->FATSize = fatSize;
313 uint32_t totalSectors = this->m_driver->get_short(TOT_SCTR_16_ADDR, buffer);
315 totalSectors = this->m_driver->get_long(TOT_SCTR_32_ADDR, buffer);
316 i->totalSectors = totalSectors;
321 i->dataSectors = totalSectors - (i->rsvdSectorCount + i->numFATs * fatSize + i->rootDirSectors);
322 i->clusterCount = i->dataSectors >> this->m_tier1sPerTier2Shift;
323 this->m_rootDirSectors = (i->rootEntryCount * 32) >> this->m_driver->get_sector_size_shift();
326 inline PropWare::ErrorCode determine_fat_type () {
328 if (FAT12_CLSTR_CNT > this->m_initFatInfo.clusterCount)
330 else if (FAT16_CLSTR_CNT > this->m_initFatInfo.clusterCount) {
331 this->m_filesystem = FAT_16;
332 this->m_entriesPerFatSector_Shift = 8;
334 this->m_filesystem = FAT_32;
335 this->m_entriesPerFatSector_Shift = 7;
341 inline void store_root_info (uint8_t buffer[]) {
343 const uint_fast32_t bootSector = this->m_initFatInfo.bootSector;
344 const uint_fast32_t reservedSectors = this->m_initFatInfo.rsvdSectorCount;
345 const uint_fast8_t numFATs = this->m_initFatInfo.numFATs;
346 this->m_fatSize = this->m_initFatInfo.FATSize;
349 this->m_fatStart = bootSector + reservedSectors;
352 this->m_firstDataAddr = this->m_fatStart + this->m_fatSize * numFATs;
353 switch (this->m_filesystem) {
355 this->m_rootAddr = this->m_firstDataAddr;
356 this->m_firstDataAddr += this->m_rootDirSectors;
359 this->m_rootCluster = this->m_driver->get_long(ROOT_CLUSTER_ADDR, buffer);
360 this->m_rootAddr = this->compute_tier1_from_tier2(this->m_rootCluster);
365 inline PropWare::ErrorCode read_fat_and_root_sectors (uint8_t buffer[]) {
366 PropWare::ErrorCode err;
369 check_errors(this->m_driver->read_data_block(this->m_fatStart, this->m_fat));
370 this->m_curFatSector = 0;
373 check_errors(this->m_driver->read_data_block(this->m_rootAddr, buffer));
374 this->m_dirMeta.curTier2Addr = this->m_rootAddr;
375 if (FAT_16 == this->m_filesystem) {
376 this->m_dir_firstCluster = (uint32_t) -1;
377 this->m_dirMeta.curTier2 = (uint32_t) -1;
379 this->m_dirMeta.curTier2 = this->m_dir_firstCluster = this->m_rootCluster;
380 check_errors(this->get_fat_value(this->m_dirMeta.curTier2, &this->m_dirMeta.nextTier2));
382 this->m_dirMeta.curTier2Addr = this->m_rootAddr;
383 this->m_dirMeta.curTier1Offset = 0;
388 bool is_eoc (int32_t value)
const {
389 switch (this->m_filesystem) {
391 return EOC_END == value;
394 return EOC_BEG <= value && EOC_END <= value;
409 PropWare::ErrorCode get_fat_value (
const uint32_t fatEntry, uint32_t *value) {
410 PropWare::ErrorCode err;
411 uint32_t firstAvailableCluster;
414 if ((fatEntry >> this->m_entriesPerFatSector_Shift) != this->m_curFatSector) {
416 this->m_curFatSector = fatEntry >> this->m_entriesPerFatSector_Shift;
417 check_errors(this->m_driver->read_data_block(this->m_curFatSector + this->m_fatStart, this->m_fat));
419 firstAvailableCluster = this->m_curFatSector << this->m_entriesPerFatSector_Shift;
425 if (FAT_16 == this->m_filesystem) {
426 *value = this->m_driver->get_short((uint16_t) ((fatEntry - firstAvailableCluster) << 1), this->m_fat);
428 }
else if (FAT_32 == this->m_filesystem) {
429 *value = this->m_driver->get_long((uint16_t) ((fatEntry - firstAvailableCluster) << 2), this->m_fat);
431 *value &= 0x0FFFFFFF;
444 uint32_t compute_tier1_from_tier2 (uint32_t tier2)
const {
446 tier2 <<= this->m_tier1sPerTier2Shift;
447 tier2 += this->m_firstDataAddr;
454 PropWare::ErrorCode extend_current_directory () {
455 return this->extend_fat(&this->m_dirMeta);
466 PropWare::ErrorCode extend_fat (BlockStorage::MetaData *bufferMetadata) {
467 PropWare::ErrorCode err;
468 uint32_t newAllocUnit;
472 if ((bufferMetadata->curTier2 >> this->m_entriesPerFatSector_Shift) != this->m_curFatSector) {
474 this->m_curFatSector = bufferMetadata->curTier2 >> this->m_entriesPerFatSector_Shift;
475 check_errors(this->m_driver->read_data_block(this->m_curFatSector + this->m_fatStart, this->m_fat));
480 const uint16_t entriesPerFatSector = (uint16_t) (1 << this->m_entriesPerFatSector_Shift);
481 const uint16_t allocUnitOffset = (uint16_t) (bufferMetadata->curTier2 % entriesPerFatSector);
482 const uint16_t fatPointerAddress = allocUnitOffset * this->m_filesystem;
483 const uint32_t nextSector = this->m_driver->get_long(fatPointerAddress, this->m_fat);
484 if (!this->is_eoc(nextSector))
488 newAllocUnit = this->find_empty_space(1);
491 const uint16_t sectorOffset = (uint16_t) ((bufferMetadata->curTier2 %
492 (1 << this->m_entriesPerFatSector_Shift)) * this->m_filesystem);
493 if (FAT_16 == this->m_filesystem)
494 this->m_driver->write_short(sectorOffset, this->m_fat, (uint16_t) newAllocUnit);
496 this->m_driver->write_long(sectorOffset, this->m_fat, newAllocUnit);
497 bufferMetadata->nextTier2 = newAllocUnit;
498 this->m_fatMod =
true;
518 uint32_t find_empty_space (
const uint8_t restore) {
519 uint16_t allocOffset = 0;
520 uint32_t fatSectorAddr = this->m_curFatSector + this->m_fatStart;
526 if (FAT_16 == this->m_filesystem) {
528 while (this->m_driver->get_short(allocOffset, this->m_fat)) {
530 while (this->m_driver->get_short(allocOffset, this->m_fat) && (this->m_sectorSize > allocOffset))
531 allocOffset += FAT_16;
533 if (this->m_sectorSize <= allocOffset) {
536 this->m_driver->read_data_block(++fatSectorAddr, this->m_fat);
539 this->m_driver->write_short(allocOffset, this->m_fat, (uint16_t) EOC_END);
540 this->m_fatMod =
true;
543 if (0 == this->m_curFatSector)
545 allocOffset = (uint16_t) (9 * FAT_32);
548 while (this->m_driver->get_long(allocOffset, this->m_fat) & EOC_MASK) {
550 while ((this->m_driver->get_long(allocOffset, this->m_fat) & EOC_MASK)
551 && (this->m_sectorSize > allocOffset))
552 allocOffset += FAT_32;
555 if (this->m_sectorSize <= allocOffset) {
558 this->m_driver->read_data_block(++fatSectorAddr, this->m_fat);
563 this->m_driver->write_long(allocOffset, this->m_fat, ((uint32_t) EOC_END) & EOC_MASK);
564 this->m_fatMod =
true;
569 if ((fatSectorAddr != (this->m_curFatSector + this->m_fatStart)) && this->m_fatMod) {
571 this->m_driver->read_data_block(this->m_curFatSector + this->m_fatStart, this->m_fat);
573 this->m_curFatSector = fatSectorAddr - this->m_fatStart;
576 retVal = this->m_curFatSector << this->m_entriesPerFatSector_Shift;
577 retVal += allocOffset / this->m_filesystem;
581 PropWare::ErrorCode flush_fat () {
582 PropWare::ErrorCode err;
584 check_errors(m_driver->write_data_block(this->m_fatStart + this->m_curFatSector, this->m_fat));
585 check_errors(m_driver->write_data_block(this->m_fatStart + this->m_curFatSector + this->m_fatSize,
600 PropWare::ErrorCode clear_chain (
const uint32_t head) {
601 PropWare::ErrorCode err;
603 uint32_t next = head;
605 const uint32_t current = next;
606 check_errors(this->get_fat_value(current, &next));
608 const uint32_t firstAvailableAllocUnit = this->m_curFatSector << this->m_entriesPerFatSector_Shift;
609 const uint16_t sectorOffset = (uint16_t) (current - firstAvailableAllocUnit);
611 if (FAT_16 == this->m_filesystem)
612 this->m_driver->write_short(sectorOffset << 1, this->m_fat, 0);
613 else if (FAT_32 == this->m_filesystem)
614 this->m_driver->write_long(sectorOffset << 2, this->m_fat, 0);
615 }
while (!this->is_eoc(next));
617 this->m_fatMod =
true;
622 void print_status (
const bool printBlocks =
false)
const {
623 this->m_logger->println(
"######################################################");
624 this->m_logger->printf(
"# FAT Filesystem Status - PropWare::FatFS@0x%08X #\n", (
unsigned int)
this);
626 this->m_logger->println(
"Driver");
627 this->m_logger->println(
"======");
628 this->m_logger->printf(
"Driver address: 0x%08X\n", (
unsigned int) this->m_driver);
629 this->m_logger->printf(
"Block size: %u\n", this->m_sectorSize);
630 this->m_logger->printf(
"Blocks-per-cluster shift: %u\n", this->m_tier1sPerTier2Shift);
631 this->m_logger->println();
634 this->m_logger->println(
"Filesystem Constants");
635 this->m_logger->println(
"====================");
636 if (this->m_mounted) {
638 this->m_logger->println(
"\tInitialization Numbers");
639 this->m_logger->println(
"\t----------------------------");
640 this->m_logger->printf(
"\tNumber of FATs: %u\n", this->m_initFatInfo.numFATs);
641 this->m_logger->printf(
"\tRoot entry count: 0x%08X/%u\n", this->m_initFatInfo.rootEntryCount,
642 this->m_initFatInfo.rootEntryCount);
643 this->m_logger->printf(
"\tRoot dir sectors: 0x%08X/%u\n", this->m_initFatInfo.rootDirSectors,
644 this->m_initFatInfo.rootDirSectors);
645 this->m_logger->printf(
"\tReserved sector count: 0x%08X/%u\n", this->m_initFatInfo.rsvdSectorCount,
646 this->m_initFatInfo.rsvdSectorCount);
647 this->m_logger->printf(
"\tTotal sectors: 0x%08X/%u\n", this->m_initFatInfo.totalSectors,
648 this->m_initFatInfo.totalSectors);
649 this->m_logger->printf(
"\tFAT Start: 0x%08X/%u\n", this->m_fatStart, this->m_fatStart);
650 this->m_logger->printf(
"\tFAT size: 0x%08X/%u\n", this->m_initFatInfo.FATSize,
651 this->m_initFatInfo.FATSize);
652 this->m_logger->printf(
"\tData sectors: 0x%08X/%u\n", this->m_initFatInfo.dataSectors,
653 this->m_initFatInfo.dataSectors);
654 this->m_logger->printf(
"\tBoot sector: 0x%08X/%u\n", this->m_initFatInfo.bootSector,
655 this->m_initFatInfo.bootSector);
656 this->m_logger->printf(
"\tCluster count: 0x%08X/%u\n", this->m_initFatInfo.clusterCount,
657 this->m_initFatInfo.clusterCount);
658 this->m_logger->println();
661 this->m_logger->println(
"Partition");
662 this->m_logger->println(
"=========");
663 this->m_logger->printf(
"\tLabel: %s\n", this->m_label);
664 switch (this->m_filesystem) {
666 this->m_logger->printf(
"\tFilesystem: FAT 32\n");
669 this->m_logger->printf(
"\tFilesystem: FAT 16\n");
672 this->m_logger->printf(
"\tFilesystem: unknown (%d)\n", this->m_filesystem);
674 this->m_logger->printf(
"\tFirst FAT sector: 0x%08X\n", this->m_fatStart);
675 this->m_logger->printf(
"\tRoot directory alloc. unit: 0x%08X\n", this->m_rootCluster);
676 this->m_logger->printf(
"\tCalculated root directory sector: 0x%08X\n",
677 this->compute_tier1_from_tier2(this->m_rootCluster));
678 this->m_logger->printf(
"\tRoot directory sector: 0x%08X\n", this->m_rootAddr);
679 this->m_logger->printf(
"\tRoot directory size (in sectors): %u\n", this->m_rootDirSectors);
680 this->m_logger->printf(
"\tFirst data sector: 0x%08X\n", this->m_firstDataAddr);
681 this->m_logger->println();
683 this->m_logger->println(
"\nNot mounted");
687 this->m_logger->println(
"FAT Buffer");
688 this->m_logger->println(
"==========");
690 this->m_logger->println();
693 this->m_logger->println(
"Current working directory");
694 this->m_logger->println(
"=========================");
695 this->m_logger->printf(
"\tID: %d\n", this->m_dirMeta.id);
697 this->m_logger->printf(
"\tCur. cluster's start sector: 0x%08X/%u\n", this->m_dirMeta.curTier2Addr,
698 this->m_dirMeta.curTier2Addr);
699 this->m_logger->printf(
"\tCur. sector offset from cluster start: %u\n", this->m_dirMeta.curTier1Offset);
700 this->m_logger->printf(
"\tCurrent allocation unit: 0x%08X/%u\n", this->m_dirMeta.curTier2, (&this->m_dirMeta)
702 this->m_logger->printf(
"\tNext allocation unit: 0x%08X/%u\n", this->m_dirMeta.nextTier2, (&this->m_dirMeta)
704 this->m_logger->println();
708 InitFATInfo m_initFatInfo;
709 uint8_t m_filesystem;
712 uint32_t m_rootCluster;
714 uint32_t m_rootDirSectors;
715 uint32_t m_firstDataAddr;
717 uint16_t m_entriesPerFatSector_Shift;
721 uint32_t m_curFatSector;
722 uint32_t m_dir_firstCluster;