aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--Makefile.flags12
-rw-r--r--archival/libarchive/decompress_uncompress.c30
-rw-r--r--miscutils/fbsplash.c5
-rw-r--r--miscutils/nandwrite.c12
-rw-r--r--networking/ifupdown.c24
-rw-r--r--shell/ash.c2
-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/get_devname.c6
-rw-r--r--util-linux/volume_id/volume_id.c3
-rw-r--r--util-linux/volume_id/volume_id_internal.h2
13 files changed, 197 insertions, 40 deletions
diff --git a/Makefile b/Makefile
index 424c3daf1..22740d983 100644
--- a/Makefile
+++ b/Makefile
@@ -297,6 +297,7 @@ NM = $(CROSS_COMPILE)nm
297STRIP = $(CROSS_COMPILE)strip 297STRIP = $(CROSS_COMPILE)strip
298OBJCOPY = $(CROSS_COMPILE)objcopy 298OBJCOPY = $(CROSS_COMPILE)objcopy
299OBJDUMP = $(CROSS_COMPILE)objdump 299OBJDUMP = $(CROSS_COMPILE)objdump
300PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
300AWK = awk 301AWK = awk
301GENKSYMS = scripts/genksyms/genksyms 302GENKSYMS = scripts/genksyms/genksyms
302DEPMOD = /sbin/depmod 303DEPMOD = /sbin/depmod
diff --git a/Makefile.flags b/Makefile.flags
index fbb348a39..ffd1f7f60 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -78,6 +78,12 @@ ARCH_FPIC ?= -fpic
78ARCH_FPIE ?= -fpie 78ARCH_FPIE ?= -fpie
79ARCH_PIE ?= -pie 79ARCH_PIE ?= -pie
80 80
81# Usage: $(eval $(call pkg_check_modules,VARIABLE-PREFIX,MODULES))
82define pkg_check_modules
83$(1)_CFLAGS := $(shell $(PKG_CONFIG) $(PKG_CONFIG_FLAGS) --cflags $(2))
84$(1)_LIBS := $(shell $(PKG_CONFIG) $(PKG_CONFIG_FLAGS) --libs $(2))
85endef
86
81ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y) 87ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y)
82# on i386: 14% smaller libbusybox.so 88# on i386: 14% smaller libbusybox.so
83# (code itself is 9% bigger, we save on relocs/PLT/GOT) 89# (code itself is 9% bigger, we save on relocs/PLT/GOT)
@@ -89,6 +95,7 @@ endif
89 95
90ifeq ($(CONFIG_STATIC),y) 96ifeq ($(CONFIG_STATIC),y)
91CFLAGS_busybox += -static 97CFLAGS_busybox += -static
98PKG_CONFIG_FLAGS += --static
92endif 99endif
93 100
94ifeq ($(CONFIG_PIE),y) 101ifeq ($(CONFIG_PIE),y)
@@ -141,7 +148,10 @@ LDLIBS += pam pam_misc pthread
141endif 148endif
142 149
143ifeq ($(CONFIG_SELINUX),y) 150ifeq ($(CONFIG_SELINUX),y)
144LDLIBS += selinux sepol 151SELINUX_PC_MODULES = libselinux libsepol
152$(eval $(call pkg_check_modules,SELINUX,$(SELINUX_PC_MODULES)))
153CPPFLAGS += $(SELINUX_CFLAGS)
154LDLIBS += $(if $(SELINUX_LIBS),$(SELINUX_LIBS:-l%=%),$(SELINUX_PC_MODULES:lib%=%))
145endif 155endif
146 156
147ifeq ($(CONFIG_EFENCE),y) 157ifeq ($(CONFIG_EFENCE),y)
diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c
index e9bbfb9bd..3826a65ea 100644
--- a/archival/libarchive/decompress_uncompress.c
+++ b/archival/libarchive/decompress_uncompress.c
@@ -78,7 +78,6 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
78 IF_DESKTOP(long long total_written = 0;) 78 IF_DESKTOP(long long total_written = 0;)
79 IF_DESKTOP(long long) int retval = -1; 79 IF_DESKTOP(long long) int retval = -1;
80 unsigned char *stackp; 80 unsigned char *stackp;
81 long code;
82 int finchar; 81 int finchar;
83 long oldcode; 82 long oldcode;
84 long incode; 83 long incode;
@@ -143,8 +142,10 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
143 /* As above, initialize the first 256 entries in the table. */ 142 /* As above, initialize the first 256 entries in the table. */
144 /*clear_tab_prefixof(); - done by xzalloc */ 143 /*clear_tab_prefixof(); - done by xzalloc */
145 144
146 for (code = 255; code >= 0; --code) { 145 {
147 tab_suffixof(code) = (unsigned char) code; 146 int i;
147 for (i = 255; i >= 0; --i)
148 tab_suffixof(i) = (unsigned char) i;
148 } 149 }
149 150
150 do { 151 do {
@@ -175,6 +176,8 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
175 (insize << 3) - (n_bits - 1)); 176 (insize << 3) - (n_bits - 1));
176 177
177 while (inbits > posbits) { 178 while (inbits > posbits) {
179 long code;
180
178 if (free_ent > maxcode) { 181 if (free_ent > maxcode) {
179 posbits = 182 posbits =
180 ((posbits - 1) + 183 ((posbits - 1) +
@@ -191,13 +194,12 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
191 } 194 }
192 { 195 {
193 unsigned char *p = &inbuf[posbits >> 3]; 196 unsigned char *p = &inbuf[posbits >> 3];
194 197 code = ((p[0]
195 code = ((((long) (p[0])) | ((long) (p[1]) << 8) | 198 | ((long) (p[1]) << 8)
196 ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask; 199 | ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask;
197 } 200 }
198 posbits += n_bits; 201 posbits += n_bits;
199 202
200
201 if (oldcode == -1) { 203 if (oldcode == -1) {
202 if (code >= 256) 204 if (code >= 256)
203 bb_error_msg_and_die("corrupted data"); /* %ld", code); */ 205 bb_error_msg_and_die("corrupted data"); /* %ld", code); */
@@ -226,15 +228,16 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
226 /* Special case for KwKwK string. */ 228 /* Special case for KwKwK string. */
227 if (code >= free_ent) { 229 if (code >= free_ent) {
228 if (code > free_ent) { 230 if (code > free_ent) {
231/*
229 unsigned char *p; 232 unsigned char *p;
230 233
231 posbits -= n_bits; 234 posbits -= n_bits;
232 p = &inbuf[posbits >> 3]; 235 p = &inbuf[posbits >> 3];
233
234 bb_error_msg 236 bb_error_msg
235 ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)", 237 ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)",
236 insize, posbits, p[-1], p[0], p[1], p[2], p[3], 238 insize, posbits, p[-1], p[0], p[1], p[2], p[3],
237 (posbits & 07)); 239 (posbits & 07));
240*/
238 bb_error_msg("corrupted data"); 241 bb_error_msg("corrupted data");
239 goto err; 242 goto err;
240 } 243 }
@@ -244,7 +247,7 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
244 } 247 }
245 248
246 /* Generate output characters in reverse order */ 249 /* Generate output characters in reverse order */
247 while ((long) code >= (long) 256) { 250 while (code >= 256) {
248 if (stackp <= &htabof(0)) 251 if (stackp <= &htabof(0))
249 bb_error_msg_and_die("corrupted data"); 252 bb_error_msg_and_die("corrupted data");
250 *--stackp = tab_suffixof(code); 253 *--stackp = tab_suffixof(code);
@@ -285,11 +288,10 @@ unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
285 } 288 }
286 289
287 /* Generate the new entry. */ 290 /* Generate the new entry. */
288 code = free_ent; 291 if (free_ent < maxmaxcode) {
289 if (code < maxmaxcode) { 292 tab_prefixof(free_ent) = (unsigned short) oldcode;
290 tab_prefixof(code) = (unsigned short) oldcode; 293 tab_suffixof(free_ent) = (unsigned char) finchar;
291 tab_suffixof(code) = (unsigned char) finchar; 294 free_ent++;
292 free_ent = code + 1;
293 } 295 }
294 296
295 /* Remember previous code. */ 297 /* Remember previous code. */
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index 37ca66559..05a77da23 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -312,8 +312,7 @@ static void fb_drawprogressbar(unsigned percent)
312 312
313 pos_x = left_x; 313 pos_x = left_x;
314 if (percent > 0) { 314 if (percent > 0) {
315 int y; 315 int i, y;
316 unsigned i;
317 316
318 // actual progress bar 317 // actual progress bar
319 pos_x += (unsigned)(width * percent) / 100; 318 pos_x += (unsigned)(width * percent) / 100;
@@ -325,7 +324,7 @@ static void fb_drawprogressbar(unsigned percent)
325 while (i >= 0) { 324 while (i >= 0) {
326 // draw one-line thick "rectangle" 325 // draw one-line thick "rectangle"
327 // top line will have gray lvl 200, bottom one 100 326 // top line will have gray lvl 200, bottom one 100
328 unsigned gray_level = 100 + i*100 / height; 327 unsigned gray_level = 100 + (unsigned)i*100 / height;
329 fb_drawfullrectangle( 328 fb_drawfullrectangle(
330 left_x, y, pos_x, y, 329 left_x, y, pos_x, y,
331 gray_level, gray_level, gray_level); 330 gray_level, gray_level, gray_level);
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c
index c636a5aa2..5908ac773 100644
--- a/miscutils/nandwrite.c
+++ b/miscutils/nandwrite.c
@@ -39,7 +39,7 @@
39//usage: "[-o] [-b] [-s ADDR] [-f FILE] MTD_DEVICE" 39//usage: "[-o] [-b] [-s ADDR] [-f FILE] MTD_DEVICE"
40//usage:#define nanddump_full_usage "\n\n" 40//usage:#define nanddump_full_usage "\n\n"
41//usage: "Dump the specified MTD device\n" 41//usage: "Dump the specified MTD device\n"
42//usage: "\n -o Omit oob data" 42//usage: "\n -o Dump oob data"
43//usage: "\n -b Omit bad block from the dump" 43//usage: "\n -b Omit bad block from the dump"
44//usage: "\n -s ADDR Start address" 44//usage: "\n -s ADDR Start address"
45//usage: "\n -l LEN Length" 45//usage: "\n -l LEN Length"
@@ -162,9 +162,9 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
162 tmp = next_good_eraseblock(fd, &meminfo, blockstart); 162 tmp = next_good_eraseblock(fd, &meminfo, blockstart);
163 if (tmp != blockstart) { 163 if (tmp != blockstart) {
164 /* bad block(s), advance mtdoffset */ 164 /* bad block(s), advance mtdoffset */
165 if (IS_NANDDUMP & !(opts & OPT_b)) { 165 if (IS_NANDDUMP && !(opts & OPT_b)) {
166 int bad_len = MIN(tmp, end_addr) - mtdoffset; 166 int bad_len = MIN(tmp, end_addr) - mtdoffset;
167 dump_bad(&meminfo, bad_len, !(opts & OPT_o)); 167 dump_bad(&meminfo, bad_len, opts & OPT_o);
168 } 168 }
169 mtdoffset = tmp; 169 mtdoffset = tmp;
170 } 170 }
@@ -182,9 +182,9 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
182 mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart); 182 mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart);
183 if (IS_NANDWRITE) 183 if (IS_NANDWRITE)
184 printf("Writing at 0x%08x\n", mtdoffset); 184 printf("Writing at 0x%08x\n", mtdoffset);
185 else if (mtdoffset > blockstart) { 185 else if (mtdoffset > blockstart && !(opts & OPT_b)) {
186 int bad_len = MIN(mtdoffset, limit) - blockstart; 186 int bad_len = MIN(mtdoffset, limit) - blockstart;
187 dump_bad(&meminfo, bad_len, !(opts & OPT_o)); 187 dump_bad(&meminfo, bad_len, opts & OPT_o);
188 } 188 }
189 if (mtdoffset >= limit) 189 if (mtdoffset >= limit)
190 break; 190 break;
@@ -210,7 +210,7 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
210 } 210 }
211 xwrite(output_fd, filebuf, meminfo_writesize); 211 xwrite(output_fd, filebuf, meminfo_writesize);
212 212
213 if (IS_NANDDUMP && !(opts & OPT_o)) { 213 if (IS_NANDDUMP && (opts & OPT_o)) {
214 /* Dump OOB data */ 214 /* Dump OOB data */
215 oob.start = mtdoffset; 215 oob.start = mtdoffset;
216 xioctl(fd, MEMREADOOB, &oob); 216 xioctl(fd, MEMREADOOB, &oob);
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index ad0a9971b..818048284 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -49,9 +49,6 @@
49#include <fnmatch.h> 49#include <fnmatch.h>
50 50
51#define MAX_OPT_DEPTH 10 51#define MAX_OPT_DEPTH 10
52#define EUNBALBRACK 10001
53#define EUNDEFVAR 10002
54#define EUNBALPER 10000
55 52
56#if ENABLE_FEATURE_IFUPDOWN_MAPPING 53#if ENABLE_FEATURE_IFUPDOWN_MAPPING
57#define MAX_INTERFACE_LENGTH 10 54#define MAX_INTERFACE_LENGTH 10
@@ -233,7 +230,7 @@ static int count_netmask_bits(const char *dotted_quad)
233static char *parse(const char *command, struct interface_defn_t *ifd) 230static char *parse(const char *command, struct interface_defn_t *ifd)
234{ 231{
235 size_t old_pos[MAX_OPT_DEPTH] = { 0 }; 232 size_t old_pos[MAX_OPT_DEPTH] = { 0 };
236 int okay[MAX_OPT_DEPTH] = { 1 }; 233 smallint okay[MAX_OPT_DEPTH] = { 1 };
237 int opt_depth = 1; 234 int opt_depth = 1;
238 char *result = NULL; 235 char *result = NULL;
239 236
@@ -244,13 +241,10 @@ static char *parse(const char *command, struct interface_defn_t *ifd)
244 command++; 241 command++;
245 break; 242 break;
246 case '\\': 243 case '\\':
247 if (command[1]) { 244 if (command[1])
248 addstr(&result, command + 1, 1);
249 command += 2;
250 } else {
251 addstr(&result, command, 1);
252 command++; 245 command++;
253 } 246 addstr(&result, command, 1);
247 command++;
254 break; 248 break;
255 case '[': 249 case '[':
256 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) { 250 if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
@@ -259,7 +253,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd)
259 opt_depth++; 253 opt_depth++;
260 command += 2; 254 command += 2;
261 } else { 255 } else {
262 addstr(&result, "[", 1); 256 addstr(&result, command, 1);
263 command++; 257 command++;
264 } 258 }
265 break; 259 break;
@@ -271,7 +265,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd)
271 } 265 }
272 command += 2; 266 command += 2;
273 } else { 267 } else {
274 addstr(&result, "]", 1); 268 addstr(&result, command, 1);
275 command++; 269 command++;
276 } 270 }
277 break; 271 break;
@@ -283,7 +277,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd)
283 command++; 277 command++;
284 nextpercent = strchr(command, '%'); 278 nextpercent = strchr(command, '%');
285 if (!nextpercent) { 279 if (!nextpercent) {
286 errno = EUNBALPER; 280 /* Unterminated %var% */
287 free(result); 281 free(result);
288 return NULL; 282 return NULL;
289 } 283 }
@@ -328,13 +322,13 @@ static char *parse(const char *command, struct interface_defn_t *ifd)
328 } 322 }
329 323
330 if (opt_depth > 1) { 324 if (opt_depth > 1) {
331 errno = EUNBALBRACK; 325 /* Unbalanced bracket */
332 free(result); 326 free(result);
333 return NULL; 327 return NULL;
334 } 328 }
335 329
336 if (!okay[0]) { 330 if (!okay[0]) {
337 errno = EUNDEFVAR; 331 /* Undefined variable and we aren't in a bracket */
338 free(result); 332 free(result);
339 return NULL; 333 return NULL;
340 } 334 }
diff --git a/shell/ash.c b/shell/ash.c
index 5c33bb817..7a50e73f3 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -9101,6 +9101,8 @@ expredir(union node *n)
9101#if ENABLE_ASH_BASH_COMPAT 9101#if ENABLE_ASH_BASH_COMPAT
9102 store_expfname: 9102 store_expfname:
9103#endif 9103#endif
9104 if (redir->nfile.expfname)
9105 stunalloc(redir->nfile.expfname);
9104 redir->nfile.expfname = fn.list->text; 9106 redir->nfile.expfname = fn.list->text;
9105 break; 9107 break;
9106 case NFROMFD: 9108 case NFROMFD:
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/get_devname.c b/util-linux/volume_id/get_devname.c
index 230102d89..665cb9b6e 100644
--- a/util-linux/volume_id/get_devname.c
+++ b/util-linux/volume_id/get_devname.c
@@ -49,7 +49,11 @@ get_label_uuid(int fd, char **label, char **uuid, const char **type)
49 if (volume_id_probe_all(vid, /*0,*/ size) != 0) 49 if (volume_id_probe_all(vid, /*0,*/ size) != 0)
50 goto ret; 50 goto ret;
51 51
52 if (vid->label[0] != '\0' || vid->uuid[0] != '\0') { 52 if (vid->label[0] != '\0' || vid->uuid[0] != '\0'
53#if ENABLE_FEATURE_BLKID_TYPE
54 || vid->type != NULL
55#endif
56 ) {
53 *label = xstrndup(vid->label, sizeof(vid->label)); 57 *label = xstrndup(vid->label, sizeof(vid->label));
54 *uuid = xstrndup(vid->uuid, sizeof(vid->uuid)); 58 *uuid = xstrndup(vid->uuid, sizeof(vid->uuid));
55#if ENABLE_FEATURE_BLKID_TYPE 59#if ENABLE_FEATURE_BLKID_TYPE
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*/);