123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- // 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] = "FILE",
- [BTRFS_FT_DIR] = "DIR",
- [BTRFS_FT_CHRDEV] = "CHRDEV",
- [BTRFS_FT_BLKDEV] = "BLKDEV",
- [BTRFS_FT_FIFO] = "FIFO",
- [BTRFS_FT_SOCK] = "SOCK",
- [BTRFS_FT_SYMLINK] = "SYMLINK",
- [BTRFS_FT_XATTR] = "XATTR"
- };
- u8 type = btrfs_dir_type(eb, di);
- char namebuf[BTRFS_NAME_LEN];
- char *target = NULL;
- char filetime[32];
- time_t mtime;
- int ret;
- 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("DIR_ITEM.%u", 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 occured 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 occured 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;
- }
|