blob: f3087f690fa4749f0ec510f630cb87eae24ee158 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Behún98ec1d12017-09-03 17:00:29 +02002/*
3 * BTRFS filesystem implementation for U-Boot
4 *
Marek Behúnd63726e2022-06-01 17:17:06 +02005 * 2017 Marek Behún, CZ.NIC, kabel@kernel.org
Marek Behún98ec1d12017-09-03 17:00:29 +02006 */
7
Marek Behún98ec1d12017-09-03 17:00:29 +02008#include <config.h>
9#include <malloc.h>
Caleb Connolly29cab7c2024-08-30 13:34:37 +010010#include <u-boot/uuid.h>
Marek Behún98ec1d12017-09-03 17:00:29 +020011#include <linux/time.h>
Qu Wenruo0e7b8542020-06-24 18:02:48 +020012#include "btrfs.h"
13#include "crypto/hash.h"
Qu Wenruo1a618082020-06-24 18:02:49 +020014#include "disk-io.h"
Marek Behún98ec1d12017-09-03 17:00:29 +020015
Qu Wenruo1d5a7b72020-06-24 18:03:01 +020016struct btrfs_fs_info *current_fs_info;
Marek Behún98ec1d12017-09-03 17:00:29 +020017
Qu Wenruo348848a2020-06-24 18:03:06 +020018static int show_dir(struct btrfs_root *root, struct extent_buffer *eb,
19 struct btrfs_dir_item *di)
Marek Behún98ec1d12017-09-03 17:00:29 +020020{
Qu Wenruo348848a2020-06-24 18:03:06 +020021 struct btrfs_fs_info *fs_info = root->fs_info;
22 struct btrfs_inode_item ii;
23 struct btrfs_key key;
24 static const char* dir_item_str[] = {
Marek Behúnb4c27732021-02-09 19:05:08 +010025 [BTRFS_FT_REG_FILE] = " ",
Wolfgang Denk62fb2b42021-09-27 17:42:39 +020026 [BTRFS_FT_DIR] = "DIR",
Marek Behúnb4c27732021-02-09 19:05:08 +010027 [BTRFS_FT_CHRDEV] = "CHR",
28 [BTRFS_FT_BLKDEV] = "BLK",
29 [BTRFS_FT_FIFO] = "FIF",
30 [BTRFS_FT_SOCK] = "SCK",
31 [BTRFS_FT_SYMLINK] = "SYM",
Marek Behún98ec1d12017-09-03 17:00:29 +020032 };
Qu Wenruo348848a2020-06-24 18:03:06 +020033 u8 type = btrfs_dir_type(eb, di);
34 char namebuf[BTRFS_NAME_LEN];
35 char *target = NULL;
36 char filetime[32];
Marek Behún98ec1d12017-09-03 17:00:29 +020037 time_t mtime;
Qu Wenruobbad1d72020-10-31 09:07:51 +080038 int ret = 0;
Marek Behún98ec1d12017-09-03 17:00:29 +020039
Marek Behúnb0cbb522021-02-09 19:05:07 +010040 /* skip XATTRs in directory listing */
41 if (type == BTRFS_FT_XATTR)
42 return 0;
43
Qu Wenruo348848a2020-06-24 18:03:06 +020044 btrfs_dir_item_key_to_cpu(eb, di, &key);
Marek Behún98ec1d12017-09-03 17:00:29 +020045
Qu Wenruo348848a2020-06-24 18:03:06 +020046 if (key.type == BTRFS_ROOT_ITEM_KEY) {
47 struct btrfs_root *subvol;
Marek Behún98ec1d12017-09-03 17:00:29 +020048
Qu Wenruo348848a2020-06-24 18:03:06 +020049 /* It's a subvolume, get its mtime from root item */
50 subvol = btrfs_read_fs_root(fs_info, &key);
51 if (IS_ERR(subvol)) {
52 ret = PTR_ERR(subvol);
53 error("Can't find root %llu", key.objectid);
54 return ret;
55 }
56 mtime = btrfs_stack_timespec_sec(&subvol->root_item.otime);
57 } else {
58 struct btrfs_path path;
Marek Behún98ec1d12017-09-03 17:00:29 +020059
Qu Wenruo348848a2020-06-24 18:03:06 +020060 /* It's regular inode, get its mtime from inode item */
61 btrfs_init_path(&path);
62 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
63 if (ret > 0)
64 ret = -ENOENT;
65 if (ret < 0) {
66 error("Can't find inode %llu", key.objectid);
67 btrfs_release_path(&path);
68 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +020069 }
Qu Wenruo348848a2020-06-24 18:03:06 +020070 read_extent_buffer(path.nodes[0], &ii,
71 btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
72 sizeof(ii));
73 btrfs_release_path(&path);
74 mtime = btrfs_stack_timespec_sec(&ii.mtime);
75 }
76 ctime_r(&mtime, filetime);
Marek Behún98ec1d12017-09-03 17:00:29 +020077
Qu Wenruo348848a2020-06-24 18:03:06 +020078 if (type == BTRFS_FT_SYMLINK) {
79 target = malloc(fs_info->sectorsize);
80 if (!target) {
81 error("Can't alloc memory for symlink %llu",
82 key.objectid);
83 return -ENOMEM;
84 }
85 ret = btrfs_readlink(root, key.objectid, target);
86 if (ret < 0) {
87 error("Failed to read symlink %llu", key.objectid);
88 goto out;
89 }
90 target[ret] = '\0';
Marek Behún98ec1d12017-09-03 17:00:29 +020091 }
92
Qu Wenruo348848a2020-06-24 18:03:06 +020093 if (type < ARRAY_SIZE(dir_item_str) && dir_item_str[type])
94 printf("<%s> ", dir_item_str[type]);
Marek Behún98ec1d12017-09-03 17:00:29 +020095 else
Marek Behúnb4c27732021-02-09 19:05:08 +010096 printf("?%3u? ", type);
Qu Wenruo348848a2020-06-24 18:03:06 +020097 if (type == BTRFS_FT_CHRDEV || type == BTRFS_FT_BLKDEV) {
98 ASSERT(key.type == BTRFS_INODE_ITEM_KEY);
99 printf("%4llu,%5llu ", btrfs_stack_inode_rdev(&ii) >> 20,
100 btrfs_stack_inode_rdev(&ii) & 0xfffff);
101 } else {
102 if (key.type == BTRFS_INODE_ITEM_KEY)
103 printf("%10llu ", btrfs_stack_inode_size(&ii));
104 else
105 printf("%10llu ", 0ULL);
Marek Behún98ec1d12017-09-03 17:00:29 +0200106 }
107
Qu Wenruo348848a2020-06-24 18:03:06 +0200108 read_extent_buffer(eb, namebuf, (unsigned long)(di + 1),
109 btrfs_dir_name_len(eb, di));
110 printf("%24.24s %.*s", filetime, btrfs_dir_name_len(eb, di), namebuf);
111 if (type == BTRFS_FT_SYMLINK)
112 printf(" -> %s", target ? target : "?");
Marek Behún98ec1d12017-09-03 17:00:29 +0200113 printf("\n");
Qu Wenruo348848a2020-06-24 18:03:06 +0200114out:
115 free(target);
116 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200117}
118
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600119int btrfs_probe(struct blk_desc *fs_dev_desc,
120 struct disk_partition *fs_partition)
Marek Behún98ec1d12017-09-03 17:00:29 +0200121{
Qu Wenruo1d5a7b72020-06-24 18:03:01 +0200122 struct btrfs_fs_info *fs_info;
123 int ret = -1;
124
Marek Behún98ec1d12017-09-03 17:00:29 +0200125 btrfs_hash_init();
Qu Wenruo1d5a7b72020-06-24 18:03:01 +0200126 fs_info = open_ctree_fs_info(fs_dev_desc, fs_partition);
127 if (fs_info) {
128 current_fs_info = fs_info;
129 ret = 0;
130 }
131 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200132}
133
134int btrfs_ls(const char *path)
135{
Qu Wenruo348848a2020-06-24 18:03:06 +0200136 struct btrfs_fs_info *fs_info = current_fs_info;
137 struct btrfs_root *root = fs_info->fs_root;
138 u64 ino = BTRFS_FIRST_FREE_OBJECTID;
Marek Behún98ec1d12017-09-03 17:00:29 +0200139 u8 type;
Qu Wenruo348848a2020-06-24 18:03:06 +0200140 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200141
Qu Wenruo348848a2020-06-24 18:03:06 +0200142 ASSERT(fs_info);
143 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
144 path, &root, &ino, &type, 40);
145 if (ret < 0) {
Marek Behún98ec1d12017-09-03 17:00:29 +0200146 printf("Cannot lookup path %s\n", path);
Qu Wenruo348848a2020-06-24 18:03:06 +0200147 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200148 }
149
150 if (type != BTRFS_FT_DIR) {
Qu Wenruo348848a2020-06-24 18:03:06 +0200151 error("Not a directory: %s", path);
152 return -ENOENT;
Marek Behún98ec1d12017-09-03 17:00:29 +0200153 }
Qu Wenruo348848a2020-06-24 18:03:06 +0200154 ret = btrfs_iter_dir(root, ino, show_dir);
155 if (ret < 0) {
Naoki Hayamac080b512020-10-12 18:35:33 +0900156 error("An error occurred while listing directory %s", path);
Qu Wenruo348848a2020-06-24 18:03:06 +0200157 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200158 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200159 return 0;
160}
161
162int btrfs_exists(const char *file)
163{
Qu Wenruof9344c32020-06-24 18:03:07 +0200164 struct btrfs_fs_info *fs_info = current_fs_info;
165 struct btrfs_root *root;
166 u64 ino;
Marek Behún98ec1d12017-09-03 17:00:29 +0200167 u8 type;
Qu Wenruof9344c32020-06-24 18:03:07 +0200168 int ret;
169
170 ASSERT(fs_info);
Marek Behún98ec1d12017-09-03 17:00:29 +0200171
Qu Wenruof9344c32020-06-24 18:03:07 +0200172 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
173 file, &root, &ino, &type, 40);
174 if (ret < 0)
175 return 0;
Marek Behún98ec1d12017-09-03 17:00:29 +0200176
Qu Wenruof9344c32020-06-24 18:03:07 +0200177 if (type == BTRFS_FT_REG_FILE)
178 return 1;
179 return 0;
Marek Behún98ec1d12017-09-03 17:00:29 +0200180}
181
182int btrfs_size(const char *file, loff_t *size)
183{
Qu Wenruof9344c32020-06-24 18:03:07 +0200184 struct btrfs_fs_info *fs_info = current_fs_info;
185 struct btrfs_inode_item *ii;
186 struct btrfs_root *root;
187 struct btrfs_path path;
188 struct btrfs_key key;
189 u64 ino;
Marek Behún98ec1d12017-09-03 17:00:29 +0200190 u8 type;
Qu Wenruof9344c32020-06-24 18:03:07 +0200191 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200192
Qu Wenruof9344c32020-06-24 18:03:07 +0200193 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
194 file, &root, &ino, &type, 40);
195 if (ret < 0) {
Dominique Martinet0e003102024-11-15 11:15:47 +0900196 debug("Cannot lookup file %s\n", file);
Qu Wenruof9344c32020-06-24 18:03:07 +0200197 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200198 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200199 if (type != BTRFS_FT_REG_FILE) {
200 printf("Not a regular file: %s\n", file);
Qu Wenruof9344c32020-06-24 18:03:07 +0200201 return -ENOENT;
Marek Behún98ec1d12017-09-03 17:00:29 +0200202 }
Qu Wenruof9344c32020-06-24 18:03:07 +0200203 btrfs_init_path(&path);
204 key.objectid = ino;
205 key.type = BTRFS_INODE_ITEM_KEY;
206 key.offset = 0;
Marek Behún98ec1d12017-09-03 17:00:29 +0200207
Qu Wenruof9344c32020-06-24 18:03:07 +0200208 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
209 if (ret < 0) {
210 printf("Cannot lookup ino %llu\n", ino);
211 return ret;
212 }
213 if (ret > 0) {
214 printf("Ino %llu does not exist\n", ino);
215 ret = -ENOENT;
216 goto out;
217 }
218 ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
219 struct btrfs_inode_item);
220 *size = btrfs_inode_size(path.nodes[0], ii);
221out:
222 btrfs_release_path(&path);
223 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200224}
225
226int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
227 loff_t *actread)
228{
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200229 struct btrfs_fs_info *fs_info = current_fs_info;
230 struct btrfs_root *root;
Sam Edwards9d1c1b42023-11-11 08:19:04 -0700231 loff_t real_size;
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200232 u64 ino;
Marek Behún98ec1d12017-09-03 17:00:29 +0200233 u8 type;
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200234 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200235
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200236 ASSERT(fs_info);
237 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
238 file, &root, &ino, &type, 40);
239 if (ret < 0) {
240 error("Cannot lookup file %s", file);
241 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200242 }
243
244 if (type != BTRFS_FT_REG_FILE) {
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200245 error("Not a regular file: %s", file);
246 return -EINVAL;
Marek Behún98ec1d12017-09-03 17:00:29 +0200247 }
248
Sam Edwards9d1c1b42023-11-11 08:19:04 -0700249 ret = btrfs_size(file, &real_size);
250 if (ret < 0) {
251 error("Failed to get inode size: %s", file);
252 return ret;
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200253 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200254
Sam Edwards9d1c1b42023-11-11 08:19:04 -0700255 if (!len || len > real_size - offset)
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200256 len = real_size - offset;
Marek Behún98ec1d12017-09-03 17:00:29 +0200257
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200258 ret = btrfs_file_read(root, ino, offset, len, buf);
259 if (ret < 0) {
Naoki Hayamac080b512020-10-12 18:35:33 +0900260 error("An error occurred while reading file %s", file);
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200261 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200262 }
263
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200264 *actread = len;
Marek Behún98ec1d12017-09-03 17:00:29 +0200265 return 0;
266}
267
268void btrfs_close(void)
269{
Qu Wenruo1d5a7b72020-06-24 18:03:01 +0200270 if (current_fs_info) {
271 close_ctree_fs_info(current_fs_info);
272 current_fs_info = NULL;
273 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200274}
275
276int btrfs_uuid(char *uuid_str)
277{
278#ifdef CONFIG_LIB_UUID
Qu Wenruof9344c32020-06-24 18:03:07 +0200279 if (current_fs_info)
280 uuid_bin_to_str(current_fs_info->super_copy->fsid, uuid_str,
281 UUID_STR_FORMAT_STD);
Marek Behún98ec1d12017-09-03 17:00:29 +0200282 return 0;
283#endif
284 return -ENOSYS;
285}