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
exfat_alloc_inode(__u16 attr)19 struct 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 = 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
exfat_free_inode(struct exfat_inode * node)40 void 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
exfat_free_children(struct exfat_inode * dir,bool file_only)49 void 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
exfat_free_file_children(struct exfat_inode * dir)67 void 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 */
exfat_free_ancestors(struct exfat_inode * child)75 void 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
exfat_free_dir_list(struct exfat * exfat)92 void 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
exfat_free_exfat(struct exfat * exfat)105 void 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->lookup_buffer)
121 free(exfat->lookup_buffer);
122 free(exfat);
123 }
124 }
125
exfat_alloc_exfat(struct exfat_blk_dev * blk_dev,struct pbr * bs)126 struct exfat *exfat_alloc_exfat(struct exfat_blk_dev *blk_dev, struct pbr *bs)
127 {
128 struct exfat *exfat;
129
130 exfat = calloc(1, sizeof(*exfat));
131 if (!exfat) {
132 free(bs);
133 return NULL;
134 }
135
136 INIT_LIST_HEAD(&exfat->dir_list);
137 exfat->blk_dev = blk_dev;
138 exfat->bs = bs;
139 exfat->clus_count = le32_to_cpu(bs->bsx.clu_count);
140 exfat->clus_size = EXFAT_CLUSTER_SIZE(bs);
141 exfat->sect_size = EXFAT_SECTOR_SIZE(bs);
142
143 /* TODO: bitmap could be very large. */
144 exfat->alloc_bitmap = calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count));
145 if (!exfat->alloc_bitmap) {
146 exfat_err("failed to allocate bitmap\n");
147 goto err;
148 }
149
150 exfat->ohead_bitmap = 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 = calloc(1, EXFAT_BITMAP_SIZE(exfat->clus_count));
157 if (!exfat->disk_bitmap) {
158 exfat_err("failed to allocate bitmap\n");
159 goto err;
160 }
161
162 exfat->buffer_count = ((MAX_EXT_DENTRIES + 1) * DENTRY_SIZE) /
163 exfat_get_read_size(exfat) + 1;
164
165 exfat->start_clu = EXFAT_FIRST_CLUSTER;
166 return exfat;
167 err:
168 exfat_free_exfat(exfat);
169 return NULL;
170 }
171
exfat_alloc_buffer(struct exfat * exfat)172 struct buffer_desc *exfat_alloc_buffer(struct exfat *exfat)
173 {
174 struct buffer_desc *bd;
175 unsigned int i;
176 unsigned int read_size = exfat_get_read_size(exfat);
177
178 bd = calloc(exfat->buffer_count, sizeof(*bd));
179 if (!bd)
180 return NULL;
181
182 for (i = 0; i < exfat->buffer_count; i++) {
183 bd[i].buffer = malloc(read_size);
184 if (!bd[i].buffer)
185 goto err;
186
187 memset(&bd[i].dirty, 0, sizeof(bd[i].dirty));
188 }
189 return bd;
190 err:
191 exfat_free_buffer(exfat, bd);
192 return NULL;
193 }
194
exfat_free_buffer(const struct exfat * exfat,struct buffer_desc * bd)195 void exfat_free_buffer(const struct exfat *exfat, struct buffer_desc *bd)
196 {
197 unsigned int i;
198
199 for (i = 0; i < exfat->buffer_count; i++) {
200 if (bd[i].buffer)
201 free(bd[i].buffer);
202 }
203 free(bd);
204 }
205
206 /*
207 * get references of ancestors that include @child until the count of
208 * ancesters is not larger than @count and the count of characters of
209 * their names is not larger than @max_char_len.
210 * return true if root is reached.
211 */
get_ancestors(struct exfat_inode * child,struct exfat_inode ** ancestors,int count,int max_char_len,int * ancestor_count)212 static bool get_ancestors(struct exfat_inode *child,
213 struct exfat_inode **ancestors, int count,
214 int max_char_len,
215 int *ancestor_count)
216 {
217 struct exfat_inode *dir;
218 int name_len, char_len;
219 int root_depth, depth, i;
220
221 root_depth = 0;
222 char_len = 0;
223 max_char_len += 1;
224
225 dir = child;
226 while (dir) {
227 name_len = exfat_utf16_len(dir->name, NAME_BUFFER_SIZE);
228 if (char_len + name_len > max_char_len)
229 break;
230
231 /* include '/' */
232 char_len += name_len + 1;
233 root_depth++;
234
235 dir = dir->parent;
236 }
237
238 depth = MIN(root_depth, count);
239
240 for (dir = child, i = depth - 1; i >= 0; dir = dir->parent, i--)
241 ancestors[i] = dir;
242
243 *ancestor_count = depth;
244 return !dir;
245 }
246
exfat_resolve_path(struct path_resolve_ctx * ctx,struct exfat_inode * child)247 int exfat_resolve_path(struct path_resolve_ctx *ctx, struct exfat_inode *child)
248 {
249 int depth, i;
250 int name_len;
251 __le16 *utf16_path;
252 size_t in_size;
253
254 ctx->local_path[0] = '\0';
255
256 get_ancestors(child,
257 ctx->ancestors,
258 sizeof(ctx->ancestors) / sizeof(ctx->ancestors[0]),
259 PATH_MAX,
260 &depth);
261
262 utf16_path = ctx->utf16_path;
263 for (i = 0; i < depth; i++) {
264 name_len = exfat_utf16_len(ctx->ancestors[i]->name,
265 NAME_BUFFER_SIZE);
266 memcpy((char *)utf16_path, (char *)ctx->ancestors[i]->name,
267 name_len * 2);
268 utf16_path += name_len;
269 *utf16_path = UTF16_SLASH;
270 utf16_path++;
271 }
272
273 if (depth > 1)
274 utf16_path--;
275 *utf16_path = UTF16_NULL;
276 utf16_path++;
277
278 in_size = (utf16_path - ctx->utf16_path) * sizeof(__le16);
279 return exfat_utf16_dec(ctx->utf16_path, in_size,
280 ctx->local_path, sizeof(ctx->local_path));
281 }
282
exfat_resolve_path_parent(struct path_resolve_ctx * ctx,struct exfat_inode * parent,struct exfat_inode * child)283 int exfat_resolve_path_parent(struct path_resolve_ctx *ctx,
284 struct exfat_inode *parent, struct exfat_inode *child)
285 {
286 int ret;
287 struct exfat_inode *old;
288
289 old = child->parent;
290 child->parent = parent;
291
292 ret = exfat_resolve_path(ctx, child);
293 child->parent = old;
294 return ret;
295 }
296