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 <config.h>
   9#include <malloc.h>
  10#include <uuid.h>
  11#include <linux/time.h>
  12#include "btrfs.h"
  13#include "crypto/hash.h"
  14#include "disk-io.h"
  15
  16struct btrfs_fs_info *current_fs_info;
  17
  18static int show_dir(struct btrfs_root *root, struct extent_buffer *eb,
  19                    struct btrfs_dir_item *di)
  20{
  21        struct btrfs_fs_info *fs_info = root->fs_info;
  22        struct btrfs_inode_item ii;
  23        struct btrfs_key key;
  24        static const char* dir_item_str[] = {
  25                [BTRFS_FT_REG_FILE]     = "   ",
  26                [BTRFS_FT_DIR]          = "DIR",
  27                [BTRFS_FT_CHRDEV]       = "CHR",
  28                [BTRFS_FT_BLKDEV]       = "BLK",
  29                [BTRFS_FT_FIFO]         = "FIF",
  30                [BTRFS_FT_SOCK]         = "SCK",
  31                [BTRFS_FT_SYMLINK]      = "SYM",
  32        };
  33        u8 type = btrfs_dir_type(eb, di);
  34        char namebuf[BTRFS_NAME_LEN];
  35        char *target = NULL;
  36        char filetime[32];
  37        time_t mtime;
  38        int ret = 0;
  39
  40        /* skip XATTRs in directory listing */
  41        if (type == BTRFS_FT_XATTR)
  42                return 0;
  43
  44        btrfs_dir_item_key_to_cpu(eb, di, &key);
  45
  46        if (key.type == BTRFS_ROOT_ITEM_KEY) {
  47                struct btrfs_root *subvol;
  48
  49                /* It's a subvolume, get its mtime from root item */
  50                subvol = btrfs_read_fs_root(fs_info, &key);
  51                if (IS_ERR(subvol)) {
  52                        ret = PTR_ERR(subvol);
  53                        error("Can't find root %llu", key.objectid);
  54                        return ret;
  55                }
  56                mtime = btrfs_stack_timespec_sec(&subvol->root_item.otime);
  57        } else {
  58                struct btrfs_path path;
  59
  60                /* It's regular inode, get its mtime from inode item */
  61                btrfs_init_path(&path);
  62                ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
  63                if (ret > 0)
  64                        ret = -ENOENT;
  65                if (ret < 0) {
  66                        error("Can't find inode %llu", key.objectid);
  67                        btrfs_release_path(&path);
  68                        return ret;
  69                }
  70                read_extent_buffer(path.nodes[0], &ii,
  71                        btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
  72                        sizeof(ii));
  73                btrfs_release_path(&path);
  74                mtime = btrfs_stack_timespec_sec(&ii.mtime);
  75        }
  76        ctime_r(&mtime, filetime);
  77
  78        if (type == BTRFS_FT_SYMLINK) {
  79                target = malloc(fs_info->sectorsize);
  80                if (!target) {
  81                        error("Can't alloc memory for symlink %llu",
  82                                key.objectid);
  83                        return -ENOMEM;
  84                }
  85                ret = btrfs_readlink(root, key.objectid, target);
  86                if (ret < 0) {
  87                        error("Failed to read symlink %llu", key.objectid);
  88                        goto out;
  89                }
  90                target[ret] = '\0';
  91        }
  92
  93        if (type < ARRAY_SIZE(dir_item_str) && dir_item_str[type])
  94                printf("<%s> ", dir_item_str[type]);
  95        else
  96                printf("?%3u? ", type);
  97        if (type == BTRFS_FT_CHRDEV || type == BTRFS_FT_BLKDEV) {
  98                ASSERT(key.type == BTRFS_INODE_ITEM_KEY);
  99                printf("%4llu,%5llu  ", btrfs_stack_inode_rdev(&ii) >> 20,
 100                                btrfs_stack_inode_rdev(&ii) & 0xfffff);
 101        } else {
 102                if (key.type == BTRFS_INODE_ITEM_KEY)
 103                        printf("%10llu  ", btrfs_stack_inode_size(&ii));
 104                else
 105                        printf("%10llu  ", 0ULL);
 106        }
 107
 108        read_extent_buffer(eb, namebuf, (unsigned long)(di + 1),
 109                           btrfs_dir_name_len(eb, di));
 110        printf("%24.24s  %.*s", filetime, btrfs_dir_name_len(eb, di), namebuf);
 111        if (type == BTRFS_FT_SYMLINK)
 112                printf(" -> %s", target ? target : "?");
 113        printf("\n");
 114out:
 115        free(target);
 116        return ret;
 117}
 118
 119int btrfs_probe(struct blk_desc *fs_dev_desc,
 120                struct disk_partition *fs_partition)
 121{
 122        struct btrfs_fs_info *fs_info;
 123        int ret = -1;
 124
 125        btrfs_hash_init();
 126        fs_info = open_ctree_fs_info(fs_dev_desc, fs_partition);
 127        if (fs_info) {
 128                current_fs_info = fs_info;
 129                ret = 0;
 130        }
 131        return ret;
 132}
 133
 134int btrfs_ls(const char *path)
 135{
 136        struct btrfs_fs_info *fs_info = current_fs_info;
 137        struct btrfs_root *root = fs_info->fs_root;
 138        u64 ino = BTRFS_FIRST_FREE_OBJECTID;
 139        u8 type;
 140        int ret;
 141
 142        ASSERT(fs_info);
 143        ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
 144                                path, &root, &ino, &type, 40);
 145        if (ret < 0) {
 146                printf("Cannot lookup path %s\n", path);
 147                return ret;
 148        }
 149
 150        if (type != BTRFS_FT_DIR) {
 151                error("Not a directory: %s", path);
 152                return -ENOENT;
 153        }
 154        ret = btrfs_iter_dir(root, ino, show_dir);
 155        if (ret < 0) {
 156                error("An error occurred while listing directory %s", path);
 157                return ret;
 158        }
 159        return 0;
 160}
 161
 162int btrfs_exists(const char *file)
 163{
 164        struct btrfs_fs_info *fs_info = current_fs_info;
 165        struct btrfs_root *root;
 166        u64 ino;
 167        u8 type;
 168        int ret;
 169
 170        ASSERT(fs_info);
 171
 172        ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
 173                                file, &root, &ino, &type, 40);
 174        if (ret < 0)
 175                return 0;
 176
 177        if (type == BTRFS_FT_REG_FILE)
 178                return 1;
 179        return 0;
 180}
 181
 182int btrfs_size(const char *file, loff_t *size)
 183{
 184        struct btrfs_fs_info *fs_info = current_fs_info;
 185        struct btrfs_inode_item *ii;
 186        struct btrfs_root *root;
 187        struct btrfs_path path;
 188        struct btrfs_key key;
 189        u64 ino;
 190        u8 type;
 191        int ret;
 192
 193        ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
 194                                file, &root, &ino, &type, 40);
 195        if (ret < 0) {
 196                printf("Cannot lookup file %s\n", file);
 197                return ret;
 198        }
 199        if (type != BTRFS_FT_REG_FILE) {
 200                printf("Not a regular file: %s\n", file);
 201                return -ENOENT;
 202        }
 203        btrfs_init_path(&path);
 204        key.objectid = ino;
 205        key.type = BTRFS_INODE_ITEM_KEY;
 206        key.offset = 0;
 207
 208        ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
 209        if (ret < 0) {
 210                printf("Cannot lookup ino %llu\n", ino);
 211                return ret;
 212        }
 213        if (ret > 0) {
 214                printf("Ino %llu does not exist\n", ino);
 215                ret = -ENOENT;
 216                goto out;
 217        }
 218        ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
 219                            struct btrfs_inode_item);
 220        *size = btrfs_inode_size(path.nodes[0], ii);
 221out:
 222        btrfs_release_path(&path);
 223        return ret;
 224}
 225
 226int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
 227               loff_t *actread)
 228{
 229        struct btrfs_fs_info *fs_info = current_fs_info;
 230        struct btrfs_root *root;
 231        loff_t real_size = 0;
 232        u64 ino;
 233        u8 type;
 234        int ret;
 235
 236        ASSERT(fs_info);
 237        ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
 238                                file, &root, &ino, &type, 40);
 239        if (ret < 0) {
 240                error("Cannot lookup file %s", file);
 241                return ret;
 242        }
 243
 244        if (type != BTRFS_FT_REG_FILE) {
 245                error("Not a regular file: %s", file);
 246                return -EINVAL;
 247        }
 248
 249        if (!len) {
 250                ret = btrfs_size(file, &real_size);
 251                if (ret < 0) {
 252                        error("Failed to get inode size: %s", file);
 253                        return ret;
 254                }
 255                len = real_size;
 256        }
 257
 258        if (len > real_size - offset)
 259                len = real_size - offset;
 260
 261        ret = btrfs_file_read(root, ino, offset, len, buf);
 262        if (ret < 0) {
 263                error("An error occurred while reading file %s", file);
 264                return ret;
 265        }
 266
 267        *actread = len;
 268        return 0;
 269}
 270
 271void btrfs_close(void)
 272{
 273        if (current_fs_info) {
 274                close_ctree_fs_info(current_fs_info);
 275                current_fs_info = NULL;
 276        }
 277}
 278
 279int btrfs_uuid(char *uuid_str)
 280{
 281#ifdef CONFIG_LIB_UUID
 282        if (current_fs_info)
 283                uuid_bin_to_str(current_fs_info->super_copy->fsid, uuid_str,
 284                                UUID_STR_FORMAT_STD);
 285        return 0;
 286#endif
 287        return -ENOSYS;
 288}
 289