xref: /openbmc/u-boot/fs/btrfs/btrfs.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
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  
readdir_callback(const struct btrfs_root * root,struct btrfs_dir_item * item)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  
btrfs_probe(struct blk_desc * fs_dev_desc,disk_partition_t * fs_partition)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  
btrfs_ls(const char * path)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  
btrfs_exists(const char * file)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  
btrfs_size(const char * file,loff_t * size)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  
btrfs_read(const char * file,void * buf,loff_t offset,loff_t len,loff_t * actread)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  
btrfs_close(void)210  void btrfs_close(void)
211  {
212  	btrfs_chunk_map_exit();
213  }
214  
btrfs_uuid(char * uuid_str)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