/* ************************************************************************* * * Microsoft exFAT file system Parser Template * * * File Name : exfat_spec.bt * Author : Lu wen jiang * Created On : Mon Aug 24 13:43:40 2009 * Last Modified By: Lu wen jiang * Last Modified On: Fri Aug 28 17:59:23 2009 * Update Count : 884 * * HISTORY * * **************************************************************************/ /**************************************************************************** EXFAT FILE SYSTEM VOLUME STRUCTURE LAYOUT |------------------------+----------------------+---------------------------| | Sub-region Name | Offset(sector) | Size(Sectors) | |------------------------+----------------------+---------------------------| | | [MAIN BOOT REGION] | | |------------------------+----------------------+---------------------------| | Main Boot Sector | 0 | 1 | |------------------------+----------------------+---------------------------| | Main Extended Boot | 1 | 8 | | Sectors | | | |------------------------+----------------------+---------------------------| | Main OEM Parameters | 9 | 1 | |------------------------+----------------------+---------------------------| | Main Reserved | 10 | 1 | |------------------------+----------------------+---------------------------| | Main Boot CheckSum | 11 | 1 | |------------------------+----------------------+---------------------------| | | [BACKUP BOOT REGION] | | |------------------------+----------------------+---------------------------| | Backup Boot Sector | 12 | 1 | |------------------------+----------------------+---------------------------| | Backup Extended Boot | 13 | 8 | | Sectors | | | |------------------------+----------------------+---------------------------| | Backup OEM Parameters | 21 | 1 | |------------------------+----------------------+---------------------------| | Backup Reserved | 22 | 1 | |------------------------+----------------------+---------------------------| | Backup Boot CheckSum | 23 | 1 | |------------------------+----------------------+---------------------------| | | [FAT REGION] | | |------------------------+----------------------+---------------------------| | FAT Alignment | 24 | x | |------------------------+----------------------+---------------------------| | First FAT | FatOffset | FatLength | |------------------------+----------------------+---------------------------| | Second FAT | FATOffset+FATLength | Fatlength* | | | | (NumberOfFats-1) | |------------------------+----------------------+---------------------------| | | [DATA REGION] | | |------------------------+----------------------+---------------------------| | Cluster Heap Alignment | (FAT End Sector) | x | |------------------------+----------------------+---------------------------| | Cluster Heap | ClusterHeapOffset | ClusterCount* | | | | 2^SectorsPerClusterShift | |------------------------+----------------------+---------------------------| | Excess Space | (Cluster End Sector) | VolumLength- | | | | (Cluster Heap End Sector) | |------------------------+----------------------+---------------------------| *****************************************************************************/ LittleEndian(); FSeek(0); typedef char S08; typedef unsigned char U08; typedef unsigned short U16; typedef unsigned int U32; typedef uint64 U64; struct tagTempVariable { local U08 flags[2]; local U32 cluster_max = 512; local U32 cluster_array[cluster_max]; local U32 cluster_count = 0; local U32 cluster_iter = 0; local U32 bitmap_cluster = 2; }exfat_temp_variable ; local U64 ______EXFAT_BOOT_SECTOR_REGION; string TotalSizeRead(struct tagTempVariable& v) { string s; SPrintf(s, "Disk Bytes: %Lu(%Lxh)", FileSize(), FileSize()); return s; } typedef U08 exFatVersion[2] ; string VersionRead(exFatVersion v ) { string s; SPrintf(s, "exFAT Revision: %01d.%02d", v[1], v[0]); return s; } string ShiftRead(U08 v) { string s; SPrintf(s, "%d(%d)", v, (1<; S08 aucFileSystemName[8]; U08 aucMustBeZero[53]; U64 ulPartitionOffset; U64 ulVolumeLength; U32 uiFatOffset; U32 uiFatLength; U32 uiClusterHeapOffset; U32 uiClusterCount; U32 uiFirstClusterOfRootDirectory; U32 uiVolumeSerialNumber ; exFatVersion usFileSystemRevision; U16 usVolumeFlags_ActiveFat:1; U16 usVolumeFlags_VolumeDirty:1; U16 usVolumeFlags_MediaFailure:1; U16 usVolumeFlags_ClearToZero:1; U16 usVolumeFlags_Reserved:12; U08 ucBytesPerSectorShift ; U08 ucSectorsPerClusterShift ; U08 ucNumberOfFats; U08 ucDriveSelect ; U08 ucPercentInUse; U08 aucReserved[7]; U08 aucBootCode[390]; U16 usBootSignature ; if (IsValidBootSector(aucJumpBoot,aucFileSystemName)==1 && (1<; BootSector_S BootSector ; string BootSectorRead(BootSector_S& v) { string s; if (IsValidBootSector(v.aucJumpBoot,v.aucFileSystemName)==1) { SPrintf(s, "Valid exFAT Volume"); } else { SPrintf(s, "Invalid exFAT Volume, %s?", v.aucFileSystemName); } return s; } if (IsValidBootSector(BootSector.aucJumpBoot,BootSector.aucFileSystemName)==0) { return 0; } local U64 ______EXFAT_VOLUME_LAYOUT_REGION; FSeek(0); typedef struct { BootSector_S BootSector; struct { U08 aucExendedBootCode[(1<; }ExtendedBootSector[8]; struct { struct { U08 aucParametersGuid[16]; U08 aucCustomDefined[32]; }stParameters[10]; U08 aucReserved[(1<; }BootChecksumSector; }Boot_Region_S ; string BootRegionRead(Boot_Region_S& boot) { string s; SPrintf(s, "Volume Bytes: %Lu(%Lxh)", boot.BootSector.ulVolumeLength<; U32 uiExcessEntry[Main_Boot_Region.BootSector.uiFatLength* (1<; }FirstFAT; if (Main_Boot_Region.BootSector.ucNumberOfFats > 1) { struct { U32 uiFatEntry[Main_Boot_Region.BootSector.uiClusterCount+2] ; U32 uiExcessEntry[Main_Boot_Region.BootSector.uiFatLength* (1<; }SecondFAT; } }Fat_Region_S ; string FatRegionRead(Fat_Region_S& v) { string s; SPrintf(s, "FATs: %d, EntryTotalPerFAT: %d", Main_Boot_Region.BootSector.ucNumberOfFats, Main_Boot_Region.BootSector.uiClusterCount+2); return s; } Fat_Region_S Fat_Region; typedef struct { local U32 uiClusterNo = 2; struct { U08 aucData[1<; string ClusterRead(Cluster_S& v) { string s; SPrintf(s, "ClusterNo: %d", v.uiClusterNo); return s; } struct tagDataRegion { if (Main_Boot_Region.BootSector.uiClusterHeapOffset - (Main_Boot_Region.BootSector.uiFatOffset + Main_Boot_Region.BootSector.ucNumberOfFats * Main_Boot_Region.BootSector.uiFatLength)) { struct { U08 aucReserved[(1<> Main_Boot_Region.BootSector.ucBytesPerSectorShift>> Main_Boot_Region.BootSector.ucSectorsPerClusterShift; if (data_cluster_total > Main_Boot_Region.BootSector.uiClusterCount) { data_cluster_total = Main_Boot_Region.BootSector.uiClusterCount; } local U32 curr_cluster_no = 0; for (exfat_temp_variable.cluster_iter = 0; exfat_temp_variable.cluster_iter < data_cluster_total; exfat_temp_variable.cluster_iter++) { Cluster_S ClusterHeap; ClusterHeap.uiClusterNo += curr_cluster_no; curr_cluster_no++; } }Data_Region ; string DataRegionRead(struct tagDataRegion& v) { string s; SPrintf(s, "Cluster Total(%s): %d(%d)", (v.data_cluster_total==Main_Boot_Region.BootSector.uiClusterCount)?"FINE":"FAIL", Main_Boot_Region.BootSector.uiClusterCount,v.data_cluster_total); return s; } if (Main_Boot_Region.BootSector.ulVolumeLength - Main_Boot_Region.BootSector.uiClusterHeapOffset - (Main_Boot_Region.BootSector.uiClusterCount<< Main_Boot_Region.BootSector.ucSectorsPerClusterShift)) { struct { struct { U08 aucReserved[(1<; string BitmapRead(Bitmap_S& stBitmapByte) { string s; SPrintf(s, "%08d: %d%d%d%d%d%d%d%d", stBitmapByte.byte_count+2, (stBitmapByte.bitmap>>0)&0x1, (stBitmapByte.bitmap>>1)&0x1, (stBitmapByte.bitmap>>2)&0x1, (stBitmapByte.bitmap>>3)&0x1, (stBitmapByte.bitmap>>4)&0x1, (stBitmapByte.bitmap>>5)&0x1, (stBitmapByte.bitmap>>6)&0x1, (stBitmapByte.bitmap>>7)&0x1); return s; } struct tagBitmapRegion { local U32 bitmap_length = Main_Boot_Region.BootSector.uiClusterCount; for (exfat_temp_variable.cluster_iter = 0; exfat_temp_variable.cluster_iter < (bitmap_length+7)/8; exfat_temp_variable.cluster_iter++) { Bitmap_S Bitmap; Bitmap.byte_count = exfat_temp_variable.cluster_iter<<3; } }BITMAP_REGION ; string AllocationBitmapRegionRead(struct tagBitmapRegion& stBitmapRegion) { string s; SPrintf(s, "Bits: %d(Bytes: %d)", stBitmapRegion.bitmap_length, (stBitmapRegion.bitmap_length+7)/8); return s; } /////////////////////////////////////////////////////////////////////// local int ______EXFAT_DIRECTORY_REGION; typedef struct { local U08 uc10msIncrement = 0; U16 bDoubleSeconds:5; U16 bMinute:6; U16 bHour:5; U16 bDay:5; U16 bMonth:4; U16 bYear:7; }FileTime_S ; string FileTimeRead(FileTime_S& v) { string s; SPrintf(s, "%04d/%02d/%02d %02d:%02d:%02d.%02d", v.bYear+1980, v.bMonth,v.bDay,v.bHour,v.bMinute, v.bDoubleSeconds*2 + v.uc10msIncrement/100, (v.uc10msIncrement%100)); return s; } typedef U08 FileName_S[30] ; typedef U08 VolumeLabel_S[22] ; typedef struct { struct { U08 bTypeCode:5; U08 bTypeImportance:1; U08 bTypeCategory:1; U08 bInUse:1; }stEntryType; if (stEntryType.bTypeCategory==0 && stEntryType.bTypeImportance==0) { switch (stEntryType.bTypeCode) { case 1: // Allocation Bitmap U08 bBitmapIdentifier:1; U08 bReserved:7; U08 aucCustomDefined[18]; U32 uiFirstCluster; U64 ulDataLength; break; case 2: // Up-case Table U08 aucReserved1[3]; U32 uiTableChecksum ; U08 aucReserved2[12]; U32 uiFirstCluster; U64 ulDataLength; break; case 3: // Volume Label U08 ucCharacterCount; VolumeLabel_S stVolumeLabel; U08 aucReserved[8]; break; case 5: // File or Directory U08 ucSecondaryCount; U16 usSetCheckSum ; U16 bAttrReadOnly:1; U16 bAttrHidden:1; U16 bAttrSystem:1; U16 bAttrReserved1:1; U16 bAttrDirectory:1; U16 bAttrArchive:1; U16 bAttrReserved2:10; U08 ausReserved1[2]; FileTime_S stCreat; FileTime_S stLastModified; FileTime_S stLastAccessed; U08 ucCreate10msIncrement; /* per 10ms */ U08 ucModified10msIncrement; /* per 10ms */ U08 ucLastAcc10msdIncrement; /* per 10ms */ U08 ausReserved2[9]; stCreat.uc10msIncrement = ucCreate10msIncrement; stLastModified.uc10msIncrement = ucModified10msIncrement; stLastAccessed.uc10msIncrement = ucLastAcc10msdIncrement; if (bAttrDirectory == 1 && stEntryType.bInUse == 1 && exfat_temp_variable.cluster_count < exfat_temp_variable.cluster_max) { exfat_temp_variable.cluster_array[exfat_temp_variable.cluster_count]=1; } break; default: U08 ucSecondaryCount; U16 usSetCheckSum ; U16 bAllocationPossible:1; U16 bNoFatChain:1; U16 bCustomDefined:14; U08 aucCustomDefined[14]; U32 uiFirstCluster; U64 ulDataLength; break; } } else if (stEntryType.bTypeCategory==0 && stEntryType.bTypeImportance==1) { switch (stEntryType.bTypeCode) { case 0: //Volume GUID U08 ucSecondaryCount; U16 usSetCheckSum; U16 bAllocationPossible:1; U16 bNoFatChain:1; U16 bCustomDefined:14; U08 aucVolumeGuid[16]; U08 aucReserved[10]; break; case 1: // TexFAT Padding U08 aucCustomDefined[31];break; case 2: // WinCE ACL Table U08 aucCustomDefined[31];break; default: // Unknow U08 aucCustomDefined[31];break; } } else if (stEntryType.bTypeCategory==1 && stEntryType.bTypeImportance==0) { switch (stEntryType.bTypeCode) { case 0: // Stream Extension U08 bAllocationPossible:1; U08 bNoFatChain:1; U08 bCustomDefined:6; U08 ucReserved1; U08 ucNameLength; U16 usNameHash ; U08 aucReserved2[2]; U64 ulValidDataLength; U08 aucReserved3[4]; U32 uiFirstCluster; U64 ulDataLength; if (stEntryType.bInUse == 1 && exfat_temp_variable.cluster_count < exfat_temp_variable.cluster_max && exfat_temp_variable.cluster_array[exfat_temp_variable.cluster_count]==1) { exfat_temp_variable.cluster_array[exfat_temp_variable.cluster_count] = uiFirstCluster; exfat_temp_variable.cluster_count++; } break; case 1: // File Name U08 bAllocationPossible:1; U08 bNoFatChain:1; U08 bCustomDefined:6; FileName_S stFileNmae; break; default: U08 bAllocationPossible:1; U08 bNoFatChain:1; U08 bCustomDefined:6; U08 aucCustomDefined[18]; U32 uiFirstCluster; U64 ulDataLength; break; } } else { U08 aucCustomDefined[31]; } }DirectoryEntry_S ; string FileNameRead(FileName_S astFileName) { char s[16]; U08 i; for (i = 0; i < 15; i++) { s[i] = astFileName[i*2]; } return s; } string VolumeLabelRead(VolumeLabel_S astFileName) { char s[12]; U08 i; for (i = 0; i < 11; i++) { s[i] = astFileName[i*2]; } return s; } string DirectoryRead(DirectoryEntry_S& stDirEntry) { string s = "Unknow Type"; if (stDirEntry.stEntryType.bTypeCategory==0 && stDirEntry.stEntryType.bTypeImportance==0) { switch (stDirEntry.stEntryType.bTypeCode) { case 1:SPrintf(s, "[C/P/%s]: Allocation Bitmap", stDirEntry.stEntryType.bInUse==0?"F":"U");break; case 2:SPrintf(s, "[C/P/%s]: Up-case Table", stDirEntry.stEntryType.bInUse==0?"F":"U");break; case 3:SPrintf(s, "[C/P/%s]: Valume Label(%s)", stDirEntry.stEntryType.bInUse==0?"F":"U", VolumeLabelRead(stDirEntry.stVolumeLabel));break; case 5:SPrintf(s, "[C/P/%s]: Regular File(%s)", stDirEntry.stEntryType.bInUse==0?"F":"U", stDirEntry.bAttrDirectory==0?"File":"Directroy");break; default:SPrintf(s, "[C/P/%s]: Unknow", stDirEntry.stEntryType.bInUse==0?"F":"U");break; } } if (stDirEntry.stEntryType.bTypeCategory==0 && stDirEntry.stEntryType.bTypeImportance==1) { switch (stDirEntry.stEntryType.bTypeCode) { case 0:SPrintf(s, "[B/P/%s]: Volume GUID", stDirEntry.stEntryType.bInUse==0?"F":"U");break; case 1:SPrintf(s, "[B/P/%s]: TexFAT Padding", stDirEntry.stEntryType.bInUse==0?"F":"U");break; case 2:SPrintf(s, "[B/P/%s]: WinCE ACL Table", stDirEntry.stEntryType.bInUse==0?"F":"U");break; default:SPrintf(s, "[B/P/%s]: Unknow", stDirEntry.stEntryType.bInUse==0?"F":"U");break; } } if (stDirEntry.stEntryType.bTypeCategory==1 && stDirEntry.stEntryType.bTypeImportance==0) { switch (stDirEntry.stEntryType.bTypeCode) { case 0:SPrintf(s, "[C/S/%s]: Stream Extension", stDirEntry.stEntryType.bInUse==0?"F":"U");break; case 1:SPrintf(s, "[C/S/%s]: File Name(%s)", stDirEntry.stEntryType.bInUse==0?"F":"U", FileNameRead(stDirEntry.stFileNmae));break; default:SPrintf(s, "[C/S/%s]: Unknow", stDirEntry.stEntryType.bInUse==0?"F":"U");break; } } if (stDirEntry.stEntryType.bTypeCategory==1 && stDirEntry.stEntryType.bTypeImportance==1) { switch (stDirEntry.stEntryType.bTypeCode) { default:SPrintf(s, "[B/S/%s]: Unknow", stDirEntry.stEntryType.bInUse==0?"F":"U");break; } } return s; } exfat_temp_variable.cluster_count = 1; exfat_temp_variable.cluster_array[0] = Main_Boot_Region.BootSector.uiFirstClusterOfRootDirectory; for (exfat_temp_variable.cluster_iter = 0; exfat_temp_variable.cluster_iter < exfat_temp_variable.cluster_count; exfat_temp_variable.cluster_iter++) { FSeek((((exfat_temp_variable.cluster_array[exfat_temp_variable.cluster_iter]-2)<< Main_Boot_Region.BootSector.ucSectorsPerClusterShift) + Main_Boot_Region.BootSector.uiClusterHeapOffset)<< Main_Boot_Region.BootSector.ucBytesPerSectorShift); struct tagDirCluster { local int dir_cluster = exfat_temp_variable.cluster_array[exfat_temp_variable.cluster_iter]; while( !FEof() ) { ReadBytes(exfat_temp_variable.flags, FTell(), 1); if (exfat_temp_variable.flags[0] == 0) { break; } DirectoryEntry_S stEntry; } }DirectoryCluster ; } string DirectoryClusterRead(struct tagDirCluster& v) { string s; SPrintf(s, "Directory Cluster No: %d", v.dir_cluster); return s; }