xref: /openbmc/u-boot/fs/btrfs/inode.c (revision 21a14fac)
1*21a14facSMarek Behún /*
2*21a14facSMarek Behún  * BTRFS filesystem implementation for U-Boot
3*21a14facSMarek Behún  *
4*21a14facSMarek Behún  * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
5*21a14facSMarek Behún  *
6*21a14facSMarek Behún  * SPDX-License-Identifier:	GPL-2.0+
7*21a14facSMarek Behún  */
8*21a14facSMarek Behún 
9*21a14facSMarek Behún #include "btrfs.h"
10*21a14facSMarek Behún #include <malloc.h>
11*21a14facSMarek Behún 
12*21a14facSMarek Behún u64 btrfs_lookup_inode_ref(struct btrfs_root *root, u64 inr,
13*21a14facSMarek Behún 			   struct btrfs_inode_ref *refp, char *name)
14*21a14facSMarek Behún {
15*21a14facSMarek Behún 	struct btrfs_path path;
16*21a14facSMarek Behún 	struct btrfs_key *key;
17*21a14facSMarek Behún 	struct btrfs_inode_ref *ref;
18*21a14facSMarek Behún 	u64 res = -1ULL;
19*21a14facSMarek Behún 
20*21a14facSMarek Behún 	key = btrfs_search_tree_key_type(root, inr, BTRFS_INODE_REF_KEY,
21*21a14facSMarek Behún 					       &path);
22*21a14facSMarek Behún 
23*21a14facSMarek Behún 	if (!key)
24*21a14facSMarek Behún 		return -1ULL;
25*21a14facSMarek Behún 
26*21a14facSMarek Behún 	ref = btrfs_path_item_ptr(&path, struct btrfs_inode_ref);
27*21a14facSMarek Behún 	btrfs_inode_ref_to_cpu(ref);
28*21a14facSMarek Behún 
29*21a14facSMarek Behún 	if (refp)
30*21a14facSMarek Behún 		*refp = *ref;
31*21a14facSMarek Behún 
32*21a14facSMarek Behún 	if (name) {
33*21a14facSMarek Behún 		if (ref->name_len > BTRFS_NAME_MAX) {
34*21a14facSMarek Behún 			printf("%s: inode name too long: %u\n", __func__,
35*21a14facSMarek Behún 			        ref->name_len);
36*21a14facSMarek Behún 			goto out;
37*21a14facSMarek Behún 		}
38*21a14facSMarek Behún 
39*21a14facSMarek Behún 		memcpy(name, ref + 1, ref->name_len);
40*21a14facSMarek Behún 	}
41*21a14facSMarek Behún 
42*21a14facSMarek Behún 	res = key->offset;
43*21a14facSMarek Behún out:
44*21a14facSMarek Behún 	btrfs_free_path(&path);
45*21a14facSMarek Behún 	return res;
46*21a14facSMarek Behún }
47*21a14facSMarek Behún 
48*21a14facSMarek Behún int btrfs_lookup_inode(const struct btrfs_root *root,
49*21a14facSMarek Behún 		       struct btrfs_key *location,
50*21a14facSMarek Behún 		       struct btrfs_inode_item *item,
51*21a14facSMarek Behún 		       struct btrfs_root *new_root)
52*21a14facSMarek Behún {
53*21a14facSMarek Behún 	struct btrfs_root tmp_root = *root;
54*21a14facSMarek Behún 	struct btrfs_path path;
55*21a14facSMarek Behún 	int res = -1;
56*21a14facSMarek Behún 
57*21a14facSMarek Behún 	if (location->type == BTRFS_ROOT_ITEM_KEY) {
58*21a14facSMarek Behún 		if (btrfs_find_root(location->objectid, &tmp_root, NULL))
59*21a14facSMarek Behún 			return -1;
60*21a14facSMarek Behún 
61*21a14facSMarek Behún 		location->objectid = tmp_root.root_dirid;
62*21a14facSMarek Behún 		location->type = BTRFS_INODE_ITEM_KEY;
63*21a14facSMarek Behún 		location->offset = 0;
64*21a14facSMarek Behún 	}
65*21a14facSMarek Behún 
66*21a14facSMarek Behún 	if (btrfs_search_tree(&tmp_root, location, &path))
67*21a14facSMarek Behún 		return res;
68*21a14facSMarek Behún 
69*21a14facSMarek Behún 	if (btrfs_comp_keys(location, btrfs_path_leaf_key(&path)))
70*21a14facSMarek Behún 		goto out;
71*21a14facSMarek Behún 
72*21a14facSMarek Behún 	if (item) {
73*21a14facSMarek Behún 		*item = *btrfs_path_item_ptr(&path, struct btrfs_inode_item);
74*21a14facSMarek Behún 		btrfs_inode_item_to_cpu(item);
75*21a14facSMarek Behún 	}
76*21a14facSMarek Behún 
77*21a14facSMarek Behún 	if (new_root)
78*21a14facSMarek Behún 		*new_root = tmp_root;
79*21a14facSMarek Behún 
80*21a14facSMarek Behún 	res = 0;
81*21a14facSMarek Behún 
82*21a14facSMarek Behún out:
83*21a14facSMarek Behún 	btrfs_free_path(&path);
84*21a14facSMarek Behún 	return res;
85*21a14facSMarek Behún }
86*21a14facSMarek Behún 
87*21a14facSMarek Behún int btrfs_readlink(const struct btrfs_root *root, u64 inr, char *target)
88*21a14facSMarek Behún {
89*21a14facSMarek Behún 	struct btrfs_path path;
90*21a14facSMarek Behún 	struct btrfs_key key;
91*21a14facSMarek Behún 	struct btrfs_file_extent_item *extent;
92*21a14facSMarek Behún 	const char *data_ptr;
93*21a14facSMarek Behún 	int res = -1;
94*21a14facSMarek Behún 
95*21a14facSMarek Behún 	key.objectid = inr;
96*21a14facSMarek Behún 	key.type = BTRFS_EXTENT_DATA_KEY;
97*21a14facSMarek Behún 	key.offset = 0;
98*21a14facSMarek Behún 
99*21a14facSMarek Behún 	if (btrfs_search_tree(root, &key, &path))
100*21a14facSMarek Behún 		return -1;
101*21a14facSMarek Behún 
102*21a14facSMarek Behún 	if (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)))
103*21a14facSMarek Behún 		goto out;
104*21a14facSMarek Behún 
105*21a14facSMarek Behún 	extent = btrfs_path_item_ptr(&path, struct btrfs_file_extent_item);
106*21a14facSMarek Behún 	if (extent->type != BTRFS_FILE_EXTENT_INLINE) {
107*21a14facSMarek Behún 		printf("%s: Extent for symlink %llu not of INLINE type\n",
108*21a14facSMarek Behún 		       __func__, inr);
109*21a14facSMarek Behún 		goto out;
110*21a14facSMarek Behún 	}
111*21a14facSMarek Behún 
112*21a14facSMarek Behún 	btrfs_file_extent_item_to_cpu_inl(extent);
113*21a14facSMarek Behún 
114*21a14facSMarek Behún 	if (extent->compression != BTRFS_COMPRESS_NONE) {
115*21a14facSMarek Behún 		printf("%s: Symlink %llu extent data compressed!\n", __func__,
116*21a14facSMarek Behún 		       inr);
117*21a14facSMarek Behún 		goto out;
118*21a14facSMarek Behún 	} else if (extent->encryption != 0) {
119*21a14facSMarek Behún 		printf("%s: Symlink %llu extent data encrypted!\n", __func__,
120*21a14facSMarek Behún 		       inr);
121*21a14facSMarek Behún 		goto out;
122*21a14facSMarek Behún 	} else if (extent->ram_bytes >= btrfs_info.sb.sectorsize) {
123*21a14facSMarek Behún 		printf("%s: Symlink %llu extent data too long (%llu)!\n",
124*21a14facSMarek Behún 		       __func__, inr, extent->ram_bytes);
125*21a14facSMarek Behún 		goto out;
126*21a14facSMarek Behún 	}
127*21a14facSMarek Behún 
128*21a14facSMarek Behún 	data_ptr = (const char *) extent
129*21a14facSMarek Behún 		   + offsetof(struct btrfs_file_extent_item, disk_bytenr);
130*21a14facSMarek Behún 
131*21a14facSMarek Behún 	memcpy(target, data_ptr, extent->ram_bytes);
132*21a14facSMarek Behún 	target[extent->ram_bytes] = '\0';
133*21a14facSMarek Behún 	res = 0;
134*21a14facSMarek Behún out:
135*21a14facSMarek Behún 	btrfs_free_path(&path);
136*21a14facSMarek Behún 	return res;
137*21a14facSMarek Behún }
138*21a14facSMarek Behún 
139*21a14facSMarek Behún /* inr must be a directory (for regular files with multiple hard links this
140*21a14facSMarek Behún    function returns only one of the parents of the file) */
141*21a14facSMarek Behún static u64 get_parent_inode(struct btrfs_root *root, u64 inr,
142*21a14facSMarek Behún 			    struct btrfs_inode_item *inode_item)
143*21a14facSMarek Behún {
144*21a14facSMarek Behún 	struct btrfs_key key;
145*21a14facSMarek Behún 	u64 res;
146*21a14facSMarek Behún 
147*21a14facSMarek Behún 	if (inr == BTRFS_FIRST_FREE_OBJECTID) {
148*21a14facSMarek Behún 		if (root->objectid != btrfs_info.fs_root.objectid) {
149*21a14facSMarek Behún 			u64 parent;
150*21a14facSMarek Behún 			struct btrfs_root_ref ref;
151*21a14facSMarek Behún 
152*21a14facSMarek Behún 			parent = btrfs_lookup_root_ref(root->objectid, &ref,
153*21a14facSMarek Behún 						       NULL);
154*21a14facSMarek Behún 			if (parent == -1ULL)
155*21a14facSMarek Behún 				return -1ULL;
156*21a14facSMarek Behún 
157*21a14facSMarek Behún 			if (btrfs_find_root(parent, root, NULL))
158*21a14facSMarek Behún 				return -1ULL;
159*21a14facSMarek Behún 
160*21a14facSMarek Behún 			inr = ref.dirid;
161*21a14facSMarek Behún 		}
162*21a14facSMarek Behún 
163*21a14facSMarek Behún 		if (inode_item) {
164*21a14facSMarek Behún 			key.objectid = inr;
165*21a14facSMarek Behún 			key.type = BTRFS_INODE_ITEM_KEY;
166*21a14facSMarek Behún 			key.offset = 0;
167*21a14facSMarek Behún 
168*21a14facSMarek Behún 			if (btrfs_lookup_inode(root, &key, inode_item, NULL))
169*21a14facSMarek Behún 				return -1ULL;
170*21a14facSMarek Behún 		}
171*21a14facSMarek Behún 
172*21a14facSMarek Behún 		return inr;
173*21a14facSMarek Behún 	}
174*21a14facSMarek Behún 
175*21a14facSMarek Behún 	res = btrfs_lookup_inode_ref(root, inr, NULL, NULL);
176*21a14facSMarek Behún 	if (res == -1ULL)
177*21a14facSMarek Behún 		return -1ULL;
178*21a14facSMarek Behún 
179*21a14facSMarek Behún 	if (inode_item) {
180*21a14facSMarek Behún 		key.objectid = res;
181*21a14facSMarek Behún 		key.type = BTRFS_INODE_ITEM_KEY;
182*21a14facSMarek Behún 		key.offset = 0;
183*21a14facSMarek Behún 
184*21a14facSMarek Behún 		if (btrfs_lookup_inode(root, &key, inode_item, NULL))
185*21a14facSMarek Behún 			return -1ULL;
186*21a14facSMarek Behún 	}
187*21a14facSMarek Behún 
188*21a14facSMarek Behún 	return res;
189*21a14facSMarek Behún }
190*21a14facSMarek Behún 
191*21a14facSMarek Behún static inline int next_length(const char *path)
192*21a14facSMarek Behún {
193*21a14facSMarek Behún 	int res = 0;
194*21a14facSMarek Behún 	while (*path != '\0' && *path != '/' && res <= BTRFS_NAME_LEN)
195*21a14facSMarek Behún 		++res, ++path;
196*21a14facSMarek Behún 	return res;
197*21a14facSMarek Behún }
198*21a14facSMarek Behún 
199*21a14facSMarek Behún static inline const char *skip_current_directories(const char *cur)
200*21a14facSMarek Behún {
201*21a14facSMarek Behún 	while (1) {
202*21a14facSMarek Behún 		if (cur[0] == '/')
203*21a14facSMarek Behún 			++cur;
204*21a14facSMarek Behún 		else if (cur[0] == '.' && cur[1] == '/')
205*21a14facSMarek Behún 			cur += 2;
206*21a14facSMarek Behún 		else
207*21a14facSMarek Behún 			break;
208*21a14facSMarek Behún 	}
209*21a14facSMarek Behún 
210*21a14facSMarek Behún 	return cur;
211*21a14facSMarek Behún }
212*21a14facSMarek Behún 
213*21a14facSMarek Behún /* inode.c, musi vratit aj root stromu kde sa inoda najde */
214*21a14facSMarek Behún u64 btrfs_lookup_path(struct btrfs_root *root, u64 inr, const char *path,
215*21a14facSMarek Behún 		      u8 *type_p, struct btrfs_inode_item *inode_item_p,
216*21a14facSMarek Behún 		      int symlink_limit)
217*21a14facSMarek Behún {
218*21a14facSMarek Behún 	struct btrfs_dir_item item;
219*21a14facSMarek Behún 	struct btrfs_inode_item inode_item;
220*21a14facSMarek Behún 	u8 type = BTRFS_FT_DIR;
221*21a14facSMarek Behún 	int len, have_inode = 0;
222*21a14facSMarek Behún 	const char *cur = path;
223*21a14facSMarek Behún 
224*21a14facSMarek Behún 	if (*cur == '/') {
225*21a14facSMarek Behún 		++cur;
226*21a14facSMarek Behún 		inr = root->root_dirid;
227*21a14facSMarek Behún 	}
228*21a14facSMarek Behún 
229*21a14facSMarek Behún 	do {
230*21a14facSMarek Behún 		cur = skip_current_directories(cur);
231*21a14facSMarek Behún 
232*21a14facSMarek Behún 		len = next_length(cur);
233*21a14facSMarek Behún 		if (len > BTRFS_NAME_LEN) {
234*21a14facSMarek Behún 			printf("%s: Name too long at \"%.*s\"\n", __func__,
235*21a14facSMarek Behún 			       BTRFS_NAME_LEN, cur);
236*21a14facSMarek Behún 			return -1ULL;
237*21a14facSMarek Behún 		}
238*21a14facSMarek Behún 
239*21a14facSMarek Behún 		if (len == 1 && cur[0] == '.')
240*21a14facSMarek Behún 			break;
241*21a14facSMarek Behún 
242*21a14facSMarek Behún 		if (len == 2 && cur[0] == '.' && cur[1] == '.') {
243*21a14facSMarek Behún 			cur += 2;
244*21a14facSMarek Behún 			inr = get_parent_inode(root, inr, &inode_item);
245*21a14facSMarek Behún 			if (inr == -1ULL)
246*21a14facSMarek Behún 				return -1ULL;
247*21a14facSMarek Behún 
248*21a14facSMarek Behún 			type = BTRFS_FT_DIR;
249*21a14facSMarek Behún 			continue;
250*21a14facSMarek Behún 		}
251*21a14facSMarek Behún 
252*21a14facSMarek Behún 		if (!*cur)
253*21a14facSMarek Behún 			break;
254*21a14facSMarek Behún 
255*21a14facSMarek Behún 		if (btrfs_lookup_dir_item(root, inr, cur, len, &item))
256*21a14facSMarek Behún 			return -1ULL;
257*21a14facSMarek Behún 
258*21a14facSMarek Behún 		type = item.type;
259*21a14facSMarek Behún 		have_inode = 1;
260*21a14facSMarek Behún 		if (btrfs_lookup_inode(root, &item.location, &inode_item, root))
261*21a14facSMarek Behún 			return -1ULL;
262*21a14facSMarek Behún 
263*21a14facSMarek Behún 		if (item.type == BTRFS_FT_SYMLINK && symlink_limit >= 0) {
264*21a14facSMarek Behún 			char *target;
265*21a14facSMarek Behún 
266*21a14facSMarek Behún 			if (!symlink_limit) {
267*21a14facSMarek Behún 				printf("%s: Too much symlinks!\n", __func__);
268*21a14facSMarek Behún 				return -1ULL;
269*21a14facSMarek Behún 			}
270*21a14facSMarek Behún 
271*21a14facSMarek Behún 			target = malloc(min(inode_item.size + 1,
272*21a14facSMarek Behún 					    (u64) btrfs_info.sb.sectorsize));
273*21a14facSMarek Behún 			if (!target)
274*21a14facSMarek Behún 				return -1ULL;
275*21a14facSMarek Behún 
276*21a14facSMarek Behún 			if (btrfs_readlink(root, item.location.objectid,
277*21a14facSMarek Behún 					   target)) {
278*21a14facSMarek Behún 				free(target);
279*21a14facSMarek Behún 				return -1ULL;
280*21a14facSMarek Behún 			}
281*21a14facSMarek Behún 
282*21a14facSMarek Behún 			inr = btrfs_lookup_path(root, inr, target, &type,
283*21a14facSMarek Behún 						&inode_item, symlink_limit - 1);
284*21a14facSMarek Behún 
285*21a14facSMarek Behún 			free(target);
286*21a14facSMarek Behún 
287*21a14facSMarek Behún 			if (inr == -1ULL)
288*21a14facSMarek Behún 				return -1ULL;
289*21a14facSMarek Behún 		} else if (item.type != BTRFS_FT_DIR && cur[len]) {
290*21a14facSMarek Behún 			printf("%s: \"%.*s\" not a directory\n", __func__,
291*21a14facSMarek Behún 			       (int) (cur - path + len), path);
292*21a14facSMarek Behún 			return -1ULL;
293*21a14facSMarek Behún 		} else {
294*21a14facSMarek Behún 			inr = item.location.objectid;
295*21a14facSMarek Behún 		}
296*21a14facSMarek Behún 
297*21a14facSMarek Behún 		cur += len;
298*21a14facSMarek Behún 	} while (*cur);
299*21a14facSMarek Behún 
300*21a14facSMarek Behún 	if (type_p)
301*21a14facSMarek Behún 		*type_p = type;
302*21a14facSMarek Behún 
303*21a14facSMarek Behún 	if (inode_item_p) {
304*21a14facSMarek Behún 		if (!have_inode) {
305*21a14facSMarek Behún 			struct btrfs_key key;
306*21a14facSMarek Behún 
307*21a14facSMarek Behún 			key.objectid = inr;
308*21a14facSMarek Behún 			key.type = BTRFS_INODE_ITEM_KEY;
309*21a14facSMarek Behún 			key.offset = 0;
310*21a14facSMarek Behún 
311*21a14facSMarek Behún 			if (btrfs_lookup_inode(root, &key, &inode_item, NULL))
312*21a14facSMarek Behún 				return -1ULL;
313*21a14facSMarek Behún 		}
314*21a14facSMarek Behún 
315*21a14facSMarek Behún 		*inode_item_p = inode_item;
316*21a14facSMarek Behún 	}
317*21a14facSMarek Behún 
318*21a14facSMarek Behún 	return inr;
319*21a14facSMarek Behún }
320*21a14facSMarek Behún 
321*21a14facSMarek Behún u64 btrfs_file_read(const struct btrfs_root *root, u64 inr, u64 offset,
322*21a14facSMarek Behún 		    u64 size, char *buf)
323*21a14facSMarek Behún {
324*21a14facSMarek Behún 	struct btrfs_path path;
325*21a14facSMarek Behún 	struct btrfs_key key;
326*21a14facSMarek Behún 	struct btrfs_file_extent_item *extent;
327*21a14facSMarek Behún 	int res;
328*21a14facSMarek Behún 	u64 rd, rd_all = -1ULL;
329*21a14facSMarek Behún 
330*21a14facSMarek Behún 	key.objectid = inr;
331*21a14facSMarek Behún 	key.type = BTRFS_EXTENT_DATA_KEY;
332*21a14facSMarek Behún 	key.offset = offset;
333*21a14facSMarek Behún 
334*21a14facSMarek Behún 	if (btrfs_search_tree(root, &key, &path))
335*21a14facSMarek Behún 		return -1ULL;
336*21a14facSMarek Behún 
337*21a14facSMarek Behún 	if (btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)) < 0) {
338*21a14facSMarek Behún 		if (btrfs_prev_slot(&path))
339*21a14facSMarek Behún 			goto out;
340*21a14facSMarek Behún 
341*21a14facSMarek Behún 		if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))
342*21a14facSMarek Behún 			goto out;
343*21a14facSMarek Behún 	}
344*21a14facSMarek Behún 
345*21a14facSMarek Behún 	rd_all = 0;
346*21a14facSMarek Behún 
347*21a14facSMarek Behún 	do {
348*21a14facSMarek Behún 		if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))
349*21a14facSMarek Behún 			break;
350*21a14facSMarek Behún 
351*21a14facSMarek Behún 		extent = btrfs_path_item_ptr(&path,
352*21a14facSMarek Behún 					     struct btrfs_file_extent_item);
353*21a14facSMarek Behún 
354*21a14facSMarek Behún 		if (extent->type == BTRFS_FILE_EXTENT_INLINE) {
355*21a14facSMarek Behún 			btrfs_file_extent_item_to_cpu_inl(extent);
356*21a14facSMarek Behún 			rd = btrfs_read_extent_inline(&path, extent, offset,
357*21a14facSMarek Behún 						      size, buf);
358*21a14facSMarek Behún 		} else {
359*21a14facSMarek Behún 			btrfs_file_extent_item_to_cpu(extent);
360*21a14facSMarek Behún 			rd = btrfs_read_extent_reg(&path, extent, offset, size,
361*21a14facSMarek Behún 						   buf);
362*21a14facSMarek Behún 		}
363*21a14facSMarek Behún 
364*21a14facSMarek Behún 		if (rd == -1ULL) {
365*21a14facSMarek Behún 			printf("%s: Error reading extent\n", __func__);
366*21a14facSMarek Behún 			rd_all = -1;
367*21a14facSMarek Behún 			goto out;
368*21a14facSMarek Behún 		}
369*21a14facSMarek Behún 
370*21a14facSMarek Behún 		offset = 0;
371*21a14facSMarek Behún 		buf += rd;
372*21a14facSMarek Behún 		rd_all += rd;
373*21a14facSMarek Behún 		size -= rd;
374*21a14facSMarek Behún 
375*21a14facSMarek Behún 		if (!size)
376*21a14facSMarek Behún 			break;
377*21a14facSMarek Behún 	} while (!(res = btrfs_next_slot(&path)));
378*21a14facSMarek Behún 
379*21a14facSMarek Behún 	if (res)
380*21a14facSMarek Behún 		return -1ULL;
381*21a14facSMarek Behún 
382*21a14facSMarek Behún out:
383*21a14facSMarek Behún 	btrfs_free_path(&path);
384*21a14facSMarek Behún 	return rd_all;
385*21a14facSMarek Behún }
386