source: MondoRescue/branches/3.3/mindi-busybox/util-linux/volume_id/exfat.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 4.8 KB
Line 
1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2012 S-G Bergh <sgb@systemasis.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_EXFAT) += exfat.o
22
23//config:
24//config:config FEATURE_VOLUMEID_EXFAT
25//config: bool "exFAT filesystem"
26//config: default y
27//config: depends on VOLUMEID
28//config: help
29//config: exFAT (extended FAT) is a proprietary file system designed especially
30//config: for flash drives. It has many features from NTFS, but with less
31//config: overhead. exFAT is used on most SDXC cards for consumer electronics.
32//config:
33
34#include "volume_id_internal.h"
35
36#define EXFAT_SB_OFFSET 0
37#define EXFAT_DIR_ENTRY_SZ 32
38#define EXFAT_MAX_DIR_ENTRIES 100
39
40struct exfat_super_block {
41/* 0x00 */ uint8_t boot_jump[3];
42/* 0x03 */ uint8_t fs_name[8];
43/* 0x0B */ uint8_t must_be_zero[53];
44/* 0x40 */ uint64_t partition_offset;
45/* 0x48 */ uint64_t volume_length;
46/* 0x50 */ uint32_t fat_offset; // Sector address of 1st FAT
47/* 0x54 */ uint32_t fat_size; // In sectors
48/* 0x58 */ uint32_t cluster_heap_offset; // Sector address of Data Region
49/* 0x5C */ uint32_t cluster_count;
50/* 0x60 */ uint32_t root_dir; // Cluster address of Root Directory
51/* 0x64 */ uint8_t vol_serial_nr[4]; // Volume ID
52/* 0x68 */ uint16_t fs_revision; // VV.MM
53/* 0x6A */ uint16_t vol_flags;
54/* 0x6C */ uint8_t bytes_per_sector; // Power of 2: 9 => 512, 12 => 4096
55/* 0x6D */ uint8_t sectors_per_cluster; // Power of 2
56/* 0x6E */ uint8_t nr_of_fats; // 2 for TexFAT
57/* 0x6F */ // ...
58} PACKED;
59
60struct exfat_dir_entry {
61/* 0x00 */ uint8_t entry_type;
62 union {
63 struct volume_label {
64/* 0x01 */ uint8_t char_count; // Length of label
65/* 0x02 */ uint16_t vol_label[11]; // UTF16 string without null termination
66/* 0x18 */ uint8_t reserved[8];
67/* 0x20 */ } PACKED label;
68 struct volume_guid {
69/* 0x01 */ uint8_t sec_count;
70/* 0x02 */ uint16_t set_checksum;
71/* 0x04 */ uint16_t flags;
72/* 0x06 */ uint8_t vol_guid[16];
73/* 0x16 */ uint8_t reserved[10];
74/* 0x20 */ } PACKED guid;
75 } PACKED type;
76} PACKED;
77
78int FAST_FUNC volume_id_probe_exfat(struct volume_id *id /*,uint64_t off*/)
79{
80 struct exfat_super_block *sb;
81 struct exfat_dir_entry *de;
82 unsigned sector_sz;
83 unsigned cluster_sz;
84 uint64_t root_dir_off;
85 unsigned count;
86 unsigned need_lbl_guid;
87
88 // Primary super block
89 dbg("exFAT: probing at offset 0x%x", EXFAT_SB_OFFSET);
90 sb = volume_id_get_buffer(id, EXFAT_SB_OFFSET, sizeof(*sb));
91
92 if (!sb)
93 return -1;
94
95 if (memcmp(sb->fs_name, "EXFAT ", 8) != 0)
96 return -1;
97
98 sector_sz = 1 << sb->bytes_per_sector;
99 cluster_sz = sector_sz << sb->sectors_per_cluster;
100 // There are no clusters 0 and 1, so the first cluster is 2.
101 root_dir_off = (uint64_t)EXFAT_SB_OFFSET +
102 // Hmm... should we cast sector_sz/cluster_sz to uint64_t?
103 (le32_to_cpu(sb->cluster_heap_offset)) * sector_sz +
104 (le32_to_cpu(sb->root_dir) - 2) * cluster_sz;
105 dbg("exFAT: sector size 0x%x bytes", sector_sz);
106 dbg("exFAT: cluster size 0x%x bytes", cluster_sz);
107 dbg("exFAT: root dir is at 0x%llx", (long long)root_dir_off);
108
109 // Use DOS uuid as fallback, if no GUID set
110 volume_id_set_uuid(id, sb->vol_serial_nr, UUID_DOS);
111
112 // EXFAT_MAX_DIR_ENTRIES is used as a safety belt.
113 // The Root Directory may hold an unlimited number of entries,
114 // so we do not want to check all. Usually label and GUID
115 // are in the beginning, but there are no guarantees.
116 need_lbl_guid = (1 << 0) | (1 << 1);
117 for (count = 0; count < EXFAT_MAX_DIR_ENTRIES; count++) {
118 de = volume_id_get_buffer(id, root_dir_off + (count * EXFAT_DIR_ENTRY_SZ), EXFAT_DIR_ENTRY_SZ);
119 if (de == NULL)
120 break;
121 if (de->entry_type == 0x00) {
122 // End of Directory Marker
123 dbg("exFAT: End of root directory reached after %u entries", count);
124 break;
125 }
126 if (de->entry_type == 0x83) {
127 // Volume Label Directory Entry
128 volume_id_set_label_unicode16(id, (uint8_t *)de->type.label.vol_label,
129 LE, 2 * de->type.label.char_count);
130 need_lbl_guid &= ~(1 << 0);
131 }
132 if (de->entry_type == 0xA0) {
133 // Volume GUID Directory Entry
134 volume_id_set_uuid(id, de->type.guid.vol_guid, UUID_DCE);
135 need_lbl_guid &= ~(1 << 1);
136 }
137 if (!need_lbl_guid)
138 break;
139 }
140
141 IF_FEATURE_BLKID_TYPE(id->type = "exfat";)
142 return 0;
143}
Note: See TracBrowser for help on using the repository browser.