xref: /openbmc/u-boot/fs/btrfs/btrfs.c (revision 87a62bce)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * BTRFS filesystem implementation for U-Boot
4  *
5  * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
6  */
7 
8 #include "btrfs.h"
9 #include <config.h>
10 #include <malloc.h>
11 #include <linux/time.h>
12 
13 struct btrfs_info btrfs_info;
14 
15 static 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 
77 int 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 
112 int 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);
122 		return 1;
123 	}
124 
125 	if (type != BTRFS_FT_DIR) {
126 		printf("Not a directory: %s\n", path);
127 		return 1;
128 	}
129 
130 	if (btrfs_readdir(&root, inr, readdir_callback)) {
131 		printf("An error occured while listing directory %s\n", path);
132 		return 1;
133 	}
134 
135 	return 0;
136 }
137 
138 int 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 
149 int 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);
161 		return 1;
162 	}
163 
164 	if (type != BTRFS_FT_REG_FILE) {
165 		printf("Not a regular file: %s\n", file);
166 		return 1;
167 	}
168 
169 	*size = inode.size;
170 	return 0;
171 }
172 
173 int 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);
186 		return 1;
187 	}
188 
189 	if (type != BTRFS_FT_REG_FILE) {
190 		printf("Not a regular file: %s\n", file);
191 		return 1;
192 	}
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);
203 		return 1;
204 	}
205 
206 	*actread = rd;
207 	return 0;
208 }
209 
210 void btrfs_close(void)
211 {
212 	btrfs_chunk_map_exit();
213 }
214 
215 int 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 }
223