1 /* 2 * Copyright (C) 2010 Andrew Nayenko <resver@gmail.com> 3 * 4 * This file may be redistributed under the terms of the 5 * GNU Lesser General Public License. 6 */ 7 #include "superblocks.h" 8 9 struct exfat_super_block { 10 uint8_t JumpBoot[3]; 11 uint8_t FileSystemName[8]; 12 uint8_t MustBeZero[53]; 13 uint64_t PartitionOffset; 14 uint64_t VolumeLength; 15 uint32_t FatOffset; 16 uint32_t FatLength; 17 uint32_t ClusterHeapOffset; 18 uint32_t ClusterCount; 19 uint32_t FirstClusterOfRootDirectory; 20 uint8_t VolumeSerialNumber[4]; 21 struct { 22 uint8_t vermin; 23 uint8_t vermaj; 24 } FileSystemRevision; 25 uint16_t VolumeFlags; 26 uint8_t BytesPerSectorShift; 27 uint8_t SectorsPerClusterShift; 28 uint8_t NumberOfFats; 29 uint8_t DriveSelect; 30 uint8_t PercentInUse; 31 uint8_t Reserved[7]; 32 uint8_t BootCode[390]; 33 uint16_t BootSignature; 34 } __attribute__((__packed__)); 35 36 struct exfat_entry_label { 37 uint8_t type; 38 uint8_t length; 39 uint8_t name[22]; 40 uint8_t reserved[8]; 41 } __attribute__((__packed__)); 42 43 #define BLOCK_SIZE(sb) ((sb)->BytesPerSectorShift < 32 ? (1u << (sb)->BytesPerSectorShift) : 0) 44 #define CLUSTER_SIZE(sb) ((sb)->SectorsPerClusterShift < 32 ? (BLOCK_SIZE(sb) << (sb)->SectorsPerClusterShift) : 0) 45 #define EXFAT_FIRST_DATA_CLUSTER 2 46 #define EXFAT_LAST_DATA_CLUSTER 0xffffff6 47 #define EXFAT_ENTRY_SIZE 32 48 49 #define EXFAT_ENTRY_EOD 0x00 50 #define EXFAT_ENTRY_LABEL 0x83 51 52 static uint64_t block_to_offset(const struct exfat_super_block *sb, 53 uint64_t block) 54 { 55 return block << sb->BytesPerSectorShift; 56 } 57 58 static uint64_t cluster_to_block(const struct exfat_super_block *sb, 59 uint32_t cluster) 60 { 61 return le32_to_cpu(sb->ClusterHeapOffset) + 62 ((uint64_t) (cluster - EXFAT_FIRST_DATA_CLUSTER) 63 << sb->SectorsPerClusterShift); 64 } 65 66 static uint64_t cluster_to_offset(const struct exfat_super_block *sb, 67 uint32_t cluster) 68 { 69 return block_to_offset(sb, cluster_to_block(sb, cluster)); 70 } 71 72 static uint32_t next_cluster(blkid_probe pr, 73 const struct exfat_super_block *sb, uint32_t cluster) 74 { 75 uint32_t *nextp, next; 76 uint64_t fat_offset; 77 78 fat_offset = block_to_offset(sb, le32_to_cpu(sb->FatOffset)) 79 + (uint64_t) cluster * sizeof(cluster); 80 nextp = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset, 81 sizeof(uint32_t)); 82 if (!nextp) 83 return 0; 84 memcpy(&next, nextp, sizeof(next)); 85 return le32_to_cpu(next); 86 } 87 88 static struct exfat_entry_label *find_label(blkid_probe pr, 89 const struct exfat_super_block *sb) 90 { 91 uint32_t cluster = le32_to_cpu(sb->FirstClusterOfRootDirectory); 92 uint64_t offset = cluster_to_offset(sb, cluster); 93 uint8_t *entry; 94 const size_t max_iter = 10000; 95 size_t i = 0; 96 97 for (; i < max_iter; i++) { 98 entry = (uint8_t *) blkid_probe_get_buffer(pr, offset, 99 EXFAT_ENTRY_SIZE); 100 if (!entry) 101 return NULL; 102 if (entry[0] == EXFAT_ENTRY_EOD) 103 return NULL; 104 if (entry[0] == EXFAT_ENTRY_LABEL) 105 return (struct exfat_entry_label *) entry; 106 107 offset += EXFAT_ENTRY_SIZE; 108 if (CLUSTER_SIZE(sb) && (offset % CLUSTER_SIZE(sb)) == 0) { 109 cluster = next_cluster(pr, sb, cluster); 110 if (cluster < EXFAT_FIRST_DATA_CLUSTER) 111 return NULL; 112 if (cluster > EXFAT_LAST_DATA_CLUSTER) 113 return NULL; 114 offset = cluster_to_offset(sb, cluster); 115 } 116 } 117 118 return NULL; 119 } 120 121 static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag) 122 { 123 struct exfat_super_block *sb; 124 struct exfat_entry_label *label; 125 126 sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block); 127 if (!sb || !CLUSTER_SIZE(sb)) 128 return errno ? -errno : BLKID_PROBE_NONE; 129 130 if (le16_to_cpu(sb->BootSignature) != 0xAA55) 131 return BLKID_PROBE_NONE; 132 133 if (memcmp(sb->JumpBoot, "\xEB\x76\x90", 3) != 0) 134 return BLKID_PROBE_NONE; 135 136 for (size_t i = 0; i < sizeof(sb->MustBeZero); i++) 137 if (sb->MustBeZero[i] != 0x00) 138 return BLKID_PROBE_NONE; 139 140 label = find_label(pr, sb); 141 if (label) 142 blkid_probe_set_utf8label(pr, label->name, 143 min((size_t) label->length * 2, sizeof(label->name)), 144 BLKID_ENC_UTF16LE); 145 else if (errno) 146 return -errno; 147 148 blkid_probe_sprintf_uuid(pr, sb->VolumeSerialNumber, 4, 149 "%02hhX%02hhX-%02hhX%02hhX", 150 sb->VolumeSerialNumber[3], sb->VolumeSerialNumber[2], 151 sb->VolumeSerialNumber[1], sb->VolumeSerialNumber[0]); 152 153 blkid_probe_sprintf_version(pr, "%u.%u", 154 sb->FileSystemRevision.vermaj, sb->FileSystemRevision.vermin); 155 156 #if 0 157 blkid_probe_set_fsblocksize(pr, BLOCK_SIZE(sb)); 158 blkid_probe_set_block_size(pr, BLOCK_SIZE(sb)); 159 blkid_probe_set_fssize(pr, BLOCK_SIZE(sb) * le64_to_cpu(sb->VolumeLength)); 160 #endif 161 162 return BLKID_PROBE_OK; 163 } 164 165 const struct blkid_idinfo exfat_idinfo = 166 { 167 .name = "exfat", 168 .usage = BLKID_USAGE_FILESYSTEM, 169 .probefunc = probe_exfat, 170 .magics = 171 { 172 { .magic = "EXFAT ", .len = 8, .sboff = 3 }, 173 { NULL } 174 } 175 }; 176
This page was automatically generated by LXR 0.3.1. • OpenWrt