183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
221a14facSMarek Behún /*
321a14facSMarek Behún * BTRFS filesystem implementation for U-Boot
421a14facSMarek Behún *
521a14facSMarek Behún * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
621a14facSMarek Behún */
721a14facSMarek Behún
821a14facSMarek Behún #include "btrfs.h"
921a14facSMarek Behún #include <malloc.h>
10*c9795396SMarek Vasut #include <memalign.h>
1121a14facSMarek Behún
btrfs_read_extent_inline(struct btrfs_path * path,struct btrfs_file_extent_item * extent,u64 offset,u64 size,char * out)1221a14facSMarek Behún u64 btrfs_read_extent_inline(struct btrfs_path *path,
1321a14facSMarek Behún struct btrfs_file_extent_item *extent, u64 offset,
1421a14facSMarek Behún u64 size, char *out)
1521a14facSMarek Behún {
1621a14facSMarek Behún u32 clen, dlen, orig_size = size, res;
1721a14facSMarek Behún const char *cbuf;
1821a14facSMarek Behún char *dbuf;
1921a14facSMarek Behún const int data_off = offsetof(struct btrfs_file_extent_item,
2021a14facSMarek Behún disk_bytenr);
2121a14facSMarek Behún
2221a14facSMarek Behún clen = btrfs_path_item_size(path) - data_off;
2321a14facSMarek Behún cbuf = (const char *) extent + data_off;
2421a14facSMarek Behún dlen = extent->ram_bytes;
2521a14facSMarek Behún
2621a14facSMarek Behún if (offset > dlen)
2721a14facSMarek Behún return -1ULL;
2821a14facSMarek Behún
2921a14facSMarek Behún if (size > dlen - offset)
3021a14facSMarek Behún size = dlen - offset;
3121a14facSMarek Behún
3221a14facSMarek Behún if (extent->compression == BTRFS_COMPRESS_NONE) {
3321a14facSMarek Behún memcpy(out, cbuf + offset, size);
3421a14facSMarek Behún return size;
3521a14facSMarek Behún }
3621a14facSMarek Behún
3721a14facSMarek Behún if (dlen > orig_size) {
3821a14facSMarek Behún dbuf = malloc(dlen);
3921a14facSMarek Behún if (!dbuf)
4021a14facSMarek Behún return -1ULL;
4121a14facSMarek Behún } else {
4221a14facSMarek Behún dbuf = out;
4321a14facSMarek Behún }
4421a14facSMarek Behún
4521a14facSMarek Behún res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen);
4621a14facSMarek Behún if (res == -1 || res != dlen)
4721a14facSMarek Behún goto err;
4821a14facSMarek Behún
4921a14facSMarek Behún if (dlen > orig_size) {
5021a14facSMarek Behún memcpy(out, dbuf + offset, size);
5121a14facSMarek Behún free(dbuf);
5221a14facSMarek Behún } else if (offset) {
5321a14facSMarek Behún memmove(out, dbuf + offset, size);
5421a14facSMarek Behún }
5521a14facSMarek Behún
5621a14facSMarek Behún return size;
5721a14facSMarek Behún
5821a14facSMarek Behún err:
5921a14facSMarek Behún if (dlen > orig_size)
6021a14facSMarek Behún free(dbuf);
6121a14facSMarek Behún return -1ULL;
6221a14facSMarek Behún }
6321a14facSMarek Behún
btrfs_read_extent_reg(struct btrfs_path * path,struct btrfs_file_extent_item * extent,u64 offset,u64 size,char * out)6421a14facSMarek Behún u64 btrfs_read_extent_reg(struct btrfs_path *path,
6521a14facSMarek Behún struct btrfs_file_extent_item *extent, u64 offset,
6621a14facSMarek Behún u64 size, char *out)
6721a14facSMarek Behún {
6821a14facSMarek Behún u64 physical, clen, dlen, orig_size = size;
6921a14facSMarek Behún u32 res;
7021a14facSMarek Behún char *cbuf, *dbuf;
7121a14facSMarek Behún
7221a14facSMarek Behún clen = extent->disk_num_bytes;
7321a14facSMarek Behún dlen = extent->num_bytes;
7421a14facSMarek Behún
7521a14facSMarek Behún if (offset > dlen)
7621a14facSMarek Behún return -1ULL;
7721a14facSMarek Behún
7821a14facSMarek Behún if (size > dlen - offset)
7921a14facSMarek Behún size = dlen - offset;
8021a14facSMarek Behún
8121a14facSMarek Behún physical = btrfs_map_logical_to_physical(extent->disk_bytenr);
8221a14facSMarek Behún if (physical == -1ULL)
8321a14facSMarek Behún return -1ULL;
8421a14facSMarek Behún
8521a14facSMarek Behún if (extent->compression == BTRFS_COMPRESS_NONE) {
8621a14facSMarek Behún physical += extent->offset + offset;
8721a14facSMarek Behún if (!btrfs_devread(physical, size, out))
8821a14facSMarek Behún return -1ULL;
8921a14facSMarek Behún
9021a14facSMarek Behún return size;
9121a14facSMarek Behún }
9221a14facSMarek Behún
93*c9795396SMarek Vasut cbuf = malloc_cache_aligned(dlen > size ? clen + dlen : clen);
9421a14facSMarek Behún if (!cbuf)
9521a14facSMarek Behún return -1ULL;
9621a14facSMarek Behún
9721a14facSMarek Behún if (dlen > orig_size)
9821a14facSMarek Behún dbuf = cbuf + clen;
9921a14facSMarek Behún else
10021a14facSMarek Behún dbuf = out;
10121a14facSMarek Behún
10221a14facSMarek Behún if (!btrfs_devread(physical, clen, cbuf))
10321a14facSMarek Behún goto err;
10421a14facSMarek Behún
10521a14facSMarek Behún res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen);
10621a14facSMarek Behún if (res == -1)
10721a14facSMarek Behún goto err;
10821a14facSMarek Behún
10921a14facSMarek Behún if (dlen > orig_size)
11021a14facSMarek Behún memcpy(out, dbuf + offset, size);
11121a14facSMarek Behún else
11221a14facSMarek Behún memmove(out, dbuf + offset, size);
11321a14facSMarek Behún
11421a14facSMarek Behún free(cbuf);
11521a14facSMarek Behún return res;
11621a14facSMarek Behún
11721a14facSMarek Behún err:
11821a14facSMarek Behún free(cbuf);
11921a14facSMarek Behún return -1ULL;
12021a14facSMarek Behún }
121