uboot/fs/btrfs/dir-item.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 "disk-io.h"
  10
  11static int verify_dir_item(struct btrfs_root *root,
  12                    struct extent_buffer *leaf,
  13                    struct btrfs_dir_item *dir_item)
  14{
  15        u16 namelen = BTRFS_NAME_LEN;
  16        u8 type = btrfs_dir_type(leaf, dir_item);
  17
  18        if (type == BTRFS_FT_XATTR)
  19                namelen = XATTR_NAME_MAX;
  20
  21        if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
  22                fprintf(stderr, "invalid dir item name len: %u\n",
  23                        (unsigned)btrfs_dir_data_len(leaf, dir_item));
  24                return 1;
  25        }
  26
  27        /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
  28        if ((btrfs_dir_data_len(leaf, dir_item) +
  29             btrfs_dir_name_len(leaf, dir_item)) >
  30                        BTRFS_MAX_XATTR_SIZE(root->fs_info)) {
  31                fprintf(stderr, "invalid dir item name + data len: %u + %u\n",
  32                        (unsigned)btrfs_dir_name_len(leaf, dir_item),
  33                        (unsigned)btrfs_dir_data_len(leaf, dir_item));
  34                return 1;
  35        }
  36
  37        return 0;
  38}
  39
  40struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
  41                              struct btrfs_path *path,
  42                              const char *name, int name_len)
  43{
  44        struct btrfs_dir_item *dir_item;
  45        unsigned long name_ptr;
  46        u32 total_len;
  47        u32 cur = 0;
  48        u32 this_len;
  49        struct extent_buffer *leaf;
  50
  51        leaf = path->nodes[0];
  52        dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
  53        total_len = btrfs_item_size_nr(leaf, path->slots[0]);
  54        if (verify_dir_item(root, leaf, dir_item))
  55                return NULL;
  56
  57        while(cur < total_len) {
  58                this_len = sizeof(*dir_item) +
  59                        btrfs_dir_name_len(leaf, dir_item) +
  60                        btrfs_dir_data_len(leaf, dir_item);
  61                if (this_len > (total_len - cur)) {
  62                        fprintf(stderr, "invalid dir item size\n");
  63                        return NULL;
  64                }
  65
  66                name_ptr = (unsigned long)(dir_item + 1);
  67
  68                if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
  69                    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
  70                        return dir_item;
  71
  72                cur += this_len;
  73                dir_item = (struct btrfs_dir_item *)((char *)dir_item +
  74                                                     this_len);
  75        }
  76        return NULL;
  77}
  78
  79struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
  80                                             struct btrfs_root *root,
  81                                             struct btrfs_path *path, u64 dir,
  82                                             const char *name, int name_len,
  83                                             int mod)
  84{
  85        int ret;
  86        struct btrfs_key key;
  87        int ins_len = mod < 0 ? -1 : 0;
  88        int cow = mod != 0;
  89        struct btrfs_key found_key;
  90        struct extent_buffer *leaf;
  91
  92        key.objectid = dir;
  93        key.type = BTRFS_DIR_ITEM_KEY;
  94
  95        key.offset = btrfs_name_hash(name, name_len);
  96
  97        ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
  98        if (ret < 0)
  99                return ERR_PTR(ret);
 100        if (ret > 0) {
 101                if (path->slots[0] == 0)
 102                        return NULL;
 103                path->slots[0]--;
 104        }
 105
 106        leaf = path->nodes[0];
 107        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 108
 109        if (found_key.objectid != dir ||
 110            found_key.type != BTRFS_DIR_ITEM_KEY ||
 111            found_key.offset != key.offset)
 112                return NULL;
 113
 114        return btrfs_match_dir_item_name(root, path, name, name_len);
 115}
 116
 117int btrfs_iter_dir(struct btrfs_root *root, u64 ino,
 118                   btrfs_iter_dir_callback_t callback)
 119{
 120        struct btrfs_path path;
 121        struct btrfs_key key;
 122        int ret;
 123
 124        btrfs_init_path(&path);
 125        key.objectid = ino;
 126        key.type = BTRFS_DIR_INDEX_KEY;
 127        key.offset = 0;
 128
 129        ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
 130        if (ret < 0)
 131                return ret;
 132        /* Should not happen */
 133        if (ret == 0) {
 134                ret = -EUCLEAN;
 135                goto out;
 136        }
 137        if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
 138                ret = btrfs_next_leaf(root, &path);
 139                if (ret < 0)
 140                        goto out;
 141                if (ret > 0) {
 142                        ret = 0;
 143                        goto out;
 144                }
 145        }
 146        do {
 147                struct btrfs_dir_item *di;
 148
 149                btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
 150                if (key.objectid != ino || key.type != BTRFS_DIR_INDEX_KEY)
 151                        break;
 152                di = btrfs_item_ptr(path.nodes[0], path.slots[0],
 153                                    struct btrfs_dir_item);
 154                if (verify_dir_item(root, path.nodes[0], di)) {
 155                        ret = -EUCLEAN;
 156                        goto out;
 157                }
 158                ret = callback(root, path.nodes[0], di);
 159                if (ret < 0)
 160                        goto out;
 161        } while (!(ret = btrfs_next_item(root, &path)));
 162
 163        if (ret > 0)
 164                ret = 0;
 165out:
 166        btrfs_release_path(&path);
 167        return ret;
 168}
 169