aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorS-G Bergh <sgb@systemasis.org>2012-11-13 14:40:37 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2012-11-13 14:40:37 +0100
commite4b9451413013388757cf48fbb16d8137ddd1ccb (patch)
treed72b10d4d8f8e735ad720c411967d725056f568a
parent3f21044f20ef304309651bbdef8b275475f03a28 (diff)
downloadbusybox-w32-e4b9451413013388757cf48fbb16d8137ddd1ccb.tar.gz
busybox-w32-e4b9451413013388757cf48fbb16d8137ddd1ccb.tar.bz2
busybox-w32-e4b9451413013388757cf48fbb16d8137ddd1ccb.zip
volume_id: add exFAT detection
function old new delta volume_id_probe_exfat - 294 +294 Signed-off-by: S-G Bergh <sgb@systemasis.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--util-linux/Config.src9
-rw-r--r--util-linux/volume_id/Kbuild.src1
-rw-r--r--util-linux/volume_id/exfat.c130
-rw-r--r--util-linux/volume_id/volume_id.c3
-rw-r--r--util-linux/volume_id/volume_id_internal.h2
5 files changed, 145 insertions, 0 deletions
diff --git a/util-linux/Config.src b/util-linux/Config.src
index 3355e9729..e4516ddb7 100644
--- a/util-linux/Config.src
+++ b/util-linux/Config.src
@@ -734,6 +734,15 @@ config FEATURE_VOLUMEID_FAT
734 help 734 help
735 TODO 735 TODO
736 736
737config FEATURE_VOLUMEID_EXFAT
738 bool "exFAT filesystem"
739 default y
740 depends on VOLUMEID
741 help
742 exFAT (extended FAT) is a proprietary file system designed especially
743 for flash drives. It has many features from NTFS, but with less
744 overhead. exFAT is used on most SDXC cards for consumer electronics.
745
737config FEATURE_VOLUMEID_HFS 746config FEATURE_VOLUMEID_HFS
738 bool "hfs filesystem" 747 bool "hfs filesystem"
739 default y 748 default y
diff --git a/util-linux/volume_id/Kbuild.src b/util-linux/volume_id/Kbuild.src
index 39a2d8cf4..759fdaae5 100644
--- a/util-linux/volume_id/Kbuild.src
+++ b/util-linux/volume_id/Kbuild.src
@@ -33,6 +33,7 @@ lib-$(CONFIG_FEATURE_VOLUMEID_LINUXSWAP) += linux_swap.o
33### lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o 33### lib-$(CONFIG_FEATURE_VOLUMEID_MSDOS) += msdos.o
34lib-$(CONFIG_FEATURE_VOLUMEID_NILFS) += nilfs.o 34lib-$(CONFIG_FEATURE_VOLUMEID_NILFS) += nilfs.o
35lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o 35lib-$(CONFIG_FEATURE_VOLUMEID_NTFS) += ntfs.o
36lib-$(CONFIG_FEATURE_VOLUMEID_EXFAT) += exfat.o
36lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o 37lib-$(CONFIG_FEATURE_VOLUMEID_REISERFS) += reiserfs.o
37lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o 38lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o
38### lib-$(CONFIG_FEATURE_VOLUMEID_UFS) += ufs.o 39### lib-$(CONFIG_FEATURE_VOLUMEID_UFS) += ufs.o
diff --git a/util-linux/volume_id/exfat.c b/util-linux/volume_id/exfat.c
new file mode 100644
index 000000000..a38a8916d
--- /dev/null
+++ b/util-linux/volume_id/exfat.c
@@ -0,0 +1,130 @@
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#include "volume_id_internal.h"
22
23#define EXFAT_SB_OFFSET 0
24#define EXFAT_DIR_ENTRY_SZ 32
25#define EXFAT_MAX_DIR_ENTRIES 100
26
27struct exfat_super_block {
28/* 0x00 */ uint8_t boot_jump[3];
29/* 0x03 */ uint8_t fs_name[8];
30/* 0x0B */ uint8_t must_be_zero[53];
31/* 0x40 */ uint64_t partition_offset;
32/* 0x48 */ uint64_t volume_length;
33/* 0x50 */ uint32_t fat_offset; // Sector address of 1st FAT
34/* 0x54 */ uint32_t fat_size; // In sectors
35/* 0x58 */ uint32_t cluster_heap_offset; // Sector address of Data Region
36/* 0x5C */ uint32_t cluster_count;
37/* 0x60 */ uint32_t root_dir; // Cluster address of Root Directory
38/* 0x64 */ uint8_t vol_serial_nr[4]; // Volume ID
39/* 0x68 */ uint16_t fs_revision; // VV.MM
40/* 0x6A */ uint16_t vol_flags;
41/* 0x6C */ uint8_t bytes_per_sector; // Power of 2: 9 => 512, 12 => 4096
42/* 0x6D */ uint8_t sectors_per_cluster; // Power of 2
43/* 0x6E */ uint8_t nr_of_fats; // 2 for TexFAT
44/* 0x6F */ // ...
45} PACKED;
46
47struct exfat_dir_entry {
48/* 0x00 */ uint8_t entry_type;
49 union {
50 struct volume_label {
51/* 0x01 */ uint8_t char_count; // Length of label
52/* 0x02 */ uint16_t vol_label[11]; // UTF16 string without null termination
53/* 0x18 */ uint8_t reserved[8];
54/* 0x20 */ } PACKED label;
55 struct volume_guid {
56/* 0x01 */ uint8_t sec_count;
57/* 0x02 */ uint16_t set_checksum;
58/* 0x04 */ uint16_t flags;
59/* 0x06 */ uint8_t vol_guid[16];
60/* 0x16 */ uint8_t reserved[10];
61/* 0x20 */ } PACKED guid;
62 } PACKED type;
63} PACKED;
64
65int FAST_FUNC volume_id_probe_exfat(struct volume_id *id /*,uint64_t off*/)
66{
67 struct exfat_super_block *sb;
68 struct exfat_dir_entry *de;
69 unsigned sector_sz;
70 unsigned cluster_sz;
71 uint64_t root_dir_off;
72 unsigned count;
73 unsigned need_lbl_guid;
74
75 // Primary super block
76 dbg("exFAT: probing at offset 0x%x", EXFAT_SB_OFFSET);
77 sb = volume_id_get_buffer(id, EXFAT_SB_OFFSET, sizeof(*sb));
78
79 if (!sb)
80 return -1;
81
82 if (memcmp(sb->fs_name, "EXFAT ", 8) != 0)
83 return -1;
84
85 sector_sz = 1 << sb->bytes_per_sector;
86 cluster_sz = sector_sz << sb->sectors_per_cluster;
87 // There are no clusters 0 and 1, so the first cluster is 2.
88 root_dir_off = (uint64_t)EXFAT_SB_OFFSET +
89 // Hmm... should we cast sector_sz/cluster_sz to uint64_t?
90 (le32_to_cpu(sb->cluster_heap_offset)) * sector_sz +
91 (le32_to_cpu(sb->root_dir) - 2) * cluster_sz;
92 dbg("exFAT: sector size 0x%x bytes", sector_sz);
93 dbg("exFAT: cluster size 0x%x bytes", cluster_sz);
94 dbg("exFAT: root dir is at 0x%llx", (long long)root_dir_off);
95
96 // Use DOS uuid as fallback, if no GUID set
97 volume_id_set_uuid(id, sb->vol_serial_nr, UUID_DOS);
98
99 // EXFAT_MAX_DIR_ENTRIES is used as a safety belt.
100 // The Root Directory may hold an unlimited number of entries,
101 // so we do not want to check all. Usually label and GUID
102 // are in the beginning, but there are no guarantees.
103 need_lbl_guid = (1 << 0) | (1 << 1);
104 for (count = 0; count < EXFAT_MAX_DIR_ENTRIES; count++) {
105 de = volume_id_get_buffer(id, root_dir_off + (count * EXFAT_DIR_ENTRY_SZ), EXFAT_DIR_ENTRY_SZ);
106 if (de == NULL)
107 break;
108 if (de->entry_type == 0x00) {
109 // End of Directory Marker
110 dbg("exFAT: End of root directory reached after %u entries", count);
111 break;
112 }
113 if (de->entry_type == 0x83) {
114 // Volume Label Directory Entry
115 volume_id_set_label_unicode16(id, (uint8_t *)de->type.label.vol_label,
116 LE, 2 * de->type.label.char_count);
117 need_lbl_guid &= ~(1 << 0);
118 }
119 if (de->entry_type == 0xA0) {
120 // Volume GUID Directory Entry
121 volume_id_set_uuid(id, de->type.guid.vol_guid, UUID_DCE);
122 need_lbl_guid &= ~(1 << 1);
123 }
124 if (!need_lbl_guid)
125 break;
126 }
127
128 IF_FEATURE_BLKID_TYPE(id->type = "exfat";)
129 return 0;
130}
diff --git a/util-linux/volume_id/volume_id.c b/util-linux/volume_id/volume_id.c
index c1d615283..3c3c69818 100644
--- a/util-linux/volume_id/volume_id.c
+++ b/util-linux/volume_id/volume_id.c
@@ -93,6 +93,9 @@ static const probe_fptr fs1[] = {
93#if ENABLE_FEATURE_VOLUMEID_FAT 93#if ENABLE_FEATURE_VOLUMEID_FAT
94 volume_id_probe_vfat, 94 volume_id_probe_vfat,
95#endif 95#endif
96#if ENABLE_FEATURE_VOLUMEID_EXFAT
97 volume_id_probe_exfat,
98#endif
96#if ENABLE_FEATURE_VOLUMEID_MAC 99#if ENABLE_FEATURE_VOLUMEID_MAC
97 volume_id_probe_mac_partition_map, 100 volume_id_probe_mac_partition_map,
98#endif 101#endif
diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h
index 1c2e0ffa6..03dc46f27 100644
--- a/util-linux/volume_id/volume_id_internal.h
+++ b/util-linux/volume_id/volume_id_internal.h
@@ -216,6 +216,8 @@ int FAST_FUNC volume_id_probe_nilfs(struct volume_id *id /*,uint64_t off*/);
216 216
217int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/); 217int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/);
218 218
219int FAST_FUNC volume_id_probe_exfat(struct volume_id *id /*,uint64_t off*/);
220
219int FAST_FUNC volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/); 221int FAST_FUNC volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/);
220 222
221int FAST_FUNC volume_id_probe_reiserfs(struct volume_id *id /*,uint64_t off*/); 223int FAST_FUNC volume_id_probe_reiserfs(struct volume_id *id /*,uint64_t off*/);