blob: b01b111bfb4d9c38a6d3c7f2bd7792c24dad337c [file] [log] [blame]
Marek BehĂșn0c936ee2017-09-03 17:00:29 +02001/*
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
14struct btrfs_info btrfs_info;
15
16static 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
78int 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
113int 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
139int 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
150int 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
174int 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
211void btrfs_close(void)
212{
213 btrfs_chunk_map_exit();
214}
215
216int 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}