void _FAT_partition_readFSinfo(PARTITION * partition) { if(partition->filesysType != FS_FAT32) return; uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector); if (!sectorBuffer) return; memset(sectorBuffer, 0, partition->bytesPerSector); // Read first sector of disc if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer)) { _FAT_mem_free(sectorBuffer); return; } if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) != 0 || memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4) != 0 || u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster) == 0) { //sector does not yet exist, create one! _FAT_partition_createFSinfo(partition); } else { partition->fat.numberFreeCluster = u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster); if(partition->fat.numberFreeCluster == 0xffffffff) { _FAT_updateFS_INFO(partition,sectorBuffer); partition->fat.numberFreeCluster = u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster); } partition->fat.numberLastAllocCluster = u8array_to_u32(sectorBuffer, FSIB_numberLastAllocCluster); } _FAT_mem_free(sectorBuffer); }
sec_t FindFirstValidPartition(const DISC_INTERFACE* disc) { uint8_t part_table[16*4]; uint8_t *ptr; int i; uint8_t sectorBuffer[BYTES_PER_READ] = {0}; // Read first sector of disc if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) { return 0; } memcpy(part_table,sectorBuffer+0x1BE,16*4); ptr = part_table; for(i=0;i<4;i++,ptr+=16) { sec_t part_lba = u8array_to_u32(ptr, 0x8); if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { return part_lba; } if(ptr[4]==0) continue; if(ptr[4]==0x0F) { sec_t part_lba2=part_lba; sec_t next_lba2=0; int n; for(n=0;n<8;n++) // max 8 logic partitions { if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer)) return 0; part_lba2 = part_lba + next_lba2 + u8array_to_u32(sectorBuffer, 0x1C6) ; next_lba2 = u8array_to_u32(sectorBuffer, 0x1D6); if(!_FAT_disc_readSectors (disc, part_lba2, 1, sectorBuffer)) return 0; if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { return part_lba2; } if(next_lba2==0) break; } } else { if(!_FAT_disc_readSectors (disc, part_lba, 1, sectorBuffer)) return 0; if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) || !memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { return part_lba; } } } return 0; }
sec_t FindFirstValidPartition_buf(const DISC_INTERFACE* disc, uint8_t *sectorBuffer) { uint8_t part_table[16*4]; uint8_t *ptr; int i; // Read first sector of disc if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) { return 0; } memcpy(part_table,sectorBuffer+0x1BE,16*4); ptr = part_table; for(i=0;i<4;i++,ptr+=16) { sec_t part_lba = u8array_to_u32(ptr, 0x8); if (isValidMBR(sectorBuffer)) { return part_lba; } if(ptr[4]==0) continue; if(ptr[4]==0x0F) { sec_t part_lba2=part_lba; sec_t next_lba2=0; int n; for(n=0;n<8;n++) // max 8 logic partitions { if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer)) return 0; part_lba2 = part_lba + next_lba2 + u8array_to_u32(sectorBuffer, 0x1C6) ; next_lba2 = u8array_to_u32(sectorBuffer, 0x1D6); if(!_FAT_disc_readSectors (disc, part_lba2, 1, sectorBuffer)) return 0; if (isValidMBR(sectorBuffer)) { return part_lba2; } if(next_lba2==0) break; } } else { if(!_FAT_disc_readSectors (disc, part_lba, 1, sectorBuffer)) return 0; if (isValidMBR(sectorBuffer)) { return part_lba; } } } return 0; }
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) { uint8_t buf[4]; if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false; switch(num_bytes) { case 1: *value = buf[0]; break; case 2: *value = u8array_to_u16(buf,0); break; case 4: *value = u8array_to_u32(buf,0); break; default: return false; } return true; }
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, sec_t startSector) { PARTITION* partition; int i; uint8_t sectorBuffer[BYTES_PER_READ] = {0}; // Read first sector of disc if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { return NULL; } // Make sure it is a valid MBR or boot sector if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA)) { return NULL; } if (startSector != 0) { // We're told where to start the partition, so just accept it } else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { // Check if there is a FAT string, which indicates this is a boot sector startSector = 0; } else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { // Check for FAT32 startSector = 0; } else { // This is an MBR // Find first valid partition from MBR // First check for an active partition for (i=0x1BE; (i < 0x1FE) && (sectorBuffer[i] != 0x80); i+= 0x10); // If it didn't find an active partition, search for any valid partition if (i == 0x1FE) { for (i=0x1BE; (i < 0x1FE) && (sectorBuffer[i+0x04] == 0x00); i+= 0x10); } if ( i != 0x1FE) { // Go to first valid partition startSector = u8array_to_u32(sectorBuffer, 0x8 + i); // Load the BPB if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { return NULL; } // Make sure it is a valid BPB if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA)) { return NULL; } } else { // No partition found, assume this is a MBR free disk startSector = 0; } } // Now verify that this is indeed a FAT partition if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) && memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { return NULL; } partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION)); if (partition == NULL) { return NULL; } // Init the partition lock _FAT_lock_init(&partition->lock); // Set partition's disc interface partition->disc = disc; // Store required information about the file system partition->fat.sectorsPerFat = u8array_to_u16(sectorBuffer, BPB_sectorsPerFAT); if (partition->fat.sectorsPerFat == 0) { partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32); } partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall); if (partition->numberOfSectors == 0) { partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors); } partition->bytesPerSector = BYTES_PER_READ; // Sector size is redefined to be 512 bytes partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster] * u8array_to_u16(sectorBuffer, BPB_bytesPerSector) / BYTES_PER_READ; partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster; partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors); partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat); partition->dataStart = partition->rootDirStart + (( u8array_to_u16(sectorBuffer, BPB_rootEntries) * DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector); partition->totalSize = ((uint64_t)partition->numberOfSectors - (partition->dataStart - startSector)) * (uint64_t)partition->bytesPerSector; // Store info about FAT partition->fat.lastCluster = (partition->numberOfSectors - (uint32_t)(partition->dataStart - startSector)) / partition->sectorsPerCluster; partition->fat.firstFree = CLUSTER_FIRST; if (partition->fat.lastCluster < CLUSTERS_PER_FAT12) { partition->filesysType = FS_FAT12; // FAT12 volume } else if (partition->fat.lastCluster < CLUSTERS_PER_FAT16) { partition->filesysType = FS_FAT16; // FAT16 volume } else { partition->filesysType = FS_FAT32; // FAT32 volume } if (partition->filesysType != FS_FAT32) { partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER; } else { // Set up for the FAT32 way partition->rootDirCluster = u8array_to_u32(sectorBuffer, BPB_FAT32_rootClus); // Check if FAT mirroring is enabled if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80)) { // Use the active FAT partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * (sectorBuffer[BPB_FAT32_extFlags] & 0x0F)); } } // Create a cache to use partition->cache = _FAT_cache_constructor (cacheSize, partition->disc); // Set current directory to the root partition->cwdCluster = partition->rootDirCluster; // Check if this disc is writable, and set the readOnly property appropriately partition->readOnly = !(_FAT_disc_features(disc) & FEATURE_MEDIUM_CANWRITE); // There are currently no open files on this partition partition->openFileCount = 0; partition->firstOpenFile = NULL; return partition; }
PARTITION* _FAT_partition_constructor_buf (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector, uint8_t *sectorBuffer) { PARTITION* partition; // Read first sector of disc if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { return NULL; } // Make sure it is a valid MBR or boot sector if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || (sectorBuffer[BPB_bootSig_AA] != 0xAA && sectorBuffer[BPB_bootSig_AA] != 0xAB)) { return NULL; } if (startSector != 0) { // We're told where to start the partition, so just accept it } else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { // Check if there is a FAT string, which indicates this is a boot sector startSector = 0; } else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) { // Check for FAT32 startSector = 0; } else { startSector = FindFirstValidPartition_buf(disc, sectorBuffer); if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) { return NULL; } } if (!isValidMBR(sectorBuffer)) { return NULL; } partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION)); if (partition == NULL) { return NULL; } // Init the partition lock _FAT_lock_init(&partition->lock); if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) strncpy(partition->label, (char*)(sectorBuffer + BPB_FAT16_volumeLabel), 11); else strncpy(partition->label, (char*)(sectorBuffer + BPB_FAT32_volumeLabel), 11); partition->label[11] = '\0'; // Set partition's disc interface partition->disc = disc; // Store required information about the file system partition->fat.sectorsPerFat = u8array_to_u16(sectorBuffer, BPB_sectorsPerFAT); if (partition->fat.sectorsPerFat == 0) { partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32); } partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall); if (partition->numberOfSectors == 0) { partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors); } partition->bytesPerSector = u8array_to_u16(sectorBuffer, BPB_bytesPerSector); if(partition->bytesPerSector < MIN_SECTOR_SIZE || partition->bytesPerSector > MAX_SECTOR_SIZE) { // Unsupported sector size _FAT_mem_free(partition); return NULL; } partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster]; partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster; partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors); partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat); partition->dataStart = partition->rootDirStart + (( u8array_to_u16(sectorBuffer, BPB_rootEntries) * DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector); partition->totalSize = ((uint64_t)partition->numberOfSectors - (partition->dataStart - startSector)) * (uint64_t)partition->bytesPerSector; //FS info sector partition->fsInfoSector = startSector + (u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) ? u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) : 1); // Store info about FAT uint32_t clusterCount = (partition->numberOfSectors - (uint32_t)(partition->dataStart - startSector)) / partition->sectorsPerCluster; partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1; partition->fat.firstFree = CLUSTER_FIRST; partition->fat.numberFreeCluster = 0; partition->fat.numberLastAllocCluster = 0; if (clusterCount < CLUSTERS_PER_FAT12) { partition->filesysType = FS_FAT12; // FAT12 volume } else if (clusterCount < CLUSTERS_PER_FAT16) { partition->filesysType = FS_FAT16; // FAT16 volume } else { partition->filesysType = FS_FAT32; // FAT32 volume } if (partition->filesysType != FS_FAT32) { partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER; } else { // Set up for the FAT32 way partition->rootDirCluster = u8array_to_u32(sectorBuffer, BPB_FAT32_rootClus); // Check if FAT mirroring is enabled if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80)) { // Use the active FAT partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * (sectorBuffer[BPB_FAT32_extFlags] & 0x0F)); } } // Create a cache to use partition->cache = _FAT_cache_constructor (cacheSize, sectorsPerPage, partition->disc, startSector+partition->numberOfSectors, partition->bytesPerSector); // Set current directory to the root partition->cwdCluster = partition->rootDirCluster; // Check if this disc is writable, and set the readOnly property appropriately partition->readOnly = !(_FAT_disc_features(disc) & FEATURE_MEDIUM_CANWRITE); // There are currently no open files on this partition partition->openFileCount = 0; partition->firstOpenFile = NULL; _FAT_partition_readFSinfo(partition); return partition; }