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