uboot/fs/btrfs/btrfs.c
<<
>>
Prefs
   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 <config.h>
  10#include <malloc.h>
  11#include <linux/time.h>
  12
  13struct btrfs_info btrfs_info;
  14
  15static int readdir_callback(const struct btrfs_root *root,
  16                            struct btrfs_dir_item *item)
  17{
  18        static const char typestr[BTRFS_FT_MAX][4] = {
  19                [BTRFS_FT_UNKNOWN]  = " ? ",
  20                [BTRFS_FT_REG_FILE] = "   ",
  21                [BTRFS_FT_DIR]      = "DIR",
  22                [BTRFS_FT_CHRDEV]   = "CHR",
  23                [BTRFS_FT_BLKDEV]   = "BLK",
  24                [BTRFS_FT_FIFO]     = "FIF",
  25                [BTRFS_FT_SOCK]     = "SCK",
  26                [BTRFS_FT_SYMLINK]  = "SYM",
  27                [BTRFS_FT_XATTR]    = " ? ",
  28        };
  29        struct btrfs_inode_item inode;
  30        const char *name = (const char *) (item + 1);
  31        char filetime[32], *target = NULL;
  32        time_t mtime;
  33
  34        if (btrfs_lookup_inode(root, &item->location, &inode, NULL)) {
  35                printf("%s: Cannot find inode item for directory entry %.*s!\n",
  36                       __func__, item->name_len, name);
  37                return 0;
  38        }
  39
  40        mtime = inode.mtime.sec;
  41        ctime_r(&mtime, filetime);
  42
  43        if (item->type == BTRFS_FT_SYMLINK) {
  44                target = malloc(min(inode.size + 1,
  45                                    (u64) btrfs_info.sb.sectorsize));
  46
  47                if (target && btrfs_readlink(root, item->location.objectid,
  48                                             target)) {
  49                        free(target);
  50                        target = NULL;
  51                }
  52
  53                if (!target)
  54                        printf("%s: Cannot read symlink target!\n", __func__);
  55        }
  56
  57        printf("<%s> ", typestr[item->type]);
  58        if (item->type == BTRFS_FT_CHRDEV || item->type == BTRFS_FT_BLKDEV)
  59                printf("%4u,%5u  ", (unsigned int) (inode.rdev >> 20),
  60                        (unsigned int) (inode.rdev & 0xfffff));
  61        else
  62                printf("%10llu  ", inode.size);
  63
  64        printf("%24.24s  %.*s", filetime, item->name_len, name);
  65
  66        if (item->type == BTRFS_FT_SYMLINK) {
  67                printf(" -> %s", target ? target : "?");
  68                if (target)
  69                        free(target);
  70        }
  71
  72        printf("\n");
  73
  74        return 0;
  75}
  76
  77int btrfs_probe(struct blk_desc *fs_dev_desc, disk_partition_t *fs_partition)
  78{
  79        btrfs_blk_desc = fs_dev_desc;
  80        btrfs_part_info = fs_partition;
  81
  82        memset(&btrfs_info, 0, sizeof(btrfs_info));
  83
  84        btrfs_hash_init();
  85        if (btrfs_read_superblock())
  86                return -1;
  87
  88        if (btrfs_chunk_map_init()) {
  89                printf("%s: failed to init chunk map\n", __func__);
  90                return -1;
  91        }
  92
  93        btrfs_info.tree_root.objectid = 0;
  94        btrfs_info.tree_root.bytenr = btrfs_info.sb.root;
  95        btrfs_info.chunk_root.objectid = 0;
  96        btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
  97
  98        if (btrfs_read_chunk_tree()) {
  99                printf("%s: failed to read chunk tree\n", __func__);
 100                return -1;
 101        }
 102
 103        if (btrfs_find_root(btrfs_get_default_subvol_objectid(),
 104                            &btrfs_info.fs_root, NULL)) {
 105                printf("%s: failed to find default subvolume\n", __func__);
 106                return -1;
 107        }
 108
 109        return 0;
 110}
 111
 112int btrfs_ls(const char *path)
 113{
 114        struct btrfs_root root = btrfs_info.fs_root;
 115        u64 inr;
 116        u8 type;
 117
 118        inr = btrfs_lookup_path(&root, root.root_dirid, path, &type, NULL, 40);
 119
 120        if (inr == -1ULL) {
 121                printf("Cannot lookup path %s\n", path);
 122                return -1;
 123        }
 124
 125        if (type != BTRFS_FT_DIR) {
 126                printf("Not a directory: %s\n", path);
 127                return -1;
 128        }
 129
 130        if (btrfs_readdir(&root, inr, readdir_callback)) {
 131                printf("An error occured while listing directory %s\n", path);
 132                return -1;
 133        }
 134
 135        return 0;
 136}
 137
 138int btrfs_exists(const char *file)
 139{
 140        struct btrfs_root root = btrfs_info.fs_root;
 141        u64 inr;
 142        u8 type;
 143
 144        inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, NULL, 40);
 145
 146        return (inr != -1ULL && type == BTRFS_FT_REG_FILE);
 147}
 148
 149int btrfs_size(const char *file, loff_t *size)
 150{
 151        struct btrfs_root root = btrfs_info.fs_root;
 152        struct btrfs_inode_item inode;
 153        u64 inr;
 154        u8 type;
 155
 156        inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
 157                                40);
 158
 159        if (inr == -1ULL) {
 160                printf("Cannot lookup file %s\n", file);
 161                return -1;
 162        }
 163
 164        if (type != BTRFS_FT_REG_FILE) {
 165                printf("Not a regular file: %s\n", file);
 166                return -1;
 167        }
 168
 169        *size = inode.size;
 170        return 0;
 171}
 172
 173int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
 174               loff_t *actread)
 175{
 176        struct btrfs_root root = btrfs_info.fs_root;
 177        struct btrfs_inode_item inode;
 178        u64 inr, rd;
 179        u8 type;
 180
 181        inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
 182                                40);
 183
 184        if (inr == -1ULL) {
 185                printf("Cannot lookup file %s\n", file);
 186                return -1;
 187        }
 188
 189        if (type != BTRFS_FT_REG_FILE) {
 190                printf("Not a regular file: %s\n", file);
 191                return -1;
 192        }
 193
 194        if (!len)
 195                len = inode.size;
 196
 197        if (len > inode.size - offset)
 198                len = inode.size - offset;
 199
 200        rd = btrfs_file_read(&root, inr, offset, len, buf);
 201        if (rd == -1ULL) {
 202                printf("An error occured while reading file %s\n", file);
 203                return -1;
 204        }
 205
 206        *actread = rd;
 207        return 0;
 208}
 209
 210void btrfs_close(void)
 211{
 212        btrfs_chunk_map_exit();
 213}
 214
 215int btrfs_uuid(char *uuid_str)
 216{
 217#ifdef CONFIG_LIB_UUID
 218        uuid_bin_to_str(btrfs_info.sb.fsid, uuid_str, UUID_STR_FORMAT_STD);
 219        return 0;
 220#endif
 221        return -ENOSYS;
 222}
 223