blob: f5d475205e0c86a09da9fd8e687cc0446596134d [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 Wenruoe3427182020-06-24 18:03:11 +0200256 struct btrfs_fs_info *fs_info = current_fs_info;
257 struct btrfs_root *root;
258 loff_t real_size = 0;
259 u64 ino;
Marek Behún0c936ee2017-09-03 17:00:29 +0200260 u8 type;
Qu Wenruoe3427182020-06-24 18:03:11 +0200261 int ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200262
Qu Wenruoe3427182020-06-24 18:03:11 +0200263 ASSERT(fs_info);
264 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
265 file, &root, &ino, &type, 40);
266 if (ret < 0) {
267 error("Cannot lookup file %s", file);
268 return ret;
Marek Behún0c936ee2017-09-03 17:00:29 +0200269 }
270
271 if (type != BTRFS_FT_REG_FILE) {
Qu Wenruoe3427182020-06-24 18:03:11 +0200272 error("Not a regular file: %s", file);
273 return -EINVAL;
Marek Behún0c936ee2017-09-03 17:00:29 +0200274 }
275
Qu Wenruoe3427182020-06-24 18:03:11 +0200276 if (!len) {
277 ret = btrfs_size(file, &real_size);
278 if (ret < 0) {
279 error("Failed to get inode size: %s", file);
280 return ret;
281 }
282 len = real_size;
Marek Behún0c936ee2017-09-03 17:00:29 +0200283 }
284
Qu Wenruoe3427182020-06-24 18:03:11 +0200285 if (len > real_size - offset)
286 len = real_size - offset;
287
288 ret = btrfs_file_read(root, ino, offset, len, buf);
289 if (ret < 0) {
290 error("An error occured while reading file %s", file);
291 return ret;
292 }
293
294 *actread = len;
Marek Behún0c936ee2017-09-03 17:00:29 +0200295 return 0;
296}
297
298void btrfs_close(void)
299{
300 btrfs_chunk_map_exit();
Qu Wenruof06bfcf2020-06-24 18:03:01 +0200301 if (current_fs_info) {
302 close_ctree_fs_info(current_fs_info);
303 current_fs_info = NULL;
304 }
Marek Behún0c936ee2017-09-03 17:00:29 +0200305}
306
307int btrfs_uuid(char *uuid_str)
308{
309#ifdef CONFIG_LIB_UUID
Qu Wenruo5bbb68d2020-06-24 18:03:07 +0200310 if (current_fs_info)
311 uuid_bin_to_str(current_fs_info->super_copy->fsid, uuid_str,
312 UUID_STR_FORMAT_STD);
Marek Behún0c936ee2017-09-03 17:00:29 +0200313 return 0;
314#endif
315 return -ENOSYS;
316}