-static struct exfat_inode *alloc_exfat_inode(__u16 attr)
-{
- struct exfat_inode *node;
- int size;
-
- size = offsetof(struct exfat_inode, name) + NAME_BUFFER_SIZE;
- node = (struct exfat_inode *)calloc(1, size);
- if (!node) {
- exfat_err("failed to allocate exfat_node\n");
- return NULL;
- }
-
- node->parent = NULL;
- INIT_LIST_HEAD(&node->children);
- INIT_LIST_HEAD(&node->sibling);
- INIT_LIST_HEAD(&node->list);
-
- node->last_pclus = EXFAT_EOF_CLUSTER;
- node->attr = attr;
- if (attr & ATTR_SUBDIR)
- exfat_stat.dir_count++;
- else
- exfat_stat.file_count++;
- return node;
-}
-
-static void free_exfat_inode(struct exfat_inode *node)
-{
- free(node);
-}
-
-static void inode_free_children(struct exfat_inode *dir, bool file_only)
-{
- struct exfat_inode *node, *i;
-
- list_for_each_entry_safe(node, i, &dir->children, sibling) {
- if (file_only) {
- if (!(node->attr & ATTR_SUBDIR)) {
- list_del(&node->sibling);
- free_exfat_inode(node);
- }
- } else {
- list_del(&node->sibling);
- list_del(&node->list);
- free_exfat_inode(node);
- }
- }
-}
-
-static void inode_free_file_children(struct exfat_inode *dir)
-{
- inode_free_children(dir, true);
-}
-
-/* delete @child and all ancestors that does not have
- * children
- */
-static void inode_free_ancestors(struct exfat_inode *child)
-{
- struct exfat_inode *parent;
-
- if (!list_empty(&child->children))
- return;
-
- do {
- if (!(child->attr & ATTR_SUBDIR)) {
- exfat_err("not directory.\n");
- return;
- }
-
- parent = child->parent;
- list_del(&child->sibling);
- free_exfat_inode(child);
-
- child = parent;
- } while (child && list_empty(&child->children));
-
- return;
-}
-
-static void free_exfat(struct exfat *exfat)
-{
- int i;
-
- if (exfat) {
- if (exfat->bs)
- free(exfat->bs);
- if (exfat->alloc_bitmap)
- free(exfat->alloc_bitmap);
- if (exfat->disk_bitmap)
- free(exfat->disk_bitmap);
- for (i = 0; i < 2; i++) {
- if (exfat->buffer_desc[i].buffer)
- free(exfat->buffer_desc[i].buffer);
- if (exfat->buffer_desc[i].dirty)
- free(exfat->buffer_desc[i].dirty);
- }
- free(exfat);
- }
-}
-
-static int init_exfat(struct exfat *exfat, struct pbr *bs)
-{
- int i;
-
- INIT_LIST_HEAD(&exfat->dir_list);
- exfat->bs = bs;
- exfat->clus_count = le32_to_cpu(bs->bsx.clu_count);
- exfat->clus_size = EXFAT_CLUSTER_SIZE(bs);
- exfat->sect_size = EXFAT_SECTOR_SIZE(bs);
-
- /* TODO: bitmap could be very large. */
- exfat->alloc_bitmap = (char *)calloc(1,
- EXFAT_BITMAP_SIZE(exfat->clus_count));
- if (!exfat->alloc_bitmap) {
- exfat_err("failed to allocate bitmap\n");
- goto err;
- }
-
- exfat->disk_bitmap = (char *)malloc(
- EXFAT_BITMAP_SIZE(exfat->clus_count));
- if (!exfat->disk_bitmap) {
- exfat_err("failed to allocate bitmap\n");
- goto err;
- }
-
- /* allocate cluster buffers */
- for (i = 0; i < 2; i++) {
- exfat->buffer_desc[i].buffer =
- (char *)malloc(exfat->clus_size);
- if (!exfat->buffer_desc[i].buffer)
- goto err;
- exfat->buffer_desc[i].dirty =
- (char *)calloc(
- (exfat->clus_size / exfat->sect_size), 1);
- if (!exfat->buffer_desc[i].dirty)
- goto err;
- }
- return 0;
-err:
- free_exfat(exfat);
- return -ENOMEM;
-}
-
-static void exfat_free_dir_list(struct exfat *exfat)
-{
- struct exfat_inode *dir, *i;
-
- list_for_each_entry_safe(dir, i, &exfat->dir_list, list) {
- inode_free_file_children(dir);
- list_del(&dir->list);
- free_exfat_inode(dir);
- }
-}
-
-/*
- * get references of ancestors that include @child until the count of
- * ancesters is not larger than @count and the count of characters of
- * their names is not larger than @max_char_len.
- * return true if root is reached.
- */
-bool get_ancestors(struct exfat_inode *child,
- struct exfat_inode **ancestors, int count,
- int max_char_len,
- int *ancestor_count)
-{
- struct exfat_inode *dir;
- int name_len, char_len;
- int root_depth, depth, i;
-
- root_depth = 0;
- char_len = 0;
- max_char_len += 1;
-
- dir = child;
- while (dir) {
- name_len = exfat_utf16_len(dir->name, NAME_BUFFER_SIZE);
- if (char_len + name_len > max_char_len)
- break;
-
- /* include '/' */
- char_len += name_len + 1;
- root_depth++;
-
- dir = dir->parent;
- }
-
- depth = MIN(root_depth, count);
-
- for (dir = child, i = depth - 1; i >= 0; dir = dir->parent, i--)
- ancestors[i] = dir;
-
- *ancestor_count = depth;
- return dir == NULL;
-}
-
-static int resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child)
-{
- int depth, i;
- int name_len;
- __le16 *utf16_path;
- static const __le16 utf16_slash = cpu_to_le16(0x002F);
- static const __le16 utf16_null = cpu_to_le16(0x0000);
- size_t in_size;
-
- ctx->local_path[0] = '\0';
-
- get_ancestors(child,
- ctx->ancestors,
- sizeof(ctx->ancestors) / sizeof(ctx->ancestors[0]),
- PATH_MAX,
- &depth);
-
- utf16_path = ctx->utf16_path;
- for (i = 0; i < depth; i++) {
- name_len = exfat_utf16_len(ctx->ancestors[i]->name,
- NAME_BUFFER_SIZE);
- memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name,
- name_len * 2);
- utf16_path += name_len;
- memcpy((char *)utf16_path, &utf16_slash, sizeof(utf16_slash));
- utf16_path++;
- }
-
- if (depth > 0)
- utf16_path--;
- memcpy((char *)utf16_path, &utf16_null, sizeof(utf16_null));
- utf16_path++;
-
- in_size = (utf16_path - ctx->utf16_path) * sizeof(__le16);
- return exfat_utf16_dec(ctx->utf16_path, in_size,
- ctx->local_path, sizeof(ctx->local_path));
-}
-
-static int resolve_path_parent(struct path_resolve_ctx *ctx,
- struct exfat_inode *parent, struct exfat_inode *child)
-{
- int ret;
- struct exfat_inode *old;
-
- old = child->parent;
- child->parent = parent;
-
- ret = resolve_path(ctx, child);
- child->parent = old;
- return ret;
-}
-