blob: aec91a57eceb131d4efdcb7355904e54ff9c729f [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 Wenruo325dd1f2020-06-24 18:03:06 +020019static int show_dir(struct btrfs_root *root, struct extent_buffer *eb,
20 struct btrfs_dir_item *di)
Marek Behún0c936ee2017-09-03 17:00:29 +020021{
Qu Wenruo325dd1f2020-06-24 18:03:06 +020022 struct btrfs_fs_info *fs_info = root->fs_info;
23 struct btrfs_inode_item ii;
24 struct btrfs_key key;
25 static const char* dir_item_str[] = {
26 [BTRFS_FT_REG_FILE] = "FILE",
27 [BTRFS_FT_DIR] = "DIR",
28 [BTRFS_FT_CHRDEV] = "CHRDEV",
29 [BTRFS_FT_BLKDEV] = "BLKDEV",
30 [BTRFS_FT_FIFO] = "FIFO",
31 [BTRFS_FT_SOCK] = "SOCK",
32 [BTRFS_FT_SYMLINK] = "SYMLINK",
33 [BTRFS_FT_XATTR] = "XATTR"
Marek Behún0c936ee2017-09-03 17:00:29 +020034 };
Qu Wenruo325dd1f2020-06-24 18:03:06 +020035 u8 type = btrfs_dir_type(eb, di);
36 char namebuf[BTRFS_NAME_LEN];
37 char *target = NULL;
38 char filetime[32];
Marek Behún0c936ee2017-09-03 17:00:29 +020039 time_t mtime;
Qu Wenruo325dd1f2020-06-24 18:03:06 +020040 int ret;
Marek Behún0c936ee2017-09-03 17:00:29 +020041
Qu Wenruo325dd1f2020-06-24 18:03:06 +020042 btrfs_dir_item_key_to_cpu(eb, di, &key);
43
44 if (key.type == BTRFS_ROOT_ITEM_KEY) {
45 struct btrfs_root *subvol;
46
47 /* It's a subvolume, get its mtime from root item */
48 subvol = btrfs_read_fs_root(fs_info, &key);
49 if (IS_ERR(subvol)) {
50 ret = PTR_ERR(subvol);
51 error("Can't find root %llu", key.objectid);
52 return ret;
53 }
54 mtime = btrfs_stack_timespec_sec(&subvol->root_item.otime);
55 } else {
56 struct btrfs_path path;
57
58 /* It's regular inode, get its mtime from inode item */
59 btrfs_init_path(&path);
60 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
61 if (ret > 0)
62 ret = -ENOENT;
63 if (ret < 0) {
64 error("Can't find inode %llu", key.objectid);
65 btrfs_release_path(&path);
66 return ret;
67 }
68 read_extent_buffer(path.nodes[0], &ii,
69 btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
70 sizeof(ii));
71 btrfs_release_path(&path);
72 mtime = btrfs_stack_timespec_sec(&ii.mtime);
Marek Behún0c936ee2017-09-03 17:00:29 +020073 }
Marek Behún0c936ee2017-09-03 17:00:29 +020074 ctime_r(&mtime, filetime);
75
Qu Wenruo325dd1f2020-06-24 18:03:06 +020076 if (type == BTRFS_FT_SYMLINK) {
77 target = malloc(fs_info->sectorsize);
78 if (!target) {
79 error("Can't alloc memory for symlink %llu",
80 key.objectid);
81 return -ENOMEM;
Marek Behún0c936ee2017-09-03 17:00:29 +020082 }
Qu Wenruo325dd1f2020-06-24 18:03:06 +020083 ret = btrfs_readlink(root, key.objectid, target);
84 if (ret < 0) {
85 error("Failed to read symlink %llu", key.objectid);
86 goto out;
87 }
88 target[ret] = '\0';
Marek Behún0c936ee2017-09-03 17:00:29 +020089 }
90
Qu Wenruo325dd1f2020-06-24 18:03:06 +020091 if (type < ARRAY_SIZE(dir_item_str) && dir_item_str[type])
92 printf("<%s> ", dir_item_str[type]);
Marek Behún0c936ee2017-09-03 17:00:29 +020093 else
Qu Wenruo325dd1f2020-06-24 18:03:06 +020094 printf("DIR_ITEM.%u", type);
95 if (type == BTRFS_FT_CHRDEV || type == BTRFS_FT_BLKDEV) {
96 ASSERT(key.type == BTRFS_INODE_ITEM_KEY);
97 printf("%4llu,%5llu ", btrfs_stack_inode_rdev(&ii) >> 20,
98 btrfs_stack_inode_rdev(&ii) & 0xfffff);
99 } else {
100 if (key.type == BTRFS_INODE_ITEM_KEY)
101 printf("%10llu ", btrfs_stack_inode_size(&ii));
102 else
103 printf("%10llu ", 0ULL);
Marek Behún0c936ee2017-09-03 17:00:29 +0200104 }
105
Qu Wenruo325dd1f2020-06-24 18:03:06 +0200106 read_extent_buffer(eb, namebuf, (unsigned long)(di + 1),
107 btrfs_dir_name_len(eb, di));
108 printf("%24.24s %.*s", filetime, btrfs_dir_name_len(eb, di), namebuf);
109 if (type == BTRFS_FT_SYMLINK)
110 printf(" -> %s", target ? target : "?");
Marek Behún0c936ee2017-09-03 17:00:29 +0200111 printf("\n");
Qu Wenruo325dd1f2020-06-24 18:03:06 +0200112out:
113 free(target);
114 return ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200115}
116
Simon Glass05289792020-05-10 11:39:57 -0600117int btrfs_probe(struct blk_desc *fs_dev_desc,
118 struct disk_partition *fs_partition)
Marek Behún0c936ee2017-09-03 17:00:29 +0200119{
Qu Wenruof06bfcf2020-06-24 18:03:01 +0200120 struct btrfs_fs_info *fs_info;
121 int ret = -1;
122
Marek Behún0c936ee2017-09-03 17:00:29 +0200123 btrfs_blk_desc = fs_dev_desc;
124 btrfs_part_info = fs_partition;
125
126 memset(&btrfs_info, 0, sizeof(btrfs_info));
127
128 btrfs_hash_init();
129 if (btrfs_read_superblock())
130 return -1;
131
132 if (btrfs_chunk_map_init()) {
133 printf("%s: failed to init chunk map\n", __func__);
134 return -1;
135 }
136
137 btrfs_info.tree_root.objectid = 0;
138 btrfs_info.tree_root.bytenr = btrfs_info.sb.root;
139 btrfs_info.chunk_root.objectid = 0;
140 btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
141
Qu Wenruo57f24f12020-06-24 18:03:00 +0200142 if (__btrfs_read_chunk_tree()) {
Marek Behún0c936ee2017-09-03 17:00:29 +0200143 printf("%s: failed to read chunk tree\n", __func__);
144 return -1;
145 }
146
147 if (btrfs_find_root(btrfs_get_default_subvol_objectid(),
148 &btrfs_info.fs_root, NULL)) {
149 printf("%s: failed to find default subvolume\n", __func__);
150 return -1;
151 }
152
Qu Wenruof06bfcf2020-06-24 18:03:01 +0200153 fs_info = open_ctree_fs_info(fs_dev_desc, fs_partition);
154 if (fs_info) {
155 current_fs_info = fs_info;
156 ret = 0;
157 }
158 return ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200159}
160
161int btrfs_ls(const char *path)
162{
Qu Wenruo325dd1f2020-06-24 18:03:06 +0200163 struct btrfs_fs_info *fs_info = current_fs_info;
164 struct btrfs_root *root = fs_info->fs_root;
165 u64 ino = BTRFS_FIRST_FREE_OBJECTID;
Marek Behún0c936ee2017-09-03 17:00:29 +0200166 u8 type;
Qu Wenruo325dd1f2020-06-24 18:03:06 +0200167 int ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200168
Qu Wenruo325dd1f2020-06-24 18:03:06 +0200169 ASSERT(fs_info);
170 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
171 path, &root, &ino, &type, 40);
172 if (ret < 0) {
Marek Behún0c936ee2017-09-03 17:00:29 +0200173 printf("Cannot lookup path %s\n", path);
Qu Wenruo325dd1f2020-06-24 18:03:06 +0200174 return ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200175 }
176
177 if (type != BTRFS_FT_DIR) {
Qu Wenruo325dd1f2020-06-24 18:03:06 +0200178 error("Not a directory: %s", path);
179 return -ENOENT;
Marek Behún0c936ee2017-09-03 17:00:29 +0200180 }
Qu Wenruo325dd1f2020-06-24 18:03:06 +0200181 ret = btrfs_iter_dir(root, ino, show_dir);
182 if (ret < 0) {
183 error("An error occured while listing directory %s", path);
184 return ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200185 }
Marek Behún0c936ee2017-09-03 17:00:29 +0200186 return 0;
187}
188
189int btrfs_exists(const char *file)
190{
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200191 struct btrfs_fs_info *fs_info = current_fs_info;
192 struct btrfs_root *root;
193 u64 ino;
Marek Behún0c936ee2017-09-03 17:00:29 +0200194 u8 type;
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200195 int ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200196
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200197 ASSERT(fs_info);
Marek Behún0c936ee2017-09-03 17:00:29 +0200198
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200199 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
200 file, &root, &ino, &type, 40);
201 if (ret < 0)
202 return 0;
203
204 if (type == BTRFS_FT_REG_FILE)
205 return 1;
206 return 0;
Marek Behún0c936ee2017-09-03 17:00:29 +0200207}
208
209int btrfs_size(const char *file, loff_t *size)
210{
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200211 struct btrfs_fs_info *fs_info = current_fs_info;
212 struct btrfs_inode_item *ii;
213 struct btrfs_root *root;
214 struct btrfs_path path;
215 struct btrfs_key key;
216 u64 ino;
Marek Behún0c936ee2017-09-03 17:00:29 +0200217 u8 type;
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200218 int ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200219
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200220 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
221 file, &root, &ino, &type, 40);
222 if (ret < 0) {
Marek Behún0c936ee2017-09-03 17:00:29 +0200223 printf("Cannot lookup file %s\n", file);
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200224 return ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200225 }
Marek Behún0c936ee2017-09-03 17:00:29 +0200226 if (type != BTRFS_FT_REG_FILE) {
227 printf("Not a regular file: %s\n", file);
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200228 return -ENOENT;
Marek Behún0c936ee2017-09-03 17:00:29 +0200229 }
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200230 btrfs_init_path(&path);
231 key.objectid = ino;
232 key.type = BTRFS_INODE_ITEM_KEY;
233 key.offset = 0;
Marek Behún0c936ee2017-09-03 17:00:29 +0200234
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200235 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
236 if (ret < 0) {
237 printf("Cannot lookup ino %llu\n", ino);
238 return ret;
239 }
240 if (ret > 0) {
241 printf("Ino %llu does not exist\n", ino);
242 ret = -ENOENT;
243 goto out;
244 }
245 ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
246 struct btrfs_inode_item);
247 *size = btrfs_inode_size(path.nodes[0], ii);
248out:
249 btrfs_release_path(&path);
250 return ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200251}
252
253int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
254 loff_t *actread)
255{
Qu Wenruo207011b2020-06-24 18:02:57 +0200256 struct __btrfs_root root = btrfs_info.fs_root;
Marek Behún0c936ee2017-09-03 17:00:29 +0200257 struct btrfs_inode_item inode;
258 u64 inr, rd;
259 u8 type;
260
Qu Wenruocafffc52020-06-24 18:03:02 +0200261 inr = __btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
Marek Behún0c936ee2017-09-03 17:00:29 +0200262 40);
263
264 if (inr == -1ULL) {
265 printf("Cannot lookup file %s\n", file);
Marek Behúncd22e342019-05-02 15:28:43 +0200266 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200267 }
268
269 if (type != BTRFS_FT_REG_FILE) {
270 printf("Not a regular file: %s\n", file);
Marek Behúncd22e342019-05-02 15:28:43 +0200271 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200272 }
273
274 if (!len)
275 len = inode.size;
276
277 if (len > inode.size - offset)
278 len = inode.size - offset;
279
280 rd = btrfs_file_read(&root, inr, offset, len, buf);
281 if (rd == -1ULL) {
282 printf("An error occured while reading file %s\n", file);
Marek Behúncd22e342019-05-02 15:28:43 +0200283 return -1;
Marek Behún0c936ee2017-09-03 17:00:29 +0200284 }
285
286 *actread = rd;
287 return 0;
288}
289
290void btrfs_close(void)
291{
292 btrfs_chunk_map_exit();
Qu Wenruof06bfcf2020-06-24 18:03:01 +0200293 if (current_fs_info) {
294 close_ctree_fs_info(current_fs_info);
295 current_fs_info = NULL;
296 }
Marek Behún0c936ee2017-09-03 17:00:29 +0200297}
298
299int btrfs_uuid(char *uuid_str)
300{
301#ifdef CONFIG_LIB_UUID
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200302 if (current_fs_info)
303 uuid_bin_to_str(current_fs_info->super_copy->fsid, uuid_str,
304 UUID_STR_FORMAT_STD);
Marek Behún0c936ee2017-09-03 17:00:29 +0200305 return 0;
306#endif
307 return -ENOSYS;
308}