blob: 2e3fcad5a809d18e178d7014a8a27122d0f05621 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Behún21a14fa2017-09-03 17:00:28 +02002/*
3 * BTRFS filesystem implementation for U-Boot
4 *
5 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
Marek Behún21a14fa2017-09-03 17:00:28 +02006 */
7
Marek Behún21a14fa2017-09-03 17:00:28 +02008#include <malloc.h>
Qu Wenruo92bc1792020-06-24 18:03:03 +02009#include "btrfs.h"
10#include "disk-io.h"
Marek Behún21a14fa2017-09-03 17:00:28 +020011
Qu Wenruocafffc52020-06-24 18:03:02 +020012u64 __btrfs_lookup_inode_ref(struct __btrfs_root *root, u64 inr,
Marek Behún21a14fa2017-09-03 17:00:28 +020013 struct btrfs_inode_ref *refp, char *name)
14{
Qu Wenruo33966de2020-06-24 18:02:56 +020015 struct __btrfs_path path;
Marek Behún21a14fa2017-09-03 17:00:28 +020016 struct btrfs_key *key;
17 struct btrfs_inode_ref *ref;
18 u64 res = -1ULL;
19
20 key = btrfs_search_tree_key_type(root, inr, BTRFS_INODE_REF_KEY,
21 &path);
22
23 if (!key)
24 return -1ULL;
25
26 ref = btrfs_path_item_ptr(&path, struct btrfs_inode_ref);
27 btrfs_inode_ref_to_cpu(ref);
28
29 if (refp)
30 *refp = *ref;
31
32 if (name) {
Qu Wenruo3b4b40c2020-06-24 18:02:47 +020033 if (ref->name_len > BTRFS_NAME_LEN) {
Marek Behún21a14fa2017-09-03 17:00:28 +020034 printf("%s: inode name too long: %u\n", __func__,
35 ref->name_len);
36 goto out;
37 }
38
39 memcpy(name, ref + 1, ref->name_len);
40 }
41
42 res = key->offset;
43out:
Qu Wenruo33966de2020-06-24 18:02:56 +020044 __btrfs_free_path(&path);
Marek Behún21a14fa2017-09-03 17:00:28 +020045 return res;
46}
47
Qu Wenruocafffc52020-06-24 18:03:02 +020048int __btrfs_lookup_inode(const struct __btrfs_root *root,
Marek Behún21a14fa2017-09-03 17:00:28 +020049 struct btrfs_key *location,
50 struct btrfs_inode_item *item,
Qu Wenruo207011b2020-06-24 18:02:57 +020051 struct __btrfs_root *new_root)
Marek Behún21a14fa2017-09-03 17:00:28 +020052{
Qu Wenruo207011b2020-06-24 18:02:57 +020053 struct __btrfs_root tmp_root = *root;
Qu Wenruo33966de2020-06-24 18:02:56 +020054 struct __btrfs_path path;
Marek Behún21a14fa2017-09-03 17:00:28 +020055 int res = -1;
56
57 if (location->type == BTRFS_ROOT_ITEM_KEY) {
58 if (btrfs_find_root(location->objectid, &tmp_root, NULL))
59 return -1;
60
61 location->objectid = tmp_root.root_dirid;
62 location->type = BTRFS_INODE_ITEM_KEY;
63 location->offset = 0;
64 }
65
66 if (btrfs_search_tree(&tmp_root, location, &path))
67 return res;
68
Qu Wenruo75b08172020-06-24 18:02:55 +020069 if (__btrfs_comp_keys(location, btrfs_path_leaf_key(&path)))
Marek Behún21a14fa2017-09-03 17:00:28 +020070 goto out;
71
72 if (item) {
73 *item = *btrfs_path_item_ptr(&path, struct btrfs_inode_item);
74 btrfs_inode_item_to_cpu(item);
75 }
76
77 if (new_root)
78 *new_root = tmp_root;
79
80 res = 0;
81
82out:
Qu Wenruo33966de2020-06-24 18:02:56 +020083 __btrfs_free_path(&path);
Marek Behún21a14fa2017-09-03 17:00:28 +020084 return res;
85}
86
Qu Wenruo92bc1792020-06-24 18:03:03 +020087/*
88 * Read the content of symlink inode @ino of @root, into @target.
89 * NOTE: @target will not be \0 termiated, caller should handle it properly.
90 *
91 * Return the number of read data.
92 * Return <0 for error.
93 */
94int btrfs_readlink(struct btrfs_root *root, u64 ino, char *target)
Marek Behún21a14fa2017-09-03 17:00:28 +020095{
Qu Wenruo92bc1792020-06-24 18:03:03 +020096 struct btrfs_path path;
Marek Behún21a14fa2017-09-03 17:00:28 +020097 struct btrfs_key key;
Qu Wenruo92bc1792020-06-24 18:03:03 +020098 struct btrfs_file_extent_item *fi;
99 int ret;
Marek Behún21a14fa2017-09-03 17:00:28 +0200100
Qu Wenruo92bc1792020-06-24 18:03:03 +0200101 key.objectid = ino;
Marek Behún21a14fa2017-09-03 17:00:28 +0200102 key.type = BTRFS_EXTENT_DATA_KEY;
103 key.offset = 0;
Qu Wenruo92bc1792020-06-24 18:03:03 +0200104 btrfs_init_path(&path);
Marek Behún21a14fa2017-09-03 17:00:28 +0200105
Qu Wenruo92bc1792020-06-24 18:03:03 +0200106 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
107 if (ret < 0)
108 return ret;
109 if (ret > 0) {
110 ret = -ENOENT;
111 goto out;
112 }
113 fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
114 struct btrfs_file_extent_item);
115 if (btrfs_file_extent_type(path.nodes[0], fi) !=
116 BTRFS_FILE_EXTENT_INLINE) {
117 ret = -EUCLEAN;
118 error("Extent for symlink %llu must be INLINE type!", ino);
119 goto out;
120 }
121 if (btrfs_file_extent_compression(path.nodes[0], fi) !=
122 BTRFS_COMPRESS_NONE) {
123 ret = -EUCLEAN;
124 error("Extent for symlink %llu must not be compressed!", ino);
125 goto out;
126 }
127 if (btrfs_file_extent_ram_bytes(path.nodes[0], fi) >=
128 root->fs_info->sectorsize) {
129 ret = -EUCLEAN;
130 error("Symlink %llu extent data too large (%llu)!\n",
131 ino, btrfs_file_extent_ram_bytes(path.nodes[0], fi));
132 goto out;
133 }
134 read_extent_buffer(path.nodes[0], target,
135 btrfs_file_extent_inline_start(fi),
136 btrfs_file_extent_ram_bytes(path.nodes[0], fi));
137 ret = btrfs_file_extent_ram_bytes(path.nodes[0], fi);
138out:
139 btrfs_release_path(&path);
140 return ret;
141}
142
143int __btrfs_readlink(const struct __btrfs_root *root, u64 inr, char *target)
144{
145 struct btrfs_root *subvolume;
146 struct btrfs_fs_info *fs_info = current_fs_info;
147 struct btrfs_key key;
148 int ret;
149
150 ASSERT(fs_info);
151 key.objectid = root->objectid;
152 key.type = BTRFS_ROOT_ITEM_KEY;
153 key.offset = (u64)-1;
154 subvolume = btrfs_read_fs_root(fs_info, &key);
155 if (IS_ERR(subvolume))
Marek Behún21a14fa2017-09-03 17:00:28 +0200156 return -1;
157
Qu Wenruo92bc1792020-06-24 18:03:03 +0200158 ret = btrfs_readlink(subvolume, inr, target);
159 if (ret < 0)
160 return -1;
161 target[ret] = '\0';
162 return 0;
Marek Behún21a14fa2017-09-03 17:00:28 +0200163}
164
Qu Wenruoc921aa22020-06-24 18:03:05 +0200165static int lookup_root_ref(struct btrfs_fs_info *fs_info,
166 u64 rootid, u64 *root_ret, u64 *dir_ret)
167{
168 struct btrfs_root *root = fs_info->tree_root;
169 struct btrfs_root_ref *root_ref;
170 struct btrfs_path path;
171 struct btrfs_key key;
172 int ret;
173
174 btrfs_init_path(&path);
175 key.objectid = rootid;
176 key.type = BTRFS_ROOT_BACKREF_KEY;
177 key.offset = (u64)-1;
178
179 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
180 if (ret < 0)
181 return ret;
182 /* Should not happen */
183 if (ret == 0) {
184 ret = -EUCLEAN;
185 goto out;
186 }
187 ret = btrfs_previous_item(root, &path, rootid, BTRFS_ROOT_BACKREF_KEY);
188 if (ret < 0)
189 goto out;
190 if (ret > 0) {
191 ret = -ENOENT;
192 goto out;
193 }
194 btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
195 root_ref = btrfs_item_ptr(path.nodes[0], path.slots[0],
196 struct btrfs_root_ref);
197 *root_ret = key.offset;
198 *dir_ret = btrfs_root_ref_dirid(path.nodes[0], root_ref);
199out:
200 btrfs_release_path(&path);
201 return ret;
202}
203
204/*
205 * To get the parent inode of @ino of @root.
206 *
207 * @root_ret and @ino_ret will be filled.
208 *
209 * NOTE: This function is not reliable. It can only get one parent inode.
210 * The get the proper parent inode, we need a full VFS inodes stack to
211 * resolve properly.
212 */
213static int get_parent_inode(struct btrfs_root *root, u64 ino,
214 struct btrfs_root **root_ret, u64 *ino_ret)
215{
216 struct btrfs_fs_info *fs_info = root->fs_info;
217 struct btrfs_path path;
218 struct btrfs_key key;
219 int ret;
220
221 if (ino == BTRFS_FIRST_FREE_OBJECTID) {
222 u64 parent_root = -1;
223
224 /* It's top level already, no more parent */
225 if (root->root_key.objectid == BTRFS_FS_TREE_OBJECTID) {
226 *root_ret = fs_info->fs_root;
227 *ino_ret = BTRFS_FIRST_FREE_OBJECTID;
228 return 0;
229 }
230
231 ret = lookup_root_ref(fs_info, root->root_key.objectid,
232 &parent_root, ino_ret);
233 if (ret < 0)
234 return ret;
235
236 key.objectid = parent_root;
237 key.type = BTRFS_ROOT_ITEM_KEY;
238 key.offset = (u64)-1;
239 *root_ret = btrfs_read_fs_root(fs_info, &key);
240 if (IS_ERR(*root_ret))
241 return PTR_ERR(*root_ret);
242
243 return 0;
244 }
245
246 btrfs_init_path(&path);
247 key.objectid = ino;
248 key.type = BTRFS_INODE_REF_KEY;
249 key.offset = (u64)-1;
250
251 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
252 if (ret < 0)
253 return ret;
254 /* Should not happen */
255 if (ret == 0) {
256 ret = -EUCLEAN;
257 goto out;
258 }
259 ret = btrfs_previous_item(root, &path, ino, BTRFS_INODE_REF_KEY);
260 if (ret < 0)
261 goto out;
262 if (ret > 0) {
263 ret = -ENOENT;
264 goto out;
265 }
266 btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
267 *root_ret = root;
268 *ino_ret = key.offset;
269out:
270 btrfs_release_path(&path);
271 return ret;
272}
273
Marek Behún21a14fa2017-09-03 17:00:28 +0200274/* inr must be a directory (for regular files with multiple hard links this
275 function returns only one of the parents of the file) */
Qu Wenruocafffc52020-06-24 18:03:02 +0200276static u64 __get_parent_inode(struct __btrfs_root *root, u64 inr,
Marek Behún21a14fa2017-09-03 17:00:28 +0200277 struct btrfs_inode_item *inode_item)
278{
279 struct btrfs_key key;
280 u64 res;
281
282 if (inr == BTRFS_FIRST_FREE_OBJECTID) {
283 if (root->objectid != btrfs_info.fs_root.objectid) {
284 u64 parent;
285 struct btrfs_root_ref ref;
286
287 parent = btrfs_lookup_root_ref(root->objectid, &ref,
288 NULL);
289 if (parent == -1ULL)
290 return -1ULL;
291
292 if (btrfs_find_root(parent, root, NULL))
293 return -1ULL;
294
295 inr = ref.dirid;
296 }
297
298 if (inode_item) {
299 key.objectid = inr;
300 key.type = BTRFS_INODE_ITEM_KEY;
301 key.offset = 0;
302
Qu Wenruocafffc52020-06-24 18:03:02 +0200303 if (__btrfs_lookup_inode(root, &key, inode_item, NULL))
Marek Behún21a14fa2017-09-03 17:00:28 +0200304 return -1ULL;
305 }
306
307 return inr;
308 }
309
Qu Wenruocafffc52020-06-24 18:03:02 +0200310 res = __btrfs_lookup_inode_ref(root, inr, NULL, NULL);
Marek Behún21a14fa2017-09-03 17:00:28 +0200311 if (res == -1ULL)
312 return -1ULL;
313
314 if (inode_item) {
315 key.objectid = res;
316 key.type = BTRFS_INODE_ITEM_KEY;
317 key.offset = 0;
318
Qu Wenruocafffc52020-06-24 18:03:02 +0200319 if (__btrfs_lookup_inode(root, &key, inode_item, NULL))
Marek Behún21a14fa2017-09-03 17:00:28 +0200320 return -1ULL;
321 }
322
323 return res;
324}
325
326static inline int next_length(const char *path)
327{
328 int res = 0;
Qu Wenruo5bdcb372020-06-24 18:03:04 +0200329 while (*path != '\0' && *path != '/') {
330 ++res;
331 ++path;
332 if (res > BTRFS_NAME_LEN)
333 break;
334 }
Marek Behún21a14fa2017-09-03 17:00:28 +0200335 return res;
336}
337
338static inline const char *skip_current_directories(const char *cur)
339{
340 while (1) {
341 if (cur[0] == '/')
342 ++cur;
343 else if (cur[0] == '.' && cur[1] == '/')
344 cur += 2;
345 else
346 break;
347 }
348
349 return cur;
350}
351
Qu Wenruoc921aa22020-06-24 18:03:05 +0200352/*
353 * Resolve one filename of @ino of @root.
354 *
355 * key_ret: The child key (either INODE_ITEM or ROOT_ITEM type)
356 * type_ret: BTRFS_FT_* of the child inode.
357 *
358 * Return 0 with above members filled.
359 * Return <0 for error.
360 */
361static int resolve_one_filename(struct btrfs_root *root, u64 ino,
362 const char *name, int namelen,
363 struct btrfs_key *key_ret, u8 *type_ret)
364{
365 struct btrfs_dir_item *dir_item;
366 struct btrfs_path path;
367 int ret = 0;
368
369 btrfs_init_path(&path);
370
371 dir_item = btrfs_lookup_dir_item(NULL, root, &path, ino, name,
372 namelen, 0);
373 if (IS_ERR(dir_item)) {
374 ret = PTR_ERR(dir_item);
375 goto out;
376 }
377
378 btrfs_dir_item_key_to_cpu(path.nodes[0], dir_item, key_ret);
379 *type_ret = btrfs_dir_type(path.nodes[0], dir_item);
380out:
381 btrfs_release_path(&path);
382 return ret;
383}
384
385/*
386 * Resolve a full path @filename. The start point is @ino of @root.
387 *
388 * The result will be filled into @root_ret, @ino_ret and @type_ret.
389 */
390int btrfs_lookup_path(struct btrfs_root *root, u64 ino, const char *filename,
391 struct btrfs_root **root_ret, u64 *ino_ret,
392 u8 *type_ret, int symlink_limit)
393{
394 struct btrfs_fs_info *fs_info = root->fs_info;
395 struct btrfs_root *next_root;
396 struct btrfs_key key;
397 const char *cur = filename;
398 u64 next_ino;
399 u8 next_type;
400 u8 type;
401 int len;
402 int ret = 0;
403
404 /* If the path is absolute path, also search from fs root */
405 if (*cur == '/') {
406 root = fs_info->fs_root;
407 ino = btrfs_root_dirid(&root->root_item);
408 type = BTRFS_FT_DIR;
409 }
410
411 while (*cur != '\0') {
412 cur = skip_current_directories(cur);
413
414 len = next_length(cur);
415 if (len > BTRFS_NAME_LEN) {
416 error("%s: Name too long at \"%.*s\"", __func__,
417 BTRFS_NAME_LEN, cur);
418 return -ENAMETOOLONG;
419 }
420
421 if (len == 1 && cur[0] == '.')
422 break;
423
424 if (len == 2 && cur[0] == '.' && cur[1] == '.') {
425 /* Go one level up */
426 ret = get_parent_inode(root, ino, &next_root, &next_ino);
427 if (ret < 0)
428 return ret;
429 root = next_root;
430 ino = next_ino;
431 goto next;
432 }
433
434 if (!*cur)
435 break;
436
437 ret = resolve_one_filename(root, ino, cur, len, &key, &type);
438 if (ret < 0)
439 return ret;
440
441 if (key.type == BTRFS_ROOT_ITEM_KEY) {
442 /* Child inode is a subvolume */
443
444 next_root = btrfs_read_fs_root(fs_info, &key);
445 if (IS_ERR(next_root))
446 return PTR_ERR(next_root);
447 root = next_root;
448 ino = btrfs_root_dirid(&root->root_item);
449 } else if (type == BTRFS_FT_SYMLINK && symlink_limit >= 0) {
450 /* Child inode is a symlink */
451
452 char *target;
453
454 if (symlink_limit == 0) {
455 error("%s: Too much symlinks!", __func__);
456 return -EMLINK;
457 }
458 target = malloc(fs_info->sectorsize);
459 if (!target)
460 return -ENOMEM;
461 ret = btrfs_readlink(root, key.objectid, target);
462 if (ret < 0) {
463 free(target);
464 return ret;
465 }
466 target[ret] = '\0';
467
468 ret = btrfs_lookup_path(root, ino, target, &next_root,
469 &next_ino, &next_type,
470 symlink_limit);
471 if (ret < 0)
472 return ret;
473 root = next_root;
474 ino = next_ino;
475 type = next_type;
476 } else {
477 /* Child inode is an inode */
478 ino = key.objectid;
479 }
480next:
481 cur += len;
482 }
483
484 if (!ret) {
485 *root_ret = root;
486 *ino_ret = ino;
487 *type_ret = type;
488 }
489
490 return ret;
491}
492
Qu Wenruocafffc52020-06-24 18:03:02 +0200493u64 __btrfs_lookup_path(struct __btrfs_root *root, u64 inr, const char *path,
Marek Behún21a14fa2017-09-03 17:00:28 +0200494 u8 *type_p, struct btrfs_inode_item *inode_item_p,
495 int symlink_limit)
496{
497 struct btrfs_dir_item item;
498 struct btrfs_inode_item inode_item;
499 u8 type = BTRFS_FT_DIR;
500 int len, have_inode = 0;
501 const char *cur = path;
502
503 if (*cur == '/') {
504 ++cur;
505 inr = root->root_dirid;
506 }
507
508 do {
509 cur = skip_current_directories(cur);
510
511 len = next_length(cur);
512 if (len > BTRFS_NAME_LEN) {
513 printf("%s: Name too long at \"%.*s\"\n", __func__,
514 BTRFS_NAME_LEN, cur);
515 return -1ULL;
516 }
517
518 if (len == 1 && cur[0] == '.')
519 break;
520
521 if (len == 2 && cur[0] == '.' && cur[1] == '.') {
522 cur += 2;
Qu Wenruocafffc52020-06-24 18:03:02 +0200523 inr = __get_parent_inode(root, inr, &inode_item);
Marek Behún21a14fa2017-09-03 17:00:28 +0200524 if (inr == -1ULL)
525 return -1ULL;
526
527 type = BTRFS_FT_DIR;
528 continue;
529 }
530
531 if (!*cur)
532 break;
533
Qu Wenruocafffc52020-06-24 18:03:02 +0200534 if (__btrfs_lookup_dir_item(root, inr, cur, len, &item))
Marek Behún21a14fa2017-09-03 17:00:28 +0200535 return -1ULL;
536
537 type = item.type;
538 have_inode = 1;
Qu Wenruocafffc52020-06-24 18:03:02 +0200539 if (__btrfs_lookup_inode(root, (struct btrfs_key *)&item.location,
Qu Wenruo3b4b40c2020-06-24 18:02:47 +0200540 &inode_item, root))
Marek Behún21a14fa2017-09-03 17:00:28 +0200541 return -1ULL;
542
543 if (item.type == BTRFS_FT_SYMLINK && symlink_limit >= 0) {
544 char *target;
545
546 if (!symlink_limit) {
547 printf("%s: Too much symlinks!\n", __func__);
548 return -1ULL;
549 }
550
551 target = malloc(min(inode_item.size + 1,
552 (u64) btrfs_info.sb.sectorsize));
553 if (!target)
554 return -1ULL;
555
Qu Wenruocafffc52020-06-24 18:03:02 +0200556 if (__btrfs_readlink(root, item.location.objectid,
Marek Behún21a14fa2017-09-03 17:00:28 +0200557 target)) {
558 free(target);
559 return -1ULL;
560 }
561
Qu Wenruocafffc52020-06-24 18:03:02 +0200562 inr = __btrfs_lookup_path(root, inr, target, &type,
Marek Behún21a14fa2017-09-03 17:00:28 +0200563 &inode_item, symlink_limit - 1);
564
565 free(target);
566
567 if (inr == -1ULL)
568 return -1ULL;
569 } else if (item.type != BTRFS_FT_DIR && cur[len]) {
570 printf("%s: \"%.*s\" not a directory\n", __func__,
571 (int) (cur - path + len), path);
572 return -1ULL;
573 } else {
574 inr = item.location.objectid;
575 }
576
577 cur += len;
578 } while (*cur);
579
580 if (type_p)
581 *type_p = type;
582
583 if (inode_item_p) {
584 if (!have_inode) {
585 struct btrfs_key key;
586
587 key.objectid = inr;
588 key.type = BTRFS_INODE_ITEM_KEY;
589 key.offset = 0;
590
Qu Wenruocafffc52020-06-24 18:03:02 +0200591 if (__btrfs_lookup_inode(root, &key, &inode_item, NULL))
Marek Behún21a14fa2017-09-03 17:00:28 +0200592 return -1ULL;
593 }
594
595 *inode_item_p = inode_item;
596 }
597
598 return inr;
599}
600
Qu Wenruo207011b2020-06-24 18:02:57 +0200601u64 btrfs_file_read(const struct __btrfs_root *root, u64 inr, u64 offset,
Marek Behún21a14fa2017-09-03 17:00:28 +0200602 u64 size, char *buf)
603{
Qu Wenruo33966de2020-06-24 18:02:56 +0200604 struct __btrfs_path path;
Marek Behún21a14fa2017-09-03 17:00:28 +0200605 struct btrfs_key key;
606 struct btrfs_file_extent_item *extent;
Marek Behúnecab8812017-10-06 15:04:57 +0200607 int res = 0;
Marek Behún21a14fa2017-09-03 17:00:28 +0200608 u64 rd, rd_all = -1ULL;
609
610 key.objectid = inr;
611 key.type = BTRFS_EXTENT_DATA_KEY;
612 key.offset = offset;
613
614 if (btrfs_search_tree(root, &key, &path))
615 return -1ULL;
616
Qu Wenruo75b08172020-06-24 18:02:55 +0200617 if (__btrfs_comp_keys(&key, btrfs_path_leaf_key(&path)) < 0) {
Marek Behún21a14fa2017-09-03 17:00:28 +0200618 if (btrfs_prev_slot(&path))
619 goto out;
620
621 if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))
622 goto out;
623 }
624
625 rd_all = 0;
626
627 do {
628 if (btrfs_comp_keys_type(&key, btrfs_path_leaf_key(&path)))
629 break;
630
631 extent = btrfs_path_item_ptr(&path,
632 struct btrfs_file_extent_item);
633
634 if (extent->type == BTRFS_FILE_EXTENT_INLINE) {
635 btrfs_file_extent_item_to_cpu_inl(extent);
636 rd = btrfs_read_extent_inline(&path, extent, offset,
637 size, buf);
638 } else {
639 btrfs_file_extent_item_to_cpu(extent);
640 rd = btrfs_read_extent_reg(&path, extent, offset, size,
641 buf);
642 }
643
644 if (rd == -1ULL) {
645 printf("%s: Error reading extent\n", __func__);
646 rd_all = -1;
647 goto out;
648 }
649
650 offset = 0;
651 buf += rd;
652 rd_all += rd;
653 size -= rd;
654
655 if (!size)
656 break;
657 } while (!(res = btrfs_next_slot(&path)));
658
659 if (res)
660 return -1ULL;
661
662out:
Qu Wenruo33966de2020-06-24 18:02:56 +0200663 __btrfs_free_path(&path);
Marek Behún21a14fa2017-09-03 17:00:28 +0200664 return rd_all;
665}