blob: 2278b52e4d0e84c4f7decc9eb8fc72d54ae052ea [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
16struct btrfs_info btrfs_info;
Qu Wenruo1d5a7b72020-06-24 18:03:01 +020017struct btrfs_fs_info *current_fs_info;
Marek Behún98ec1d12017-09-03 17:00:29 +020018
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +020021{
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +020034 };
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +020039 time_t mtime;
Qu Wenruo348848a2020-06-24 18:03:06 +020040 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +020041
Qu Wenruo348848a2020-06-24 18:03:06 +020042 btrfs_dir_item_key_to_cpu(eb, di, &key);
Marek Behún98ec1d12017-09-03 17:00:29 +020043
Qu Wenruo348848a2020-06-24 18:03:06 +020044 if (key.type == BTRFS_ROOT_ITEM_KEY) {
45 struct btrfs_root *subvol;
Marek Behún98ec1d12017-09-03 17:00:29 +020046
Qu Wenruo348848a2020-06-24 18:03:06 +020047 /* 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;
Marek Behún98ec1d12017-09-03 17:00:29 +020057
Qu Wenruo348848a2020-06-24 18:03:06 +020058 /* 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;
Marek Behún98ec1d12017-09-03 17:00:29 +020067 }
Qu Wenruo348848a2020-06-24 18:03:06 +020068 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);
73 }
74 ctime_r(&mtime, filetime);
Marek Behún98ec1d12017-09-03 17:00:29 +020075
Qu Wenruo348848a2020-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;
82 }
83 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ún98ec1d12017-09-03 17:00:29 +020089 }
90
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +020093 else
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +0200104 }
105
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +0200111 printf("\n");
Qu Wenruo348848a2020-06-24 18:03:06 +0200112out:
113 free(target);
114 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200115}
116
Simon Glassc1c4a8f2020-05-10 11:39:57 -0600117int btrfs_probe(struct blk_desc *fs_dev_desc,
118 struct disk_partition *fs_partition)
Marek Behún98ec1d12017-09-03 17:00:29 +0200119{
Qu Wenruo1d5a7b72020-06-24 18:03:01 +0200120 struct btrfs_fs_info *fs_info;
121 int ret = -1;
122
Marek Behún98ec1d12017-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 Wenruo8f267cf2020-06-24 18:03:00 +0200142 if (__btrfs_read_chunk_tree()) {
Marek Behún98ec1d12017-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 Wenruo1d5a7b72020-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ún98ec1d12017-09-03 17:00:29 +0200159}
160
161int btrfs_ls(const char *path)
162{
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +0200166 u8 type;
Qu Wenruo348848a2020-06-24 18:03:06 +0200167 int ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200168
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +0200173 printf("Cannot lookup path %s\n", path);
Qu Wenruo348848a2020-06-24 18:03:06 +0200174 return ret;
Marek Behún98ec1d12017-09-03 17:00:29 +0200175 }
176
177 if (type != BTRFS_FT_DIR) {
Qu Wenruo348848a2020-06-24 18:03:06 +0200178 error("Not a directory: %s", path);
179 return -ENOENT;
Marek Behún98ec1d12017-09-03 17:00:29 +0200180 }
Qu Wenruo348848a2020-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ún98ec1d12017-09-03 17:00:29 +0200185 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200186 return 0;
187}
188
189int btrfs_exists(const char *file)
190{
Qu Wenruof6d5af72020-06-24 18:02:57 +0200191 struct __btrfs_root root = btrfs_info.fs_root;
Marek Behún98ec1d12017-09-03 17:00:29 +0200192 u64 inr;
193 u8 type;
194
Qu Wenruodca22af2020-06-24 18:03:02 +0200195 inr = __btrfs_lookup_path(&root, root.root_dirid, file, &type, NULL, 40);
Marek Behún98ec1d12017-09-03 17:00:29 +0200196
197 return (inr != -1ULL && type == BTRFS_FT_REG_FILE);
198}
199
200int btrfs_size(const char *file, loff_t *size)
201{
Qu Wenruof6d5af72020-06-24 18:02:57 +0200202 struct __btrfs_root root = btrfs_info.fs_root;
Marek Behún98ec1d12017-09-03 17:00:29 +0200203 struct btrfs_inode_item inode;
204 u64 inr;
205 u8 type;
206
Qu Wenruodca22af2020-06-24 18:03:02 +0200207 inr = __btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
Marek Behún98ec1d12017-09-03 17:00:29 +0200208 40);
209
210 if (inr == -1ULL) {
211 printf("Cannot lookup file %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200212 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200213 }
214
215 if (type != BTRFS_FT_REG_FILE) {
216 printf("Not a regular file: %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200217 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200218 }
219
220 *size = inode.size;
221 return 0;
222}
223
224int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
225 loff_t *actread)
226{
Qu Wenruof6d5af72020-06-24 18:02:57 +0200227 struct __btrfs_root root = btrfs_info.fs_root;
Marek Behún98ec1d12017-09-03 17:00:29 +0200228 struct btrfs_inode_item inode;
229 u64 inr, rd;
230 u8 type;
231
Qu Wenruodca22af2020-06-24 18:03:02 +0200232 inr = __btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
Marek Behún98ec1d12017-09-03 17:00:29 +0200233 40);
234
235 if (inr == -1ULL) {
236 printf("Cannot lookup file %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200237 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200238 }
239
240 if (type != BTRFS_FT_REG_FILE) {
241 printf("Not a regular file: %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200242 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200243 }
244
245 if (!len)
246 len = inode.size;
247
248 if (len > inode.size - offset)
249 len = inode.size - offset;
250
251 rd = btrfs_file_read(&root, inr, offset, len, buf);
252 if (rd == -1ULL) {
253 printf("An error occured while reading file %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200254 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200255 }
256
257 *actread = rd;
258 return 0;
259}
260
261void btrfs_close(void)
262{
263 btrfs_chunk_map_exit();
Qu Wenruo1d5a7b72020-06-24 18:03:01 +0200264 if (current_fs_info) {
265 close_ctree_fs_info(current_fs_info);
266 current_fs_info = NULL;
267 }
Marek Behún98ec1d12017-09-03 17:00:29 +0200268}
269
270int btrfs_uuid(char *uuid_str)
271{
272#ifdef CONFIG_LIB_UUID
273 uuid_bin_to_str(btrfs_info.sb.fsid, uuid_str, UUID_STR_FORMAT_STD);
274 return 0;
275#endif
276 return -ENOSYS;
277}