xref: /openbmc/u-boot/fs/btrfs/btrfs.c (revision 0ed232b1)
1 /*
2  * BTRFS filesystem implementation for U-Boot
3  *
4  * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
5  *
6  * SPDX-License-Identifier:	GPL-2.0+
7  */
8 
9 #include "btrfs.h"
10 #include <config.h>
11 #include <malloc.h>
12 #include <linux/time.h>
13 
14 struct btrfs_info btrfs_info;
15 
16 static 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 
78 int btrfs_probe(struct blk_desc *fs_dev_desc, disk_partition_t *fs_partition)
79 {
80 	btrfs_blk_desc = fs_dev_desc;
81 	btrfs_part_info = fs_partition;
82 
83 	memset(&btrfs_info, 0, sizeof(btrfs_info));
84 
85 	btrfs_hash_init();
86 	if (btrfs_read_superblock())
87 		return -1;
88 
89 	if (btrfs_chunk_map_init()) {
90 		printf("%s: failed to init chunk map\n", __func__);
91 		return -1;
92 	}
93 
94 	btrfs_info.tree_root.objectid = 0;
95 	btrfs_info.tree_root.bytenr = btrfs_info.sb.root;
96 	btrfs_info.chunk_root.objectid = 0;
97 	btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
98 
99 	if (btrfs_read_chunk_tree()) {
100 		printf("%s: failed to read chunk tree\n", __func__);
101 		return -1;
102 	}
103 
104 	if (btrfs_find_root(btrfs_get_default_subvol_objectid(),
105 			    &btrfs_info.fs_root, NULL)) {
106 		printf("%s: failed to find default subvolume\n", __func__);
107 		return -1;
108 	}
109 
110 	return 0;
111 }
112 
113 int btrfs_ls(const char *path)
114 {
115 	struct btrfs_root root = btrfs_info.fs_root;
116 	u64 inr;
117 	u8 type;
118 
119 	inr = btrfs_lookup_path(&root, root.root_dirid, path, &type, NULL, 40);
120 
121 	if (inr == -1ULL) {
122 		printf("Cannot lookup path %s\n", path);
123 		return 1;
124 	}
125 
126 	if (type != BTRFS_FT_DIR) {
127 		printf("Not a directory: %s\n", path);
128 		return 1;
129 	}
130 
131 	if (btrfs_readdir(&root, inr, readdir_callback)) {
132 		printf("An error occured while listing directory %s\n", path);
133 		return 1;
134 	}
135 
136 	return 0;
137 }
138 
139 int btrfs_exists(const char *file)
140 {
141 	struct btrfs_root root = btrfs_info.fs_root;
142 	u64 inr;
143 	u8 type;
144 
145 	inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, NULL, 40);
146 
147 	return (inr != -1ULL && type == BTRFS_FT_REG_FILE);
148 }
149 
150 int btrfs_size(const char *file, loff_t *size)
151 {
152 	struct btrfs_root root = btrfs_info.fs_root;
153 	struct btrfs_inode_item inode;
154 	u64 inr;
155 	u8 type;
156 
157 	inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
158 				40);
159 
160 	if (inr == -1ULL) {
161 		printf("Cannot lookup file %s\n", file);
162 		return 1;
163 	}
164 
165 	if (type != BTRFS_FT_REG_FILE) {
166 		printf("Not a regular file: %s\n", file);
167 		return 1;
168 	}
169 
170 	*size = inode.size;
171 	return 0;
172 }
173 
174 int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
175 	       loff_t *actread)
176 {
177 	struct btrfs_root root = btrfs_info.fs_root;
178 	struct btrfs_inode_item inode;
179 	u64 inr, rd;
180 	u8 type;
181 
182 	inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
183 				40);
184 
185 	if (inr == -1ULL) {
186 		printf("Cannot lookup file %s\n", file);
187 		return 1;
188 	}
189 
190 	if (type != BTRFS_FT_REG_FILE) {
191 		printf("Not a regular file: %s\n", file);
192 		return 1;
193 	}
194 
195 	if (!len)
196 		len = inode.size;
197 
198 	if (len > inode.size - offset)
199 		len = inode.size - offset;
200 
201 	rd = btrfs_file_read(&root, inr, offset, len, buf);
202 	if (rd == -1ULL) {
203 		printf("An error occured while reading file %s\n", file);
204 		return 1;
205 	}
206 
207 	*actread = rd;
208 	return 0;
209 }
210 
211 void btrfs_close(void)
212 {
213 	btrfs_chunk_map_exit();
214 }
215 
216 int btrfs_uuid(char *uuid_str)
217 {
218 #ifdef CONFIG_LIB_UUID
219 	uuid_bin_to_str(btrfs_info.sb.fsid, uuid_str, UUID_STR_FORMAT_STD);
220 	return 0;
221 #endif
222 	return -ENOSYS;
223 }
224