1 /* 2 * BTRFS filesystem implementation for U-Boot 3 * 4 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include "btrfs.h" 10 #include <config.h> 11 #include <malloc.h> 12 #include <linux/time.h> 13 14 struct btrfs_info btrfs_info; 15 16 static int readdir_callback(const struct btrfs_root *root, 17 struct btrfs_dir_item *item) 18 { 19 static const char typestr[BTRFS_FT_MAX][4] = { 20 [BTRFS_FT_UNKNOWN] = " ? ", 21 [BTRFS_FT_REG_FILE] = " ", 22 [BTRFS_FT_DIR] = "DIR", 23 [BTRFS_FT_CHRDEV] = "CHR", 24 [BTRFS_FT_BLKDEV] = "BLK", 25 [BTRFS_FT_FIFO] = "FIF", 26 [BTRFS_FT_SOCK] = "SCK", 27 [BTRFS_FT_SYMLINK] = "SYM", 28 [BTRFS_FT_XATTR] = " ? ", 29 }; 30 struct btrfs_inode_item inode; 31 const char *name = (const char *) (item + 1); 32 char filetime[32], *target = NULL; 33 time_t mtime; 34 35 if (btrfs_lookup_inode(root, &item->location, &inode, NULL)) { 36 printf("%s: Cannot find inode item for directory entry %.*s!\n", 37 __func__, item->name_len, name); 38 return 0; 39 } 40 41 mtime = inode.mtime.sec; 42 ctime_r(&mtime, filetime); 43 44 if (item->type == BTRFS_FT_SYMLINK) { 45 target = malloc(min(inode.size + 1, 46 (u64) btrfs_info.sb.sectorsize)); 47 48 if (target && btrfs_readlink(root, item->location.objectid, 49 target)) { 50 free(target); 51 target = NULL; 52 } 53 54 if (!target) 55 printf("%s: Cannot read symlink target!\n", __func__); 56 } 57 58 printf("<%s> ", typestr[item->type]); 59 if (item->type == BTRFS_FT_CHRDEV || item->type == BTRFS_FT_BLKDEV) 60 printf("%4u,%5u ", (unsigned int) (inode.rdev >> 20), 61 (unsigned int) (inode.rdev & 0xfffff)); 62 else 63 printf("%10llu ", inode.size); 64 65 printf("%24.24s %.*s", filetime, item->name_len, name); 66 67 if (item->type == BTRFS_FT_SYMLINK) { 68 printf(" -> %s", target ? target : "?"); 69 if (target) 70 free(target); 71 } 72 73 printf("\n"); 74 75 return 0; 76 } 77 78 int btrfs_probe(struct blk_desc *fs_dev_desc, disk_partition_t *fs_partition) 79 { 80 btrfs_blk_desc = fs_dev_desc; 81 btrfs_part_info = fs_partition; 82 83 memset(&btrfs_info, 0, sizeof(btrfs_info)); 84 85 btrfs_hash_init(); 86 if (btrfs_read_superblock()) 87 return -1; 88 89 if (btrfs_chunk_map_init()) { 90 printf("%s: failed to init chunk map\n", __func__); 91 return -1; 92 } 93 94 btrfs_info.tree_root.objectid = 0; 95 btrfs_info.tree_root.bytenr = btrfs_info.sb.root; 96 btrfs_info.chunk_root.objectid = 0; 97 btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root; 98 99 if (btrfs_read_chunk_tree()) { 100 printf("%s: failed to read chunk tree\n", __func__); 101 return -1; 102 } 103 104 if (btrfs_find_root(btrfs_get_default_subvol_objectid(), 105 &btrfs_info.fs_root, NULL)) { 106 printf("%s: failed to find default subvolume\n", __func__); 107 return -1; 108 } 109 110 return 0; 111 } 112 113 int btrfs_ls(const char *path) 114 { 115 struct btrfs_root root = btrfs_info.fs_root; 116 u64 inr; 117 u8 type; 118 119 inr = btrfs_lookup_path(&root, root.root_dirid, path, &type, NULL, 40); 120 121 if (inr == -1ULL) { 122 printf("Cannot lookup path %s\n", path); 123 return 1; 124 } 125 126 if (type != BTRFS_FT_DIR) { 127 printf("Not a directory: %s\n", path); 128 return 1; 129 } 130 131 if (btrfs_readdir(&root, inr, readdir_callback)) { 132 printf("An error occured while listing directory %s\n", path); 133 return 1; 134 } 135 136 return 0; 137 } 138 139 int btrfs_exists(const char *file) 140 { 141 struct btrfs_root root = btrfs_info.fs_root; 142 u64 inr; 143 u8 type; 144 145 inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, NULL, 40); 146 147 return (inr != -1ULL && type == BTRFS_FT_REG_FILE); 148 } 149 150 int btrfs_size(const char *file, loff_t *size) 151 { 152 struct btrfs_root root = btrfs_info.fs_root; 153 struct btrfs_inode_item inode; 154 u64 inr; 155 u8 type; 156 157 inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode, 158 40); 159 160 if (inr == -1ULL) { 161 printf("Cannot lookup file %s\n", file); 162 return 1; 163 } 164 165 if (type != BTRFS_FT_REG_FILE) { 166 printf("Not a regular file: %s\n", file); 167 return 1; 168 } 169 170 *size = inode.size; 171 return 0; 172 } 173 174 int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len, 175 loff_t *actread) 176 { 177 struct btrfs_root root = btrfs_info.fs_root; 178 struct btrfs_inode_item inode; 179 u64 inr, rd; 180 u8 type; 181 182 inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode, 183 40); 184 185 if (inr == -1ULL) { 186 printf("Cannot lookup file %s\n", file); 187 return 1; 188 } 189 190 if (type != BTRFS_FT_REG_FILE) { 191 printf("Not a regular file: %s\n", file); 192 return 1; 193 } 194 195 if (!len) 196 len = inode.size; 197 198 if (len > inode.size - offset) 199 len = inode.size - offset; 200 201 rd = btrfs_file_read(&root, inr, offset, len, buf); 202 if (rd == -1ULL) { 203 printf("An error occured while reading file %s\n", file); 204 return 1; 205 } 206 207 *actread = rd; 208 return 0; 209 } 210 211 void btrfs_close(void) 212 { 213 btrfs_chunk_map_exit(); 214 } 215 216 int btrfs_uuid(char *uuid_str) 217 { 218 #ifdef CONFIG_LIB_UUID 219 uuid_bin_to_str(btrfs_info.sb.fsid, uuid_str, UUID_STR_FORMAT_STD); 220 return 0; 221 #endif 222 return -ENOSYS; 223 } 224