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