blob: cbf9dcffeb20c74643561f6d76fd0ceedf4b3b11 [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 *
5 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
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>
Simon Glass6f044982020-05-10 11:39:52 -060010#include <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[] = {
25 [BTRFS_FT_REG_FILE] = "FILE",
26 [BTRFS_FT_DIR] = "DIR",
27 [BTRFS_FT_CHRDEV] = "CHRDEV",
28 [BTRFS_FT_BLKDEV] = "BLKDEV",
29 [BTRFS_FT_FIFO] = "FIFO",
30 [BTRFS_FT_SOCK] = "SOCK",
31 [BTRFS_FT_SYMLINK] = "SYMLINK",
32 [BTRFS_FT_XATTR] = "XATTR"
Marek Behún98ec1d12017-09-03 17:00:29 +020033 };
Qu Wenruo348848a2020-06-24 18:03:06 +020034 u8 type = btrfs_dir_type(eb, di);
35 char namebuf[BTRFS_NAME_LEN];
36 char *target = NULL;
37 char filetime[32];
Marek Behún98ec1d12017-09-03 17:00:29 +020038 time_t mtime;
Qu Wenruo348848a2020-06-24 18:03:06 +020039 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +020040
Qu Wenruo348848a2020-06-24 18:03:06 +020041 btrfs_dir_item_key_to_cpu(eb, di, &key);
Marek Behún98ec1d12017-09-03 17:00:29 +020042
Qu Wenruo348848a2020-06-24 18:03:06 +020043 if (key.type == BTRFS_ROOT_ITEM_KEY) {
44 struct btrfs_root *subvol;
Marek Behún98ec1d12017-09-03 17:00:29 +020045
Qu Wenruo348848a2020-06-24 18:03:06 +020046 /* It's a subvolume, get its mtime from root item */
47 subvol = btrfs_read_fs_root(fs_info, &key);
48 if (IS_ERR(subvol)) {
49 ret = PTR_ERR(subvol);
50 error("Can't find root %llu", key.objectid);
51 return ret;
52 }
53 mtime = btrfs_stack_timespec_sec(&subvol->root_item.otime);
54 } else {
55 struct btrfs_path path;
Marek Behún98ec1d12017-09-03 17:00:29 +020056
Qu Wenruo348848a2020-06-24 18:03:06 +020057 /* It's regular inode, get its mtime from inode item */
58 btrfs_init_path(&path);
59 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
60 if (ret > 0)
61 ret = -ENOENT;
62 if (ret < 0) {
63 error("Can't find inode %llu", key.objectid);
64 btrfs_release_path(&path);
65 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +020066 }
Qu Wenruo348848a2020-06-24 18:03:06 +020067 read_extent_buffer(path.nodes[0], &ii,
68 btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
69 sizeof(ii));
70 btrfs_release_path(&path);
71 mtime = btrfs_stack_timespec_sec(&ii.mtime);
72 }
73 ctime_r(&mtime, filetime);
Marek Behún98ec1d12017-09-03 17:00:29 +020074
Qu Wenruo348848a2020-06-24 18:03:06 +020075 if (type == BTRFS_FT_SYMLINK) {
76 target = malloc(fs_info->sectorsize);
77 if (!target) {
78 error("Can't alloc memory for symlink %llu",
79 key.objectid);
80 return -ENOMEM;
81 }
82 ret = btrfs_readlink(root, key.objectid, target);
83 if (ret < 0) {
84 error("Failed to read symlink %llu", key.objectid);
85 goto out;
86 }
87 target[ret] = '\0';
Marek Behún98ec1d12017-09-03 17:00:29 +020088 }
89
Qu Wenruo348848a2020-06-24 18:03:06 +020090 if (type < ARRAY_SIZE(dir_item_str) && dir_item_str[type])
91 printf("<%s> ", dir_item_str[type]);
Marek Behún98ec1d12017-09-03 17:00:29 +020092 else
Qu Wenruo348848a2020-06-24 18:03:06 +020093 printf("DIR_ITEM.%u", type);
94 if (type == BTRFS_FT_CHRDEV || type == BTRFS_FT_BLKDEV) {
95 ASSERT(key.type == BTRFS_INODE_ITEM_KEY);
96 printf("%4llu,%5llu ", btrfs_stack_inode_rdev(&ii) >> 20,
97 btrfs_stack_inode_rdev(&ii) & 0xfffff);
98 } else {
99 if (key.type == BTRFS_INODE_ITEM_KEY)
100 printf("%10llu ", btrfs_stack_inode_size(&ii));
101 else
102 printf("%10llu ", 0ULL);
Marek Behún98ec1d12017-09-03 17:00:29 +0200103 }
104
Qu Wenruo348848a2020-06-24 18:03:06 +0200105 read_extent_buffer(eb, namebuf, (unsigned long)(di + 1),
106 btrfs_dir_name_len(eb, di));
107 printf("%24.24s %.*s", filetime, btrfs_dir_name_len(eb, di), namebuf);
108 if (type == BTRFS_FT_SYMLINK)
109 printf(" -> %s", target ? target : "?");
Marek Behún98ec1d12017-09-03 17:00:29 +0200110 printf("\n");
Qu Wenruo348848a2020-06-24 18:03:06 +0200111out:
112 free(target);
113 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200114}
115
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600116int btrfs_probe(struct blk_desc *fs_dev_desc,
117 struct disk_partition *fs_partition)
Marek Behún98ec1d12017-09-03 17:00:29 +0200118{
Qu Wenruo1d5a7b72020-06-24 18:03:01 +0200119 struct btrfs_fs_info *fs_info;
120 int ret = -1;
121
Marek Behún98ec1d12017-09-03 17:00:29 +0200122 btrfs_hash_init();
Qu Wenruo1d5a7b72020-06-24 18:03:01 +0200123 fs_info = open_ctree_fs_info(fs_dev_desc, fs_partition);
124 if (fs_info) {
125 current_fs_info = fs_info;
126 ret = 0;
127 }
128 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200129}
130
131int btrfs_ls(const char *path)
132{
Qu Wenruo348848a2020-06-24 18:03:06 +0200133 struct btrfs_fs_info *fs_info = current_fs_info;
134 struct btrfs_root *root = fs_info->fs_root;
135 u64 ino = BTRFS_FIRST_FREE_OBJECTID;
Marek Behún98ec1d12017-09-03 17:00:29 +0200136 u8 type;
Qu Wenruo348848a2020-06-24 18:03:06 +0200137 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200138
Qu Wenruo348848a2020-06-24 18:03:06 +0200139 ASSERT(fs_info);
140 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
141 path, &root, &ino, &type, 40);
142 if (ret < 0) {
Marek Behún98ec1d12017-09-03 17:00:29 +0200143 printf("Cannot lookup path %s\n", path);
Qu Wenruo348848a2020-06-24 18:03:06 +0200144 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200145 }
146
147 if (type != BTRFS_FT_DIR) {
Qu Wenruo348848a2020-06-24 18:03:06 +0200148 error("Not a directory: %s", path);
149 return -ENOENT;
Marek Behún98ec1d12017-09-03 17:00:29 +0200150 }
Qu Wenruo348848a2020-06-24 18:03:06 +0200151 ret = btrfs_iter_dir(root, ino, show_dir);
152 if (ret < 0) {
153 error("An error occured while listing directory %s", path);
154 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200155 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200156 return 0;
157}
158
159int btrfs_exists(const char *file)
160{
Qu Wenruof9344c32020-06-24 18:03:07 +0200161 struct btrfs_fs_info *fs_info = current_fs_info;
162 struct btrfs_root *root;
163 u64 ino;
Marek Behún98ec1d12017-09-03 17:00:29 +0200164 u8 type;
Qu Wenruof9344c32020-06-24 18:03:07 +0200165 int ret;
166
167 ASSERT(fs_info);
Marek Behún98ec1d12017-09-03 17:00:29 +0200168
Qu Wenruof9344c32020-06-24 18:03:07 +0200169 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
170 file, &root, &ino, &type, 40);
171 if (ret < 0)
172 return 0;
Marek Behún98ec1d12017-09-03 17:00:29 +0200173
Qu Wenruof9344c32020-06-24 18:03:07 +0200174 if (type == BTRFS_FT_REG_FILE)
175 return 1;
176 return 0;
Marek Behún98ec1d12017-09-03 17:00:29 +0200177}
178
179int btrfs_size(const char *file, loff_t *size)
180{
Qu Wenruof9344c32020-06-24 18:03:07 +0200181 struct btrfs_fs_info *fs_info = current_fs_info;
182 struct btrfs_inode_item *ii;
183 struct btrfs_root *root;
184 struct btrfs_path path;
185 struct btrfs_key key;
186 u64 ino;
Marek Behún98ec1d12017-09-03 17:00:29 +0200187 u8 type;
Qu Wenruof9344c32020-06-24 18:03:07 +0200188 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200189
Qu Wenruof9344c32020-06-24 18:03:07 +0200190 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
191 file, &root, &ino, &type, 40);
192 if (ret < 0) {
Marek Behún98ec1d12017-09-03 17:00:29 +0200193 printf("Cannot lookup file %s\n", file);
Qu Wenruof9344c32020-06-24 18:03:07 +0200194 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200195 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200196 if (type != BTRFS_FT_REG_FILE) {
197 printf("Not a regular file: %s\n", file);
Qu Wenruof9344c32020-06-24 18:03:07 +0200198 return -ENOENT;
Marek Behún98ec1d12017-09-03 17:00:29 +0200199 }
Qu Wenruof9344c32020-06-24 18:03:07 +0200200 btrfs_init_path(&path);
201 key.objectid = ino;
202 key.type = BTRFS_INODE_ITEM_KEY;
203 key.offset = 0;
Marek Behún98ec1d12017-09-03 17:00:29 +0200204
Qu Wenruof9344c32020-06-24 18:03:07 +0200205 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
206 if (ret < 0) {
207 printf("Cannot lookup ino %llu\n", ino);
208 return ret;
209 }
210 if (ret > 0) {
211 printf("Ino %llu does not exist\n", ino);
212 ret = -ENOENT;
213 goto out;
214 }
215 ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
216 struct btrfs_inode_item);
217 *size = btrfs_inode_size(path.nodes[0], ii);
218out:
219 btrfs_release_path(&path);
220 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200221}
222
223int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
224 loff_t *actread)
225{
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200226 struct btrfs_fs_info *fs_info = current_fs_info;
227 struct btrfs_root *root;
228 loff_t real_size = 0;
229 u64 ino;
Marek Behún98ec1d12017-09-03 17:00:29 +0200230 u8 type;
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200231 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200232
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200233 ASSERT(fs_info);
234 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
235 file, &root, &ino, &type, 40);
236 if (ret < 0) {
237 error("Cannot lookup file %s", file);
238 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200239 }
240
241 if (type != BTRFS_FT_REG_FILE) {
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200242 error("Not a regular file: %s", file);
243 return -EINVAL;
Marek Behún98ec1d12017-09-03 17:00:29 +0200244 }
245
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200246 if (!len) {
247 ret = btrfs_size(file, &real_size);
248 if (ret < 0) {
249 error("Failed to get inode size: %s", file);
250 return ret;
251 }
252 len = real_size;
253 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200254
Qu Wenruocf5a3a02020-06-24 18:03:11 +0200255 if (len > real_size - offset)
256 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) {
260 error("An error occured while reading file %s", file);
261 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}