btrfs.c 5.1 KB

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