3 exFAT file system implementation library.
5 Free exFAT implementation.
6 Copyright (C) 2010-2013 Andrew Nayenko
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 /* on-disk nodes iterator */
37 struct exfat_node* exfat_get_node(struct exfat_node* node)
39 /* if we switch to multi-threaded mode we will need atomic
40 increment here and atomic decrement in exfat_put_node() */
45 void exfat_put_node(struct exfat* ef, struct exfat_node* node)
47 if (--node->references < 0)
49 char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
50 exfat_get_name(node, buffer, sizeof(buffer) - 1);
51 exfat_bug("reference counter of `%s' is below zero", buffer);
54 if (node->references == 0)
56 exfat_flush_node(ef, node);
57 if (node->flags & EXFAT_ATTRIB_UNLINKED)
59 /* free all clusters and node structure itself */
60 exfat_truncate(ef, node, 0, true);
68 * Cluster + offset from the beginning of the directory to absolute offset.
70 static off_t co2o(struct exfat* ef, cluster_t cluster, off_t offset)
72 return exfat_c2o(ef, cluster) + offset % CLUSTER_SIZE(*ef->sb);
75 static int opendir(struct exfat* ef, const struct exfat_node* dir,
78 if (!(dir->flags & EXFAT_ATTRIB_DIR))
79 exfat_bug("not a directory");
80 it->cluster = dir->start_cluster;
82 it->contiguous = IS_CONTIGUOUS(*dir);
83 it->chunk = malloc(CLUSTER_SIZE(*ef->sb));
84 if (it->chunk == NULL)
86 exfat_error("out of memory");
89 exfat_pread(ef->dev, it->chunk, CLUSTER_SIZE(*ef->sb),
90 exfat_c2o(ef, it->cluster));
94 static void closedir(struct iterator* it)
103 static int fetch_next_entry(struct exfat* ef, const struct exfat_node* parent,
106 /* move iterator to the next entry in the directory */
107 it->offset += sizeof(struct exfat_entry);
108 /* fetch the next cluster if needed */
109 if ((it->offset & (CLUSTER_SIZE(*ef->sb) - 1)) == 0)
111 /* reached the end of directory; the caller should check this
113 if (it->offset >= parent->size)
115 it->cluster = exfat_next_cluster(ef, parent, it->cluster);
116 if (CLUSTER_INVALID(it->cluster))
118 exfat_error("invalid cluster 0x%x while reading directory",
122 exfat_pread(ef->dev, it->chunk, CLUSTER_SIZE(*ef->sb),
123 exfat_c2o(ef, it->cluster));
128 static struct exfat_node* allocate_node(void)
130 struct exfat_node* node = malloc(sizeof(struct exfat_node));
133 exfat_error("failed to allocate node");
136 memset(node, 0, sizeof(struct exfat_node));
140 static void init_node_meta1(struct exfat_node* node,
141 const struct exfat_entry_meta1* meta1)
143 node->flags = le16_to_cpu(meta1->attrib);
144 node->mtime = exfat_exfat2unix(meta1->mdate, meta1->mtime,
146 /* there is no centiseconds field for atime */
147 node->atime = exfat_exfat2unix(meta1->adate, meta1->atime, 0);
150 static void init_node_meta2(struct exfat_node* node,
151 const struct exfat_entry_meta2* meta2)
153 node->size = le64_to_cpu(meta2->size);
154 node->start_cluster = le32_to_cpu(meta2->start_cluster);
155 node->fptr_cluster = node->start_cluster;
156 if (meta2->flags & EXFAT_FLAG_CONTIGUOUS)
157 node->flags |= EXFAT_ATTRIB_CONTIGUOUS;
160 static const struct exfat_entry* get_entry_ptr(const struct exfat* ef,
161 const struct iterator* it)
163 return (const struct exfat_entry*)
164 (it->chunk + it->offset % CLUSTER_SIZE(*ef->sb));
168 * Reads one entry in directory at position pointed by iterator and fills
171 static int readdir(struct exfat* ef, const struct exfat_node* parent,
172 struct exfat_node** node, struct iterator* it)
175 const struct exfat_entry* entry;
176 const struct exfat_entry_meta1* meta1;
177 const struct exfat_entry_meta2* meta2;
178 const struct exfat_entry_name* file_name;
179 const struct exfat_entry_upcase* upcase;
180 const struct exfat_entry_bitmap* bitmap;
181 const struct exfat_entry_label* label;
182 uint8_t continuations = 0;
183 le16_t* namep = NULL;
184 uint16_t reference_checksum = 0;
185 uint16_t actual_checksum = 0;
186 uint64_t real_size = 0;
192 if (it->offset >= parent->size)
194 if (continuations != 0)
196 exfat_error("expected %hhu continuations", continuations);
199 return -ENOENT; /* that's OK, means end of directory */
202 entry = get_entry_ptr(ef, it);
205 case EXFAT_ENTRY_FILE:
206 if (continuations != 0)
208 exfat_error("expected %hhu continuations before new entry",
212 meta1 = (const struct exfat_entry_meta1*) entry;
213 continuations = meta1->continuations;
214 /* each file entry must have at least 2 continuations:
216 if (continuations < 2)
218 exfat_error("too few continuations (%hhu)", continuations);
221 if (continuations > 1 +
222 DIV_ROUND_UP(EXFAT_NAME_MAX, EXFAT_ENAME_MAX))
224 exfat_error("too many continuations (%hhu)", continuations);
227 reference_checksum = le16_to_cpu(meta1->checksum);
228 actual_checksum = exfat_start_checksum(meta1);
229 *node = allocate_node();
235 /* new node has zero reference counter */
236 (*node)->entry_cluster = it->cluster;
237 (*node)->entry_offset = it->offset;
238 init_node_meta1(*node, meta1);
239 namep = (*node)->name;
242 case EXFAT_ENTRY_FILE_INFO:
243 if (continuations < 2)
245 exfat_error("unexpected continuation (%hhu)",
249 meta2 = (const struct exfat_entry_meta2*) entry;
250 if (meta2->flags & ~(EXFAT_FLAG_ALWAYS1 | EXFAT_FLAG_CONTIGUOUS))
252 exfat_error("unknown flags in meta2 (0x%hhx)", meta2->flags);
255 init_node_meta2(*node, meta2);
256 actual_checksum = exfat_add_checksum(entry, actual_checksum);
257 real_size = le64_to_cpu(meta2->real_size);
258 /* empty files must be marked as non-contiguous */
259 if ((*node)->size == 0 && (meta2->flags & EXFAT_FLAG_CONTIGUOUS))
261 exfat_error("empty file marked as contiguous (0x%hhx)",
265 /* directories must be aligned on at cluster boundary */
266 if (((*node)->flags & EXFAT_ATTRIB_DIR) &&
267 (*node)->size % CLUSTER_SIZE(*ef->sb) != 0)
269 exfat_error("directory has invalid size %"PRIu64" bytes",
276 case EXFAT_ENTRY_FILE_NAME:
277 if (continuations == 0)
279 exfat_error("unexpected continuation");
282 file_name = (const struct exfat_entry_name*) entry;
283 actual_checksum = exfat_add_checksum(entry, actual_checksum);
285 memcpy(namep, file_name->name,
287 ((*node)->name + EXFAT_NAME_MAX - namep)) *
289 namep += EXFAT_ENAME_MAX;
290 if (--continuations == 0)
293 There are two fields that contain file size. Maybe they
294 plan to add compression support in the future and one of
295 those fields is visible (uncompressed) size and the other
296 is real (compressed) size. Anyway, currently it looks like
297 exFAT does not support compression and both fields must be
300 There is an exception though: pagefile.sys (its real_size
303 if (real_size != (*node)->size)
305 char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
307 exfat_get_name(*node, buffer, sizeof(buffer) - 1);
308 exfat_error("`%s' real size does not equal to size "
309 "(%"PRIu64" != %"PRIu64")", buffer,
310 real_size, (*node)->size);
313 if (actual_checksum != reference_checksum)
315 char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
317 exfat_get_name(*node, buffer, sizeof(buffer) - 1);
318 exfat_error("`%s' has invalid checksum (0x%hx != 0x%hx)",
319 buffer, actual_checksum, reference_checksum);
322 if (fetch_next_entry(ef, parent, it) != 0)
324 return 0; /* entry completed */
328 case EXFAT_ENTRY_UPCASE:
329 if (ef->upcase != NULL)
331 upcase = (const struct exfat_entry_upcase*) entry;
332 if (CLUSTER_INVALID(le32_to_cpu(upcase->start_cluster)))
334 exfat_error("invalid cluster 0x%x in upcase table",
335 le32_to_cpu(upcase->start_cluster));
338 if (le64_to_cpu(upcase->size) == 0 ||
339 le64_to_cpu(upcase->size) > 0xffff * sizeof(uint16_t) ||
340 le64_to_cpu(upcase->size) % sizeof(uint16_t) != 0)
342 exfat_error("bad upcase table size (%"PRIu64" bytes)",
343 le64_to_cpu(upcase->size));
346 ef->upcase = malloc(le64_to_cpu(upcase->size));
347 if (ef->upcase == NULL)
349 exfat_error("failed to allocate upcase table (%"PRIu64" bytes)",
350 le64_to_cpu(upcase->size));
354 ef->upcase_chars = le64_to_cpu(upcase->size) / sizeof(le16_t);
356 exfat_pread(ef->dev, ef->upcase, le64_to_cpu(upcase->size),
357 exfat_c2o(ef, le32_to_cpu(upcase->start_cluster)));
360 case EXFAT_ENTRY_BITMAP:
361 bitmap = (const struct exfat_entry_bitmap*) entry;
362 ef->cmap.start_cluster = le32_to_cpu(bitmap->start_cluster);
363 if (CLUSTER_INVALID(ef->cmap.start_cluster))
365 exfat_error("invalid cluster 0x%x in clusters bitmap",
366 ef->cmap.start_cluster);
369 ef->cmap.size = le32_to_cpu(ef->sb->cluster_count) -
370 EXFAT_FIRST_DATA_CLUSTER;
371 if (le64_to_cpu(bitmap->size) < (ef->cmap.size + 7) / 8)
373 exfat_error("invalid clusters bitmap size: %"PRIu64
374 " (expected at least %u)",
375 le64_to_cpu(bitmap->size), (ef->cmap.size + 7) / 8);
378 /* FIXME bitmap can be rather big, up to 512 MB */
379 ef->cmap.chunk_size = ef->cmap.size;
380 ef->cmap.chunk = malloc(le64_to_cpu(bitmap->size));
381 if (ef->cmap.chunk == NULL)
383 exfat_error("failed to allocate clusters bitmap chunk "
384 "(%"PRIu64" bytes)", le64_to_cpu(bitmap->size));
389 exfat_pread(ef->dev, ef->cmap.chunk, le64_to_cpu(bitmap->size),
390 exfat_c2o(ef, ef->cmap.start_cluster));
393 case EXFAT_ENTRY_LABEL:
394 label = (const struct exfat_entry_label*) entry;
395 if (label->length > EXFAT_ENAME_MAX)
397 exfat_error("too long label (%hhu chars)", label->length);
400 if (utf16_to_utf8(ef->label, label->name,
401 sizeof(ef->label) - 1, EXFAT_ENAME_MAX) != 0)
406 if (entry->type & EXFAT_ENTRY_VALID)
408 exfat_error("unknown entry type 0x%hhx", entry->type);
414 if (fetch_next_entry(ef, parent, it) != 0)
417 /* we never reach here */
425 int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir)
429 struct exfat_node* node;
430 struct exfat_node* current = NULL;
432 if (dir->flags & EXFAT_ATTRIB_CACHED)
433 return 0; /* already cached */
435 rc = opendir(ef, dir, &it);
438 while ((rc = readdir(ef, dir, &node, &it)) == 0)
443 current->next = node;
444 node->prev = current;
456 for (current = dir->child; current; current = node)
458 node = current->next;
465 dir->flags |= EXFAT_ATTRIB_CACHED;
469 static void tree_attach(struct exfat_node* dir, struct exfat_node* node)
474 dir->child->prev = node;
475 node->next = dir->child;
480 static void tree_detach(struct exfat_node* node)
483 node->prev->next = node->next;
484 else /* this is the first node in the list */
485 node->parent->child = node->next;
487 node->next->prev = node->prev;
493 static void reset_cache(struct exfat* ef, struct exfat_node* node)
497 struct exfat_node* p = node->child;
502 node->flags &= ~EXFAT_ATTRIB_CACHED;
503 if (node->references != 0)
505 char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
506 exfat_get_name(node, buffer, sizeof(buffer) - 1);
507 exfat_warn("non-zero reference counter (%d) for `%s'",
508 node->references, buffer);
510 while (node->references)
511 exfat_put_node(ef, node);
514 void exfat_reset_cache(struct exfat* ef)
516 reset_cache(ef, ef->root);
519 static void next_entry(struct exfat* ef, const struct exfat_node* parent,
520 cluster_t* cluster, off_t* offset)
522 *offset += sizeof(struct exfat_entry);
523 if (*offset % CLUSTER_SIZE(*ef->sb) == 0)
524 /* next cluster cannot be invalid */
525 *cluster = exfat_next_cluster(ef, parent, *cluster);
528 void exfat_flush_node(struct exfat* ef, struct exfat_node* node)
532 off_t meta1_offset, meta2_offset;
533 struct exfat_entry_meta1 meta1;
534 struct exfat_entry_meta2 meta2;
536 if (!(node->flags & EXFAT_ATTRIB_DIRTY))
537 return; /* no need to flush */
540 exfat_bug("unable to flush node to read-only FS");
542 if (node->parent == NULL)
543 return; /* do not flush unlinked node */
545 cluster = node->entry_cluster;
546 offset = node->entry_offset;
547 meta1_offset = co2o(ef, cluster, offset);
548 next_entry(ef, node->parent, &cluster, &offset);
549 meta2_offset = co2o(ef, cluster, offset);
551 exfat_pread(ef->dev, &meta1, sizeof(meta1), meta1_offset);
552 if (meta1.type != EXFAT_ENTRY_FILE)
553 exfat_bug("invalid type of meta1: 0x%hhx", meta1.type);
554 meta1.attrib = cpu_to_le16(node->flags);
555 exfat_unix2exfat(node->mtime, &meta1.mdate, &meta1.mtime, &meta1.mtime_cs);
556 exfat_unix2exfat(node->atime, &meta1.adate, &meta1.atime, NULL);
558 exfat_pread(ef->dev, &meta2, sizeof(meta2), meta2_offset);
559 if (meta2.type != EXFAT_ENTRY_FILE_INFO)
560 exfat_bug("invalid type of meta2: 0x%hhx", meta2.type);
561 meta2.size = meta2.real_size = cpu_to_le64(node->size);
562 meta2.start_cluster = cpu_to_le32(node->start_cluster);
563 meta2.flags = EXFAT_FLAG_ALWAYS1;
564 /* empty files must not be marked as contiguous */
565 if (node->size != 0 && IS_CONTIGUOUS(*node))
566 meta2.flags |= EXFAT_FLAG_CONTIGUOUS;
567 /* name hash remains unchanged, no need to recalculate it */
569 meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name);
571 exfat_pwrite(ef->dev, &meta1, sizeof(meta1), meta1_offset);
572 exfat_pwrite(ef->dev, &meta2, sizeof(meta2), meta2_offset);
574 node->flags &= ~EXFAT_ATTRIB_DIRTY;
577 static void erase_entry(struct exfat* ef, struct exfat_node* node)
579 cluster_t cluster = node->entry_cluster;
580 off_t offset = node->entry_offset;
581 int name_entries = DIV_ROUND_UP(utf16_length(node->name), EXFAT_ENAME_MAX);
584 entry_type = EXFAT_ENTRY_FILE & ~EXFAT_ENTRY_VALID;
585 exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset));
587 next_entry(ef, node->parent, &cluster, &offset);
588 entry_type = EXFAT_ENTRY_FILE_INFO & ~EXFAT_ENTRY_VALID;
589 exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset));
591 while (name_entries--)
593 next_entry(ef, node->parent, &cluster, &offset);
594 entry_type = EXFAT_ENTRY_FILE_NAME & ~EXFAT_ENTRY_VALID;
595 exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset));
599 static int shrink_directory(struct exfat* ef, struct exfat_node* dir,
600 off_t deleted_offset)
602 const struct exfat_node* node;
603 const struct exfat_node* last_node;
604 uint64_t entries = 0;
608 if (!(dir->flags & EXFAT_ATTRIB_DIR))
609 exfat_bug("attempted to shrink a file");
610 if (!(dir->flags & EXFAT_ATTRIB_CACHED))
611 exfat_bug("attempted to shrink uncached directory");
613 for (last_node = node = dir->child; node; node = node->next)
615 if (deleted_offset < node->entry_offset)
617 /* there are other entries after the removed one, no way to shrink
621 if (last_node->entry_offset < node->entry_offset)
627 /* offset of the last entry */
628 entries += last_node->entry_offset / sizeof(struct exfat_entry);
629 /* two subentries with meta info */
631 /* subentries with file name */
632 entries += DIV_ROUND_UP(utf16_length(last_node->name),
636 new_size = DIV_ROUND_UP(entries * sizeof(struct exfat_entry),
637 CLUSTER_SIZE(*ef->sb)) * CLUSTER_SIZE(*ef->sb);
638 if (new_size == 0) /* directory always has at least 1 cluster */
639 new_size = CLUSTER_SIZE(*ef->sb);
640 if (new_size == dir->size)
642 rc = exfat_truncate(ef, dir, new_size, true);
648 static int delete(struct exfat* ef, struct exfat_node* node)
650 struct exfat_node* parent = node->parent;
651 off_t deleted_offset = node->entry_offset;
654 exfat_get_node(parent);
655 erase_entry(ef, node);
656 exfat_update_mtime(parent);
658 rc = shrink_directory(ef, parent, deleted_offset);
659 exfat_put_node(ef, parent);
660 /* file clusters will be freed when node reference counter becomes 0 */
661 node->flags |= EXFAT_ATTRIB_UNLINKED;
665 int exfat_unlink(struct exfat* ef, struct exfat_node* node)
667 if (node->flags & EXFAT_ATTRIB_DIR)
669 return delete(ef, node);
672 int exfat_rmdir(struct exfat* ef, struct exfat_node* node)
674 if (!(node->flags & EXFAT_ATTRIB_DIR))
676 /* check that directory is empty */
677 exfat_cache_directory(ef, node);
680 return delete(ef, node);
683 static int grow_directory(struct exfat* ef, struct exfat_node* dir,
684 uint64_t asize, uint32_t difference)
686 return exfat_truncate(ef, dir,
687 DIV_ROUND_UP(asize + difference, CLUSTER_SIZE(*ef->sb))
688 * CLUSTER_SIZE(*ef->sb), true);
691 static int find_slot(struct exfat* ef, struct exfat_node* dir,
692 cluster_t* cluster, off_t* offset, int subentries)
696 const struct exfat_entry* entry;
699 rc = opendir(ef, dir, &it);
706 *cluster = it.cluster;
709 entry = get_entry_ptr(ef, &it);
710 if (entry->type & EXFAT_ENTRY_VALID)
714 if (contiguous == subentries)
715 break; /* suitable slot is found */
716 if (it.offset + sizeof(struct exfat_entry) >= dir->size)
718 rc = grow_directory(ef, dir, dir->size,
719 (subentries - contiguous) * sizeof(struct exfat_entry));
726 if (fetch_next_entry(ef, dir, &it) != 0)
736 static int write_entry(struct exfat* ef, struct exfat_node* dir,
737 const le16_t* name, cluster_t cluster, off_t offset, uint16_t attrib)
739 struct exfat_node* node;
740 struct exfat_entry_meta1 meta1;
741 struct exfat_entry_meta2 meta2;
742 const size_t name_length = utf16_length(name);
743 const int name_entries = DIV_ROUND_UP(name_length, EXFAT_ENAME_MAX);
746 node = allocate_node();
749 node->entry_cluster = cluster;
750 node->entry_offset = offset;
751 memcpy(node->name, name, name_length * sizeof(le16_t));
753 memset(&meta1, 0, sizeof(meta1));
754 meta1.type = EXFAT_ENTRY_FILE;
755 meta1.continuations = 1 + name_entries;
756 meta1.attrib = cpu_to_le16(attrib);
757 exfat_unix2exfat(time(NULL), &meta1.crdate, &meta1.crtime,
759 meta1.adate = meta1.mdate = meta1.crdate;
760 meta1.atime = meta1.mtime = meta1.crtime;
761 meta1.mtime_cs = meta1.crtime_cs; /* there is no atime_cs */
763 memset(&meta2, 0, sizeof(meta2));
764 meta2.type = EXFAT_ENTRY_FILE_INFO;
765 meta2.flags = EXFAT_FLAG_ALWAYS1;
766 meta2.name_length = name_length;
767 meta2.name_hash = exfat_calc_name_hash(ef, node->name);
768 meta2.start_cluster = cpu_to_le32(EXFAT_CLUSTER_FREE);
770 meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name);
772 exfat_pwrite(ef->dev, &meta1, sizeof(meta1), co2o(ef, cluster, offset));
773 next_entry(ef, dir, &cluster, &offset);
774 exfat_pwrite(ef->dev, &meta2, sizeof(meta2), co2o(ef, cluster, offset));
775 for (i = 0; i < name_entries; i++)
777 struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0};
778 memcpy(name_entry.name, node->name + i * EXFAT_ENAME_MAX,
779 MIN(EXFAT_ENAME_MAX, EXFAT_NAME_MAX - i * EXFAT_ENAME_MAX) *
781 next_entry(ef, dir, &cluster, &offset);
782 exfat_pwrite(ef->dev, &name_entry, sizeof(name_entry),
783 co2o(ef, cluster, offset));
786 init_node_meta1(node, &meta1);
787 init_node_meta2(node, &meta2);
789 tree_attach(dir, node);
790 exfat_update_mtime(dir);
794 static int create(struct exfat* ef, const char* path, uint16_t attrib)
796 struct exfat_node* dir;
797 struct exfat_node* existing;
798 cluster_t cluster = EXFAT_CLUSTER_BAD;
800 le16_t name[EXFAT_NAME_MAX + 1];
803 rc = exfat_split(ef, &dir, &existing, name, path);
806 if (existing != NULL)
808 exfat_put_node(ef, existing);
809 exfat_put_node(ef, dir);
813 rc = find_slot(ef, dir, &cluster, &offset,
814 2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX));
817 exfat_put_node(ef, dir);
820 rc = write_entry(ef, dir, name, cluster, offset, attrib);
821 exfat_put_node(ef, dir);
825 int exfat_mknod(struct exfat* ef, const char* path)
827 return create(ef, path, EXFAT_ATTRIB_ARCH);
830 int exfat_mkdir(struct exfat* ef, const char* path)
833 struct exfat_node* node;
835 rc = create(ef, path, EXFAT_ATTRIB_ARCH | EXFAT_ATTRIB_DIR);
838 rc = exfat_lookup(ef, &node, path);
841 /* directories always have at least one cluster */
842 rc = exfat_truncate(ef, node, CLUSTER_SIZE(*ef->sb), true);
846 exfat_put_node(ef, node);
849 exfat_put_node(ef, node);
853 static void rename_entry(struct exfat* ef, struct exfat_node* dir,
854 struct exfat_node* node, const le16_t* name, cluster_t new_cluster,
857 struct exfat_entry_meta1 meta1;
858 struct exfat_entry_meta2 meta2;
859 cluster_t old_cluster = node->entry_cluster;
860 off_t old_offset = node->entry_offset;
861 const size_t name_length = utf16_length(name);
862 const int name_entries = DIV_ROUND_UP(name_length, EXFAT_ENAME_MAX);
865 exfat_pread(ef->dev, &meta1, sizeof(meta1),
866 co2o(ef, old_cluster, old_offset));
867 next_entry(ef, node->parent, &old_cluster, &old_offset);
868 exfat_pread(ef->dev, &meta2, sizeof(meta2),
869 co2o(ef, old_cluster, old_offset));
870 meta1.continuations = 1 + name_entries;
871 meta2.name_hash = exfat_calc_name_hash(ef, name);
872 meta2.name_length = name_length;
873 meta1.checksum = exfat_calc_checksum(&meta1, &meta2, name);
875 erase_entry(ef, node);
877 node->entry_cluster = new_cluster;
878 node->entry_offset = new_offset;
880 exfat_pwrite(ef->dev, &meta1, sizeof(meta1),
881 co2o(ef, new_cluster, new_offset));
882 next_entry(ef, dir, &new_cluster, &new_offset);
883 exfat_pwrite(ef->dev, &meta2, sizeof(meta2),
884 co2o(ef, new_cluster, new_offset));
886 for (i = 0; i < name_entries; i++)
888 struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0};
889 memcpy(name_entry.name, name + i * EXFAT_ENAME_MAX,
890 EXFAT_ENAME_MAX * sizeof(le16_t));
891 next_entry(ef, dir, &new_cluster, &new_offset);
892 exfat_pwrite(ef->dev, &name_entry, sizeof(name_entry),
893 co2o(ef, new_cluster, new_offset));
896 memcpy(node->name, name, (EXFAT_NAME_MAX + 1) * sizeof(le16_t));
898 tree_attach(dir, node);
901 int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path)
903 struct exfat_node* node;
904 struct exfat_node* existing;
905 struct exfat_node* dir;
906 cluster_t cluster = EXFAT_CLUSTER_BAD;
908 le16_t name[EXFAT_NAME_MAX + 1];
911 rc = exfat_lookup(ef, &node, old_path);
915 rc = exfat_split(ef, &dir, &existing, name, new_path);
918 exfat_put_node(ef, node);
922 /* check that target is not a subdirectory of the source */
923 if (node->flags & EXFAT_ATTRIB_DIR)
925 struct exfat_node* p;
927 for (p = dir; p; p = p->parent)
930 if (existing != NULL)
931 exfat_put_node(ef, existing);
932 exfat_put_node(ef, dir);
933 exfat_put_node(ef, node);
938 if (existing != NULL)
940 /* remove target if it's not the same node as source */
941 if (existing != node)
943 if (existing->flags & EXFAT_ATTRIB_DIR)
945 if (node->flags & EXFAT_ATTRIB_DIR)
946 rc = exfat_rmdir(ef, existing);
952 if (!(node->flags & EXFAT_ATTRIB_DIR))
953 rc = exfat_unlink(ef, existing);
957 exfat_put_node(ef, existing);
960 exfat_put_node(ef, dir);
961 exfat_put_node(ef, node);
966 exfat_put_node(ef, existing);
969 rc = find_slot(ef, dir, &cluster, &offset,
970 2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX));
973 exfat_put_node(ef, dir);
974 exfat_put_node(ef, node);
977 rename_entry(ef, dir, node, name, cluster, offset);
978 exfat_put_node(ef, dir);
979 exfat_put_node(ef, node);
983 void exfat_utimes(struct exfat_node* node, const struct timespec tv[2])
985 node->atime = tv[0].tv_sec;
986 node->mtime = tv[1].tv_sec;
987 node->flags |= EXFAT_ATTRIB_DIRTY;
990 void exfat_update_atime(struct exfat_node* node)
992 node->atime = time(NULL);
993 node->flags |= EXFAT_ATTRIB_DIRTY;
996 void exfat_update_mtime(struct exfat_node* node)
998 node->mtime = time(NULL);
999 node->flags |= EXFAT_ATTRIB_DIRTY;
1002 const char* exfat_get_label(struct exfat* ef)
1007 static int find_label(struct exfat* ef, cluster_t* cluster, off_t* offset)
1012 rc = opendir(ef, ef->root, &it);
1018 if (it.offset >= ef->root->size)
1024 if (get_entry_ptr(ef, &it)->type == EXFAT_ENTRY_LABEL)
1026 *cluster = it.cluster;
1027 *offset = it.offset;
1032 if (fetch_next_entry(ef, ef->root, &it) != 0)
1040 int exfat_set_label(struct exfat* ef, const char* label)
1042 le16_t label_utf16[EXFAT_ENAME_MAX + 1];
1046 struct exfat_entry_label entry;
1048 memset(label_utf16, 0, sizeof(label_utf16));
1049 rc = utf8_to_utf16(label_utf16, label, EXFAT_ENAME_MAX, strlen(label));
1053 rc = find_label(ef, &cluster, &offset);
1055 rc = find_slot(ef, ef->root, &cluster, &offset, 1);
1059 entry.type = EXFAT_ENTRY_LABEL;
1060 entry.length = utf16_length(label_utf16);
1061 memcpy(entry.name, label_utf16, sizeof(entry.name));
1062 if (entry.length == 0)
1063 entry.type ^= EXFAT_ENTRY_VALID;
1065 exfat_pwrite(ef->dev, &entry, sizeof(struct exfat_entry_label),
1066 co2o(ef, cluster, offset));
1067 strcpy(ef->label, label);