aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/fs/btrfs/btrfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/fs/btrfs/btrfs.c')
-rw-r--r--roms/u-boot/fs/btrfs/btrfs.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/roms/u-boot/fs/btrfs/btrfs.c b/roms/u-boot/fs/btrfs/btrfs.c
new file mode 100644
index 000000000..52a243a65
--- /dev/null
+++ b/roms/u-boot/fs/btrfs/btrfs.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * BTRFS filesystem implementation for U-Boot
+ *
+ * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
+ */
+
+#include <config.h>
+#include <malloc.h>
+#include <uuid.h>
+#include <linux/time.h>
+#include "btrfs.h"
+#include "crypto/hash.h"
+#include "disk-io.h"
+
+struct btrfs_fs_info *current_fs_info;
+
+static int show_dir(struct btrfs_root *root, struct extent_buffer *eb,
+ struct btrfs_dir_item *di)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_inode_item ii;
+ struct btrfs_key key;
+ static const char* dir_item_str[] = {
+ [BTRFS_FT_REG_FILE] = " ",
+ [BTRFS_FT_DIR] = "DIR",
+ [BTRFS_FT_CHRDEV] = "CHR",
+ [BTRFS_FT_BLKDEV] = "BLK",
+ [BTRFS_FT_FIFO] = "FIF",
+ [BTRFS_FT_SOCK] = "SCK",
+ [BTRFS_FT_SYMLINK] = "SYM",
+ };
+ u8 type = btrfs_dir_type(eb, di);
+ char namebuf[BTRFS_NAME_LEN];
+ char *target = NULL;
+ char filetime[32];
+ time_t mtime;
+ int ret = 0;
+
+ /* skip XATTRs in directory listing */
+ if (type == BTRFS_FT_XATTR)
+ return 0;
+
+ btrfs_dir_item_key_to_cpu(eb, di, &key);
+
+ if (key.type == BTRFS_ROOT_ITEM_KEY) {
+ struct btrfs_root *subvol;
+
+ /* It's a subvolume, get its mtime from root item */
+ subvol = btrfs_read_fs_root(fs_info, &key);
+ if (IS_ERR(subvol)) {
+ ret = PTR_ERR(subvol);
+ error("Can't find root %llu", key.objectid);
+ return ret;
+ }
+ mtime = btrfs_stack_timespec_sec(&subvol->root_item.otime);
+ } else {
+ struct btrfs_path path;
+
+ /* It's regular inode, get its mtime from inode item */
+ btrfs_init_path(&path);
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret < 0) {
+ error("Can't find inode %llu", key.objectid);
+ btrfs_release_path(&path);
+ return ret;
+ }
+ read_extent_buffer(path.nodes[0], &ii,
+ btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
+ sizeof(ii));
+ btrfs_release_path(&path);
+ mtime = btrfs_stack_timespec_sec(&ii.mtime);
+ }
+ ctime_r(&mtime, filetime);
+
+ if (type == BTRFS_FT_SYMLINK) {
+ target = malloc(fs_info->sectorsize);
+ if (!target) {
+ error("Can't alloc memory for symlink %llu",
+ key.objectid);
+ return -ENOMEM;
+ }
+ ret = btrfs_readlink(root, key.objectid, target);
+ if (ret < 0) {
+ error("Failed to read symlink %llu", key.objectid);
+ goto out;
+ }
+ target[ret] = '\0';
+ }
+
+ if (type < ARRAY_SIZE(dir_item_str) && dir_item_str[type])
+ printf("<%s> ", dir_item_str[type]);
+ else
+ printf("?%3u? ", type);
+ if (type == BTRFS_FT_CHRDEV || type == BTRFS_FT_BLKDEV) {
+ ASSERT(key.type == BTRFS_INODE_ITEM_KEY);
+ printf("%4llu,%5llu ", btrfs_stack_inode_rdev(&ii) >> 20,
+ btrfs_stack_inode_rdev(&ii) & 0xfffff);
+ } else {
+ if (key.type == BTRFS_INODE_ITEM_KEY)
+ printf("%10llu ", btrfs_stack_inode_size(&ii));
+ else
+ printf("%10llu ", 0ULL);
+ }
+
+ read_extent_buffer(eb, namebuf, (unsigned long)(di + 1),
+ btrfs_dir_name_len(eb, di));
+ printf("%24.24s %.*s", filetime, btrfs_dir_name_len(eb, di), namebuf);
+ if (type == BTRFS_FT_SYMLINK)
+ printf(" -> %s", target ? target : "?");
+ printf("\n");
+out:
+ free(target);
+ return ret;
+}
+
+int btrfs_probe(struct blk_desc *fs_dev_desc,
+ struct disk_partition *fs_partition)
+{
+ struct btrfs_fs_info *fs_info;
+ int ret = -1;
+
+ btrfs_hash_init();
+ fs_info = open_ctree_fs_info(fs_dev_desc, fs_partition);
+ if (fs_info) {
+ current_fs_info = fs_info;
+ ret = 0;
+ }
+ return ret;
+}
+
+int btrfs_ls(const char *path)
+{
+ struct btrfs_fs_info *fs_info = current_fs_info;
+ struct btrfs_root *root = fs_info->fs_root;
+ u64 ino = BTRFS_FIRST_FREE_OBJECTID;
+ u8 type;
+ int ret;
+
+ ASSERT(fs_info);
+ ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
+ path, &root, &ino, &type, 40);
+ if (ret < 0) {
+ printf("Cannot lookup path %s\n", path);
+ return ret;
+ }
+
+ if (type != BTRFS_FT_DIR) {
+ error("Not a directory: %s", path);
+ return -ENOENT;
+ }
+ ret = btrfs_iter_dir(root, ino, show_dir);
+ if (ret < 0) {
+ error("An error occurred while listing directory %s", path);
+ return ret;
+ }
+ return 0;
+}
+
+int btrfs_exists(const char *file)
+{
+ struct btrfs_fs_info *fs_info = current_fs_info;
+ struct btrfs_root *root;
+ u64 ino;
+ u8 type;
+ int ret;
+
+ ASSERT(fs_info);
+
+ ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
+ file, &root, &ino, &type, 40);
+ if (ret < 0)
+ return 0;
+
+ if (type == BTRFS_FT_REG_FILE)
+ return 1;
+ return 0;
+}
+
+int btrfs_size(const char *file, loff_t *size)
+{
+ struct btrfs_fs_info *fs_info = current_fs_info;
+ struct btrfs_inode_item *ii;
+ struct btrfs_root *root;
+ struct btrfs_path path;
+ struct btrfs_key key;
+ u64 ino;
+ u8 type;
+ int ret;
+
+ ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
+ file, &root, &ino, &type, 40);
+ if (ret < 0) {
+ printf("Cannot lookup file %s\n", file);
+ return ret;
+ }
+ if (type != BTRFS_FT_REG_FILE) {
+ printf("Not a regular file: %s\n", file);
+ return -ENOENT;
+ }
+ btrfs_init_path(&path);
+ key.objectid = ino;
+ key.type = BTRFS_INODE_ITEM_KEY;
+ key.offset = 0;
+
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+ if (ret < 0) {
+ printf("Cannot lookup ino %llu\n", ino);
+ return ret;
+ }
+ if (ret > 0) {
+ printf("Ino %llu does not exist\n", ino);
+ ret = -ENOENT;
+ goto out;
+ }
+ ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
+ struct btrfs_inode_item);
+ *size = btrfs_inode_size(path.nodes[0], ii);
+out:
+ btrfs_release_path(&path);
+ return ret;
+}
+
+int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
+ loff_t *actread)
+{
+ struct btrfs_fs_info *fs_info = current_fs_info;
+ struct btrfs_root *root;
+ loff_t real_size = 0;
+ u64 ino;
+ u8 type;
+ int ret;
+
+ ASSERT(fs_info);
+ ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
+ file, &root, &ino, &type, 40);
+ if (ret < 0) {
+ error("Cannot lookup file %s", file);
+ return ret;
+ }
+
+ if (type != BTRFS_FT_REG_FILE) {
+ error("Not a regular file: %s", file);
+ return -EINVAL;
+ }
+
+ if (!len) {
+ ret = btrfs_size(file, &real_size);
+ if (ret < 0) {
+ error("Failed to get inode size: %s", file);
+ return ret;
+ }
+ len = real_size;
+ }
+
+ if (len > real_size - offset)
+ len = real_size - offset;
+
+ ret = btrfs_file_read(root, ino, offset, len, buf);
+ if (ret < 0) {
+ error("An error occurred while reading file %s", file);
+ return ret;
+ }
+
+ *actread = len;
+ return 0;
+}
+
+void btrfs_close(void)
+{
+ if (current_fs_info) {
+ close_ctree_fs_info(current_fs_info);
+ current_fs_info = NULL;
+ }
+}
+
+int btrfs_uuid(char *uuid_str)
+{
+#ifdef CONFIG_LIB_UUID
+ if (current_fs_info)
+ uuid_bin_to_str(current_fs_info->super_copy->fsid, uuid_str,
+ UUID_STR_FORMAT_STD);
+ return 0;
+#endif
+ return -ENOSYS;
+}