struct exfat_node* parent;
struct exfat_node* node;
struct exfat_iterator it;
+ int rc;
char subpath[EXFAT_NAME_MAX + 1];
if (exfat_lookup(ef, &parent, path) != 0)
if (!(parent->flags & EXFAT_ATTRIB_DIR))
exfat_bug("`%s' is not a directory (0x%x)", path, parent->flags);
- exfat_opendir(parent, &it);
- while (exfat_readdir(ef, parent, &node, &it) == 0)
+ rc = exfat_opendir(ef, parent, &it);
+ if (rc != 0)
+ {
+ exfat_put_node(parent);
+ exfat_error("failed to open directory `%s'", path);
+ return;
+ }
+ while ((node = exfat_readdir(ef, &it)))
{
strcpy(subpath, path);
strcat(subpath, "/");
if (!(parent->flags & EXFAT_ATTRIB_DIR))
{
exfat_put_node(parent);
+ exfat_error("`%s' is not a directory (0x%x)", path, parent->flags);
return -ENOTDIR;
}
filler(buffer, ".", NULL, 0);
filler(buffer, "..", NULL, 0);
- exfat_opendir(parent, &it);
- while (exfat_readdir(&ef, parent, &node, &it) == 0)
+ rc = exfat_opendir(&ef, parent, &it);
+ if (rc != 0)
+ {
+ exfat_put_node(parent);
+ exfat_error("failed to open directory `%s'", path);
+ return rc;
+ }
+ while ((node = exfat_readdir(&ef, &it)))
{
exfat_get_name(node, name, EXFAT_NAME_MAX);
exfat_debug("[fuse_exfat_readdir] %s: %s, %llu bytes, cluster %u",
- name, IS_CONTIGUOUS(node) ? "contiguous" : "fragmented",
+ name, IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
node->size, node->start_cluster);
filler(buffer, name, NULL, 0);
exfat_put_node(node);
#define EXFAT_NAME_MAX 256
#define EXFAT_ATTRIB_CONTIGUOUS 0x10000
+#define EXFAT_ATTRIB_CACHED 0x20000
#define IS_CONTIGUOUS(node) (((node).flags & EXFAT_ATTRIB_CONTIGUOUS) != 0)
#define BLOCK_SIZE(sb) (1 << (sb).block_bits)
#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb).bpc_bits)
#define CLUSTER_INVALID(c) ((c) == EXFAT_CLUSTER_BAD || (c) == EXFAT_CLUSTER_END)
-struct exfat
-{
- struct exfat_super_block* sb;
- int fd;
- uint64_t rootdir_size;
- le16_t* upcase;
- size_t upcase_chars;
-};
-
struct exfat_node
{
+ struct exfat_node* child;
+ struct exfat_node* next;
+ struct exfat_node* prev;
+
+ int references;
cluster_t start_cluster;
int flags;
uint64_t size;
le16_t name[EXFAT_NAME_MAX + 1];
};
+struct exfat
+{
+ struct exfat_super_block* sb;
+ int fd;
+ uint64_t rootdir_size;
+ le16_t* upcase;
+ size_t upcase_chars;
+ struct exfat_node* root;
+};
+
+/* in-core nodes iterator */
struct exfat_iterator
{
- cluster_t cluster;
- off_t offset;
- int contiguous;
- char* chunk;
+ struct exfat_node* parent;
+ struct exfat_node* current;
};
extern int exfat_errors;
ssize_t exfat_read(const struct exfat* ef, const struct exfat_node* node,
void* buffer, size_t size, off_t offset);
-void exfat_put_node(struct exfat_node* node);
-void exfat_opendir(const struct exfat_node* node, struct exfat_iterator* it);
+int exfat_opendir(struct exfat* ef, struct exfat_node* dir,
+ struct exfat_iterator* it);
void exfat_closedir(struct exfat_iterator* it);
-int exfat_readdir(struct exfat* ef, const struct exfat_node* parent,
- struct exfat_node** node, struct exfat_iterator* it);
+struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it);
int exfat_lookup(struct exfat* ef, struct exfat_node** node,
const char* path);
int utf8_to_utf16(le16_t* output, const char* input, size_t outsize,
size_t insize);
+struct exfat_node* exfat_get_node(struct exfat_node* node);
+void exfat_put_node(struct exfat_node* node);
+int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir);
+void exfat_reset_cache(struct exfat* ef);
+
#endif /* ifndef EXFAT_H_INCLUDED */
#include <errno.h>
#include <inttypes.h>
-void exfat_put_node(struct exfat_node* node)
+int exfat_opendir(struct exfat* ef, struct exfat_node* dir,
+ struct exfat_iterator* it)
{
- free(node);
-}
+ int rc;
-void exfat_opendir(const struct exfat_node* node, struct exfat_iterator* it)
-{
- if (!(node->flags & EXFAT_ATTRIB_DIR))
- exfat_bug("`%s' is not a directory", node->name);
- it->cluster = node->start_cluster;
- it->offset = 0;
- it->contiguous = IS_CONTIGUOUS(*node);
- it->chunk = NULL;
+ exfat_get_node(dir);
+ it->parent = dir;
+ it->current = NULL;
+ rc = exfat_cache_directory(ef, dir);
+ if (rc != 0)
+ exfat_put_node(dir);
+ return rc;
}
void exfat_closedir(struct exfat_iterator* it)
{
- it->cluster = 0;
- it->offset = 0;
- it->contiguous = 0;
- free(it->chunk);
- it->chunk = NULL;
+ exfat_put_node(it->parent);
+ it->parent = NULL;
+ it->current = NULL;
}
-/*
- * Reads one entry in directory at position pointed by iterator and fills
- * node structure.
- */
-int exfat_readdir(struct exfat* ef, const struct exfat_node* parent,
- struct exfat_node** node, struct exfat_iterator* it)
+struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it)
{
- const struct exfat_entry* entry;
- const struct exfat_file* file;
- const struct exfat_file_info* file_info;
- const struct exfat_file_name* file_name;
- const struct exfat_upcase* upcase;
- const struct exfat_bitmap* bitmap;
- const struct exfat_label* label;
- uint8_t continuations = 0;
- le16_t* namep = NULL;
-
- *node = NULL;
-
- if (it->chunk == NULL)
- {
- it->chunk = malloc(CLUSTER_SIZE(*ef->sb));
- if (it->chunk == NULL)
- {
- exfat_error("out of memory");
- return -ENOMEM;
- }
- exfat_read_raw(it->chunk, CLUSTER_SIZE(*ef->sb),
- exfat_c2o(ef, it->cluster), ef->fd);
- }
-
- for (;;)
- {
- /* every directory (even empty one) occupies at least one cluster and
- must contain EOD entry */
- entry = (const struct exfat_entry*)
- (it->chunk + it->offset % CLUSTER_SIZE(*ef->sb));
- /* move iterator to the next entry in the directory */
- it->offset += sizeof(struct exfat_entry);
-
- switch (entry->type)
- {
- case EXFAT_ENTRY_EOD:
- if (continuations != 0)
- {
- exfat_error("expected %hhu continuations before EOD",
- continuations);
- goto error;
- }
- return -ENOENT; /* that's OK, means end of directory */
-
- case EXFAT_ENTRY_FILE:
- if (continuations != 0)
- {
- exfat_error("expected %hhu continuations before new entry",
- continuations);
- goto error;
- }
- file = (const struct exfat_file*) entry;
- continuations = file->continuations;
- /* each file entry must have at least 2 continuations:
- info and name */
- if (continuations < 2)
- {
- exfat_error("too few continuations (%hhu)", continuations);
- return -EIO;
- }
- *node = malloc(sizeof(struct exfat_node));
- if (*node == NULL)
- {
- exfat_error("failed to allocate node");
- return -ENOMEM;
- }
- memset(*node, 0, sizeof(struct exfat_node));
- (*node)->flags = le16_to_cpu(file->attrib);
- (*node)->mtime = exfat_exfat2unix(file->mdate, file->mtime);
- (*node)->atime = exfat_exfat2unix(file->adate, file->atime);
- namep = (*node)->name;
- break;
-
- case EXFAT_ENTRY_FILE_INFO:
- if (continuations < 2)
- {
- exfat_error("unexpected continuation (%hhu)",
- continuations);
- goto error;
- }
- file_info = (const struct exfat_file_info*) entry;
- (*node)->size = le64_to_cpu(file_info->size);
- (*node)->start_cluster = le32_to_cpu(file_info->start_cluster);
- if (file_info->flag == EXFAT_FLAG_CONTIGUOUS)
- (*node)->flags |= EXFAT_ATTRIB_CONTIGUOUS;
- --continuations;
- break;
-
- case EXFAT_ENTRY_FILE_NAME:
- if (continuations == 0)
- {
- exfat_error("unexpected continuation");
- goto error;
- }
- file_name = (const struct exfat_file_name*) entry;
- memcpy(namep, file_name->name, EXFAT_ENAME_MAX * sizeof(le16_t));
- namep += EXFAT_ENAME_MAX;
- if (--continuations == 0)
- return 0; /* entry completed */
- break;
-
- case EXFAT_ENTRY_UPCASE:
- if (ef->upcase != NULL)
- break;
- upcase = (const struct exfat_upcase*) entry;
- if (CLUSTER_INVALID(le32_to_cpu(upcase->start_cluster)))
- {
- exfat_error("invalid cluster in upcase table");
- return -EIO;
- }
- if (le64_to_cpu(upcase->size) == 0 ||
- le64_to_cpu(upcase->size) > 0xffff * sizeof(uint16_t) ||
- le64_to_cpu(upcase->size) % sizeof(uint16_t) != 0)
- {
- exfat_error("bad upcase table size (%"PRIu64" bytes)",
- le64_to_cpu(upcase->size));
- return -EIO;
- }
- ef->upcase = malloc(le64_to_cpu(upcase->size));
- if (ef->upcase == NULL)
- {
- exfat_error("failed to allocate upcase table (%"PRIu64" bytes)",
- le64_to_cpu(upcase->size));
- return -ENOMEM;
- }
- ef->upcase_chars = le64_to_cpu(upcase->size) / sizeof(le16_t);
-
- exfat_read_raw(ef->upcase, le64_to_cpu(upcase->size),
- exfat_c2o(ef, le32_to_cpu(upcase->start_cluster)), ef->fd);
- break;
-
- case EXFAT_ENTRY_BITMAP:
- bitmap = (const struct exfat_bitmap*) entry;
- if (CLUSTER_INVALID(le32_to_cpu(bitmap->start_cluster)))
- {
- exfat_error("invalid cluster in clusters bitmap");
- return -EIO;
- }
- if (le64_to_cpu(bitmap->size) !=
- ((le32_to_cpu(ef->sb->cluster_count) + 7) / 8))
- {
- exfat_error("invalid bitmap size: %"PRIu64" (expected %u)",
- le64_to_cpu(bitmap->size),
- (le32_to_cpu(ef->sb->cluster_count) + 7) / 8);
- return -EIO;
- }
- break;
-
- case EXFAT_ENTRY_LABEL:
- label = (const struct exfat_label*) entry;
- if (label->length > EXFAT_ENAME_MAX)
- {
- exfat_error("too long label (%hhu chars)", label->length);
- return -EIO;
- }
- break;
-
- default:
- if (entry->type & EXFAT_ENTRY_VALID)
- {
- exfat_error("unknown entry type 0x%hhu", entry->type);
- goto error;
- }
- break;
- }
-
- /* fetch the next cluster if needed */
- if ((it->offset & (CLUSTER_SIZE(*ef->sb) - 1)) == 0)
- {
- it->cluster = exfat_next_cluster(ef, it->cluster, it->contiguous);
- if (CLUSTER_INVALID(it->cluster))
- {
- exfat_error("invalid cluster while reading directory");
- goto error;
- }
- exfat_read_raw(it->chunk, CLUSTER_SIZE(*ef->sb),
- exfat_c2o(ef, it->cluster), ef->fd);
- }
- }
- /* we never reach here */
+ if (it->current == NULL)
+ it->current = it->parent->child;
+ else
+ it->current = it->current->next;
-error:
- if (*node != NULL)
- {
- free(*node);
- *node = NULL;
- }
- return -EIO;
+ if (it->current != NULL)
+ return exfat_get_node(it->current);
+ else
+ return NULL;
}
static int compare_char(struct exfat* ef, uint16_t a, uint16_t b)
return compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b));
}
-static int lookup_name(struct exfat* ef, const struct exfat_node* parent,
+static int lookup_name(struct exfat* ef, struct exfat_node* parent,
struct exfat_node** node, const char* name, size_t n)
{
struct exfat_iterator it;
if (rc != 0)
return rc;
- exfat_opendir(parent, &it);
- while (exfat_readdir(ef, parent, node, &it) == 0)
+ rc = exfat_opendir(ef, parent, &it);
+ if (rc != 0)
+ return rc;
+ while ((*node = exfat_readdir(ef, &it)))
{
if (compare_name(ef, buffer, (*node)->name) == 0)
{
const char* p;
size_t n;
- parent = *node = malloc(sizeof(struct exfat_node));
- if (parent == NULL)
- {
- exfat_error("failed to allocate root node");
- return -ENOMEM;
- }
-
/* start from the root directory */
- parent->flags = EXFAT_ATTRIB_DIR;
- parent->size = ef->rootdir_size;
- parent->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
- parent->name[0] = cpu_to_le16('\0');
- /* exFAT does not have time attributes for the root directory */
- parent->mtime = 0;
- parent->atime = 0;
-
+ parent = *node = exfat_get_node(ef->root);
for (p = path; (n = get_comp(p, &p)); p += n)
{
if (n == 1 && *p == '.') /* skip "." component */
continue;
if (lookup_name(ef, parent, node, p, n) != 0)
+ {
+ exfat_put_node(parent);
return -ENOENT;
+ }
exfat_put_node(parent);
parent = *node;
}
--- /dev/null
+/*
+ * node.c
+ * exFAT file system implementation library.
+ *
+ * Created by Andrew Nayenko on 09.10.09.
+ * This software is distributed under the GNU General Public License
+ * version 3 or any later.
+ */
+
+#include "exfat.h"
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+
+/* on-disk nodes iterator */
+struct iterator
+{
+ cluster_t cluster;
+ off_t offset;
+ int contiguous;
+ char* chunk;
+};
+
+struct exfat_node* exfat_get_node(struct exfat_node* node)
+{
+ /* if we switch to multi-threaded mode we will need atomic
+ increment here and atomic decrement in exfat_put_node() */
+ node->references++;
+ return node;
+}
+
+void exfat_put_node(struct exfat_node* node)
+{
+ if (--node->references < 0)
+ {
+ char buffer[EXFAT_NAME_MAX + 1];
+ exfat_get_name(node, buffer, EXFAT_NAME_MAX);
+ exfat_bug("reference counter of `%s' is below zero", buffer);
+ }
+}
+
+static void opendir(const struct exfat_node* dir, struct iterator* it)
+{
+ if (!(dir->flags & EXFAT_ATTRIB_DIR))
+ exfat_bug("`%s' is not a directory", dir->name);
+ it->cluster = dir->start_cluster;
+ it->offset = 0;
+ it->contiguous = IS_CONTIGUOUS(*dir);
+ it->chunk = NULL;
+}
+
+static void closedir(struct iterator* it)
+{
+ it->cluster = 0;
+ it->offset = 0;
+ it->contiguous = 0;
+ free(it->chunk);
+ it->chunk = NULL;
+}
+
+/*
+ * Reads one entry in directory at position pointed by iterator and fills
+ * node structure.
+ */
+static int readdir(struct exfat* ef, const struct exfat_node* parent,
+ struct exfat_node** node, struct iterator* it)
+{
+ const struct exfat_entry* entry;
+ const struct exfat_file* file;
+ const struct exfat_file_info* file_info;
+ const struct exfat_file_name* file_name;
+ const struct exfat_upcase* upcase;
+ const struct exfat_bitmap* bitmap;
+ const struct exfat_label* label;
+ uint8_t continuations = 0;
+ le16_t* namep = NULL;
+
+ *node = NULL;
+
+ if (it->chunk == NULL)
+ {
+ it->chunk = malloc(CLUSTER_SIZE(*ef->sb));
+ if (it->chunk == NULL)
+ {
+ exfat_error("out of memory");
+ return -ENOMEM;
+ }
+ exfat_read_raw(it->chunk, CLUSTER_SIZE(*ef->sb),
+ exfat_c2o(ef, it->cluster), ef->fd);
+ }
+
+ for (;;)
+ {
+ /* every directory (even empty one) occupies at least one cluster and
+ must contain EOD entry */
+ entry = (const struct exfat_entry*)
+ (it->chunk + it->offset % CLUSTER_SIZE(*ef->sb));
+ /* move iterator to the next entry in the directory */
+ it->offset += sizeof(struct exfat_entry);
+
+ switch (entry->type)
+ {
+ case EXFAT_ENTRY_EOD:
+ if (continuations != 0)
+ {
+ exfat_error("expected %hhu continuations before EOD",
+ continuations);
+ goto error;
+ }
+ return -ENOENT; /* that's OK, means end of directory */
+
+ case EXFAT_ENTRY_FILE:
+ if (continuations != 0)
+ {
+ exfat_error("expected %hhu continuations before new entry",
+ continuations);
+ goto error;
+ }
+ file = (const struct exfat_file*) entry;
+ continuations = file->continuations;
+ /* each file entry must have at least 2 continuations:
+ info and name */
+ if (continuations < 2)
+ {
+ exfat_error("too few continuations (%hhu)", continuations);
+ return -EIO;
+ }
+ *node = malloc(sizeof(struct exfat_node));
+ if (*node == NULL)
+ {
+ exfat_error("failed to allocate node");
+ return -ENOMEM;
+ }
+ memset(*node, 0, sizeof(struct exfat_node));
+ /* new node has zero reference counter */
+ (*node)->flags = le16_to_cpu(file->attrib);
+ (*node)->mtime = exfat_exfat2unix(file->mdate, file->mtime);
+ (*node)->atime = exfat_exfat2unix(file->adate, file->atime);
+ namep = (*node)->name;
+ break;
+
+ case EXFAT_ENTRY_FILE_INFO:
+ if (continuations < 2)
+ {
+ exfat_error("unexpected continuation (%hhu)",
+ continuations);
+ goto error;
+ }
+ file_info = (const struct exfat_file_info*) entry;
+ (*node)->size = le64_to_cpu(file_info->size);
+ (*node)->start_cluster = le32_to_cpu(file_info->start_cluster);
+ if (file_info->flag == EXFAT_FLAG_CONTIGUOUS)
+ (*node)->flags |= EXFAT_ATTRIB_CONTIGUOUS;
+ --continuations;
+ break;
+
+ case EXFAT_ENTRY_FILE_NAME:
+ if (continuations == 0)
+ {
+ exfat_error("unexpected continuation");
+ goto error;
+ }
+ file_name = (const struct exfat_file_name*) entry;
+ memcpy(namep, file_name->name, EXFAT_ENAME_MAX * sizeof(le16_t));
+ namep += EXFAT_ENAME_MAX;
+ if (--continuations == 0)
+ return 0; /* entry completed */
+ break;
+
+ case EXFAT_ENTRY_UPCASE:
+ if (ef->upcase != NULL)
+ break;
+ upcase = (const struct exfat_upcase*) entry;
+ if (CLUSTER_INVALID(le32_to_cpu(upcase->start_cluster)))
+ {
+ exfat_error("invalid cluster in upcase table");
+ return -EIO;
+ }
+ if (le64_to_cpu(upcase->size) == 0 ||
+ le64_to_cpu(upcase->size) > 0xffff * sizeof(uint16_t) ||
+ le64_to_cpu(upcase->size) % sizeof(uint16_t) != 0)
+ {
+ exfat_error("bad upcase table size (%"PRIu64" bytes)",
+ le64_to_cpu(upcase->size));
+ return -EIO;
+ }
+ ef->upcase = malloc(le64_to_cpu(upcase->size));
+ if (ef->upcase == NULL)
+ {
+ exfat_error("failed to allocate upcase table (%"PRIu64" bytes)",
+ le64_to_cpu(upcase->size));
+ return -ENOMEM;
+ }
+ ef->upcase_chars = le64_to_cpu(upcase->size) / sizeof(le16_t);
+
+ exfat_read_raw(ef->upcase, le64_to_cpu(upcase->size),
+ exfat_c2o(ef, le32_to_cpu(upcase->start_cluster)), ef->fd);
+ break;
+
+ case EXFAT_ENTRY_BITMAP:
+ bitmap = (const struct exfat_bitmap*) entry;
+ if (CLUSTER_INVALID(le32_to_cpu(bitmap->start_cluster)))
+ {
+ exfat_error("invalid cluster in clusters bitmap");
+ return -EIO;
+ }
+ if (le64_to_cpu(bitmap->size) !=
+ ((le32_to_cpu(ef->sb->cluster_count) + 7) / 8))
+ {
+ exfat_error("invalid bitmap size: %"PRIu64" (expected %u)",
+ le64_to_cpu(bitmap->size),
+ (le32_to_cpu(ef->sb->cluster_count) + 7) / 8);
+ return -EIO;
+ }
+ break;
+
+ case EXFAT_ENTRY_LABEL:
+ label = (const struct exfat_label*) entry;
+ if (label->length > EXFAT_ENAME_MAX)
+ {
+ exfat_error("too long label (%hhu chars)", label->length);
+ return -EIO;
+ }
+ break;
+
+ default:
+ if (entry->type & EXFAT_ENTRY_VALID)
+ {
+ exfat_error("unknown entry type 0x%hhu", entry->type);
+ goto error;
+ }
+ break;
+ }
+
+ /* fetch the next cluster if needed */
+ if ((it->offset & (CLUSTER_SIZE(*ef->sb) - 1)) == 0)
+ {
+ it->cluster = exfat_next_cluster(ef, it->cluster, it->contiguous);
+ if (CLUSTER_INVALID(it->cluster))
+ {
+ exfat_error("invalid cluster while reading directory");
+ goto error;
+ }
+ exfat_read_raw(it->chunk, CLUSTER_SIZE(*ef->sb),
+ exfat_c2o(ef, it->cluster), ef->fd);
+ }
+ }
+ /* we never reach here */
+
+error:
+ free(*node);
+ *node = NULL;
+ return -EIO;
+}
+
+int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir)
+{
+ struct iterator it;
+ int rc;
+ struct exfat_node* node;
+ struct exfat_node* current = NULL;
+
+ if (dir->flags & EXFAT_ATTRIB_CACHED)
+ return 0; /* already cached */
+
+ opendir(dir, &it);
+ while ((rc = readdir(ef, dir, &node, &it)) == 0)
+ {
+ if (current != NULL)
+ {
+ current->next = node;
+ node->prev = current;
+ }
+ else
+ dir->child = node;
+
+ current = node;
+ }
+ closedir(&it);
+
+ if (rc != -ENOENT)
+ {
+ /* rollback */
+ for (current = dir->child; current; current = node)
+ {
+ node = current->next;
+ free(current);
+ }
+ dir->child = NULL;
+ return rc;
+ }
+
+ dir->flags |= EXFAT_ATTRIB_CACHED;
+ return 0;
+}
+
+static void reset_cache(struct exfat_node* node)
+{
+ struct exfat_node* child;
+ struct exfat_node* next;
+
+ for (child = node->child; child; child = next)
+ {
+ reset_cache(child);
+ next = child->next;
+ free(child);
+ }
+ if (node->references != 0)
+ {
+ char buffer[EXFAT_NAME_MAX + 1];
+ exfat_get_name(node, buffer, EXFAT_NAME_MAX);
+ exfat_warn("non-zero reference counter (%d) for `%s'",
+ node->references, buffer);
+ }
+ node->child = NULL;
+ node->flags &= ~EXFAT_ATTRIB_CACHED;
+}
+
+void exfat_reset_cache(struct exfat* ef)
+{
+ reset_cache(ef->root);
+}
ef->upcase_chars = 0;
ef->rootdir_size = rootdir_size(ef);
+ ef->root = malloc(sizeof(struct exfat_node));
+ if (ef->root == NULL)
+ {
+ close(ef->fd);
+ free(ef->sb);
+ exfat_error("failed to allocate root node");
+ return -ENOMEM;
+ }
+ memset(ef->root, 0, sizeof(struct exfat_node));
+ ef->root->flags = EXFAT_ATTRIB_DIR;
+ ef->root->size = ef->rootdir_size;
+ ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster);
+ ef->root->name[0] = cpu_to_le16('\0');
+ /* exFAT does not have time attributes for the root directory */
+ ef->root->mtime = 0;
+ ef->root->atime = 0;
+ /* always keep at least 1 reference to the root node */
+ exfat_get_node(ef->root);
+
return 0;
}
void exfat_unmount(struct exfat* ef)
{
+ exfat_put_node(ef->root);
+ exfat_reset_cache(ef);
+ ef->root = NULL;
close(ef->fd);
ef->fd = 0;
free(ef->sb);