diff options
Diffstat (limited to 'fs/btrfs/extent-io.c')
-rw-r--r-- | fs/btrfs/extent-io.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/fs/btrfs/extent-io.c b/fs/btrfs/extent-io.c new file mode 100644 index 0000000000..feb91432e9 --- /dev/null +++ b/fs/btrfs/extent-io.c @@ -0,0 +1,120 @@ +/* + * BTRFS filesystem implementation for U-Boot + * + * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "btrfs.h" +#include <malloc.h> + +u64 btrfs_read_extent_inline(struct btrfs_path *path, + struct btrfs_file_extent_item *extent, u64 offset, + u64 size, char *out) +{ + u32 clen, dlen, orig_size = size, res; + const char *cbuf; + char *dbuf; + const int data_off = offsetof(struct btrfs_file_extent_item, + disk_bytenr); + + clen = btrfs_path_item_size(path) - data_off; + cbuf = (const char *) extent + data_off; + dlen = extent->ram_bytes; + + if (offset > dlen) + return -1ULL; + + if (size > dlen - offset) + size = dlen - offset; + + if (extent->compression == BTRFS_COMPRESS_NONE) { + memcpy(out, cbuf + offset, size); + return size; + } + + if (dlen > orig_size) { + dbuf = malloc(dlen); + if (!dbuf) + return -1ULL; + } else { + dbuf = out; + } + + res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen); + if (res == -1 || res != dlen) + goto err; + + if (dlen > orig_size) { + memcpy(out, dbuf + offset, size); + free(dbuf); + } else if (offset) { + memmove(out, dbuf + offset, size); + } + + return size; + +err: + if (dlen > orig_size) + free(dbuf); + return -1ULL; +} + +u64 btrfs_read_extent_reg(struct btrfs_path *path, + struct btrfs_file_extent_item *extent, u64 offset, + u64 size, char *out) +{ + u64 physical, clen, dlen, orig_size = size; + u32 res; + char *cbuf, *dbuf; + + clen = extent->disk_num_bytes; + dlen = extent->num_bytes; + + if (offset > dlen) + return -1ULL; + + if (size > dlen - offset) + size = dlen - offset; + + physical = btrfs_map_logical_to_physical(extent->disk_bytenr); + if (physical == -1ULL) + return -1ULL; + + if (extent->compression == BTRFS_COMPRESS_NONE) { + physical += extent->offset + offset; + if (!btrfs_devread(physical, size, out)) + return -1ULL; + + return size; + } + + cbuf = malloc(dlen > size ? clen + dlen : clen); + if (!cbuf) + return -1ULL; + + if (dlen > orig_size) + dbuf = cbuf + clen; + else + dbuf = out; + + if (!btrfs_devread(physical, clen, cbuf)) + goto err; + + res = btrfs_decompress(extent->compression, cbuf, clen, dbuf, dlen); + if (res == -1) + goto err; + + if (dlen > orig_size) + memcpy(out, dbuf + offset, size); + else + memmove(out, dbuf + offset, size); + + free(cbuf); + return res; + +err: + free(cbuf); + return -1ULL; +} |