]> Git Repo - J-u-boot.git/blame - fs/btrfs/btrfs.c
fs: btrfs: Introduce function to resolve the path of one subvolume
[J-u-boot.git] / fs / btrfs / btrfs.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
0c936ee3
MB
2/*
3 * BTRFS filesystem implementation for U-Boot
4 *
5 * 2017 Marek Behun, CZ.NIC, [email protected]
0c936ee3
MB
6 */
7
0c936ee3
MB
8#include <config.h>
9#include <malloc.h>
ba06b3c5 10#include <uuid.h>
0c936ee3 11#include <linux/time.h>
565a4147
QW
12#include "btrfs.h"
13#include "crypto/hash.h"
4aebb994 14#include "disk-io.h"
0c936ee3
MB
15
16struct btrfs_info btrfs_info;
f06bfcf5 17struct btrfs_fs_info *current_fs_info;
0c936ee3 18
325dd1f6
QW
19static int show_dir(struct btrfs_root *root, struct extent_buffer *eb,
20 struct btrfs_dir_item *di)
0c936ee3 21{
325dd1f6
QW
22 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"
0c936ee3 34 };
325dd1f6
QW
35 u8 type = btrfs_dir_type(eb, di);
36 char namebuf[BTRFS_NAME_LEN];
37 char *target = NULL;
38 char filetime[32];
0c936ee3 39 time_t mtime;
325dd1f6 40 int ret;
0c936ee3 41
325dd1f6 42 btrfs_dir_item_key_to_cpu(eb, di, &key);
0c936ee3 43
325dd1f6
QW
44 if (key.type == BTRFS_ROOT_ITEM_KEY) {
45 struct btrfs_root *subvol;
0c936ee3 46
325dd1f6
QW
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;
0c936ee3 53 }
325dd1f6
QW
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);
73 }
74 ctime_r(&mtime, filetime);
0c936ee3 75
325dd1f6
QW
76 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';
0c936ee3
MB
89 }
90
325dd1f6
QW
91 if (type < ARRAY_SIZE(dir_item_str) && dir_item_str[type])
92 printf("<%s> ", dir_item_str[type]);
0c936ee3 93 else
325dd1f6
QW
94 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);
0c936ee3
MB
104 }
105
325dd1f6
QW
106 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 : "?");
0c936ee3 111 printf("\n");
325dd1f6
QW
112out:
113 free(target);
114 return ret;
0c936ee3
MB
115}
116
0528979f
SG
117int btrfs_probe(struct blk_desc *fs_dev_desc,
118 struct disk_partition *fs_partition)
0c936ee3 119{
f06bfcf5
QW
120 struct btrfs_fs_info *fs_info;
121 int ret = -1;
122
0c936ee3
MB
123 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
57f24f10 142 if (__btrfs_read_chunk_tree()) {
0c936ee3
MB
143 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
f06bfcf5
QW
153 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;
0c936ee3
MB
159}
160
161int btrfs_ls(const char *path)
162{
325dd1f6
QW
163 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;
0c936ee3 166 u8 type;
325dd1f6 167 int ret;
0c936ee3 168
325dd1f6
QW
169 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) {
0c936ee3 173 printf("Cannot lookup path %s\n", path);
325dd1f6 174 return ret;
0c936ee3
MB
175 }
176
177 if (type != BTRFS_FT_DIR) {
325dd1f6
QW
178 error("Not a directory: %s", path);
179 return -ENOENT;
0c936ee3 180 }
325dd1f6
QW
181 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;
0c936ee3 185 }
0c936ee3
MB
186 return 0;
187}
188
189int btrfs_exists(const char *file)
190{
5bbb68d5
QW
191 struct btrfs_fs_info *fs_info = current_fs_info;
192 struct btrfs_root *root;
193 u64 ino;
0c936ee3 194 u8 type;
5bbb68d5
QW
195 int ret;
196
197 ASSERT(fs_info);
0c936ee3 198
5bbb68d5
QW
199 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;
0c936ee3 203
5bbb68d5
QW
204 if (type == BTRFS_FT_REG_FILE)
205 return 1;
206 return 0;
0c936ee3
MB
207}
208
209int btrfs_size(const char *file, loff_t *size)
210{
5bbb68d5
QW
211 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;
0c936ee3 217 u8 type;
5bbb68d5 218 int ret;
0c936ee3 219
5bbb68d5
QW
220 ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
221 file, &root, &ino, &type, 40);
222 if (ret < 0) {
0c936ee3 223 printf("Cannot lookup file %s\n", file);
5bbb68d5 224 return ret;
0c936ee3 225 }
0c936ee3
MB
226 if (type != BTRFS_FT_REG_FILE) {
227 printf("Not a regular file: %s\n", file);
5bbb68d5 228 return -ENOENT;
0c936ee3 229 }
5bbb68d5
QW
230 btrfs_init_path(&path);
231 key.objectid = ino;
232 key.type = BTRFS_INODE_ITEM_KEY;
233 key.offset = 0;
0c936ee3 234
5bbb68d5
QW
235 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;
0c936ee3
MB
251}
252
253int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
254 loff_t *actread)
255{
e3427184
QW
256 struct btrfs_fs_info *fs_info = current_fs_info;
257 struct btrfs_root *root;
258 loff_t real_size = 0;
259 u64 ino;
0c936ee3 260 u8 type;
e3427184 261 int ret;
0c936ee3 262
e3427184
QW
263 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;
0c936ee3
MB
269 }
270
271 if (type != BTRFS_FT_REG_FILE) {
e3427184
QW
272 error("Not a regular file: %s", file);
273 return -EINVAL;
0c936ee3
MB
274 }
275
e3427184
QW
276 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;
283 }
0c936ee3 284
e3427184
QW
285 if (len > real_size - offset)
286 len = real_size - offset;
0c936ee3 287
e3427184
QW
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;
0c936ee3
MB
292 }
293
e3427184 294 *actread = len;
0c936ee3
MB
295 return 0;
296}
297
298void btrfs_close(void)
299{
300 btrfs_chunk_map_exit();
f06bfcf5
QW
301 if (current_fs_info) {
302 close_ctree_fs_info(current_fs_info);
303 current_fs_info = NULL;
304 }
0c936ee3
MB
305}
306
307int btrfs_uuid(char *uuid_str)
308{
309#ifdef CONFIG_LIB_UUID
5bbb68d5
QW
310 if (current_fs_info)
311 uuid_bin_to_str(current_fs_info->super_copy->fsid, uuid_str,
312 UUID_STR_FORMAT_STD);
0c936ee3
MB
313 return 0;
314#endif
315 return -ENOSYS;
316}
This page took 0.201548 seconds and 4 git commands to generate.