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 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 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 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 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 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 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 2100c936ee3SMarek Behún void btrfs_close(void) 2110c936ee3SMarek Behún { 2120c936ee3SMarek Behún btrfs_chunk_map_exit(); 2130c936ee3SMarek Behún } 2140c936ee3SMarek Behún 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