Android-x86
Fork
Donation

  • R/O
  • HTTP
  • SSH
  • HTTPS

external-exfat: Commit

external/exfat


Commit MetaInfo

Revisión49421bf5ddbb3d16000d858a0c576b65eb7a4e61 (tree)
Tiempo2017-03-23 23:52:59
AutorChih-Wei Huang <cwhuang@linu...>
CommiterChih-Wei Huang

Log Message

Merge branch 'master' of git://github.com/relan/exfat into marshmallow-x86

Cambiar Resumen

Diferencia

--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
1+1.2.6 (2017-01-28)
2+
3+* Operations with directories (except initial listing) now make less
4+read/write system calls.
5+* Fixed handling of files with optional tail entries (0xe0-0xff): videoclip
6+files created by Sony cameras were missing.
7+* Write operations now correctly return ENOSPC (instead of EIO) when there is
8+no free disk space left.
9+* Fixed max file name length: it's 255 16-bit code units (not 256).
10+
11+1.2.5 (2016-12-05)
12+
13+* Added an option for dumpexfat to show file fragments [Daniel Drake].
14+* Fixed crash when directory starts with an invalid cluster.
15+* Daylight saving time in now properly reflected in file timestamps.
16+
117 1.2.4 (2016-06-03)
218
319 * Fixed wrong files names hashes when upper case table is compressed.
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,7 @@
33 # Automake source.
44 #
55 # Free exFAT implementation.
6-# Copyright (C) 2010-2016 Andrew Nayenko
6+# Copyright (C) 2010-2017 Andrew Nayenko
77 #
88 # This program is free software; you can redistribute it and/or modify
99 # it under the terms of the GNU General Public License as published by
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@
33 # Autoconf source.
44 #
55 # Free exFAT implementation.
6-# Copyright (C) 2010-2016 Andrew Nayenko
6+# Copyright (C) 2010-2017 Andrew Nayenko
77 #
88 # This program is free software; you can redistribute it and/or modify
99 # it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
2121 #
2222
2323 AC_INIT([Free exFAT implementation],
24- [1.2.4],
24+ [1.2.6],
2525 [relan@users.noreply.github.com],
2626 [exfat],
2727 [https://github.com/relan/exfat])
--- a/dump/Makefile.am
+++ b/dump/Makefile.am
@@ -3,7 +3,7 @@
33 # Automake source.
44 #
55 # Free exFAT implementation.
6-# Copyright (C) 2011-2016 Andrew Nayenko
6+# Copyright (C) 2011-2017 Andrew Nayenko
77 #
88 # This program is free software; you can redistribute it and/or modify
99 # it under the terms of the GNU General Public License as published by
--- a/dump/dumpexfat.8
+++ b/dump/dumpexfat.8
@@ -13,6 +13,10 @@
1313 .B \-u
1414 ]
1515 [
16+.B \-f
17+.I file
18+]
19+[
1620 .B \-V
1721 ]
1822 .I device
@@ -33,6 +37,11 @@ systems.
3337 Dump ranges of used sectors starting from 0 and separated with spaces. May be
3438 useful for backup tools.
3539 .TP
40+.B \-f file
41+Print out a list of fragments that compose the given file. Each fragment is
42+printed on its own line, as the start offset (in bytes) into the file system,
43+and the length (in bytes).
44+.TP
3645 .BI \-V
3746 Print version and copyright.
3847
--- a/dump/main.c
+++ b/dump/main.c
@@ -3,7 +3,7 @@
33 Prints detailed information about exFAT volume.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -140,9 +140,66 @@ static int dump_full(const char* spec, bool used_sectors)
140140 return 0;
141141 }
142142
143+static int dump_file_fragments(const char* spec, const char* path)
144+{
145+ struct exfat ef;
146+ struct exfat_node* node;
147+ cluster_t cluster;
148+ cluster_t next_cluster;
149+ cluster_t fragment_start_cluster;
150+ off_t remainder;
151+ off_t fragment_size = 0;
152+ int rc = 0;
153+
154+ if (exfat_mount(&ef, spec, "ro") != 0)
155+ return 1;
156+
157+ rc = exfat_lookup(&ef, &node, path);
158+ if (rc != 0)
159+ {
160+ exfat_unmount(&ef);
161+ exfat_error("'%s': %s", path, strerror(-rc));
162+ return 1;
163+ }
164+
165+ cluster = fragment_start_cluster = node->start_cluster;
166+ remainder = node->size;
167+ while (remainder > 0)
168+ {
169+ off_t lsize;
170+
171+ if (CLUSTER_INVALID(cluster))
172+ {
173+ exfat_error("'%s' has invalid cluster %#x", path, cluster);
174+ rc = 1;
175+ break;
176+ }
177+
178+ lsize = MIN(CLUSTER_SIZE(*ef.sb), remainder);
179+ fragment_size += lsize;
180+ remainder -= lsize;
181+
182+ next_cluster = exfat_next_cluster(&ef, node, cluster);
183+ if (next_cluster != cluster + 1 || remainder == 0)
184+ {
185+ /* next cluster is not contiguous or this is EOF */
186+ printf("%"PRIu64" %"PRIu64"\n",
187+ exfat_c2o(&ef, fragment_start_cluster), fragment_size);
188+ /* start a new fragment */
189+ fragment_start_cluster = next_cluster;
190+ fragment_size = 0;
191+ }
192+ cluster = next_cluster;
193+ }
194+
195+ exfat_put_node(&ef, node);
196+ exfat_unmount(&ef);
197+ return rc;
198+}
199+
143200 static void usage(const char* prog)
144201 {
145- fprintf(stderr, "Usage: %s [-s] [-u] [-V] <device>\n", prog);
202+ fprintf(stderr, "Usage: %s [-s] [-u] [-f file] [-V] <device>\n", prog);
146203 exit(1);
147204 }
148205
@@ -152,10 +209,9 @@ int main(int argc, char* argv[])
152209 const char* spec = NULL;
153210 bool sb_only = false;
154211 bool used_sectors = false;
212+ const char* file_path = NULL;
155213
156- printf("dumpexfat %s\n", VERSION);
157-
158- while ((opt = getopt(argc, argv, "suV")) != -1)
214+ while ((opt = getopt(argc, argv, "suf:V")) != -1)
159215 {
160216 switch (opt)
161217 {
@@ -165,8 +221,12 @@ int main(int argc, char* argv[])
165221 case 'u':
166222 used_sectors = true;
167223 break;
224+ case 'f':
225+ file_path = optarg;
226+ break;
168227 case 'V':
169- puts("Copyright (C) 2011-2016 Andrew Nayenko");
228+ printf("dumpexfat %s\n", VERSION);
229+ puts("Copyright (C) 2011-2017 Andrew Nayenko");
170230 return 0;
171231 default:
172232 usage(argv[0]);
@@ -176,6 +236,9 @@ int main(int argc, char* argv[])
176236 usage(argv[0]);
177237 spec = argv[optind];
178238
239+ if (file_path)
240+ return dump_file_fragments(spec, file_path);
241+
179242 if (sb_only)
180243 return dump_sb(spec);
181244
--- a/fsck/Makefile.am
+++ b/fsck/Makefile.am
@@ -3,7 +3,7 @@
33 # Automake source.
44 #
55 # Free exFAT implementation.
6-# Copyright (C) 2011-2016 Andrew Nayenko
6+# Copyright (C) 2011-2017 Andrew Nayenko
77 #
88 # This program is free software; you can redistribute it and/or modify
99 # it under the terms of the GNU General Public License as published by
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -3,7 +3,7 @@
33 exFAT file system checker.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ uint64_t files_count, directories_count;
3333 static int nodeck(struct exfat* ef, struct exfat_node* node)
3434 {
3535 const cluster_t cluster_size = CLUSTER_SIZE(*ef->sb);
36- cluster_t clusters = (node->size + cluster_size - 1) / cluster_size;
36+ cluster_t clusters = DIV_ROUND_UP(node->size, cluster_size);
3737 cluster_t c = node->start_cluster;
3838 int rc = 0;
3939
@@ -41,18 +41,18 @@ static int nodeck(struct exfat* ef, struct exfat_node* node)
4141 {
4242 if (CLUSTER_INVALID(c))
4343 {
44- char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
44+ char name[EXFAT_UTF8_NAME_BUFFER_MAX];
4545
46- exfat_get_name(node, name, sizeof(name) - 1);
46+ exfat_get_name(node, name);
4747 exfat_error("file '%s' has invalid cluster 0x%x", name, c);
4848 rc = 1;
4949 break;
5050 }
5151 if (BMAP_GET(ef->cmap.chunk, c - EXFAT_FIRST_DATA_CLUSTER) == 0)
5252 {
53- char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
53+ char name[EXFAT_UTF8_NAME_BUFFER_MAX];
5454
55- exfat_get_name(node, name, sizeof(name) - 1);
55+ exfat_get_name(node, name);
5656 exfat_error("cluster 0x%x of file '%s' is not allocated", c, name);
5757 rc = 1;
5858 }
@@ -72,8 +72,8 @@ static void dirck(struct exfat* ef, const char* path)
7272
7373 if (exfat_lookup(ef, &parent, path) != 0)
7474 exfat_bug("directory '%s' is not found", path);
75- if (!(parent->flags & EXFAT_ATTRIB_DIR))
76- exfat_bug("'%s' is not a directory (0x%x)", path, parent->flags);
75+ if (!(parent->attrib & EXFAT_ATTRIB_DIR))
76+ exfat_bug("'%s' is not a directory (%#hx)", path, parent->attrib);
7777 if (nodeck(ef, parent) != 0)
7878 {
7979 exfat_put_node(ef, parent);
@@ -81,7 +81,7 @@ static void dirck(struct exfat* ef, const char* path)
8181 }
8282
8383 path_length = strlen(path);
84- entry_path = malloc(path_length + 1 + UTF8_BYTES(EXFAT_NAME_MAX) + 1);
84+ entry_path = malloc(path_length + 1 + EXFAT_UTF8_NAME_BUFFER_MAX);
8585 if (entry_path == NULL)
8686 {
8787 exfat_put_node(ef, parent);
@@ -100,12 +100,11 @@ static void dirck(struct exfat* ef, const char* path)
100100 }
101101 while ((node = exfat_readdir(ef, &it)))
102102 {
103- exfat_get_name(node, entry_path + path_length + 1,
104- UTF8_BYTES(EXFAT_NAME_MAX));
103+ exfat_get_name(node, entry_path + path_length + 1);
105104 exfat_debug("%s: %s, %"PRIu64" bytes, cluster %u", entry_path,
106- IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
105+ node->is_contiguous ? "contiguous" : "fragmented",
107106 node->size, node->start_cluster);
108- if (node->flags & EXFAT_ATTRIB_DIR)
107+ if (node->attrib & EXFAT_ATTRIB_DIR)
109108 {
110109 directories_count++;
111110 dirck(ef, entry_path);
@@ -147,7 +146,7 @@ int main(int argc, char* argv[])
147146 switch (opt)
148147 {
149148 case 'V':
150- puts("Copyright (C) 2011-2016 Andrew Nayenko");
149+ puts("Copyright (C) 2011-2017 Andrew Nayenko");
151150 return 0;
152151 default:
153152 usage(argv[0]);
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -3,7 +3,7 @@
33 # Automake source.
44 #
55 # Free exFAT implementation.
6-# Copyright (C) 2010-2016 Andrew Nayenko
6+# Copyright (C) 2010-2017 Andrew Nayenko
77 #
88 # This program is free software; you can redistribute it and/or modify
99 # it under the terms of the GNU General Public License as published by
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -3,7 +3,7 @@
33 FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -104,17 +104,17 @@ static int fuse_exfat_readdir(const char* path, void* buffer,
104104 struct exfat_node* node;
105105 struct exfat_iterator it;
106106 int rc;
107- char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
107+ char name[EXFAT_UTF8_NAME_BUFFER_MAX];
108108
109109 exfat_debug("[%s] %s", __func__, path);
110110
111111 rc = exfat_lookup(&ef, &parent, path);
112112 if (rc != 0)
113113 return rc;
114- if (!(parent->flags & EXFAT_ATTRIB_DIR))
114+ if (!(parent->attrib & EXFAT_ATTRIB_DIR))
115115 {
116116 exfat_put_node(&ef, parent);
117- exfat_error("'%s' is not a directory (0x%x)", path, parent->flags);
117+ exfat_error("'%s' is not a directory (%#hx)", path, parent->attrib);
118118 return -ENOTDIR;
119119 }
120120
@@ -130,9 +130,9 @@ static int fuse_exfat_readdir(const char* path, void* buffer,
130130 }
131131 while ((node = exfat_readdir(&ef, &it)))
132132 {
133- exfat_get_name(node, name, sizeof(name) - 1);
133+ exfat_get_name(node, name);
134134 exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
135- name, IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
135+ name, node->is_contiguous ? "contiguous" : "fragmented",
136136 node->size, node->start_cluster);
137137 filler(buffer, name, NULL, 0);
138138 exfat_put_node(&ef, node);
@@ -218,25 +218,15 @@ static int fuse_exfat_fsync(const char* path, int datasync,
218218 static int fuse_exfat_read(const char* path, char* buffer, size_t size,
219219 off_t offset, struct fuse_file_info* fi)
220220 {
221- ssize_t ret;
222-
223221 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
224- ret = exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
225- if (ret < 0)
226- return -EIO;
227- return ret;
222+ return exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
228223 }
229224
230225 static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
231226 off_t offset, struct fuse_file_info* fi)
232227 {
233- ssize_t ret;
234-
235228 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
236- ret = exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
237- if (ret < 0)
238- return -EIO;
239- return ret;
229+ return exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
240230 }
241231
242232 static int fuse_exfat_unlink(const char* path)
@@ -538,7 +528,7 @@ int main(int argc, char* argv[])
538528 break;
539529 case 'V':
540530 free(mount_options);
541- puts("Copyright (C) 2010-2016 Andrew Nayenko");
531+ puts("Copyright (C) 2010-2017 Andrew Nayenko");
542532 return 0;
543533 case 'v':
544534 break;
--- a/label/Makefile.am
+++ b/label/Makefile.am
@@ -3,7 +3,7 @@
33 # Automake source.
44 #
55 # Free exFAT implementation.
6-# Copyright (C) 2011-2016 Andrew Nayenko
6+# Copyright (C) 2011-2017 Andrew Nayenko
77 #
88 # This program is free software; you can redistribute it and/or modify
99 # it under the terms of the GNU General Public License as published by
--- a/label/main.c
+++ b/label/main.c
@@ -3,7 +3,7 @@
33 Prints or changes exFAT volume label.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@ int main(int argc, char* argv[])
3434 if (strcmp(*pp, "-V") == 0)
3535 {
3636 printf("exfatlabel %s\n", VERSION);
37- puts("Copyright (C) 2011-2016 Andrew Nayenko");
37+ puts("Copyright (C) 2011-2017 Andrew Nayenko");
3838 return 0;
3939 }
4040
--- a/libexfat/Makefile.am
+++ b/libexfat/Makefile.am
@@ -3,7 +3,7 @@
33 # Automake source.
44 #
55 # Free exFAT implementation.
6-# Copyright (C) 2010-2016 Andrew Nayenko
6+# Copyright (C) 2010-2017 Andrew Nayenko
77 #
88 # This program is free software; you can redistribute it and/or modify
99 # it under the terms of the GNU General Public License as published by
--- a/libexfat/byteorder.h
+++ b/libexfat/byteorder.h
@@ -3,7 +3,7 @@
33 Endianness stuff. exFAT uses little-endian byte order.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/libexfat/cluster.c
+++ b/libexfat/cluster.c
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -67,7 +67,7 @@ static cluster_t s2c(const struct exfat* ef, off_t sector)
6767 static uint32_t bytes2clusters(const struct exfat* ef, uint64_t bytes)
6868 {
6969 uint64_t cluster_size = CLUSTER_SIZE(*ef->sb);
70- return (bytes + cluster_size - 1) / cluster_size;
70+ return DIV_ROUND_UP(bytes, cluster_size);
7171 }
7272
7373 cluster_t exfat_next_cluster(const struct exfat* ef,
@@ -79,7 +79,7 @@ cluster_t exfat_next_cluster(const struct exfat* ef,
7979 if (cluster < EXFAT_FIRST_DATA_CLUSTER)
8080 exfat_bug("bad cluster 0x%x", cluster);
8181
82- if (IS_CONTIGUOUS(*node))
82+ if (node->is_contiguous)
8383 return cluster + 1;
8484 fat_offset = s2o(ef, le32_to_cpu(ef->sb->fat_sector_start))
8585 + cluster * sizeof(cluster_t);
@@ -270,7 +270,7 @@ static int grow_file(struct exfat* ef, struct exfat_node* node,
270270 node->fptr_cluster = node->start_cluster = previous;
271271 allocated = 1;
272272 /* file consists of only one cluster, so it's contiguous */
273- node->flags |= EXFAT_ATTRIB_CONTIGUOUS;
273+ node->is_contiguous = true;
274274 }
275275
276276 while (allocated < difference)
@@ -282,22 +282,22 @@ static int grow_file(struct exfat* ef, struct exfat_node* node,
282282 shrink_file(ef, node, current + allocated, allocated);
283283 return -ENOSPC;
284284 }
285- if (next != previous - 1 && IS_CONTIGUOUS(*node))
285+ if (next != previous - 1 && node->is_contiguous)
286286 {
287287 /* it's a pity, but we are not able to keep the file contiguous
288288 anymore */
289289 if (!make_noncontiguous(ef, node->start_cluster, previous))
290290 return -EIO;
291- node->flags &= ~EXFAT_ATTRIB_CONTIGUOUS;
292- node->flags |= EXFAT_ATTRIB_DIRTY;
291+ node->is_contiguous = false;
292+ node->is_dirty = true;
293293 }
294- if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), previous, next))
294+ if (!set_next_cluster(ef, node->is_contiguous, previous, next))
295295 return -EIO;
296296 previous = next;
297297 allocated++;
298298 }
299299
300- if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), previous,
300+ if (!set_next_cluster(ef, node->is_contiguous, previous,
301301 EXFAT_CLUSTER_END))
302302 return -EIO;
303303 return 0;
@@ -327,7 +327,7 @@ static int shrink_file(struct exfat* ef, struct exfat_node* node,
327327 return -EIO;
328328 }
329329 previous = exfat_next_cluster(ef, node, last);
330- if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), last,
330+ if (!set_next_cluster(ef, node->is_contiguous, last,
331331 EXFAT_CLUSTER_END))
332332 return -EIO;
333333 }
@@ -335,7 +335,7 @@ static int shrink_file(struct exfat* ef, struct exfat_node* node,
335335 {
336336 previous = node->start_cluster;
337337 node->start_cluster = EXFAT_CLUSTER_FREE;
338- node->flags |= EXFAT_ATTRIB_DIRTY;
338+ node->is_dirty = true;
339339 }
340340 node->fptr_index = 0;
341341 node->fptr_cluster = node->start_cluster;
@@ -350,7 +350,7 @@ static int shrink_file(struct exfat* ef, struct exfat_node* node,
350350 return -EIO;
351351 }
352352 next = exfat_next_cluster(ef, node, previous);
353- if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), previous,
353+ if (!set_next_cluster(ef, node->is_contiguous, previous,
354354 EXFAT_CLUSTER_FREE))
355355 return -EIO;
356356 free_cluster(ef, previous);
@@ -434,7 +434,7 @@ int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,
434434
435435 exfat_update_mtime(node);
436436 node->size = size;
437- node->flags |= EXFAT_ATTRIB_DIRTY;
437+ node->is_dirty = true;
438438 return 0;
439439 }
440440
--- a/libexfat/compiler.h
+++ b/libexfat/compiler.h
@@ -4,7 +4,7 @@
44 showstopper.
55
66 Free exFAT implementation.
7- Copyright (C) 2010-2016 Andrew Nayenko
7+ Copyright (C) 2010-2017 Andrew Nayenko
88
99 This program is free software; you can redistribute it and/or modify
1010 it under the terms of the GNU General Public License as published by
--- a/libexfat/exfat.h
+++ b/libexfat/exfat.h
@@ -4,7 +4,7 @@
44 implementation.
55
66 Free exFAT implementation.
7- Copyright (C) 2010-2016 Andrew Nayenko
7+ Copyright (C) 2010-2017 Andrew Nayenko
88
99 This program is free software; you can redistribute it and/or modify
1010 it under the terms of the GNU General Public License as published by
@@ -38,12 +38,13 @@
3838 #include <sys/stat.h>
3939 #include <sys/types.h>
4040
41-#define EXFAT_NAME_MAX 256
42-#define EXFAT_ATTRIB_CONTIGUOUS 0x10000
43-#define EXFAT_ATTRIB_CACHED 0x20000
44-#define EXFAT_ATTRIB_DIRTY 0x40000
45-#define EXFAT_ATTRIB_UNLINKED 0x80000
46-#define IS_CONTIGUOUS(node) (((node).flags & EXFAT_ATTRIB_CONTIGUOUS) != 0)
41+#define EXFAT_NAME_MAX 255
42+/* UTF-16 encodes code points up to U+FFFF as single 16-bit code units.
43+ UTF-8 uses up to 3 bytes (i.e. 8-bit code units) to encode code points
44+ up to U+FFFF. One additional character is for null terminator. */
45+#define EXFAT_UTF8_NAME_BUFFER_MAX (EXFAT_NAME_MAX * 3 + 1)
46+#define EXFAT_UTF8_ENAME_BUFFER_MAX (EXFAT_ENAME_MAX * 3 + 1)
47+
4748 #define SECTOR_SIZE(sb) (1 << (sb).sector_bits)
4849 #define CLUSTER_SIZE(sb) (SECTOR_SIZE(sb) << (sb).spc_bits)
4950 #define CLUSTER_INVALID(c) \
@@ -53,7 +54,6 @@
5354 #define MAX(a, b) ((a) > (b) ? (a) : (b))
5455 #define DIV_ROUND_UP(x, d) (((x) + (d) - 1) / (d))
5556 #define ROUND_UP(x, d) (DIV_ROUND_UP(x, d) * (d))
56-#define UTF8_BYTES(c) ((c) * 6) /* UTF-8 character can occupy up to 6 bytes */
5757
5858 #define BMAP_SIZE(count) (ROUND_UP(count, sizeof(bitmap_t) * 8) / 8)
5959 #define BMAP_BLOCK(index) ((index) / sizeof(bitmap_t) / 8)
@@ -79,10 +79,14 @@ struct exfat_node
7979 int references;
8080 uint32_t fptr_index;
8181 cluster_t fptr_cluster;
82- cluster_t entry_cluster;
8382 off_t entry_offset;
8483 cluster_t start_cluster;
85- int flags;
84+ uint16_t attrib;
85+ uint8_t continuations;
86+ bool is_contiguous : 1;
87+ bool is_cached : 1;
88+ bool is_dirty : 1;
89+ bool is_unlinked : 1;
8690 uint64_t size;
8791 time_t mtime, atime;
8892 le16_t name[EXFAT_NAME_MAX + 1];
@@ -112,7 +116,7 @@ struct exfat
112116 bool dirty;
113117 }
114118 cmap;
115- char label[UTF8_BYTES(EXFAT_ENAME_MAX) + 1];
119+ char label[EXFAT_UTF8_ENAME_BUFFER_MAX];
116120 void* zero_cluster;
117121 int dmask, fmask;
118122 uid_t uid;
@@ -181,14 +185,15 @@ int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b);
181185
182186 void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
183187 struct stat* stbuf);
184-void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n);
188+void exfat_get_name(const struct exfat_node* node,
189+ char buffer[EXFAT_UTF8_NAME_BUFFER_MAX]);
185190 uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry);
186191 uint16_t exfat_add_checksum(const void* entry, uint16_t sum);
187-le16_t exfat_calc_checksum(const struct exfat_entry_meta1* meta1,
188- const struct exfat_entry_meta2* meta2, const le16_t* name);
192+le16_t exfat_calc_checksum(const struct exfat_entry* entries, int n);
189193 uint32_t exfat_vbr_start_checksum(const void* sector, size_t size);
190194 uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum);
191-le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name);
195+le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name,
196+ size_t length);
192197 void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb);
193198 void exfat_print_info(const struct exfat_super_block* sb,
194199 uint32_t free_clusters);
--- a/libexfat/exfatfs.h
+++ b/libexfat/exfatfs.h
@@ -3,7 +3,7 @@
33 Definitions of structures and constants used in exFAT file system.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -78,6 +78,9 @@ STATIC_ASSERT(sizeof(struct exfat_super_block) == 512);
7878 #define EXFAT_ENTRY_FILE (0x05 | EXFAT_ENTRY_VALID)
7979 #define EXFAT_ENTRY_FILE_INFO (0x00 | EXFAT_ENTRY_VALID | EXFAT_ENTRY_CONTINUED)
8080 #define EXFAT_ENTRY_FILE_NAME (0x01 | EXFAT_ENTRY_VALID | EXFAT_ENTRY_CONTINUED)
81+#define EXFAT_ENTRY_FILE_TAIL (0x00 | EXFAT_ENTRY_VALID \
82+ | EXFAT_ENTRY_CONTINUED \
83+ | EXFAT_ENTRY_OPTIONAL)
8184
8285 struct exfat_entry /* common container for all entries */
8386 {
--- a/libexfat/io.c
+++ b/libexfat/io.c
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -304,7 +304,7 @@ ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
304304 if (CLUSTER_INVALID(cluster))
305305 {
306306 exfat_error("invalid cluster 0x%x while reading", cluster);
307- return -1;
307+ return -EIO;
308308 }
309309
310310 loffset = offset % CLUSTER_SIZE(*ef->sb);
@@ -314,21 +314,21 @@ ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
314314 if (CLUSTER_INVALID(cluster))
315315 {
316316 exfat_error("invalid cluster 0x%x while reading", cluster);
317- return -1;
317+ return -EIO;
318318 }
319319 lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
320320 if (exfat_pread(ef->dev, bufp, lsize,
321321 exfat_c2o(ef, cluster) + loffset) < 0)
322322 {
323323 exfat_error("failed to read cluster %#x", cluster);
324- return -1;
324+ return -EIO;
325325 }
326326 bufp += lsize;
327327 loffset = 0;
328328 remainder -= lsize;
329329 cluster = exfat_next_cluster(ef, node, cluster);
330330 }
331- if (!ef->ro && !ef->noatime)
331+ if (!(node->attrib & EXFAT_ATTRIB_DIR) && !ef->ro && !ef->noatime)
332332 exfat_update_atime(node);
333333 return MIN(size, node->size - offset) - remainder;
334334 }
@@ -336,16 +336,23 @@ ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
336336 ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
337337 const void* buffer, size_t size, off_t offset)
338338 {
339+ int rc;
339340 cluster_t cluster;
340341 const char* bufp = buffer;
341342 off_t lsize, loffset, remainder;
342343
343344 if (offset > node->size)
344- if (exfat_truncate(ef, node, offset, true) != 0)
345- return -1;
345+ {
346+ rc = exfat_truncate(ef, node, offset, true);
347+ if (rc != 0)
348+ return rc;
349+ }
346350 if (offset + size > node->size)
347- if (exfat_truncate(ef, node, offset + size, false) != 0)
348- return -1;
351+ {
352+ rc = exfat_truncate(ef, node, offset + size, false);
353+ if (rc != 0)
354+ return rc;
355+ }
349356 if (size == 0)
350357 return 0;
351358
@@ -353,7 +360,7 @@ ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
353360 if (CLUSTER_INVALID(cluster))
354361 {
355362 exfat_error("invalid cluster 0x%x while writing", cluster);
356- return -1;
363+ return -EIO;
357364 }
358365
359366 loffset = offset % CLUSTER_SIZE(*ef->sb);
@@ -363,20 +370,23 @@ ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
363370 if (CLUSTER_INVALID(cluster))
364371 {
365372 exfat_error("invalid cluster 0x%x while writing", cluster);
366- return -1;
373+ return -EIO;
367374 }
368375 lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder);
369376 if (exfat_pwrite(ef->dev, bufp, lsize,
370377 exfat_c2o(ef, cluster) + loffset) < 0)
371378 {
372379 exfat_error("failed to write cluster %#x", cluster);
373- return -1;
380+ return -EIO;
374381 }
375382 bufp += lsize;
376383 loffset = 0;
377384 remainder -= lsize;
378385 cluster = exfat_next_cluster(ef, node, cluster);
379386 }
380- exfat_update_mtime(node);
387+ if (!(node->attrib & EXFAT_ATTRIB_DIR))
388+ /* directory's mtime should be updated by the caller only when it
389+ creates or removes something in this directory */
390+ exfat_update_mtime(node);
381391 return size - remainder;
382392 }
--- a/libexfat/log.c
+++ b/libexfat/log.c
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/libexfat/lookup.c
+++ b/libexfat/lookup.c
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -87,7 +87,7 @@ static int lookup_name(struct exfat* ef, struct exfat_node* parent,
8787
8888 *node = NULL;
8989
90- rc = utf8_to_utf16(buffer, name, EXFAT_NAME_MAX, n);
90+ rc = utf8_to_utf16(buffer, name, EXFAT_NAME_MAX + 1, n);
9191 if (rc != 0)
9292 return rc;
9393
@@ -195,7 +195,7 @@ int exfat_split(struct exfat* ef, struct exfat_node** parent,
195195 exfat_put_node(ef, *parent);
196196 return -ENOENT;
197197 }
198- rc = utf8_to_utf16(name, p, EXFAT_NAME_MAX, n);
198+ rc = utf8_to_utf16(name, p, EXFAT_NAME_MAX + 1, n);
199199 if (rc != 0)
200200 {
201201 exfat_put_node(ef, *parent);
--- a/libexfat/mount.c
+++ b/libexfat/mount.c
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -287,7 +287,7 @@ int exfat_mount(struct exfat* ef, const char* spec, const char* options)
287287 return -ENOMEM;
288288 }
289289 memset(ef->root, 0, sizeof(struct exfat_node));
290- ef->root->flags = EXFAT_ATTRIB_DIR;
290+ ef->root->attrib = EXFAT_ATTRIB_DIR;
291291 ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
292292 ef->root->fptr_cluster = ef->root->start_cluster;
293293 ef->root->name[0] = cpu_to_le16('\0');
--- a/libexfat/node.c
+++ b/libexfat/node.c
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -26,14 +26,7 @@
2626 #include <string.h>
2727 #include <inttypes.h>
2828
29-/* on-disk nodes iterator */
30-struct iterator
31-{
32- cluster_t cluster;
33- off_t offset;
34- int contiguous;
35- char* chunk;
36-};
29+#define EXFAT_ENTRY_NONE (-1)
3730
3831 struct exfat_node* exfat_get_node(struct exfat_node* node)
3932 {
@@ -45,19 +38,19 @@ struct exfat_node* exfat_get_node(struct exfat_node* node)
4538
4639 void exfat_put_node(struct exfat* ef, struct exfat_node* node)
4740 {
48- char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
41+ char buffer[EXFAT_UTF8_NAME_BUFFER_MAX];
4942
5043 --node->references;
5144 if (node->references < 0)
5245 {
53- exfat_get_name(node, buffer, sizeof(buffer) - 1);
46+ exfat_get_name(node, buffer);
5447 exfat_bug("reference counter of '%s' is below zero", buffer);
5548 }
5649 else if (node->references == 0 && node != ef->root)
5750 {
58- if (node->flags & EXFAT_ATTRIB_DIRTY)
51+ if (node->is_dirty)
5952 {
60- exfat_get_name(node, buffer, sizeof(buffer) - 1);
53+ exfat_get_name(node, buffer);
6154 exfat_warn("dirty node '%s' with zero references", buffer);
6255 }
6356 }
@@ -75,7 +68,7 @@ int exfat_cleanup_node(struct exfat* ef, struct exfat_node* node)
7568 exfat_bug("unable to cleanup a node with %d references",
7669 node->references);
7770
78- if (node->flags & EXFAT_ATTRIB_UNLINKED)
71+ if (node->is_unlinked)
7972 {
8073 /* free all clusters and node structure itself */
8174 rc = exfat_truncate(ef, node, 0, true);
@@ -85,74 +78,44 @@ int exfat_cleanup_node(struct exfat* ef, struct exfat_node* node)
8578 return rc;
8679 }
8780
88-/**
89- * Cluster + offset from the beginning of the directory to absolute offset.
90- */
91-static off_t co2o(struct exfat* ef, cluster_t cluster, off_t offset)
81+static int read_entries(struct exfat* ef, struct exfat_node* dir,
82+ struct exfat_entry* entries, int n, off_t offset)
9283 {
93- return exfat_c2o(ef, cluster) + offset % CLUSTER_SIZE(*ef->sb);
94-}
95-
96-static int opendir(struct exfat* ef, const struct exfat_node* dir,
97- struct iterator* it)
98-{
99- if (!(dir->flags & EXFAT_ATTRIB_DIR))
100- exfat_bug("not a directory");
101- it->cluster = dir->start_cluster;
102- it->offset = 0;
103- it->contiguous = IS_CONTIGUOUS(*dir);
104- it->chunk = malloc(CLUSTER_SIZE(*ef->sb));
105- if (it->chunk == NULL)
106- {
107- exfat_error("out of memory");
108- return -ENOMEM;
109- }
110- if (exfat_pread(ef->dev, it->chunk, CLUSTER_SIZE(*ef->sb),
111- exfat_c2o(ef, it->cluster)) < 0)
112- {
113- exfat_error("failed to read directory cluster %#x", it->cluster);
84+ ssize_t size;
85+
86+ if (!(dir->attrib & EXFAT_ATTRIB_DIR))
87+ exfat_bug("attempted to read entries from a file");
88+
89+ size = exfat_generic_pread(ef, dir, entries,
90+ sizeof(struct exfat_entry[n]), offset);
91+ if (size == sizeof(struct exfat_entry[n]))
92+ return 0; /* success */
93+ if (size == 0)
94+ return -ENOENT;
95+ if (size < 0)
11496 return -EIO;
115- }
116- return 0;
97+ exfat_error("read %zd bytes instead of %zu bytes", size,
98+ sizeof(struct exfat_entry[n]));
99+ return -EIO;
117100 }
118101
119-static void closedir(struct iterator* it)
102+static int write_entries(struct exfat* ef, struct exfat_node* dir,
103+ const struct exfat_entry* entries, int n, off_t offset)
120104 {
121- it->cluster = 0;
122- it->offset = 0;
123- it->contiguous = 0;
124- free(it->chunk);
125- it->chunk = NULL;
126-}
105+ ssize_t size;
127106
128-static bool fetch_next_entry(struct exfat* ef, const struct exfat_node* parent,
129- struct iterator* it)
130-{
131- /* move iterator to the next entry in the directory */
132- it->offset += sizeof(struct exfat_entry);
133- /* fetch the next cluster if needed */
134- if ((it->offset & (CLUSTER_SIZE(*ef->sb) - 1)) == 0)
135- {
136- /* reached the end of directory; the caller should check this
137- condition too */
138- if (it->offset >= parent->size)
139- return true;
140- it->cluster = exfat_next_cluster(ef, parent, it->cluster);
141- if (CLUSTER_INVALID(it->cluster))
142- {
143- exfat_error("invalid cluster 0x%x while reading directory",
144- it->cluster);
145- return false;
146- }
147- if (exfat_pread(ef->dev, it->chunk, CLUSTER_SIZE(*ef->sb),
148- exfat_c2o(ef, it->cluster)) < 0)
149- {
150- exfat_error("failed to read the next directory cluster %#x",
151- it->cluster);
152- return false;
153- }
154- }
155- return true;
107+ if (!(dir->attrib & EXFAT_ATTRIB_DIR))
108+ exfat_bug("attempted to write entries into a file");
109+
110+ size = exfat_generic_pwrite(ef, dir, entries,
111+ sizeof(struct exfat_entry[n]), offset);
112+ if (size == sizeof(struct exfat_entry[n]))
113+ return 0; /* success */
114+ if (size < 0)
115+ return -EIO;
116+ exfat_error("wrote %zd bytes instead of %zu bytes", size,
117+ sizeof(struct exfat_entry[n]));
118+ return -EIO;
156119 }
157120
158121 static struct exfat_node* allocate_node(void)
@@ -170,7 +133,8 @@ static struct exfat_node* allocate_node(void)
170133 static void init_node_meta1(struct exfat_node* node,
171134 const struct exfat_entry_meta1* meta1)
172135 {
173- node->flags = le16_to_cpu(meta1->attrib);
136+ node->attrib = le16_to_cpu(meta1->attrib);
137+ node->continuations = meta1->continuations;
174138 node->mtime = exfat_exfat2unix(meta1->mdate, meta1->mtime,
175139 meta1->mtime_cs);
176140 /* there is no centiseconds field for atime */
@@ -183,32 +147,81 @@ static void init_node_meta2(struct exfat_node* node,
183147 node->size = le64_to_cpu(meta2->size);
184148 node->start_cluster = le32_to_cpu(meta2->start_cluster);
185149 node->fptr_cluster = node->start_cluster;
186- if (meta2->flags & EXFAT_FLAG_CONTIGUOUS)
187- node->flags |= EXFAT_ATTRIB_CONTIGUOUS;
150+ node->is_contiguous = ((meta2->flags & EXFAT_FLAG_CONTIGUOUS) != 0);
188151 }
189152
190-static const struct exfat_entry* get_entry_ptr(const struct exfat* ef,
191- const struct iterator* it)
153+static void init_node_name(struct exfat_node* node,
154+ const struct exfat_entry* entries, int n)
192155 {
193- return (const struct exfat_entry*)
194- (it->chunk + it->offset % CLUSTER_SIZE(*ef->sb));
156+ int i;
157+
158+ for (i = 0; i < n; i++)
159+ memcpy(node->name + i * EXFAT_ENAME_MAX,
160+ ((const struct exfat_entry_name*) &entries[i])->name,
161+ EXFAT_ENAME_MAX * sizeof(le16_t));
195162 }
196163
197-static bool check_node(const struct exfat_node* node, uint16_t actual_checksum,
198- uint16_t reference_checksum, uint64_t valid_size)
164+static bool check_entries(const struct exfat_entry* entry, int n)
199165 {
200- char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
166+ int previous = EXFAT_ENTRY_NONE;
167+ int current;
168+ int i;
169+
170+ /* check transitions between entries types */
171+ for (i = 0; i < n + 1; previous = current, i++)
172+ {
173+ bool valid = false;
174+
175+ current = (i < n) ? entry[i].type : EXFAT_ENTRY_NONE;
176+ switch (previous)
177+ {
178+ case EXFAT_ENTRY_NONE:
179+ valid = (current == EXFAT_ENTRY_FILE);
180+ break;
181+ case EXFAT_ENTRY_FILE:
182+ valid = (current == EXFAT_ENTRY_FILE_INFO);
183+ break;
184+ case EXFAT_ENTRY_FILE_INFO:
185+ valid = (current == EXFAT_ENTRY_FILE_NAME);
186+ break;
187+ case EXFAT_ENTRY_FILE_NAME:
188+ valid = (current == EXFAT_ENTRY_FILE_NAME ||
189+ current == EXFAT_ENTRY_NONE ||
190+ current >= EXFAT_ENTRY_FILE_TAIL);
191+ break;
192+ case EXFAT_ENTRY_FILE_TAIL ... 0xff:
193+ valid = (current >= EXFAT_ENTRY_FILE_TAIL ||
194+ current == EXFAT_ENTRY_NONE);
195+ break;
196+ }
197+
198+ if (!valid)
199+ {
200+ exfat_error("unexpected entry type %#x after %#x at %d/%d",
201+ current, previous, i, n);
202+ return false;
203+ }
204+ }
205+ return true;
206+}
207+
208+static bool check_node(const struct exfat_node* node, le16_t actual_checksum,
209+ int cluster_size, const struct exfat_entry_meta1* meta1,
210+ const struct exfat_entry_meta2* meta2)
211+{
212+ char buffer[EXFAT_UTF8_NAME_BUFFER_MAX];
213+ bool ret = true;
201214
202215 /*
203216 Validate checksum first. If it's invalid all other fields probably
204217 contain just garbage.
205218 */
206- if (actual_checksum != reference_checksum)
219+ if (le16_to_cpu(actual_checksum) != le16_to_cpu(meta1->checksum))
207220 {
208- exfat_get_name(node, buffer, sizeof(buffer) - 1);
221+ exfat_get_name(node, buffer);
209222 exfat_error("'%s' has invalid checksum (%#hx != %#hx)", buffer,
210- actual_checksum, reference_checksum);
211- return false;
223+ le16_to_cpu(actual_checksum), le16_to_cpu(meta1->checksum));
224+ ret = false;
212225 }
213226
214227 /*
@@ -217,15 +230,123 @@ static bool check_node(const struct exfat_node* node, uint16_t actual_checksum,
217230 cannot be greater than file size. See SetFileValidData() function
218231 description in MSDN.
219232 */
220- if (valid_size > node->size)
233+ if (le64_to_cpu(meta2->valid_size) > node->size)
221234 {
222- exfat_get_name(node, buffer, sizeof(buffer) - 1);
235+ exfat_get_name(node, buffer);
223236 exfat_error("'%s' has valid size (%"PRIu64") greater than size "
224- "(%"PRIu64")", buffer, valid_size, node->size);
225- return false;
237+ "(%"PRIu64")", buffer, le64_to_cpu(meta2->valid_size),
238+ node->size);
239+ ret = false;
226240 }
227241
228- return true;
242+ /*
243+ Empty file must have zero start cluster. Non-empty file must start
244+ with a valid cluster. Directories cannot be empty (i.e. must always
245+ have a valid start cluster), but we will check this later while
246+ reading that directory to give user a chance to read this directory.
247+ */
248+ if (node->size == 0 && node->start_cluster != EXFAT_CLUSTER_FREE)
249+ {
250+ exfat_get_name(node, buffer);
251+ exfat_error("'%s' is empty but start cluster is %#x", buffer,
252+ node->start_cluster);
253+ ret = false;
254+ }
255+ if (node->size > 0 && CLUSTER_INVALID(node->start_cluster))
256+ {
257+ exfat_get_name(node, buffer);
258+ exfat_error("'%s' points to invalid cluster %#x", buffer,
259+ node->start_cluster);
260+ ret = false;
261+ }
262+
263+ /* Empty file or directory must be marked as non-contiguous. */
264+ if (node->size == 0 && node->is_contiguous)
265+ {
266+ exfat_get_name(node, buffer);
267+ exfat_error("'%s' is empty but marked as contiguous (%#hx)", buffer,
268+ node->attrib);
269+ ret = false;
270+ }
271+
272+ /* Directory size must be aligned on at cluster boundary. */
273+ if ((node->attrib & EXFAT_ATTRIB_DIR) && node->size % cluster_size != 0)
274+ {
275+ exfat_get_name(node, buffer);
276+ exfat_error("'%s' directory size %"PRIu64" is not divisible by %d", buffer,
277+ node->size, cluster_size);
278+ ret = false;
279+ }
280+
281+ return ret;
282+}
283+
284+static int parse_file_entries(struct exfat* ef, struct exfat_node* parent,
285+ struct exfat_node* node, const struct exfat_entry* entries, int n)
286+{
287+ const struct exfat_entry_meta1* meta1;
288+ const struct exfat_entry_meta2* meta2;
289+ int mandatory_entries;
290+
291+ if (!check_entries(entries, n))
292+ return -EIO;
293+
294+ meta1 = (const struct exfat_entry_meta1*) &entries[0];
295+ if (meta1->continuations < 2)
296+ {
297+ exfat_error("too few continuations (%hhu)", meta1->continuations);
298+ return -EIO;
299+ }
300+ meta2 = (const struct exfat_entry_meta2*) &entries[1];
301+ if (meta2->flags & ~(EXFAT_FLAG_ALWAYS1 | EXFAT_FLAG_CONTIGUOUS))
302+ {
303+ exfat_error("unknown flags in meta2 (%#hhx)", meta2->flags);
304+ return -EIO;
305+ }
306+ mandatory_entries = 2 + DIV_ROUND_UP(meta2->name_length, EXFAT_ENAME_MAX);
307+ if (meta1->continuations < mandatory_entries - 1)
308+ {
309+ exfat_error("too few continuations (%hhu < %d)",
310+ meta1->continuations, mandatory_entries - 1);
311+ return -EIO;
312+ }
313+
314+ init_node_meta1(node, meta1);
315+ init_node_meta2(node, meta2);
316+ init_node_name(node, entries + 2, mandatory_entries - 2);
317+
318+ if (!check_node(node, exfat_calc_checksum(entries, n),
319+ CLUSTER_SIZE(*ef->sb), meta1, meta2))
320+ return -EIO;
321+
322+ return 0;
323+}
324+
325+static int parse_file_entry(struct exfat* ef, struct exfat_node* parent,
326+ struct exfat_node** node, off_t* offset, int n)
327+{
328+ struct exfat_entry entries[n];
329+ int rc;
330+
331+ rc = read_entries(ef, parent, entries, n, *offset);
332+ if (rc != 0)
333+ return rc;
334+
335+ /* a new node has zero references */
336+ *node = allocate_node();
337+ if (*node == NULL)
338+ return -ENOMEM;
339+ (*node)->entry_offset = *offset;
340+
341+ rc = parse_file_entries(ef, parent, *node, entries, n);
342+ if (rc != 0)
343+ {
344+ free(*node);
345+ return rc;
346+ }
347+
348+ *offset += sizeof(struct exfat_entry[n]);
349+ return 0;
229350 }
230351
231352 static void decompress_upcase(uint16_t* output, const le16_t* source,
@@ -249,150 +370,43 @@ static void decompress_upcase(uint16_t* output, const le16_t* source,
249370 }
250371
251372 /*
252- * Reads one entry in directory at position pointed by iterator and fills
253- * node structure.
373+ * Read one entry in a directory at offset position and build a new node
374+ * structure.
254375 */
255-static int readdir(struct exfat* ef, const struct exfat_node* parent,
256- struct exfat_node** node, struct iterator* it)
376+static int readdir(struct exfat* ef, struct exfat_node* parent,
377+ struct exfat_node** node, off_t* offset)
257378 {
258- int rc = -EIO;
259- const struct exfat_entry* entry;
379+ int rc;
380+ struct exfat_entry entry;
260381 const struct exfat_entry_meta1* meta1;
261- const struct exfat_entry_meta2* meta2;
262- const struct exfat_entry_name* file_name;
263382 const struct exfat_entry_upcase* upcase;
264383 const struct exfat_entry_bitmap* bitmap;
265384 const struct exfat_entry_label* label;
266- uint8_t continuations = 0;
267- le16_t* namep = NULL;
268- uint16_t reference_checksum = 0;
269- uint16_t actual_checksum = 0;
270- uint64_t valid_size = 0;
271385 uint64_t upcase_size = 0;
272386 le16_t* upcase_comp = NULL;
273387
274- *node = NULL;
275-
276388 for (;;)
277389 {
278- if (it->offset >= parent->size)
279- {
280- if (continuations != 0)
281- {
282- exfat_error("expected %hhu continuations", continuations);
283- goto error;
284- }
285- return -ENOENT; /* that's OK, means end of directory */
286- }
390+ rc = read_entries(ef, parent, &entry, 1, *offset);
391+ if (rc != 0)
392+ return rc;
287393
288- entry = get_entry_ptr(ef, it);
289- switch (entry->type)
394+ switch (entry.type)
290395 {
291396 case EXFAT_ENTRY_FILE:
292- if (continuations != 0)
293- {
294- exfat_error("expected %hhu continuations before new entry",
295- continuations);
296- goto error;
297- }
298- meta1 = (const struct exfat_entry_meta1*) entry;
299- continuations = meta1->continuations;
300- /* each file entry must have at least 2 continuations:
301- info and name */
302- if (continuations < 2)
303- {
304- exfat_error("too few continuations (%hhu)", continuations);
305- goto error;
306- }
307- if (continuations > 1 +
308- DIV_ROUND_UP(EXFAT_NAME_MAX, EXFAT_ENAME_MAX))
309- {
310- exfat_error("too many continuations (%hhu)", continuations);
311- goto error;
312- }
313- reference_checksum = le16_to_cpu(meta1->checksum);
314- actual_checksum = exfat_start_checksum(meta1);
315- *node = allocate_node();
316- if (*node == NULL)
317- {
318- rc = -ENOMEM;
319- goto error;
320- }
321- /* new node has zero reference counter */
322- (*node)->entry_cluster = it->cluster;
323- (*node)->entry_offset = it->offset;
324- init_node_meta1(*node, meta1);
325- namep = (*node)->name;
326- break;
327-
328- case EXFAT_ENTRY_FILE_INFO:
329- if (continuations < 2)
330- {
331- exfat_error("unexpected continuation (%hhu)",
332- continuations);
333- goto error;
334- }
335- meta2 = (const struct exfat_entry_meta2*) entry;
336- if (meta2->flags & ~(EXFAT_FLAG_ALWAYS1 | EXFAT_FLAG_CONTIGUOUS))
337- {
338- exfat_error("unknown flags in meta2 (0x%hhx)", meta2->flags);
339- goto error;
340- }
341- init_node_meta2(*node, meta2);
342- actual_checksum = exfat_add_checksum(entry, actual_checksum);
343- valid_size = le64_to_cpu(meta2->valid_size);
344- /* empty files must be marked as non-contiguous */
345- if ((*node)->size == 0 && (meta2->flags & EXFAT_FLAG_CONTIGUOUS))
346- {
347- exfat_error("empty file marked as contiguous (0x%hhx)",
348- meta2->flags);
349- goto error;
350- }
351- /* directories must be aligned on at cluster boundary */
352- if (((*node)->flags & EXFAT_ATTRIB_DIR) &&
353- (*node)->size % CLUSTER_SIZE(*ef->sb) != 0)
354- {
355- exfat_error("directory has invalid size %"PRIu64" bytes",
356- (*node)->size);
357- goto error;
358- }
359- --continuations;
360- break;
361-
362- case EXFAT_ENTRY_FILE_NAME:
363- if (continuations == 0)
364- {
365- exfat_error("unexpected continuation");
366- goto error;
367- }
368- file_name = (const struct exfat_entry_name*) entry;
369- actual_checksum = exfat_add_checksum(entry, actual_checksum);
370-
371- memcpy(namep, file_name->name,
372- MIN(EXFAT_ENAME_MAX,
373- ((*node)->name + EXFAT_NAME_MAX - namep)) *
374- sizeof(le16_t));
375- namep += EXFAT_ENAME_MAX;
376- if (--continuations == 0)
377- {
378- if (!check_node(*node, actual_checksum, reference_checksum,
379- valid_size))
380- goto error;
381- if (!fetch_next_entry(ef, parent, it))
382- goto error;
383- return 0; /* entry completed */
384- }
385- break;
397+ meta1 = (const struct exfat_entry_meta1*) &entry;
398+ return parse_file_entry(ef, parent, node, offset,
399+ 1 + meta1->continuations);
386400
387401 case EXFAT_ENTRY_UPCASE:
388402 if (ef->upcase != NULL)
389403 break;
390- upcase = (const struct exfat_entry_upcase*) entry;
404+ upcase = (const struct exfat_entry_upcase*) &entry;
391405 if (CLUSTER_INVALID(le32_to_cpu(upcase->start_cluster)))
392406 {
393407 exfat_error("invalid cluster 0x%x in upcase table",
394408 le32_to_cpu(upcase->start_cluster));
395- goto error;
409+ return -EIO;
396410 }
397411 upcase_size = le64_to_cpu(upcase->size);
398412 if (upcase_size == 0 ||
@@ -401,15 +415,14 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
401415 {
402416 exfat_error("bad upcase table size (%"PRIu64" bytes)",
403417 upcase_size);
404- goto error;
418+ return -EIO;
405419 }
406420 upcase_comp = malloc(upcase_size);
407421 if (upcase_comp == NULL)
408422 {
409423 exfat_error("failed to allocate upcase table (%"PRIu64" bytes)",
410424 upcase_size);
411- rc = -ENOMEM;
412- goto error;
425+ return -ENOMEM;
413426 }
414427
415428 /* read compressed upcase table */
@@ -421,7 +434,7 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
421434 "(%"PRIu64" bytes starting at cluster %#x)",
422435 upcase_size,
423436 le32_to_cpu(upcase->start_cluster));
424- goto error;
437+ return -EIO;
425438 }
426439
427440 /* decompress upcase table */
@@ -430,8 +443,7 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
430443 {
431444 free(upcase_comp);
432445 exfat_error("failed to allocate decompressed upcase table");
433- rc = -ENOMEM;
434- goto error;
446+ return -ENOMEM;
435447 }
436448 decompress_upcase(ef->upcase, upcase_comp,
437449 upcase_size / sizeof(uint16_t));
@@ -439,13 +451,13 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
439451 break;
440452
441453 case EXFAT_ENTRY_BITMAP:
442- bitmap = (const struct exfat_entry_bitmap*) entry;
454+ bitmap = (const struct exfat_entry_bitmap*) &entry;
443455 ef->cmap.start_cluster = le32_to_cpu(bitmap->start_cluster);
444456 if (CLUSTER_INVALID(ef->cmap.start_cluster))
445457 {
446458 exfat_error("invalid cluster 0x%x in clusters bitmap",
447459 ef->cmap.start_cluster);
448- goto error;
460+ return -EIO;
449461 }
450462 ef->cmap.size = le32_to_cpu(ef->sb->cluster_count) -
451463 EXFAT_FIRST_DATA_CLUSTER;
@@ -455,7 +467,7 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
455467 " (expected at least %u)",
456468 le64_to_cpu(bitmap->size),
457469 DIV_ROUND_UP(ef->cmap.size, 8));
458- goto error;
470+ return -EIO;
459471 }
460472 /* FIXME bitmap can be rather big, up to 512 MB */
461473 ef->cmap.chunk_size = ef->cmap.size;
@@ -464,8 +476,7 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
464476 {
465477 exfat_error("failed to allocate clusters bitmap chunk "
466478 "(%"PRIu64" bytes)", le64_to_cpu(bitmap->size));
467- rc = -ENOMEM;
468- goto error;
479+ return -ENOMEM;
469480 }
470481
471482 if (exfat_pread(ef->dev, ef->cmap.chunk,
@@ -475,66 +486,45 @@ static int readdir(struct exfat* ef, const struct exfat_node* parent,
475486 exfat_error("failed to read clusters bitmap "
476487 "(%"PRIu64" bytes starting at cluster %#x)",
477488 le64_to_cpu(bitmap->size), ef->cmap.start_cluster);
478- goto error;
489+ return -EIO;
479490 }
480491 break;
481492
482493 case EXFAT_ENTRY_LABEL:
483- label = (const struct exfat_entry_label*) entry;
494+ label = (const struct exfat_entry_label*) &entry;
484495 if (label->length > EXFAT_ENAME_MAX)
485496 {
486497 exfat_error("too long label (%hhu chars)", label->length);
487- goto error;
498+ return -EIO;
488499 }
489500 if (utf16_to_utf8(ef->label, label->name,
490- sizeof(ef->label) - 1, EXFAT_ENAME_MAX) != 0)
491- goto error;
501+ sizeof(ef->label), EXFAT_ENAME_MAX) != 0)
502+ return -EIO;
492503 break;
493504
494505 default:
495- if (!(entry->type & EXFAT_ENTRY_VALID))
506+ if (!(entry.type & EXFAT_ENTRY_VALID))
496507 break; /* deleted entry, ignore it */
497- if (!(entry->type & EXFAT_ENTRY_OPTIONAL))
498- {
499- exfat_error("unknown entry type %#hhx", entry->type);
500- goto error;
501- }
502- /* optional entry, warn and skip */
503- exfat_warn("unknown entry type %#hhx", entry->type);
504- if (continuations == 0)
505- {
506- exfat_error("unexpected continuation");
507- goto error;
508- }
509- --continuations;
510- break;
511- }
512508
513- if (!fetch_next_entry(ef, parent, it))
514- goto error;
509+ exfat_error("unknown entry type %#hhx", entry.type);
510+ return -EIO;
511+ }
512+ *offset += sizeof(entry);
515513 }
516514 /* we never reach here */
517-
518-error:
519- free(*node);
520- *node = NULL;
521- return rc;
522515 }
523516
524517 int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir)
525518 {
526- struct iterator it;
519+ off_t offset = 0;
527520 int rc;
528521 struct exfat_node* node;
529522 struct exfat_node* current = NULL;
530523
531- if (dir->flags & EXFAT_ATTRIB_CACHED)
524+ if (dir->is_cached)
532525 return 0; /* already cached */
533526
534- rc = opendir(ef, dir, &it);
535- if (rc != 0)
536- return rc;
537- while ((rc = readdir(ef, dir, &node, &it)) == 0)
527+ while ((rc = readdir(ef, dir, &node, &offset)) == 0)
538528 {
539529 node->parent = dir;
540530 if (current != NULL)
@@ -547,7 +537,6 @@ int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir)
547537
548538 current = node;
549539 }
550- closedir(&it);
551540
552541 if (rc != -ENOENT)
553542 {
@@ -561,7 +550,7 @@ int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir)
561550 return rc;
562551 }
563552
564- dir->flags |= EXFAT_ATTRIB_CACHED;
553+ dir->is_cached = true;
565554 return 0;
566555 }
567556
@@ -591,7 +580,7 @@ static void tree_detach(struct exfat_node* node)
591580
592581 static void reset_cache(struct exfat* ef, struct exfat_node* node)
593582 {
594- char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
583+ char buffer[EXFAT_UTF8_NAME_BUFFER_MAX];
595584
596585 while (node->child)
597586 {
@@ -600,16 +589,16 @@ static void reset_cache(struct exfat* ef, struct exfat_node* node)
600589 tree_detach(p);
601590 free(p);
602591 }
603- node->flags &= ~EXFAT_ATTRIB_CACHED;
592+ node->is_cached = false;
604593 if (node->references != 0)
605594 {
606- exfat_get_name(node, buffer, sizeof(buffer) - 1);
595+ exfat_get_name(node, buffer);
607596 exfat_warn("non-zero reference counter (%d) for '%s'",
608597 node->references, buffer);
609598 }
610- if (node != ef->root && (node->flags & EXFAT_ATTRIB_DIRTY))
599+ if (node != ef->root && node->is_dirty)
611600 {
612- exfat_get_name(node, buffer, sizeof(buffer) - 1);
601+ exfat_get_name(node, buffer);
613602 exfat_bug("node '%s' is dirty", buffer);
614603 }
615604 while (node->references)
@@ -621,32 +610,14 @@ void exfat_reset_cache(struct exfat* ef)
621610 reset_cache(ef, ef->root);
622611 }
623612
624-static bool next_entry(struct exfat* ef, const struct exfat_node* parent,
625- cluster_t* cluster, off_t* offset)
626-{
627- *offset += sizeof(struct exfat_entry);
628- if (*offset % CLUSTER_SIZE(*ef->sb) == 0)
629- {
630- *cluster = exfat_next_cluster(ef, parent, *cluster);
631- if (CLUSTER_INVALID(*cluster))
632- {
633- exfat_error("invalid cluster %#x while getting next entry",
634- *cluster);
635- return false;
636- }
637- }
638- return true;
639-}
640-
641613 int exfat_flush_node(struct exfat* ef, struct exfat_node* node)
642614 {
643- cluster_t cluster;
644- off_t offset;
645- off_t meta1_offset, meta2_offset;
646- struct exfat_entry_meta1 meta1;
647- struct exfat_entry_meta2 meta2;
615+ struct exfat_entry entries[1 + node->continuations];
616+ struct exfat_entry_meta1* meta1 = (struct exfat_entry_meta1*) &entries[0];
617+ struct exfat_entry_meta2* meta2 = (struct exfat_entry_meta2*) &entries[1];
618+ int rc;
648619
649- if (!(node->flags & EXFAT_ATTRIB_DIRTY))
620+ if (!node->is_dirty)
650621 return 0; /* no need to flush */
651622
652623 if (ef->ro)
@@ -655,92 +626,65 @@ int exfat_flush_node(struct exfat* ef, struct exfat_node* node)
655626 if (node->parent == NULL)
656627 return 0; /* do not flush unlinked node */
657628
658- cluster = node->entry_cluster;
659- offset = node->entry_offset;
660- meta1_offset = co2o(ef, cluster, offset);
661- if (!next_entry(ef, node->parent, &cluster, &offset))
662- return -EIO;
663- meta2_offset = co2o(ef, cluster, offset);
664-
665- if (exfat_pread(ef->dev, &meta1, sizeof(meta1), meta1_offset) < 0)
666- {
667- exfat_error("failed to read meta1 entry on flush");
629+ rc = read_entries(ef, node->parent, entries, 1 + node->continuations,
630+ node->entry_offset);
631+ if (rc != 0)
632+ return rc;
633+ if (!check_entries(entries, 1 + node->continuations))
668634 return -EIO;
669- }
670- if (meta1.type != EXFAT_ENTRY_FILE)
671- exfat_bug("invalid type of meta1: 0x%hhx", meta1.type);
672- meta1.attrib = cpu_to_le16(node->flags);
673- exfat_unix2exfat(node->mtime, &meta1.mdate, &meta1.mtime, &meta1.mtime_cs);
674- exfat_unix2exfat(node->atime, &meta1.adate, &meta1.atime, NULL);
675635
676- if (exfat_pread(ef->dev, &meta2, sizeof(meta2), meta2_offset) < 0)
677- {
678- exfat_error("failed to read meta2 entry on flush");
679- return -EIO;
680- }
681- if (meta2.type != EXFAT_ENTRY_FILE_INFO)
682- exfat_bug("invalid type of meta2: 0x%hhx", meta2.type);
683- meta2.size = meta2.valid_size = cpu_to_le64(node->size);
684- meta2.start_cluster = cpu_to_le32(node->start_cluster);
685- meta2.flags = EXFAT_FLAG_ALWAYS1;
636+ meta1->attrib = cpu_to_le16(node->attrib);
637+ exfat_unix2exfat(node->mtime, &meta1->mdate, &meta1->mtime,
638+ &meta1->mtime_cs);
639+ exfat_unix2exfat(node->atime, &meta1->adate, &meta1->atime, NULL);
640+ meta2->size = meta2->valid_size = cpu_to_le64(node->size);
641+ meta2->start_cluster = cpu_to_le32(node->start_cluster);
642+ meta2->flags = EXFAT_FLAG_ALWAYS1;
686643 /* empty files must not be marked as contiguous */
687- if (node->size != 0 && IS_CONTIGUOUS(*node))
688- meta2.flags |= EXFAT_FLAG_CONTIGUOUS;
644+ if (node->size != 0 && node->is_contiguous)
645+ meta2->flags |= EXFAT_FLAG_CONTIGUOUS;
689646 /* name hash remains unchanged, no need to recalculate it */
690647
691- meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name);
692-
693- if (exfat_pwrite(ef->dev, &meta1, sizeof(meta1), meta1_offset) < 0)
694- {
695- exfat_error("failed to write meta1 entry on flush");
696- return -EIO;
697- }
698- if (exfat_pwrite(ef->dev, &meta2, sizeof(meta2), meta2_offset) < 0)
699- {
700- exfat_error("failed to write meta2 entry on flush");
701- return -EIO;
702- }
648+ meta1->checksum = exfat_calc_checksum(entries, 1 + node->continuations);
649+ rc = write_entries(ef, node->parent, entries, 1 + node->continuations,
650+ node->entry_offset);
651+ if (rc != 0)
652+ return rc;
703653
704- node->flags &= ~EXFAT_ATTRIB_DIRTY;
654+ node->is_dirty = false;
705655 return exfat_flush(ef);
706656 }
707657
708-static bool erase_entry(struct exfat* ef, struct exfat_node* node)
658+static int erase_entries(struct exfat* ef, struct exfat_node* dir, int n,
659+ off_t offset)
709660 {
710- cluster_t cluster = node->entry_cluster;
711- off_t offset = node->entry_offset;
712- int name_entries = DIV_ROUND_UP(utf16_length(node->name), EXFAT_ENAME_MAX);
713- uint8_t entry_type;
661+ struct exfat_entry entries[n];
662+ int rc;
663+ int i;
714664
715- entry_type = EXFAT_ENTRY_FILE & ~EXFAT_ENTRY_VALID;
716- if (exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset)) < 0)
717- {
718- exfat_error("failed to erase meta1 entry");
719- return false;
720- }
665+ rc = read_entries(ef, dir, entries, n, offset);
666+ if (rc != 0)
667+ return rc;
668+ for (i = 0; i < n; i++)
669+ entries[i].type &= ~EXFAT_ENTRY_VALID;
670+ return write_entries(ef, dir, entries, n, offset);
671+}
721672
722- if (!next_entry(ef, node->parent, &cluster, &offset))
723- return false;
724- entry_type = EXFAT_ENTRY_FILE_INFO & ~EXFAT_ENTRY_VALID;
725- if (exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset)) < 0)
726- {
727- exfat_error("failed to erase meta2 entry");
728- return false;
729- }
673+static int erase_node(struct exfat* ef, struct exfat_node* node)
674+{
675+ int rc;
730676
731- while (name_entries--)
677+ exfat_get_node(node->parent);
678+ rc = erase_entries(ef, node->parent, 1 + node->continuations,
679+ node->entry_offset);
680+ if (rc != 0)
732681 {
733- if (!next_entry(ef, node->parent, &cluster, &offset))
734- return false;
735- entry_type = EXFAT_ENTRY_FILE_NAME & ~EXFAT_ENTRY_VALID;
736- if (exfat_pwrite(ef->dev, &entry_type, 1,
737- co2o(ef, cluster, offset)) < 0)
738- {
739- exfat_error("failed to erase name entry");
740- return false;
741- }
682+ exfat_put_node(ef, node->parent);
683+ return rc;
742684 }
743- return true;
685+ rc = exfat_flush_node(ef, node->parent);
686+ exfat_put_node(ef, node->parent);
687+ return rc;
744688 }
745689
746690 static int shrink_directory(struct exfat* ef, struct exfat_node* dir,
@@ -751,9 +695,9 @@ static int shrink_directory(struct exfat* ef, struct exfat_node* dir,
751695 uint64_t entries = 0;
752696 uint64_t new_size;
753697
754- if (!(dir->flags & EXFAT_ATTRIB_DIR))
698+ if (!(dir->attrib & EXFAT_ATTRIB_DIR))
755699 exfat_bug("attempted to shrink a file");
756- if (!(dir->flags & EXFAT_ATTRIB_CACHED))
700+ if (!dir->is_cached)
757701 exfat_bug("attempted to shrink uncached directory");
758702
759703 for (last_node = node = dir->child; node; node = node->next)
@@ -795,21 +739,22 @@ static int delete(struct exfat* ef, struct exfat_node* node)
795739 int rc;
796740
797741 exfat_get_node(parent);
798- if (!erase_entry(ef, node))
742+ rc = erase_node(ef, node);
743+ if (rc != 0)
799744 {
800745 exfat_put_node(ef, parent);
801- return -EIO;
746+ return rc;
802747 }
803- exfat_update_mtime(parent);
804748 tree_detach(node);
805749 rc = shrink_directory(ef, parent, deleted_offset);
806- node->flags |= EXFAT_ATTRIB_UNLINKED;
750+ node->is_unlinked = true;
807751 if (rc != 0)
808752 {
809753 exfat_flush_node(ef, parent);
810754 exfat_put_node(ef, parent);
811755 return rc;
812756 }
757+ exfat_update_mtime(parent);
813758 rc = exfat_flush_node(ef, parent);
814759 exfat_put_node(ef, parent);
815760 return rc;
@@ -817,7 +762,7 @@ static int delete(struct exfat* ef, struct exfat_node* node)
817762
818763 int exfat_unlink(struct exfat* ef, struct exfat_node* node)
819764 {
820- if (node->flags & EXFAT_ATTRIB_DIR)
765+ if (node->attrib & EXFAT_ATTRIB_DIR)
821766 return -EISDIR;
822767 return delete(ef, node);
823768 }
@@ -826,7 +771,7 @@ int exfat_rmdir(struct exfat* ef, struct exfat_node* node)
826771 {
827772 int rc;
828773
829- if (!(node->flags & EXFAT_ATTRIB_DIR))
774+ if (!(node->attrib & EXFAT_ATTRIB_DIR))
830775 return -ENOTDIR;
831776 /* check that directory is empty */
832777 rc = exfat_cache_directory(ef, node);
@@ -837,130 +782,143 @@ int exfat_rmdir(struct exfat* ef, struct exfat_node* node)
837782 return delete(ef, node);
838783 }
839784
840-static int grow_directory(struct exfat* ef, struct exfat_node* dir,
841- uint64_t asize, uint32_t difference)
785+static int check_slot(struct exfat* ef, struct exfat_node* dir, off_t offset,
786+ int n)
842787 {
843- return exfat_truncate(ef, dir,
844- DIV_ROUND_UP(asize + difference, CLUSTER_SIZE(*ef->sb))
845- * CLUSTER_SIZE(*ef->sb), true);
788+ struct exfat_entry entries[n];
789+ int rc;
790+ size_t i;
791+
792+ /* Root directory contains entries, that don't have any nodes associated
793+ with them (clusters bitmap, upper case table, label). We need to be
794+ careful not to overwrite them. */
795+ if (dir != ef->root)
796+ return 0;
797+
798+ rc = read_entries(ef, dir, entries, n, offset);
799+ if (rc != 0)
800+ return rc;
801+ for (i = 0; i < n; i++)
802+ if (entries[i].type & EXFAT_ENTRY_VALID)
803+ return -EINVAL;
804+ return 0;
846805 }
847806
848807 static int find_slot(struct exfat* ef, struct exfat_node* dir,
849- cluster_t* cluster, off_t* offset, int subentries)
808+ off_t* offset, int n)
850809 {
851- struct iterator it;
852- int rc;
853- const struct exfat_entry* entry;
810+ bitmap_t* dmap;
811+ struct exfat_node* p;
812+ size_t i;
854813 int contiguous = 0;
855814
856- rc = opendir(ef, dir, &it);
857- if (rc != 0)
858- return rc;
859- for (;;)
815+ if (!dir->is_cached)
816+ exfat_bug("directory is not cached");
817+
818+ /* build a bitmap of valid entries in the directory */
819+ dmap = calloc(BMAP_SIZE(dir->size / sizeof(struct exfat_entry)),
820+ sizeof(bitmap_t));
821+ if (dmap == NULL)
822+ {
823+ exfat_error("failed to allocate directory bitmap (%"PRIu64")",
824+ dir->size / sizeof(struct exfat_entry));
825+ return -ENOMEM;
826+ }
827+ for (p = dir->child; p != NULL; p = p->next)
828+ for (i = 0; i < 1 + p->continuations; i++)
829+ BMAP_SET(dmap, p->entry_offset / sizeof(struct exfat_entry) + i);
830+
831+ /* find a slot in the directory entries bitmap */
832+ for (i = 0; i < dir->size / sizeof(struct exfat_entry); i++)
860833 {
861- if (contiguous == 0)
834+ if (BMAP_GET(dmap, i) == 0)
862835 {
863- *cluster = it.cluster;
864- *offset = it.offset;
836+ if (contiguous++ == 0)
837+ *offset = (off_t) i * sizeof(struct exfat_entry);
838+ if (contiguous == n)
839+ /* suitable slot is found, check that it's not occupied */
840+ switch (check_slot(ef, dir, *offset, n))
841+ {
842+ case 0:
843+ free(dmap);
844+ return 0;
845+ case -EIO:
846+ free(dmap);
847+ return -EIO;
848+ case -EINVAL:
849+ /* slot is occupied, continue searching */
850+ contiguous = 0;
851+ break;
852+ }
865853 }
866- entry = get_entry_ptr(ef, &it);
867- if (entry->type & EXFAT_ENTRY_VALID)
868- contiguous = 0;
869854 else
870- contiguous++;
871- if (contiguous == subentries)
872- break; /* suitable slot is found */
873- if (it.offset + sizeof(struct exfat_entry) >= dir->size)
874- {
875- rc = grow_directory(ef, dir, dir->size,
876- (subentries - contiguous) * sizeof(struct exfat_entry));
877- if (rc != 0)
878- {
879- closedir(&it);
880- return rc;
881- }
882- }
883- if (!fetch_next_entry(ef, dir, &it))
884- {
885- closedir(&it);
886- return -EIO;
887- }
855+ contiguous = 0;
888856 }
889- closedir(&it);
890- return 0;
857+ free(dmap);
858+
859+ /* no suitable slots found, extend the directory */
860+ if (contiguous == 0)
861+ *offset = dir->size;
862+ return exfat_truncate(ef, dir,
863+ ROUND_UP(dir->size + sizeof(struct exfat_entry[n - contiguous]),
864+ CLUSTER_SIZE(*ef->sb)),
865+ true);
891866 }
892867
893-static int write_entry(struct exfat* ef, struct exfat_node* dir,
868+static int commit_entry(struct exfat* ef, struct exfat_node* dir,
894869 const le16_t* name, cluster_t cluster, off_t offset, uint16_t attrib)
895870 {
896871 struct exfat_node* node;
897- struct exfat_entry_meta1 meta1;
898- struct exfat_entry_meta2 meta2;
899872 const size_t name_length = utf16_length(name);
900873 const int name_entries = DIV_ROUND_UP(name_length, EXFAT_ENAME_MAX);
874+ struct exfat_entry entries[2 + name_entries];
875+ struct exfat_entry_meta1* meta1 = (struct exfat_entry_meta1*) &entries[0];
876+ struct exfat_entry_meta2* meta2 = (struct exfat_entry_meta2*) &entries[1];
901877 int i;
878+ int rc;
902879
903- node = allocate_node();
904- if (node == NULL)
905- return -ENOMEM;
906- node->entry_cluster = cluster;
907- node->entry_offset = offset;
908- memcpy(node->name, name, name_length * sizeof(le16_t));
880+ memset(entries, 0, sizeof(struct exfat_entry[2]));
881+
882+ meta1->type = EXFAT_ENTRY_FILE;
883+ meta1->continuations = 1 + name_entries;
884+ meta1->attrib = cpu_to_le16(attrib);
885+ exfat_unix2exfat(time(NULL), &meta1->crdate, &meta1->crtime,
886+ &meta1->crtime_cs);
887+ meta1->adate = meta1->mdate = meta1->crdate;
888+ meta1->atime = meta1->mtime = meta1->crtime;
889+ meta1->mtime_cs = meta1->crtime_cs; /* there is no atime_cs */
890+
891+ meta2->type = EXFAT_ENTRY_FILE_INFO;
892+ meta2->flags = EXFAT_FLAG_ALWAYS1;
893+ meta2->name_length = name_length;
894+ meta2->name_hash = exfat_calc_name_hash(ef, name, name_length);
895+ meta2->start_cluster = cpu_to_le32(EXFAT_CLUSTER_FREE);
909896
910- memset(&meta1, 0, sizeof(meta1));
911- meta1.type = EXFAT_ENTRY_FILE;
912- meta1.continuations = 1 + name_entries;
913- meta1.attrib = cpu_to_le16(attrib);
914- exfat_unix2exfat(time(NULL), &meta1.crdate, &meta1.crtime,
915- &meta1.crtime_cs);
916- meta1.adate = meta1.mdate = meta1.crdate;
917- meta1.atime = meta1.mtime = meta1.crtime;
918- meta1.mtime_cs = meta1.crtime_cs; /* there is no atime_cs */
919-
920- memset(&meta2, 0, sizeof(meta2));
921- meta2.type = EXFAT_ENTRY_FILE_INFO;
922- meta2.flags = EXFAT_FLAG_ALWAYS1;
923- meta2.name_length = name_length;
924- meta2.name_hash = exfat_calc_name_hash(ef, node->name);
925- meta2.start_cluster = cpu_to_le32(EXFAT_CLUSTER_FREE);
926-
927- meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name);
928-
929- if (exfat_pwrite(ef->dev, &meta1, sizeof(meta1),
930- co2o(ef, cluster, offset)) < 0)
931- {
932- exfat_error("failed to write meta1 entry");
933- return -EIO;
934- }
935- if (!next_entry(ef, dir, &cluster, &offset))
936- return -EIO;
937- if (exfat_pwrite(ef->dev, &meta2, sizeof(meta2),
938- co2o(ef, cluster, offset)) < 0)
939- {
940- exfat_error("failed to write meta2 entry");
941- return -EIO;
942- }
943897 for (i = 0; i < name_entries; i++)
944898 {
945- struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0};
946- memcpy(name_entry.name, node->name + i * EXFAT_ENAME_MAX,
947- MIN(EXFAT_ENAME_MAX, EXFAT_NAME_MAX - i * EXFAT_ENAME_MAX) *
948- sizeof(le16_t));
949- if (!next_entry(ef, dir, &cluster, &offset))
950- return -EIO;
951- if (exfat_pwrite(ef->dev, &name_entry, sizeof(name_entry),
952- co2o(ef, cluster, offset)) < 0)
953- {
954- exfat_error("failed to write name entry");
955- return -EIO;
956- }
899+ struct exfat_entry_name* name_entry;
900+
901+ name_entry = (struct exfat_entry_name*) &entries[2 + i];
902+ name_entry->type = EXFAT_ENTRY_FILE_NAME;
903+ name_entry->__unknown = 0;
904+ memcpy(name_entry->name, name + i * EXFAT_ENAME_MAX,
905+ EXFAT_ENAME_MAX * sizeof(le16_t));
957906 }
958907
959- init_node_meta1(node, &meta1);
960- init_node_meta2(node, &meta2);
908+ meta1->checksum = exfat_calc_checksum(entries, 2 + name_entries);
909+ rc = write_entries(ef, dir, entries, 2 + name_entries, offset);
910+ if (rc != 0)
911+ return rc;
912+
913+ node = allocate_node();
914+ if (node == NULL)
915+ return -ENOMEM;
916+ node->entry_offset = offset;
917+ memcpy(node->name, name, name_length * sizeof(le16_t));
918+ init_node_meta1(node, meta1);
919+ init_node_meta2(node, meta2);
961920
962921 tree_attach(dir, node);
963- exfat_update_mtime(dir);
964922 return 0;
965923 }
966924
@@ -983,19 +941,20 @@ static int create(struct exfat* ef, const char* path, uint16_t attrib)
983941 return -EEXIST;
984942 }
985943
986- rc = find_slot(ef, dir, &cluster, &offset,
944+ rc = find_slot(ef, dir, &offset,
987945 2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX));
988946 if (rc != 0)
989947 {
990948 exfat_put_node(ef, dir);
991949 return rc;
992950 }
993- rc = write_entry(ef, dir, name, cluster, offset, attrib);
951+ rc = commit_entry(ef, dir, name, cluster, offset, attrib);
994952 if (rc != 0)
995953 {
996954 exfat_put_node(ef, dir);
997955 return rc;
998956 }
957+ exfat_update_mtime(dir);
999958 rc = exfat_flush_node(ef, dir);
1000959 exfat_put_node(ef, dir);
1001960 return rc;
@@ -1040,69 +999,45 @@ static int rename_entry(struct exfat* ef, struct exfat_node* dir,
1040999 struct exfat_node* node, const le16_t* name, cluster_t new_cluster,
10411000 off_t new_offset)
10421001 {
1043- struct exfat_entry_meta1 meta1;
1044- struct exfat_entry_meta2 meta2;
1045- cluster_t old_cluster = node->entry_cluster;
1046- off_t old_offset = node->entry_offset;
10471002 const size_t name_length = utf16_length(name);
10481003 const int name_entries = DIV_ROUND_UP(name_length, EXFAT_ENAME_MAX);
1004+ struct exfat_entry entries[2 + name_entries];
1005+ struct exfat_entry_meta1* meta1 = (struct exfat_entry_meta1*) &entries[0];
1006+ struct exfat_entry_meta2* meta2 = (struct exfat_entry_meta2*) &entries[1];
1007+ int rc;
10491008 int i;
10501009
1051- if (exfat_pread(ef->dev, &meta1, sizeof(meta1),
1052- co2o(ef, old_cluster, old_offset)) < 0)
1053- {
1054- exfat_error("failed to read meta1 entry on rename");
1055- return -EIO;
1056- }
1057- if (!next_entry(ef, node->parent, &old_cluster, &old_offset))
1058- return -EIO;
1059- if (exfat_pread(ef->dev, &meta2, sizeof(meta2),
1060- co2o(ef, old_cluster, old_offset)) < 0)
1061- {
1062- exfat_error("failed to read meta2 entry on rename");
1063- return -EIO;
1064- }
1065- meta1.continuations = 1 + name_entries;
1066- meta2.name_hash = exfat_calc_name_hash(ef, name);
1067- meta2.name_length = name_length;
1068- meta1.checksum = exfat_calc_checksum(&meta1, &meta2, name);
1010+ rc = read_entries(ef, node->parent, entries, 2, node->entry_offset);
1011+ if (rc != 0)
1012+ return rc;
10691013
1070- if (!erase_entry(ef, node))
1071- return -EIO;
1014+ meta1->continuations = 1 + name_entries;
1015+ meta2->name_length = name_length;
1016+ meta2->name_hash = exfat_calc_name_hash(ef, name, name_length);
10721017
1073- node->entry_cluster = new_cluster;
1074- node->entry_offset = new_offset;
1018+ rc = erase_node(ef, node);
1019+ if (rc != 0)
1020+ return rc;
10751021
1076- if (exfat_pwrite(ef->dev, &meta1, sizeof(meta1),
1077- co2o(ef, new_cluster, new_offset)) < 0)
1078- {
1079- exfat_error("failed to write meta1 entry on rename");
1080- return -EIO;
1081- }
1082- if (!next_entry(ef, dir, &new_cluster, &new_offset))
1083- return -EIO;
1084- if (exfat_pwrite(ef->dev, &meta2, sizeof(meta2),
1085- co2o(ef, new_cluster, new_offset)) < 0)
1086- {
1087- exfat_error("failed to write meta2 entry on rename");
1088- return -EIO;
1089- }
1022+ node->entry_offset = new_offset;
1023+ node->continuations = 1 + name_entries;
10901024
10911025 for (i = 0; i < name_entries; i++)
10921026 {
1093- struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0};
1094- memcpy(name_entry.name, name + i * EXFAT_ENAME_MAX,
1027+ struct exfat_entry_name* name_entry;
1028+
1029+ name_entry = (struct exfat_entry_name*) &entries[2 + i];
1030+ name_entry->type = EXFAT_ENTRY_FILE_NAME;
1031+ name_entry->__unknown = 0;
1032+ memcpy(name_entry->name, name + i * EXFAT_ENAME_MAX,
10951033 EXFAT_ENAME_MAX * sizeof(le16_t));
1096- if (!next_entry(ef, dir, &new_cluster, &new_offset))
1097- return -EIO;
1098- if (exfat_pwrite(ef->dev, &name_entry, sizeof(name_entry),
1099- co2o(ef, new_cluster, new_offset)) < 0)
1100- {
1101- exfat_error("failed to write name entry on rename");
1102- return -EIO;
1103- }
11041034 }
11051035
1036+ meta1->checksum = exfat_calc_checksum(entries, 2 + name_entries);
1037+ rc = write_entries(ef, dir, entries, 2 + name_entries, new_offset);
1038+ if (rc != 0)
1039+ return rc;
1040+
11061041 memcpy(node->name, name, (EXFAT_NAME_MAX + 1) * sizeof(le16_t));
11071042 tree_detach(node);
11081043 tree_attach(dir, node);
@@ -1131,7 +1066,7 @@ int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path)
11311066 }
11321067
11331068 /* check that target is not a subdirectory of the source */
1134- if (node->flags & EXFAT_ATTRIB_DIR)
1069+ if (node->attrib & EXFAT_ATTRIB_DIR)
11351070 {
11361071 struct exfat_node* p;
11371072
@@ -1151,16 +1086,16 @@ int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path)
11511086 /* remove target if it's not the same node as source */
11521087 if (existing != node)
11531088 {
1154- if (existing->flags & EXFAT_ATTRIB_DIR)
1089+ if (existing->attrib & EXFAT_ATTRIB_DIR)
11551090 {
1156- if (node->flags & EXFAT_ATTRIB_DIR)
1091+ if (node->attrib & EXFAT_ATTRIB_DIR)
11571092 rc = exfat_rmdir(ef, existing);
11581093 else
11591094 rc = -ENOTDIR;
11601095 }
11611096 else
11621097 {
1163- if (!(node->flags & EXFAT_ATTRIB_DIR))
1098+ if (!(node->attrib & EXFAT_ATTRIB_DIR))
11641099 rc = exfat_unlink(ef, existing);
11651100 else
11661101 rc = -EISDIR;
@@ -1187,7 +1122,7 @@ int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path)
11871122 exfat_put_node(ef, existing);
11881123 }
11891124
1190- rc = find_slot(ef, dir, &cluster, &offset,
1125+ rc = find_slot(ef, dir, &offset,
11911126 2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX));
11921127 if (rc != 0)
11931128 {
@@ -1196,8 +1131,16 @@ int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path)
11961131 return rc;
11971132 }
11981133 rc = rename_entry(ef, dir, node, name, cluster, offset);
1134+ if (rc != 0)
1135+ {
1136+ exfat_put_node(ef, dir);
1137+ exfat_put_node(ef, node);
1138+ return rc;
1139+ }
1140+ rc = exfat_flush_node(ef, dir);
11991141 exfat_put_node(ef, dir);
12001142 exfat_put_node(ef, node);
1143+ /* node itself is not marked as dirty, no need to flush it */
12011144 return rc;
12021145 }
12031146
@@ -1205,19 +1148,19 @@ void exfat_utimes(struct exfat_node* node, const struct timespec tv[2])
12051148 {
12061149 node->atime = tv[0].tv_sec;
12071150 node->mtime = tv[1].tv_sec;
1208- node->flags |= EXFAT_ATTRIB_DIRTY;
1151+ node->is_dirty = true;
12091152 }
12101153
12111154 void exfat_update_atime(struct exfat_node* node)
12121155 {
12131156 node->atime = time(NULL);
1214- node->flags |= EXFAT_ATTRIB_DIRTY;
1157+ node->is_dirty = true;
12151158 }
12161159
12171160 void exfat_update_mtime(struct exfat_node* node)
12181161 {
12191162 node->mtime = time(NULL);
1220- node->flags |= EXFAT_ATTRIB_DIRTY;
1163+ node->is_dirty = true;
12211164 }
12221165
12231166 const char* exfat_get_label(struct exfat* ef)
@@ -1225,36 +1168,19 @@ const char* exfat_get_label(struct exfat* ef)
12251168 return ef->label;
12261169 }
12271170
1228-static int find_label(struct exfat* ef, cluster_t* cluster, off_t* offset)
1171+static int find_label(struct exfat* ef, off_t* offset)
12291172 {
1230- struct iterator it;
1173+ struct exfat_entry entry;
12311174 int rc;
12321175
1233- rc = opendir(ef, ef->root, &it);
1234- if (rc != 0)
1235- return rc;
1236-
1237- for (;;)
1176+ for (*offset = 0; ; *offset += sizeof(entry))
12381177 {
1239- if (it.offset >= ef->root->size)
1240- {
1241- closedir(&it);
1242- return -ENOENT;
1243- }
1178+ rc = read_entries(ef, ef->root, &entry, 1, *offset);
1179+ if (rc != 0)
1180+ return rc;
12441181
1245- if (get_entry_ptr(ef, &it)->type == EXFAT_ENTRY_LABEL)
1246- {
1247- *cluster = it.cluster;
1248- *offset = it.offset;
1249- closedir(&it);
1182+ if (entry.type == EXFAT_ENTRY_LABEL)
12501183 return 0;
1251- }
1252-
1253- if (!fetch_next_entry(ef, ef->root, &it))
1254- {
1255- closedir(&it);
1256- return -EIO;
1257- }
12581184 }
12591185 }
12601186
@@ -1262,18 +1188,17 @@ int exfat_set_label(struct exfat* ef, const char* label)
12621188 {
12631189 le16_t label_utf16[EXFAT_ENAME_MAX + 1];
12641190 int rc;
1265- cluster_t cluster;
12661191 off_t offset;
12671192 struct exfat_entry_label entry;
12681193
12691194 memset(label_utf16, 0, sizeof(label_utf16));
1270- rc = utf8_to_utf16(label_utf16, label, EXFAT_ENAME_MAX, strlen(label));
1195+ rc = utf8_to_utf16(label_utf16, label, EXFAT_ENAME_MAX + 1, strlen(label));
12711196 if (rc != 0)
12721197 return rc;
12731198
1274- rc = find_label(ef, &cluster, &offset);
1199+ rc = find_label(ef, &offset);
12751200 if (rc == -ENOENT)
1276- rc = find_slot(ef, ef->root, &cluster, &offset, 1);
1201+ rc = find_slot(ef, ef->root, &offset, 1);
12771202 if (rc != 0)
12781203 return rc;
12791204
@@ -1283,12 +1208,10 @@ int exfat_set_label(struct exfat* ef, const char* label)
12831208 if (entry.length == 0)
12841209 entry.type ^= EXFAT_ENTRY_VALID;
12851210
1286- if (exfat_pwrite(ef->dev, &entry, sizeof(struct exfat_entry_label),
1287- co2o(ef, cluster, offset)) < 0)
1288- {
1289- exfat_error("failed to write label entry");
1290- return -EIO;
1291- }
1211+ rc = write_entries(ef, ef->root, (struct exfat_entry*) &entry, 1, offset);
1212+ if (rc != 0)
1213+ return rc;
1214+
12921215 strcpy(ef->label, label);
12931216 return 0;
12941217 }
--- a/libexfat/platform.h
+++ b/libexfat/platform.h
@@ -4,7 +4,7 @@
44 same kernel can use different libc implementations.
55
66 Free exFAT implementation.
7- Copyright (C) 2010-2016 Andrew Nayenko
7+ Copyright (C) 2010-2017 Andrew Nayenko
88
99 This program is free software; you can redistribute it and/or modify
1010 it under the terms of the GNU General Public License as published by
--- a/libexfat/time.c
+++ b/libexfat/time.c
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -151,8 +151,14 @@ void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
151151 void exfat_tzset(void)
152152 {
153153 time_t now;
154+ struct tm* utc;
154155
155156 tzset();
156157 now = time(NULL);
157- exfat_timezone = mktime(gmtime(&now)) - now;
158+ utc = gmtime(&now);
159+ /* gmtime() always sets tm_isdst to 0 because daylight savings never
160+ affect UTC. Setting tm_isdst to -1 makes mktime() to determine whether
161+ summer time is in effect. */
162+ utc->tm_isdst = -1;
163+ exfat_timezone = mktime(utc) - now;
158164 }
--- a/libexfat/utf.h
+++ b/libexfat/utf.h
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -108,7 +108,7 @@ static inline int utf16_to_utf8(char* output, const le16_t* input, size_t outsiz
108108 char* outp = output;
109109 wchar_t wc;
110110
111- while (inp - input < insize && le16_to_cpu(*inp))
111+ while (inp - input < insize)
112112 {
113113 inp = utf16_to_wchar(inp, &wc, insize - (inp - input));
114114 if (inp == NULL)
@@ -122,6 +122,13 @@ static inline int utf16_to_utf8(char* output, const le16_t* input, size_t outsiz
122122 exfat_error("name is too long");
123123 return -ENAMETOOLONG;
124124 }
125+ if (wc == 0)
126+ return 0;
127+ }
128+ if (outp - output >= outsize)
129+ {
130+ exfat_error("name is too long");
131+ return -ENAMETOOLONG;
125132 }
126133 *outp = '\0';
127134 return 0;
@@ -202,7 +209,7 @@ static le16_t* wchar_to_utf16(le16_t* output, wchar_t wc, size_t outsize)
202209 le16_t* outp = output;
203210 wchar_t wc;
204211
205- while (inp - input < insize && *inp)
212+ while (inp - input < insize)
206213 {
207214 inp = utf8_to_wchar(inp, &wc, insize - (inp - input));
208215 if (inp == NULL)
@@ -216,6 +223,13 @@ static le16_t* wchar_to_utf16(le16_t* output, wchar_t wc, size_t outsize)
216223 exfat_error("name is too long");
217224 return -ENAMETOOLONG;
218225 }
226+ if (wc == 0)
227+ break;
228+ }
229+ if (outp - output >= outsize)
230+ {
231+ exfat_error("name is too long");
232+ return -ENAMETOOLONG;
219233 }
220234 *outp = cpu_to_le16(0);
221235 return 0;
--- a/libexfat/utils.c
+++ b/libexfat/utils.c
@@ -3,7 +3,7 @@
33 exFAT file system implementation library.
44
55 Free exFAT implementation.
6- Copyright (C) 2010-2016 Andrew Nayenko
6+ Copyright (C) 2010-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
3030 struct stat* stbuf)
3131 {
3232 memset(stbuf, 0, sizeof(struct stat));
33- if (node->flags & EXFAT_ATTRIB_DIR)
33+ if (node->attrib & EXFAT_ATTRIB_DIR)
3434 stbuf->st_mode = S_IFDIR | (0777 & ~ef->dmask);
3535 else
3636 stbuf->st_mode = S_IFREG | (0777 & ~ef->fmask);
@@ -38,8 +38,7 @@ void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
3838 stbuf->st_uid = ef->uid;
3939 stbuf->st_gid = ef->gid;
4040 stbuf->st_size = node->size;
41- stbuf->st_blocks = DIV_ROUND_UP(node->size, CLUSTER_SIZE(*ef->sb)) *
42- CLUSTER_SIZE(*ef->sb) / 512;
41+ stbuf->st_blocks = ROUND_UP(node->size, CLUSTER_SIZE(*ef->sb)) / 512;
4342 stbuf->st_mtime = node->mtime;
4443 stbuf->st_atime = node->atime;
4544 /* set ctime to mtime to ensure we don't break programs that rely on ctime
@@ -47,12 +46,28 @@ void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
4746 stbuf->st_ctime = node->mtime;
4847 }
4948
50-void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n)
49+void exfat_get_name(const struct exfat_node* node,
50+ char buffer[EXFAT_UTF8_NAME_BUFFER_MAX])
5151 {
52- if (utf16_to_utf8(buffer, node->name, n, EXFAT_NAME_MAX) != 0)
52+ if (utf16_to_utf8(buffer, node->name, EXFAT_UTF8_NAME_BUFFER_MAX,
53+ EXFAT_NAME_MAX) != 0)
5354 exfat_bug("failed to convert name to UTF-8");
5455 }
5556
57+static uint16_t add_checksum_byte(uint16_t sum, uint8_t byte)
58+{
59+ return ((sum << 15) | (sum >> 1)) + byte;
60+}
61+
62+static uint16_t add_checksum_bytes(uint16_t sum, const void* buffer, size_t n)
63+{
64+ int i;
65+
66+ for (i = 0; i < n; i++)
67+ sum = add_checksum_byte(sum, ((const uint8_t*) buffer)[i]);
68+ return sum;
69+}
70+
5671 uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry)
5772 {
5873 uint16_t sum = 0;
@@ -60,36 +75,23 @@ uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry)
6075
6176 for (i = 0; i < sizeof(struct exfat_entry); i++)
6277 if (i != 2 && i != 3) /* skip checksum field itself */
63- sum = ((sum << 15) | (sum >> 1)) + ((const uint8_t*) entry)[i];
78+ sum = add_checksum_byte(sum, ((const uint8_t*) entry)[i]);
6479 return sum;
6580 }
6681
6782 uint16_t exfat_add_checksum(const void* entry, uint16_t sum)
6883 {
69- int i;
70-
71- for (i = 0; i < sizeof(struct exfat_entry); i++)
72- sum = ((sum << 15) | (sum >> 1)) + ((const uint8_t*) entry)[i];
73- return sum;
84+ return add_checksum_bytes(sum, entry, sizeof(struct exfat_entry));
7485 }
7586
76-le16_t exfat_calc_checksum(const struct exfat_entry_meta1* meta1,
77- const struct exfat_entry_meta2* meta2, const le16_t* name)
87+le16_t exfat_calc_checksum(const struct exfat_entry* entries, int n)
7888 {
7989 uint16_t checksum;
80- const int name_entries = DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX);
8190 int i;
8291
83- checksum = exfat_start_checksum(meta1);
84- checksum = exfat_add_checksum(meta2, checksum);
85- for (i = 0; i < name_entries; i++)
86- {
87- struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0};
88- memcpy(name_entry.name, name + i * EXFAT_ENAME_MAX,
89- MIN(EXFAT_ENAME_MAX, EXFAT_NAME_MAX - i * EXFAT_ENAME_MAX) *
90- sizeof(le16_t));
91- checksum = exfat_add_checksum(&name_entry, checksum);
92- }
92+ checksum = exfat_start_checksum((const struct exfat_entry_meta1*) entries);
93+ for (i = 1; i < n; i++)
94+ checksum = exfat_add_checksum(entries + i, checksum);
9395 return cpu_to_le16(checksum);
9496 }
9597
@@ -114,10 +116,10 @@ uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum)
114116 return sum;
115117 }
116118
117-le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name)
119+le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name,
120+ size_t length)
118121 {
119122 size_t i;
120- size_t length = utf16_length(name);
121123 uint16_t hash = 0;
122124
123125 for (i = 0; i < length; i++)
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -3,7 +3,7 @@
33 # Automake source.
44 #
55 # Free exFAT implementation.
6-# Copyright (C) 2011-2016 Andrew Nayenko
6+# Copyright (C) 2011-2017 Andrew Nayenko
77 #
88 # This program is free software; you can redistribute it and/or modify
99 # it under the terms of the GNU General Public License as published by
--- a/mkfs/cbm.c
+++ b/mkfs/cbm.c
@@ -3,7 +3,7 @@
33 Clusters Bitmap creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/cbm.h
+++ b/mkfs/cbm.h
@@ -3,7 +3,7 @@
33 Clusters Bitmap creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/fat.c
+++ b/mkfs/fat.c
@@ -3,7 +3,7 @@
33 File Allocation Table creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/fat.h
+++ b/mkfs/fat.h
@@ -3,7 +3,7 @@
33 File Allocation Table creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -3,7 +3,7 @@
33 Creates exFAT file system.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
@@ -137,7 +137,7 @@ static int setup_volume_label(le16_t label[EXFAT_ENAME_MAX + 1], const char* s)
137137 memset(label, 0, (EXFAT_ENAME_MAX + 1) * sizeof(le16_t));
138138 if (s == NULL)
139139 return 0;
140- return utf8_to_utf16(label, s, EXFAT_ENAME_MAX, strlen(s));
140+ return utf8_to_utf16(label, s, EXFAT_ENAME_MAX + 1, strlen(s));
141141 }
142142
143143 static uint32_t setup_volume_serial(uint32_t user_defined)
@@ -229,7 +229,7 @@ int main(int argc, char* argv[])
229229 }
230230 break;
231231 case 'V':
232- puts("Copyright (C) 2011-2016 Andrew Nayenko");
232+ puts("Copyright (C) 2011-2017 Andrew Nayenko");
233233 return 0;
234234 default:
235235 usage(argv[0]);
--- a/mkfs/mkexfat.c
+++ b/mkfs/mkexfat.c
@@ -3,7 +3,7 @@
33 FS creation engine.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/mkexfat.h
+++ b/mkfs/mkexfat.h
@@ -3,7 +3,7 @@
33 FS creation engine.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -3,7 +3,7 @@
33 Root directory creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/rootdir.h
+++ b/mkfs/rootdir.h
@@ -3,7 +3,7 @@
33 Root directory creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/uct.c
+++ b/mkfs/uct.c
@@ -3,7 +3,7 @@
33 Upper Case Table creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/uct.h
+++ b/mkfs/uct.h
@@ -3,7 +3,7 @@
33 Upper Case Table creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/uctc.c
+++ b/mkfs/uctc.c
@@ -3,7 +3,7 @@
33 Upper Case Table contents.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/uctc.h
+++ b/mkfs/uctc.h
@@ -3,7 +3,7 @@
33 Upper Case Table declaration.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/vbr.c
+++ b/mkfs/vbr.c
@@ -3,7 +3,7 @@
33 Volume Boot Record creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
--- a/mkfs/vbr.h
+++ b/mkfs/vbr.h
@@ -3,7 +3,7 @@
33 Volume Boot Record creation code.
44
55 Free exFAT implementation.
6- Copyright (C) 2011-2016 Andrew Nayenko
6+ Copyright (C) 2011-2017 Andrew Nayenko
77
88 This program is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
Show on old repository browser