xref: /openbmc/u-boot/fs/btrfs/btrfs.c (revision e8f80a5a)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
20c936ee3SMarek Behún /*
30c936ee3SMarek Behún  * BTRFS filesystem implementation for U-Boot
40c936ee3SMarek Behún  *
50c936ee3SMarek Behún  * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
60c936ee3SMarek Behún  */
70c936ee3SMarek Behún 
80c936ee3SMarek Behún #include "btrfs.h"
90c936ee3SMarek Behún #include <config.h>
100c936ee3SMarek Behún #include <malloc.h>
110c936ee3SMarek Behún #include <linux/time.h>
120c936ee3SMarek Behún 
130c936ee3SMarek Behún struct btrfs_info btrfs_info;
140c936ee3SMarek Behún 
readdir_callback(const struct btrfs_root * root,struct btrfs_dir_item * item)150c936ee3SMarek Behún static int readdir_callback(const struct btrfs_root *root,
160c936ee3SMarek Behún 			    struct btrfs_dir_item *item)
170c936ee3SMarek Behún {
180c936ee3SMarek Behún 	static const char typestr[BTRFS_FT_MAX][4] = {
190c936ee3SMarek Behún 		[BTRFS_FT_UNKNOWN]  = " ? ",
200c936ee3SMarek Behún 		[BTRFS_FT_REG_FILE] = "   ",
210c936ee3SMarek Behún 		[BTRFS_FT_DIR]      = "DIR",
220c936ee3SMarek Behún 		[BTRFS_FT_CHRDEV]   = "CHR",
230c936ee3SMarek Behún 		[BTRFS_FT_BLKDEV]   = "BLK",
240c936ee3SMarek Behún 		[BTRFS_FT_FIFO]     = "FIF",
250c936ee3SMarek Behún 		[BTRFS_FT_SOCK]     = "SCK",
260c936ee3SMarek Behún 		[BTRFS_FT_SYMLINK]  = "SYM",
270c936ee3SMarek Behún 		[BTRFS_FT_XATTR]    = " ? ",
280c936ee3SMarek Behún 	};
290c936ee3SMarek Behún 	struct btrfs_inode_item inode;
300c936ee3SMarek Behún 	const char *name = (const char *) (item + 1);
310c936ee3SMarek Behún 	char filetime[32], *target = NULL;
320c936ee3SMarek Behún 	time_t mtime;
330c936ee3SMarek Behún 
340c936ee3SMarek Behún 	if (btrfs_lookup_inode(root, &item->location, &inode, NULL)) {
350c936ee3SMarek Behún 		printf("%s: Cannot find inode item for directory entry %.*s!\n",
360c936ee3SMarek Behún 		       __func__, item->name_len, name);
370c936ee3SMarek Behún 		return 0;
380c936ee3SMarek Behún 	}
390c936ee3SMarek Behún 
400c936ee3SMarek Behún 	mtime = inode.mtime.sec;
410c936ee3SMarek Behún 	ctime_r(&mtime, filetime);
420c936ee3SMarek Behún 
430c936ee3SMarek Behún 	if (item->type == BTRFS_FT_SYMLINK) {
440c936ee3SMarek Behún 		target = malloc(min(inode.size + 1,
450c936ee3SMarek Behún 				    (u64) btrfs_info.sb.sectorsize));
460c936ee3SMarek Behún 
470c936ee3SMarek Behún 		if (target && btrfs_readlink(root, item->location.objectid,
480c936ee3SMarek Behún 					     target)) {
490c936ee3SMarek Behún 			free(target);
500c936ee3SMarek Behún 			target = NULL;
510c936ee3SMarek Behún 		}
520c936ee3SMarek Behún 
530c936ee3SMarek Behún 		if (!target)
540c936ee3SMarek Behún 			printf("%s: Cannot read symlink target!\n", __func__);
550c936ee3SMarek Behún 	}
560c936ee3SMarek Behún 
570c936ee3SMarek Behún 	printf("<%s> ", typestr[item->type]);
580c936ee3SMarek Behún 	if (item->type == BTRFS_FT_CHRDEV || item->type == BTRFS_FT_BLKDEV)
590c936ee3SMarek Behún 		printf("%4u,%5u  ", (unsigned int) (inode.rdev >> 20),
600c936ee3SMarek Behún 			(unsigned int) (inode.rdev & 0xfffff));
610c936ee3SMarek Behún 	else
620c936ee3SMarek Behún 		printf("%10llu  ", inode.size);
630c936ee3SMarek Behún 
640c936ee3SMarek Behún 	printf("%24.24s  %.*s", filetime, item->name_len, name);
650c936ee3SMarek Behún 
660c936ee3SMarek Behún 	if (item->type == BTRFS_FT_SYMLINK) {
670c936ee3SMarek Behún 		printf(" -> %s", target ? target : "?");
680c936ee3SMarek Behún 		if (target)
690c936ee3SMarek Behún 			free(target);
700c936ee3SMarek Behún 	}
710c936ee3SMarek Behún 
720c936ee3SMarek Behún 	printf("\n");
730c936ee3SMarek Behún 
740c936ee3SMarek Behún 	return 0;
750c936ee3SMarek Behún }
760c936ee3SMarek Behún 
btrfs_probe(struct blk_desc * fs_dev_desc,disk_partition_t * fs_partition)770c936ee3SMarek Behún int btrfs_probe(struct blk_desc *fs_dev_desc, disk_partition_t *fs_partition)
780c936ee3SMarek Behún {
790c936ee3SMarek Behún 	btrfs_blk_desc = fs_dev_desc;
800c936ee3SMarek Behún 	btrfs_part_info = fs_partition;
810c936ee3SMarek Behún 
820c936ee3SMarek Behún 	memset(&btrfs_info, 0, sizeof(btrfs_info));
830c936ee3SMarek Behún 
840c936ee3SMarek Behún 	btrfs_hash_init();
850c936ee3SMarek Behún 	if (btrfs_read_superblock())
860c936ee3SMarek Behún 		return -1;
870c936ee3SMarek Behún 
880c936ee3SMarek Behún 	if (btrfs_chunk_map_init()) {
890c936ee3SMarek Behún 		printf("%s: failed to init chunk map\n", __func__);
900c936ee3SMarek Behún 		return -1;
910c936ee3SMarek Behún 	}
920c936ee3SMarek Behún 
930c936ee3SMarek Behún 	btrfs_info.tree_root.objectid = 0;
940c936ee3SMarek Behún 	btrfs_info.tree_root.bytenr = btrfs_info.sb.root;
950c936ee3SMarek Behún 	btrfs_info.chunk_root.objectid = 0;
960c936ee3SMarek Behún 	btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
970c936ee3SMarek Behún 
980c936ee3SMarek Behún 	if (btrfs_read_chunk_tree()) {
990c936ee3SMarek Behún 		printf("%s: failed to read chunk tree\n", __func__);
1000c936ee3SMarek Behún 		return -1;
1010c936ee3SMarek Behún 	}
1020c936ee3SMarek Behún 
1030c936ee3SMarek Behún 	if (btrfs_find_root(btrfs_get_default_subvol_objectid(),
1040c936ee3SMarek Behún 			    &btrfs_info.fs_root, NULL)) {
1050c936ee3SMarek Behún 		printf("%s: failed to find default subvolume\n", __func__);
1060c936ee3SMarek Behún 		return -1;
1070c936ee3SMarek Behún 	}
1080c936ee3SMarek Behún 
1090c936ee3SMarek Behún 	return 0;
1100c936ee3SMarek Behún }
1110c936ee3SMarek Behún 
btrfs_ls(const char * path)1120c936ee3SMarek Behún int btrfs_ls(const char *path)
1130c936ee3SMarek Behún {
1140c936ee3SMarek Behún 	struct btrfs_root root = btrfs_info.fs_root;
1150c936ee3SMarek Behún 	u64 inr;
1160c936ee3SMarek Behún 	u8 type;
1170c936ee3SMarek Behún 
1180c936ee3SMarek Behún 	inr = btrfs_lookup_path(&root, root.root_dirid, path, &type, NULL, 40);
1190c936ee3SMarek Behún 
1200c936ee3SMarek Behún 	if (inr == -1ULL) {
1210c936ee3SMarek Behún 		printf("Cannot lookup path %s\n", path);
1220c936ee3SMarek Behún 		return 1;
1230c936ee3SMarek Behún 	}
1240c936ee3SMarek Behún 
1250c936ee3SMarek Behún 	if (type != BTRFS_FT_DIR) {
1260c936ee3SMarek Behún 		printf("Not a directory: %s\n", path);
1270c936ee3SMarek Behún 		return 1;
1280c936ee3SMarek Behún 	}
1290c936ee3SMarek Behún 
1300c936ee3SMarek Behún 	if (btrfs_readdir(&root, inr, readdir_callback)) {
1310c936ee3SMarek Behún 		printf("An error occured while listing directory %s\n", path);
1320c936ee3SMarek Behún 		return 1;
1330c936ee3SMarek Behún 	}
1340c936ee3SMarek Behún 
1350c936ee3SMarek Behún 	return 0;
1360c936ee3SMarek Behún }
1370c936ee3SMarek Behún 
btrfs_exists(const char * file)1380c936ee3SMarek Behún int btrfs_exists(const char *file)
1390c936ee3SMarek Behún {
1400c936ee3SMarek Behún 	struct btrfs_root root = btrfs_info.fs_root;
1410c936ee3SMarek Behún 	u64 inr;
1420c936ee3SMarek Behún 	u8 type;
1430c936ee3SMarek Behún 
1440c936ee3SMarek Behún 	inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, NULL, 40);
1450c936ee3SMarek Behún 
1460c936ee3SMarek Behún 	return (inr != -1ULL && type == BTRFS_FT_REG_FILE);
1470c936ee3SMarek Behún }
1480c936ee3SMarek Behún 
btrfs_size(const char * file,loff_t * size)1490c936ee3SMarek Behún int btrfs_size(const char *file, loff_t *size)
1500c936ee3SMarek Behún {
1510c936ee3SMarek Behún 	struct btrfs_root root = btrfs_info.fs_root;
1520c936ee3SMarek Behún 	struct btrfs_inode_item inode;
1530c936ee3SMarek Behún 	u64 inr;
1540c936ee3SMarek Behún 	u8 type;
1550c936ee3SMarek Behún 
1560c936ee3SMarek Behún 	inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
1570c936ee3SMarek Behún 				40);
1580c936ee3SMarek Behún 
1590c936ee3SMarek Behún 	if (inr == -1ULL) {
1600c936ee3SMarek Behún 		printf("Cannot lookup file %s\n", file);
1610c936ee3SMarek Behún 		return 1;
1620c936ee3SMarek Behún 	}
1630c936ee3SMarek Behún 
1640c936ee3SMarek Behún 	if (type != BTRFS_FT_REG_FILE) {
1650c936ee3SMarek Behún 		printf("Not a regular file: %s\n", file);
1660c936ee3SMarek Behún 		return 1;
1670c936ee3SMarek Behún 	}
1680c936ee3SMarek Behún 
1690c936ee3SMarek Behún 	*size = inode.size;
1700c936ee3SMarek Behún 	return 0;
1710c936ee3SMarek Behún }
1720c936ee3SMarek Behún 
btrfs_read(const char * file,void * buf,loff_t offset,loff_t len,loff_t * actread)1730c936ee3SMarek Behún int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
1740c936ee3SMarek Behún 	       loff_t *actread)
1750c936ee3SMarek Behún {
1760c936ee3SMarek Behún 	struct btrfs_root root = btrfs_info.fs_root;
1770c936ee3SMarek Behún 	struct btrfs_inode_item inode;
1780c936ee3SMarek Behún 	u64 inr, rd;
1790c936ee3SMarek Behún 	u8 type;
1800c936ee3SMarek Behún 
1810c936ee3SMarek Behún 	inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
1820c936ee3SMarek Behún 				40);
1830c936ee3SMarek Behún 
1840c936ee3SMarek Behún 	if (inr == -1ULL) {
1850c936ee3SMarek Behún 		printf("Cannot lookup file %s\n", file);
1860c936ee3SMarek Behún 		return 1;
1870c936ee3SMarek Behún 	}
1880c936ee3SMarek Behún 
1890c936ee3SMarek Behún 	if (type != BTRFS_FT_REG_FILE) {
1900c936ee3SMarek Behún 		printf("Not a regular file: %s\n", file);
1910c936ee3SMarek Behún 		return 1;
1920c936ee3SMarek Behún 	}
1930c936ee3SMarek Behún 
1940c936ee3SMarek Behún 	if (!len)
1950c936ee3SMarek Behún 		len = inode.size;
1960c936ee3SMarek Behún 
1970c936ee3SMarek Behún 	if (len > inode.size - offset)
1980c936ee3SMarek Behún 		len = inode.size - offset;
1990c936ee3SMarek Behún 
2000c936ee3SMarek Behún 	rd = btrfs_file_read(&root, inr, offset, len, buf);
2010c936ee3SMarek Behún 	if (rd == -1ULL) {
2020c936ee3SMarek Behún 		printf("An error occured while reading file %s\n", file);
2030c936ee3SMarek Behún 		return 1;
2040c936ee3SMarek Behún 	}
2050c936ee3SMarek Behún 
2060c936ee3SMarek Behún 	*actread = rd;
2070c936ee3SMarek Behún 	return 0;
2080c936ee3SMarek Behún }
2090c936ee3SMarek Behún 
btrfs_close(void)2100c936ee3SMarek Behún void btrfs_close(void)
2110c936ee3SMarek Behún {
2120c936ee3SMarek Behún 	btrfs_chunk_map_exit();
2130c936ee3SMarek Behún }
2140c936ee3SMarek Behún 
btrfs_uuid(char * uuid_str)2150c936ee3SMarek Behún int btrfs_uuid(char *uuid_str)
2160c936ee3SMarek Behún {
2170c936ee3SMarek Behún #ifdef CONFIG_LIB_UUID
2180c936ee3SMarek Behún 	uuid_bin_to_str(btrfs_info.sb.fsid, uuid_str, UUID_STR_FORMAT_STD);
2190c936ee3SMarek Behún 	return 0;
2200c936ee3SMarek Behún #endif
2210c936ee3SMarek Behún 	return -ENOSYS;
2220c936ee3SMarek Behún }
223