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