Home | History | Annotate | Download | only in btrfs
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * BTRFS filesystem implementation for U-Boot
      4  *
      5  * 2017 Marek Behun, CZ.NIC, marek.behun (at) 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