3 * exFAT file system implementation library.
5 * Created by Andrew Nayenko on 09.10.09.
6 * This software is distributed under the GNU General Public License
7 * version 3 or any later.
15 /* on-disk nodes iterator */
24 struct exfat_node* exfat_get_node(struct exfat_node* node)
26 /* if we switch to multi-threaded mode we will need atomic
27 increment here and atomic decrement in exfat_put_node() */
32 void exfat_put_node(struct exfat* ef, struct exfat_node* node)
34 if (--node->references < 0)
36 char buffer[EXFAT_NAME_MAX + 1];
37 exfat_get_name(node, buffer, EXFAT_NAME_MAX);
38 exfat_bug("reference counter of `%s' is below zero", buffer);
41 if (node->references == 0)
43 if (node->flags & EXFAT_ATTRIB_DIRTY)
44 exfat_flush_node(ef, node);
45 if (node->flags & EXFAT_ATTRIB_UNLINKED)
47 /* free all clusters and node structure itself */
48 exfat_truncate(ef, node, 0);
56 static int opendir(struct exfat* ef, const struct exfat_node* dir,
59 if (!(dir->flags & EXFAT_ATTRIB_DIR))
60 exfat_bug("`%s' is not a directory", dir->name);
61 it->cluster = dir->start_cluster;
63 it->contiguous = IS_CONTIGUOUS(*dir);
64 it->chunk = malloc(CLUSTER_SIZE(*ef->sb));
65 if (it->chunk == NULL)
67 exfat_error("out of memory");
70 exfat_read_raw(it->chunk, CLUSTER_SIZE(*ef->sb),
71 exfat_c2o(ef, it->cluster), ef->fd);
75 static void closedir(struct iterator* it)
84 static int fetch_next_entry(struct exfat* ef, const struct exfat_node* parent,
87 /* move iterator to the next entry in the directory */
88 it->offset += sizeof(struct exfat_entry);
89 /* fetch the next cluster if needed */
90 if ((it->offset & (CLUSTER_SIZE(*ef->sb) - 1)) == 0)
92 it->cluster = exfat_next_cluster(ef, parent, it->cluster);
93 if (CLUSTER_INVALID(it->cluster))
95 exfat_error("invalid cluster while reading directory");
98 exfat_read_raw(it->chunk, CLUSTER_SIZE(*ef->sb),
99 exfat_c2o(ef, it->cluster), ef->fd);
104 static struct exfat_node* allocate_node(void)
106 struct exfat_node* node = malloc(sizeof(struct exfat_node));
109 exfat_error("failed to allocate node");
112 memset(node, 0, sizeof(struct exfat_node));
116 static void init_node_meta1(struct exfat_node* node,
117 const struct exfat_file* meta1)
119 node->flags = le16_to_cpu(meta1->attrib);
120 node->mtime = exfat_exfat2unix(meta1->mdate, meta1->mtime);
121 node->atime = exfat_exfat2unix(meta1->adate, meta1->atime);
124 static void init_node_meta2(struct exfat_node* node,
125 const struct exfat_file_info* meta2)
127 node->size = le64_to_cpu(meta2->size);
128 node->start_cluster = le32_to_cpu(meta2->start_cluster);
129 node->fptr_cluster = node->start_cluster;
130 if (meta2->flag == EXFAT_FLAG_CONTIGUOUS)
131 node->flags |= EXFAT_ATTRIB_CONTIGUOUS;
135 * Reads one entry in directory at position pointed by iterator and fills
138 static int readdir(struct exfat* ef, const struct exfat_node* parent,
139 struct exfat_node** node, struct iterator* it)
141 const struct exfat_entry* entry;
142 const struct exfat_file* file;
143 const struct exfat_file_info* file_info;
144 const struct exfat_file_name* file_name;
145 const struct exfat_upcase* upcase;
146 const struct exfat_bitmap* bitmap;
147 const struct exfat_label* label;
148 uint8_t continuations = 0;
149 le16_t* namep = NULL;
150 uint16_t reference_checksum = 0;
151 uint16_t actual_checksum = 0;
157 /* every directory (even empty one) occupies at least one cluster and
158 must contain EOD entry */
159 entry = (const struct exfat_entry*)
160 (it->chunk + it->offset % CLUSTER_SIZE(*ef->sb));
164 case EXFAT_ENTRY_EOD:
165 if (continuations != 0)
167 exfat_error("expected %hhu continuations before EOD",
171 return -ENOENT; /* that's OK, means end of directory */
173 case EXFAT_ENTRY_FILE:
174 if (continuations != 0)
176 exfat_error("expected %hhu continuations before new entry",
180 file = (const struct exfat_file*) entry;
181 continuations = file->continuations;
182 /* each file entry must have at least 2 continuations:
184 if (continuations < 2)
186 exfat_error("too few continuations (%hhu)", continuations);
189 reference_checksum = le16_to_cpu(file->checksum);
190 actual_checksum = exfat_start_checksum(file);
191 *node = allocate_node();
194 /* new node has zero reference counter */
195 (*node)->entry_cluster = it->cluster;
196 (*node)->entry_offset = it->offset % CLUSTER_SIZE(*ef->sb);
197 init_node_meta1(*node, file);
198 namep = (*node)->name;
201 case EXFAT_ENTRY_FILE_INFO:
202 if (continuations < 2)
204 exfat_error("unexpected continuation (%hhu)",
208 file_info = (const struct exfat_file_info*) entry;
209 init_node_meta2(*node, file_info);
210 actual_checksum = exfat_add_checksum(entry, actual_checksum);
211 /* There are two fields that contain file size. Maybe they plan
212 to add compression support in the future and one of those
213 fields is visible (uncompressed) size and the other is real
214 (compressed) size. Anyway, currently it looks like exFAT does
215 not support compression and both fields must be equal. */
216 if (le64_to_cpu(file_info->real_size) != (*node)->size)
218 exfat_error("real size does not equal to size "
219 "(%"PRIu64" != %"PRIu64")",
220 le64_to_cpu(file_info->real_size), (*node)->size);
223 /* directories must be aligned on at cluster boundary */
224 if (((*node)->flags & EXFAT_ATTRIB_DIR) &&
225 (*node)->size % CLUSTER_SIZE(*ef->sb) != 0)
227 char buffer[EXFAT_NAME_MAX + 1];
229 exfat_get_name(*node, buffer, EXFAT_NAME_MAX);
230 exfat_error("directory `%s' has invalid size %"PRIu64" bytes",
231 buffer, (*node)->size);
237 case EXFAT_ENTRY_FILE_NAME:
238 if (continuations == 0)
240 exfat_error("unexpected continuation");
243 file_name = (const struct exfat_file_name*) entry;
244 actual_checksum = exfat_add_checksum(entry, actual_checksum);
246 memcpy(namep, file_name->name, EXFAT_ENAME_MAX * sizeof(le16_t));
247 namep += EXFAT_ENAME_MAX;
248 if (--continuations == 0)
250 if (actual_checksum != reference_checksum)
252 exfat_error("invalid checksum (0x%hx != 0x%hx)",
253 actual_checksum, reference_checksum);
256 if (fetch_next_entry(ef, parent, it) != 0)
258 return 0; /* entry completed */
262 case EXFAT_ENTRY_UPCASE:
263 if (ef->upcase != NULL)
265 upcase = (const struct exfat_upcase*) entry;
266 if (CLUSTER_INVALID(le32_to_cpu(upcase->start_cluster)))
268 exfat_error("invalid cluster in upcase table");
271 if (le64_to_cpu(upcase->size) == 0 ||
272 le64_to_cpu(upcase->size) > 0xffff * sizeof(uint16_t) ||
273 le64_to_cpu(upcase->size) % sizeof(uint16_t) != 0)
275 exfat_error("bad upcase table size (%"PRIu64" bytes)",
276 le64_to_cpu(upcase->size));
279 ef->upcase = malloc(le64_to_cpu(upcase->size));
280 if (ef->upcase == NULL)
282 exfat_error("failed to allocate upcase table (%"PRIu64" bytes)",
283 le64_to_cpu(upcase->size));
286 ef->upcase_chars = le64_to_cpu(upcase->size) / sizeof(le16_t);
288 exfat_read_raw(ef->upcase, le64_to_cpu(upcase->size),
289 exfat_c2o(ef, le32_to_cpu(upcase->start_cluster)), ef->fd);
292 case EXFAT_ENTRY_BITMAP:
293 bitmap = (const struct exfat_bitmap*) entry;
294 if (CLUSTER_INVALID(le32_to_cpu(bitmap->start_cluster)))
296 exfat_error("invalid cluster in clusters bitmap");
299 ef->cmap.size = le32_to_cpu(ef->sb->cluster_count) -
300 EXFAT_FIRST_DATA_CLUSTER;
301 if (le64_to_cpu(bitmap->size) != (ef->cmap.size + 7) / 8)
303 exfat_error("invalid bitmap size: %"PRIu64" (expected %u)",
304 le64_to_cpu(bitmap->size), (ef->cmap.size + 7) / 8);
307 ef->cmap.start_cluster = le32_to_cpu(bitmap->start_cluster);
308 /* FIXME bitmap can be rather big, up to 512 MB */
309 ef->cmap.chunk_size = ef->cmap.size;
310 ef->cmap.chunk = malloc(le64_to_cpu(bitmap->size));
311 if (ef->cmap.chunk == NULL)
313 exfat_error("failed to allocate clusters map chunk "
314 "(%"PRIu64" bytes)", le64_to_cpu(bitmap->size));
318 exfat_read_raw(ef->cmap.chunk, le64_to_cpu(bitmap->size),
319 exfat_c2o(ef, ef->cmap.start_cluster), ef->fd);
322 case EXFAT_ENTRY_LABEL:
323 label = (const struct exfat_label*) entry;
324 if (label->length > EXFAT_ENAME_MAX)
326 exfat_error("too long label (%hhu chars)", label->length);
332 if (entry->type & EXFAT_ENTRY_VALID)
334 exfat_error("unknown entry type 0x%hhu", entry->type);
340 if (fetch_next_entry(ef, parent, it) != 0)
343 /* we never reach here */
351 int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir)
355 struct exfat_node* node;
356 struct exfat_node* current = NULL;
358 if (dir->flags & EXFAT_ATTRIB_CACHED)
359 return 0; /* already cached */
361 rc = opendir(ef, dir, &it);
364 while ((rc = readdir(ef, dir, &node, &it)) == 0)
369 current->next = node;
370 node->prev = current;
382 for (current = dir->child; current; current = node)
384 node = current->next;
391 dir->flags |= EXFAT_ATTRIB_CACHED;
395 static void reset_cache(struct exfat* ef, struct exfat_node* node)
397 struct exfat_node* child;
398 struct exfat_node* next;
400 for (child = node->child; child; child = next)
402 reset_cache(ef, child);
406 if (node->references != 0)
408 char buffer[EXFAT_NAME_MAX + 1];
409 exfat_get_name(node, buffer, EXFAT_NAME_MAX);
410 exfat_warn("non-zero reference counter (%d) for `%s'",
411 node->references, buffer);
413 while (node->references--)
414 exfat_put_node(ef, node);
416 node->flags &= ~EXFAT_ATTRIB_CACHED;
419 void exfat_reset_cache(struct exfat* ef)
421 reset_cache(ef, ef->root);
424 void next_entry(struct exfat* ef, const struct exfat_node* parent,
425 cluster_t* cluster, off_t* offset)
427 if (*offset + sizeof(struct exfat_entry) == CLUSTER_SIZE(*ef->sb))
429 /* next cluster cannot be invalid */
430 *cluster = exfat_next_cluster(ef, parent, *cluster);
434 *offset += sizeof(struct exfat_entry);
438 void exfat_flush_node(struct exfat* ef, struct exfat_node* node)
442 off_t meta1_offset, meta2_offset;
443 struct exfat_file meta1;
444 struct exfat_file_info meta2;
446 if (node->parent == NULL)
447 return; /* do not flush unlinked node */
449 cluster = node->entry_cluster;
450 offset = node->entry_offset;
451 meta1_offset = exfat_c2o(ef, cluster) + offset;
452 next_entry(ef, node->parent, &cluster, &offset);
453 meta2_offset = exfat_c2o(ef, cluster) + offset;
455 exfat_read_raw(&meta1, sizeof(meta1), meta1_offset, ef->fd);
456 if (meta1.type != EXFAT_ENTRY_FILE)
457 exfat_bug("invalid type of meta1: 0x%hhx", meta1.type);
458 meta1.attrib = cpu_to_le16(node->flags);
459 exfat_unix2exfat(node->mtime, &meta1.mdate, &meta1.mtime);
460 exfat_unix2exfat(node->atime, &meta1.adate, &meta1.atime);
462 exfat_read_raw(&meta2, sizeof(meta2), meta2_offset, ef->fd);
463 if (meta2.type != EXFAT_ENTRY_FILE_INFO)
464 exfat_bug("invalid type of meta2: 0x%hhx", meta2.type);
465 meta2.size = meta2.real_size = cpu_to_le64(node->size);
466 meta2.start_cluster = cpu_to_le32(node->start_cluster);
467 /* empty files must be marked as fragmented */
468 if (node->size != 0 && IS_CONTIGUOUS(*node))
469 meta2.flag = EXFAT_FLAG_CONTIGUOUS;
471 meta2.flag = EXFAT_FLAG_FRAGMENTED;
472 /* FIXME name hash */
474 meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name);
476 exfat_write_raw(&meta1, sizeof(meta1), meta1_offset, ef->fd);
477 exfat_write_raw(&meta2, sizeof(meta2), meta2_offset, ef->fd);
479 node->flags &= ~EXFAT_ATTRIB_DIRTY;
482 static void erase_entry(struct exfat* ef, struct exfat_node* node)
484 cluster_t cluster = node->entry_cluster;
485 off_t offset = node->entry_offset;
486 int name_entries = DIV_ROUND_UP(utf16_length(node->name), EXFAT_ENAME_MAX);
489 entry_type = EXFAT_ENTRY_FILE & ~EXFAT_ENTRY_VALID;
490 exfat_write_raw(&entry_type, 1, exfat_c2o(ef, cluster) + offset, ef->fd);
492 next_entry(ef, node->parent, &cluster, &offset);
493 entry_type = EXFAT_ENTRY_FILE_INFO & ~EXFAT_ENTRY_VALID;
494 exfat_write_raw(&entry_type, 1, exfat_c2o(ef, cluster) + offset, ef->fd);
496 while (name_entries--)
498 next_entry(ef, node->parent, &cluster, &offset);
499 entry_type = EXFAT_ENTRY_FILE_NAME & ~EXFAT_ENTRY_VALID;
500 exfat_write_raw(&entry_type, 1, exfat_c2o(ef, cluster) + offset,
505 static void delete(struct exfat* ef, struct exfat_node* node)
507 erase_entry(ef, node);
509 node->prev->next = node->next;
510 else /* this is the first node in the list */
511 node->parent->child = node->next;
513 node->next->prev = node->prev;
517 /* file clusters will be freed when node reference counter becomes 0 */
518 node->flags |= EXFAT_ATTRIB_UNLINKED;
521 int exfat_unlink(struct exfat* ef, struct exfat_node* node)
523 if (node->flags & EXFAT_ATTRIB_DIR)
529 int exfat_rmdir(struct exfat* ef, struct exfat_node* node)
531 if (!(node->flags & EXFAT_ATTRIB_DIR))
533 /* check that directory is empty */
534 exfat_cache_directory(ef, node);