• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/fstools/libblkid-tiny/exfat.c

  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