1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2021 LG Electronics. 4 * 5 * Author(s): Hyunchul Lee <hyc.lee@gmail.com> 6 */ 7 8#include <stdlib.h> 9#include <stdio.h> 10#include <string.h> 11#include <errno.h> 12 13#include "exfat_ondisk.h" 14#include "libexfat.h" 15 16#include "exfat_fs.h" 17#include "exfat_dir.h" 18 19struct exfat_inode *exfat_alloc_inode(__u16 attr) 20{ 21 struct exfat_inode *node; 22 int size; 23 24 size = offsetof(struct exfat_inode, name) + NAME_BUFFER_SIZE; 25 node = (struct exfat_inode *)calloc(1, size); 26 if (!node) { 27 exfat_err("failed to allocate exfat_node\n"); 28 return NULL; 29 } 30 31 node->parent = NULL; 32 INIT_LIST_HEAD(&node->children); 33 INIT_LIST_HEAD(&node->sibling); 34 INIT_LIST_HEAD(&node->list); 35 36 node->attr = attr; 37 return node; 38} 39 40void exfat_free_inode(struct exfat_inode *node) 41{ 42 if (node) { 43 if (node->dentry_set) 44 free(node->dentry_set); 45 free(node); 46 } 47} 48 49void exfat_free_children(struct exfat_inode *dir, bool file_only) 50{ 51 struct exfat_inode *node, *i; 52 53 list_for_each_entry_safe(node, i, &dir->children, sibling) { 54 if (file_only) { 55 if (!(node->attr & ATTR_SUBDIR)) { 56 list_del(&node->sibling); 57 exfat_free_inode(node); 58 } 59 } else { 60 list_del(&node->sibling); 61 list_del(&node->list); 62 exfat_free_inode(node); 63 } 64 } 65} 66 67void exfat_free_file_children(struct exfat_inode *dir) 68{ 69 exfat_free_children(dir, true); 70} 71 72/* delete @child and all ancestors that does not have 73 * children 74 */ 75void exfat_free_ancestors(struct exfat_inode *child) 76{ 77 struct exfat_inode *parent; 78 79 while (child && list_empty(&child->children)) { 80 if (!child->parent || !(child->attr & ATTR_SUBDIR)) 81 return; 82 83 parent = child->parent; 84 list_del(&child->sibling); 85 exfat_free_inode(child); 86 87 child = parent; 88 } 89 return; 90} 91 92void exfat_free_dir_list(struct exfat *exfat) 93{ 94 struct exfat_inode *dir, *i; 95 96 list_for_each_entry_safe(dir, i, &exfat->dir_list, list) { 97 if (!dir->parent) 98 continue; 99 exfat_free_file_children(dir); 100 list_del(&dir->list); 101 exfat_free_inode(dir); 102 } 103} 104 105void exfat_free_exfat(struct exfat *exfat) 106{ 107 if (exfat) { 108 if (exfat->bs) 109 free(exfat->bs); 110 if (exfat->alloc_bitmap) 111 free(exfat->alloc_bitmap); 112 if (exfat->disk_bitmap) 113 free(exfat->disk_bitmap); 114 if (exfat->ohead_bitmap) 115 free(exfat->ohead_bitmap); 116 if (exfat->upcase_table) 117 free(exfat->upcase_table); 118 if (exfat->root) 119 exfat_free_inode(exfat->root); 120 if (exfat->zero_cluster) 121 free(exfat->zero_cluster); 122 free(exfat); 123 } 124} 125 126struct exfat *exfat_alloc_exfat(struct exfat_blk_dev *blk_dev, struct pbr *bs) 127{ 128 struct exfat *exfat; 129 130 exfat = (struct exfat *)calloc(1, sizeof(*exfat)); 131 if (!exfat) 132 return NULL; 133 134 INIT_LIST_HEAD(&exfat->dir_list); 135 exfat->blk_dev = blk_dev; 136 exfat->bs = bs; 137 exfat->clus_count = le32_to_cpu(bs->bsx.clu_count); 138 exfat->clus_size = EXFAT_CLUSTER_SIZE(bs); 139 exfat->sect_size = EXFAT_SECTOR_SIZE(bs); 140 141 /* TODO: bitmap could be very large. */ 142 exfat->alloc_bitmap = (char *)calloc(1, 143 EXFAT_BITMAP_SIZE(exfat->clus_count)); 144 if (!exfat->alloc_bitmap) { 145 exfat_err("failed to allocate bitmap\n"); 146 goto err; 147 } 148 149 exfat->ohead_bitmap = 150 calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count)); 151 if (!exfat->ohead_bitmap) { 152 exfat_err("failed to allocate bitmap\n"); 153 goto err; 154 } 155 156 exfat->disk_bitmap = 157 calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count)); 158 if (!exfat->disk_bitmap) { 159 exfat_err("failed to allocate bitmap\n"); 160 goto err; 161 } 162 163 exfat->zero_cluster = calloc(1, exfat->clus_size); 164 if (!exfat->zero_cluster) { 165 exfat_err("failed to allocate a zero-filled cluster buffer\n"); 166 goto err; 167 } 168 169 exfat->start_clu = EXFAT_FIRST_CLUSTER; 170 return exfat; 171err: 172 exfat_free_exfat(exfat); 173 return NULL; 174} 175 176struct buffer_desc *exfat_alloc_buffer(int count, 177 unsigned int clu_size, unsigned int sect_size) 178{ 179 struct buffer_desc *bd; 180 int i; 181 182 bd = (struct buffer_desc *)calloc(sizeof(*bd), count); 183 if (!bd) 184 return NULL; 185 186 for (i = 0; i < count; i++) { 187 bd[i].buffer = (char *)malloc(clu_size); 188 if (!bd[i].buffer) 189 goto err; 190 bd[i].dirty = (char *)calloc(clu_size / sect_size, 1); 191 if (!bd[i].dirty) 192 goto err; 193 } 194 return bd; 195err: 196 exfat_free_buffer(bd, count); 197 return NULL; 198} 199 200void exfat_free_buffer(struct buffer_desc *bd, int count) 201{ 202 int i; 203 204 for (i = 0; i < count; i++) { 205 if (bd[i].buffer) 206 free(bd[i].buffer); 207 if (bd[i].dirty) 208 free(bd[i].dirty); 209 } 210 free(bd); 211} 212 213/* 214 * get references of ancestors that include @child until the count of 215 * ancesters is not larger than @count and the count of characters of 216 * their names is not larger than @max_char_len. 217 * return true if root is reached. 218 */ 219static bool get_ancestors(struct exfat_inode *child, 220 struct exfat_inode **ancestors, int count, 221 int max_char_len, 222 int *ancestor_count) 223{ 224 struct exfat_inode *dir; 225 int name_len, char_len; 226 int root_depth, depth, i; 227 228 root_depth = 0; 229 char_len = 0; 230 max_char_len += 1; 231 232 dir = child; 233 while (dir) { 234 name_len = exfat_utf16_len(dir->name, NAME_BUFFER_SIZE); 235 if (char_len + name_len > max_char_len) 236 break; 237 238 /* include '/' */ 239 char_len += name_len + 1; 240 root_depth++; 241 242 dir = dir->parent; 243 } 244 245 depth = MIN(root_depth, count); 246 247 for (dir = child, i = depth - 1; i >= 0; dir = dir->parent, i--) 248 ancestors[i] = dir; 249 250 *ancestor_count = depth; 251 return !dir; 252} 253 254int exfat_resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child) 255{ 256 int depth, i; 257 int name_len; 258 __le16 *utf16_path; 259 static const __le16 utf16_slash = cpu_to_le16(0x002F); 260 static const __le16 utf16_null = cpu_to_le16(0x0000); 261 size_t in_size; 262 263 ctx->local_path[0] = '\0'; 264 265 get_ancestors(child, 266 ctx->ancestors, 267 sizeof(ctx->ancestors) / sizeof(ctx->ancestors[0]), 268 PATH_MAX, 269 &depth); 270 271 utf16_path = ctx->utf16_path; 272 for (i = 0; i < depth; i++) { 273 name_len = exfat_utf16_len(ctx->ancestors[i]->name, 274 NAME_BUFFER_SIZE); 275 memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name, 276 name_len * 2); 277 utf16_path += name_len; 278 memcpy((char *)utf16_path, &utf16_slash, sizeof(utf16_slash)); 279 utf16_path++; 280 } 281 282 if (depth > 1) 283 utf16_path--; 284 memcpy((char *)utf16_path, &utf16_null, sizeof(utf16_null)); 285 utf16_path++; 286 287 in_size = (utf16_path - ctx->utf16_path) * sizeof(__le16); 288 return exfat_utf16_dec(ctx->utf16_path, in_size, 289 ctx->local_path, sizeof(ctx->local_path)); 290} 291 292int exfat_resolve_path_parent(struct path_resolve_ctx *ctx, 293 struct exfat_inode *parent, struct exfat_inode *child) 294{ 295 int ret; 296 struct exfat_inode *old; 297 298 old = child->parent; 299 child->parent = parent; 300 301 ret = exfat_resolve_path(ctx, child); 302 child->parent = old; 303 return ret; 304} 305