blob: c967c114ccf5eb1d2edbb97a0a4519ec0040345b [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Behún0c936ee2017-09-03 17:00:29 +02002/*
3 * BTRFS filesystem implementation for U-Boot
4 *
5 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
Marek Behún0c936ee2017-09-03 17:00:29 +02006 */
7
Marek Behún0c936ee2017-09-03 17:00:29 +02008#include <config.h>
9#include <malloc.h>
Simon Glassba06b3c2020-05-10 11:39:52 -060010#include <uuid.h>
Marek Behún0c936ee2017-09-03 17:00:29 +020011#include <linux/time.h>
Qu Wenruo565a4142020-06-24 18:02:48 +020012#include "btrfs.h"
13#include "crypto/hash.h"
Qu Wenruo4aebb992020-06-24 18:02:49 +020014#include "disk-io.h"
Marek Behún0c936ee2017-09-03 17:00:29 +020015
16struct btrfs_info btrfs_info;
Qu Wenruof06bfcf2020-06-24 18:03:01 +020017struct btrfs_fs_info *current_fs_info;
Marek Behún0c936ee2017-09-03 17:00:29 +020018
Qu Wenruo207011b2020-06-24 18:02:57 +020019static int readdir_callback(const struct __btrfs_root *root,
Marek Behún0c936ee2017-09-03 17:00:29 +020020 struct btrfs_dir_item *item)
21{
22 static const char typestr[BTRFS_FT_MAX][4] = {
23 [BTRFS_FT_UNKNOWN] = " ? ",
24 [BTRFS_FT_REG_FILE] = " ",
25 [BTRFS_FT_DIR] = "DIR",
26 [BTRFS_FT_CHRDEV] = "CHR",
27 [BTRFS_FT_BLKDEV] = "BLK",
28 [BTRFS_FT_FIFO] = "FIF",
29 [BTRFS_FT_SOCK] = "SCK",
30 [BTRFS_FT_SYMLINK] = "SYM",
31 [BTRFS_FT_XATTR] = " ? ",
32 };
33 struct btrfs_inode_item inode;
34 const char *name = (const char *) (item + 1);
35 char filetime[32], *target = NULL;
36 time_t mtime;
37
Qu Wenruocafffc52020-06-24 18:03:02 +020038 if (__btrfs_lookup_inode(root, (struct btrfs_key *)&item->location,
Qu Wenruo3b4b40c2020-06-24 18:02:47 +020039 &inode, NULL)) {
Marek Behún0c936ee2017-09-03 17:00:29 +020040 printf("%s: Cannot find inode item for directory entry %.*s!\n",
41 __func__, item->name_len, name);
42 return 0;
43 }
44
45 mtime = inode.mtime.sec;
46 ctime_r(&mtime, filetime);
47
48 if (item->type == BTRFS_FT_SYMLINK) {
49 target = malloc(min(inode.size + 1,
50 (u64) btrfs_info.sb.sectorsize));
51
Qu Wenruocafffc52020-06-24 18:03:02 +020052 if (target && __btrfs_readlink(root, item->location.objectid,
Marek Behún0c936ee2017-09-03 17:00:29 +020053 target)) {
54 free(target);
55 target = NULL;
56 }
57
58 if (!target)
59 printf("%s: Cannot read symlink target!\n", __func__);
60 }
61
62 printf("<%s> ", typestr[item->type]);
63 if (item->type == BTRFS_FT_CHRDEV || item->type == BTRFS_FT_BLKDEV)
64 printf("%4u,%5u ", (unsigned int) (inode.rdev >> 20),
65 (unsigned int) (inode.rdev & 0xfffff));
66 else
67 printf("%10llu ", inode.size);
68
69 printf("%24.24s %.*s", filetime, item->name_len, name);
70
71 if (item->type == BTRFS_FT_SYMLINK) {
72 printf(" -> %s", target ? target : "?");
73 if (target)
74 free(target);
75 }
76
77 printf("\n");
78
79 return 0;
80}
81
Simon Glass05289792020-05-10 11:39:57 -060082int btrfs_probe(struct blk_desc *fs_dev_desc,
83 struct disk_partition *fs_partition)
Marek Behún0c936ee2017-09-03 17:00:29 +020084{
Qu Wenruof06bfcf2020-06-24 18:03:01 +020085 struct btrfs_fs_info *fs_info;
86 int ret = -1;
87
Marek Behún0c936ee2017-09-03 17:00:29 +020088 btrfs_blk_desc = fs_dev_desc;
89 btrfs_part_info = fs_partition;
90
91 memset(&btrfs_info, 0, sizeof(btrfs_info));
92
93 btrfs_hash_init();
94 if (btrfs_read_superblock())
95 return -1;
96
97 if (btrfs_chunk_map_init()) {
98 printf("%s: failed to init chunk map\n", __func__);
99 return -1;
100 }
101
102 btrfs_info.tree_root.objectid = 0;
103 btrfs_info.tree_root.bytenr = btrfs_info.sb.root;
104 btrfs_info.chunk_root.objectid = 0;
105 btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
106
Qu Wenruo57f24f12020-06-24 18:03:00 +0200107 if (__btrfs_read_chunk_tree()) {
Marek Behún0c936ee2017-09-03 17:00:29 +0200108 printf("%s: failed to read chunk tree\n", __func__);
109 return -1;
110 }
111
112 if (btrfs_find_root(btrfs_get_default_subvol_objectid(),
113 &btrfs_info.fs_root, NULL)) {
114 printf("%s: failed to find default subvolume\n", __func__);
115 return -1;
116 }
117
Qu Wenruof06bfcf2020-06-24 18:03:01 +0200118 fs_info = open_ctree_fs_info(fs_dev_desc, fs_partition);
119 if (fs_info) {
120 current_fs_info = fs_info;
121 ret = 0;
122 }
123 return ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200124}
125
126int btrfs_ls(const char *path)
127{
Qu Wenruo207011b2020-06-24 18:02:57 +0200128 struct __btrfs_root root = btrfs_info.fs_root;
Marek Behún0c936ee2017-09-03 17:00:29 +0200129 u64 inr;
130 u8 type;
131
Qu Wenruocafffc52020-06-24 18:03:02 +0200132 inr = __btrfs_lookup_path(&root, root.root_dirid, path, &type, NULL, 40);
Marek Behún0c936ee2017-09-03 17:00:29 +0200133
134 if (inr == -1ULL) {
135 printf("Cannot lookup path %s\n", path);
Marek Behúncd22e342019-05-02 15:28:43 +0200136 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200137 }
138
139 if (type != BTRFS_FT_DIR) {
140 printf("Not a directory: %s\n", path);
Marek Behúncd22e342019-05-02 15:28:43 +0200141 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200142 }
143
144 if (btrfs_readdir(&root, inr, readdir_callback)) {
145 printf("An error occured while listing directory %s\n", path);
Marek Behúncd22e342019-05-02 15:28:43 +0200146 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200147 }
148
149 return 0;
150}
151
152int btrfs_exists(const char *file)
153{
Qu Wenruo207011b2020-06-24 18:02:57 +0200154 struct __btrfs_root root = btrfs_info.fs_root;
Marek Behún0c936ee2017-09-03 17:00:29 +0200155 u64 inr;
156 u8 type;
157
Qu Wenruocafffc52020-06-24 18:03:02 +0200158 inr = __btrfs_lookup_path(&root, root.root_dirid, file, &type, NULL, 40);
Marek Behún0c936ee2017-09-03 17:00:29 +0200159
160 return (inr != -1ULL && type == BTRFS_FT_REG_FILE);
161}
162
163int btrfs_size(const char *file, loff_t *size)
164{
Qu Wenruo207011b2020-06-24 18:02:57 +0200165 struct __btrfs_root root = btrfs_info.fs_root;
Marek Behún0c936ee2017-09-03 17:00:29 +0200166 struct btrfs_inode_item inode;
167 u64 inr;
168 u8 type;
169
Qu Wenruocafffc52020-06-24 18:03:02 +0200170 inr = __btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
Marek Behún0c936ee2017-09-03 17:00:29 +0200171 40);
172
173 if (inr == -1ULL) {
174 printf("Cannot lookup file %s\n", file);
Marek Behúncd22e342019-05-02 15:28:43 +0200175 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200176 }
177
178 if (type != BTRFS_FT_REG_FILE) {
179 printf("Not a regular file: %s\n", file);
Marek Behúncd22e342019-05-02 15:28:43 +0200180 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200181 }
182
183 *size = inode.size;
184 return 0;
185}
186
187int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
188 loff_t *actread)
189{
Qu Wenruo207011b2020-06-24 18:02:57 +0200190 struct __btrfs_root root = btrfs_info.fs_root;
Marek Behún0c936ee2017-09-03 17:00:29 +0200191 struct btrfs_inode_item inode;
192 u64 inr, rd;
193 u8 type;
194
Qu Wenruocafffc52020-06-24 18:03:02 +0200195 inr = __btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
Marek Behún0c936ee2017-09-03 17:00:29 +0200196 40);
197
198 if (inr == -1ULL) {
199 printf("Cannot lookup file %s\n", file);
Marek Behúncd22e342019-05-02 15:28:43 +0200200 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200201 }
202
203 if (type != BTRFS_FT_REG_FILE) {
204 printf("Not a regular file: %s\n", file);
Marek Behúncd22e342019-05-02 15:28:43 +0200205 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200206 }
207
208 if (!len)
209 len = inode.size;
210
211 if (len > inode.size - offset)
212 len = inode.size - offset;
213
214 rd = btrfs_file_read(&root, inr, offset, len, buf);
215 if (rd == -1ULL) {
216 printf("An error occured while reading file %s\n", file);
Marek Behúncd22e342019-05-02 15:28:43 +0200217 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200218 }
219
220 *actread = rd;
221 return 0;
222}
223
224void btrfs_close(void)
225{
226 btrfs_chunk_map_exit();
Qu Wenruof06bfcf2020-06-24 18:03:01 +0200227 if (current_fs_info) {
228 close_ctree_fs_info(current_fs_info);
229 current_fs_info = NULL;
230 }
Marek Behún0c936ee2017-09-03 17:00:29 +0200231}
232
233int btrfs_uuid(char *uuid_str)
234{
235#ifdef CONFIG_LIB_UUID
236 uuid_bin_to_str(btrfs_info.sb.fsid, uuid_str, UUID_STR_FORMAT_STD);
237 return 0;
238#endif
239 return -ENOSYS;
240}