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 #include <memalign.h> 11 12 u64 btrfs_read_extent_inline(struct btrfs_path *path, 13 struct btrfs_file_extent_item *extent, u64 offset, 14 u64 size, char *out) 15 { 16 u32 clen, dlen, orig_size = size, res; 17 const char *cbuf; 18 char *dbuf; 19 const int data_off = offsetof(struct btrfs_file_extent_item, 20 disk_bytenr); 21 22 clen = btrfs_path_item_size(path) - data_off; 23 cbuf = (const char *) extent + data_off; 24 dlen = extent->ram_bytes; 25 26 if (offset > dlen) 27 return -1ULL; 28 29 if (size > dlen - offset) 30 size = dlen - offset; 31 32 if (extent->compression == BTRFS_COMPRESS_NONE) { 33 memcpy(out, cbuf + offset, size); 34 return size; 35 } 36 37 if (dlen > orig_size) { 38 dbuf = malloc(dlen); 39 if (!dbuf) 40 return -1ULL; 41 } else { 42 dbuf = out; 43 } 44 45 res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen); 46 if (res == -1 || res != dlen) 47 goto err; 48 49 if (dlen > orig_size) { 50 memcpy(out, dbuf + offset, size); 51 free(dbuf); 52 } else if (offset) { 53 memmove(out, dbuf + offset, size); 54 } 55 56 return size; 57 58 err: 59 if (dlen > orig_size) 60 free(dbuf); 61 return -1ULL; 62 } 63 64 u64 btrfs_read_extent_reg(struct btrfs_path *path, 65 struct btrfs_file_extent_item *extent, u64 offset, 66 u64 size, char *out) 67 { 68 u64 physical, clen, dlen, orig_size = size; 69 u32 res; 70 char *cbuf, *dbuf; 71 72 clen = extent->disk_num_bytes; 73 dlen = extent->num_bytes; 74 75 if (offset > dlen) 76 return -1ULL; 77 78 if (size > dlen - offset) 79 size = dlen - offset; 80 81 physical = btrfs_map_logical_to_physical(extent->disk_bytenr); 82 if (physical == -1ULL) 83 return -1ULL; 84 85 if (extent->compression == BTRFS_COMPRESS_NONE) { 86 physical += extent->offset + offset; 87 if (!btrfs_devread(physical, size, out)) 88 return -1ULL; 89 90 return size; 91 } 92 93 cbuf = malloc_cache_aligned(dlen > size ? clen + dlen : clen); 94 if (!cbuf) 95 return -1ULL; 96 97 if (dlen > orig_size) 98 dbuf = cbuf + clen; 99 else 100 dbuf = out; 101 102 if (!btrfs_devread(physical, clen, cbuf)) 103 goto err; 104 105 res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen); 106 if (res == -1) 107 goto err; 108 109 if (dlen > orig_size) 110 memcpy(out, dbuf + offset, size); 111 else 112 memmove(out, dbuf + offset, size); 113 114 free(cbuf); 115 return res; 116 117 err: 118 free(cbuf); 119 return -1ULL; 120 } 121