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