btrfs.c 6.4 KB

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