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