xref: /openbmc/u-boot/fs/btrfs/extent-io.c (revision 87a62bce)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * BTRFS filesystem implementation for U-Boot
4  *
5  * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
6  */
7 
8 #include "btrfs.h"
9 #include <malloc.h>
10 
11 u64 btrfs_read_extent_inline(struct btrfs_path *path,
12 			     struct btrfs_file_extent_item *extent, u64 offset,
13 			     u64 size, char *out)
14 {
15 	u32 clen, dlen, orig_size = size, res;
16 	const char *cbuf;
17 	char *dbuf;
18 	const int data_off = offsetof(struct btrfs_file_extent_item,
19 				      disk_bytenr);
20 
21 	clen = btrfs_path_item_size(path) - data_off;
22 	cbuf = (const char *) extent + data_off;
23 	dlen = extent->ram_bytes;
24 
25 	if (offset > dlen)
26 		return -1ULL;
27 
28 	if (size > dlen - offset)
29 		size = dlen - offset;
30 
31 	if (extent->compression == BTRFS_COMPRESS_NONE) {
32 		memcpy(out, cbuf + offset, size);
33 		return size;
34 	}
35 
36 	if (dlen > orig_size) {
37 		dbuf = malloc(dlen);
38 		if (!dbuf)
39 			return -1ULL;
40 	} else {
41 		dbuf = out;
42 	}
43 
44 	res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen);
45 	if (res == -1 || res != dlen)
46 		goto err;
47 
48 	if (dlen > orig_size) {
49 		memcpy(out, dbuf + offset, size);
50 		free(dbuf);
51 	} else if (offset) {
52 		memmove(out, dbuf + offset, size);
53 	}
54 
55 	return size;
56 
57 err:
58 	if (dlen > orig_size)
59 		free(dbuf);
60 	return -1ULL;
61 }
62 
63 u64 btrfs_read_extent_reg(struct btrfs_path *path,
64 			  struct btrfs_file_extent_item *extent, u64 offset,
65 			  u64 size, char *out)
66 {
67 	u64 physical, clen, dlen, orig_size = size;
68 	u32 res;
69 	char *cbuf, *dbuf;
70 
71 	clen = extent->disk_num_bytes;
72 	dlen = extent->num_bytes;
73 
74 	if (offset > dlen)
75 		return -1ULL;
76 
77 	if (size > dlen - offset)
78 		size = dlen - offset;
79 
80 	physical = btrfs_map_logical_to_physical(extent->disk_bytenr);
81 	if (physical == -1ULL)
82 		return -1ULL;
83 
84 	if (extent->compression == BTRFS_COMPRESS_NONE) {
85 		physical += extent->offset + offset;
86 		if (!btrfs_devread(physical, size, out))
87 			return -1ULL;
88 
89 		return size;
90 	}
91 
92 	cbuf = malloc(dlen > size ? clen + dlen : clen);
93 	if (!cbuf)
94 		return -1ULL;
95 
96 	if (dlen > orig_size)
97 		dbuf = cbuf + clen;
98 	else
99 		dbuf = out;
100 
101 	if (!btrfs_devread(physical, clen, cbuf))
102 		goto err;
103 
104 	res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen);
105 	if (res == -1)
106 		goto err;
107 
108 	if (dlen > orig_size)
109 		memcpy(out, dbuf + offset, size);
110 	else
111 		memmove(out, dbuf + offset, size);
112 
113 	free(cbuf);
114 	return res;
115 
116 err:
117 	free(cbuf);
118 	return -1ULL;
119 }
120