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 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