blob: d5a87c175c52bcee9bc56e2a299c9631370a7900 [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"
Marek Behún98ec1d12017-09-03 17:00:29 +020014
15struct btrfs_info btrfs_info;
16
17static int readdir_callback(const struct btrfs_root *root,
18 struct btrfs_dir_item *item)
19{
20 static const char typestr[BTRFS_FT_MAX][4] = {
21 [BTRFS_FT_UNKNOWN] = " ? ",
22 [BTRFS_FT_REG_FILE] = " ",
23 [BTRFS_FT_DIR] = "DIR",
24 [BTRFS_FT_CHRDEV] = "CHR",
25 [BTRFS_FT_BLKDEV] = "BLK",
26 [BTRFS_FT_FIFO] = "FIF",
27 [BTRFS_FT_SOCK] = "SCK",
28 [BTRFS_FT_SYMLINK] = "SYM",
29 [BTRFS_FT_XATTR] = " ? ",
30 };
31 struct btrfs_inode_item inode;
32 const char *name = (const char *) (item + 1);
33 char filetime[32], *target = NULL;
34 time_t mtime;
35
Qu Wenruo07d977f2020-06-24 18:02:47 +020036 if (btrfs_lookup_inode(root, (struct btrfs_key *)&item->location,
37 &inode, NULL)) {
Marek Behún98ec1d12017-09-03 17:00:29 +020038 printf("%s: Cannot find inode item for directory entry %.*s!\n",
39 __func__, item->name_len, name);
40 return 0;
41 }
42
43 mtime = inode.mtime.sec;
44 ctime_r(&mtime, filetime);
45
46 if (item->type == BTRFS_FT_SYMLINK) {
47 target = malloc(min(inode.size + 1,
48 (u64) btrfs_info.sb.sectorsize));
49
50 if (target && btrfs_readlink(root, item->location.objectid,
51 target)) {
52 free(target);
53 target = NULL;
54 }
55
56 if (!target)
57 printf("%s: Cannot read symlink target!\n", __func__);
58 }
59
60 printf("<%s> ", typestr[item->type]);
61 if (item->type == BTRFS_FT_CHRDEV || item->type == BTRFS_FT_BLKDEV)
62 printf("%4u,%5u ", (unsigned int) (inode.rdev >> 20),
63 (unsigned int) (inode.rdev & 0xfffff));
64 else
65 printf("%10llu ", inode.size);
66
67 printf("%24.24s %.*s", filetime, item->name_len, name);
68
69 if (item->type == BTRFS_FT_SYMLINK) {
70 printf(" -> %s", target ? target : "?");
71 if (target)
72 free(target);
73 }
74
75 printf("\n");
76
77 return 0;
78}
79
Simon Glassc1c4a8f2020-05-10 11:39:57 -060080int btrfs_probe(struct blk_desc *fs_dev_desc,
81 struct disk_partition *fs_partition)
Marek Behún98ec1d12017-09-03 17:00:29 +020082{
83 btrfs_blk_desc = fs_dev_desc;
84 btrfs_part_info = fs_partition;
85
86 memset(&btrfs_info, 0, sizeof(btrfs_info));
87
88 btrfs_hash_init();
89 if (btrfs_read_superblock())
90 return -1;
91
92 if (btrfs_chunk_map_init()) {
93 printf("%s: failed to init chunk map\n", __func__);
94 return -1;
95 }
96
97 btrfs_info.tree_root.objectid = 0;
98 btrfs_info.tree_root.bytenr = btrfs_info.sb.root;
99 btrfs_info.chunk_root.objectid = 0;
100 btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
101
102 if (btrfs_read_chunk_tree()) {
103 printf("%s: failed to read chunk tree\n", __func__);
104 return -1;
105 }
106
107 if (btrfs_find_root(btrfs_get_default_subvol_objectid(),
108 &btrfs_info.fs_root, NULL)) {
109 printf("%s: failed to find default subvolume\n", __func__);
110 return -1;
111 }
112
113 return 0;
114}
115
116int btrfs_ls(const char *path)
117{
118 struct btrfs_root root = btrfs_info.fs_root;
119 u64 inr;
120 u8 type;
121
122 inr = btrfs_lookup_path(&root, root.root_dirid, path, &type, NULL, 40);
123
124 if (inr == -1ULL) {
125 printf("Cannot lookup path %s\n", path);
Marek Behúne55462b2019-05-02 15:28:43 +0200126 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200127 }
128
129 if (type != BTRFS_FT_DIR) {
130 printf("Not a directory: %s\n", path);
Marek Behúne55462b2019-05-02 15:28:43 +0200131 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200132 }
133
134 if (btrfs_readdir(&root, inr, readdir_callback)) {
135 printf("An error occured while listing directory %s\n", path);
Marek Behúne55462b2019-05-02 15:28:43 +0200136 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200137 }
138
139 return 0;
140}
141
142int btrfs_exists(const char *file)
143{
144 struct btrfs_root root = btrfs_info.fs_root;
145 u64 inr;
146 u8 type;
147
148 inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, NULL, 40);
149
150 return (inr != -1ULL && type == BTRFS_FT_REG_FILE);
151}
152
153int btrfs_size(const char *file, loff_t *size)
154{
155 struct btrfs_root root = btrfs_info.fs_root;
156 struct btrfs_inode_item inode;
157 u64 inr;
158 u8 type;
159
160 inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
161 40);
162
163 if (inr == -1ULL) {
164 printf("Cannot lookup file %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200165 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200166 }
167
168 if (type != BTRFS_FT_REG_FILE) {
169 printf("Not a regular file: %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200170 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200171 }
172
173 *size = inode.size;
174 return 0;
175}
176
177int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
178 loff_t *actread)
179{
180 struct btrfs_root root = btrfs_info.fs_root;
181 struct btrfs_inode_item inode;
182 u64 inr, rd;
183 u8 type;
184
185 inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
186 40);
187
188 if (inr == -1ULL) {
189 printf("Cannot lookup file %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200190 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200191 }
192
193 if (type != BTRFS_FT_REG_FILE) {
194 printf("Not a regular file: %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200195 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200196 }
197
198 if (!len)
199 len = inode.size;
200
201 if (len > inode.size - offset)
202 len = inode.size - offset;
203
204 rd = btrfs_file_read(&root, inr, offset, len, buf);
205 if (rd == -1ULL) {
206 printf("An error occured while reading file %s\n", file);
Marek Behúne55462b2019-05-02 15:28:43 +0200207 return -1;
Marek Behún98ec1d12017-09-03 17:00:29 +0200208 }
209
210 *actread = rd;
211 return 0;
212}
213
214void btrfs_close(void)
215{
216 btrfs_chunk_map_exit();
217}
218
219int btrfs_uuid(char *uuid_str)
220{
221#ifdef CONFIG_LIB_UUID
222 uuid_bin_to_str(btrfs_info.sb.fsid, uuid_str, UUID_STR_FORMAT_STD);
223 return 0;
224#endif
225 return -ENOSYS;
226}