dir-item.c 4.0 KB

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