test/py: Add usb gadget binding test
[platform/kernel/u-boot.git] / fs / btrfs / btrfs.c
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 <config.h>
9 #include <malloc.h>
10 #include <uuid.h>
11 #include <linux/time.h>
12 #include "btrfs.h"
13 #include "crypto/hash.h"
14 #include "disk-io.h"
15
16 struct btrfs_fs_info *current_fs_info;
17
18 static int show_dir(struct btrfs_root *root, struct extent_buffer *eb,
19                     struct btrfs_dir_item *di)
20 {
21         struct btrfs_fs_info *fs_info = root->fs_info;
22         struct btrfs_inode_item ii;
23         struct btrfs_key key;
24         static const char* dir_item_str[] = {
25                 [BTRFS_FT_REG_FILE]     = "   ",
26                 [BTRFS_FT_DIR]          = "DIR",
27                 [BTRFS_FT_CHRDEV]       = "CHR",
28                 [BTRFS_FT_BLKDEV]       = "BLK",
29                 [BTRFS_FT_FIFO]         = "FIF",
30                 [BTRFS_FT_SOCK]         = "SCK",
31                 [BTRFS_FT_SYMLINK]      = "SYM",
32         };
33         u8 type = btrfs_dir_type(eb, di);
34         char namebuf[BTRFS_NAME_LEN];
35         char *target = NULL;
36         char filetime[32];
37         time_t mtime;
38         int ret = 0;
39
40         /* skip XATTRs in directory listing */
41         if (type == BTRFS_FT_XATTR)
42                 return 0;
43
44         btrfs_dir_item_key_to_cpu(eb, di, &key);
45
46         if (key.type == BTRFS_ROOT_ITEM_KEY) {
47                 struct btrfs_root *subvol;
48
49                 /* It's a subvolume, get its mtime from root item */
50                 subvol = btrfs_read_fs_root(fs_info, &key);
51                 if (IS_ERR(subvol)) {
52                         ret = PTR_ERR(subvol);
53                         error("Can't find root %llu", key.objectid);
54                         return ret;
55                 }
56                 mtime = btrfs_stack_timespec_sec(&subvol->root_item.otime);
57         } else {
58                 struct btrfs_path path;
59
60                 /* It's regular inode, get its mtime from inode item */
61                 btrfs_init_path(&path);
62                 ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
63                 if (ret > 0)
64                         ret = -ENOENT;
65                 if (ret < 0) {
66                         error("Can't find inode %llu", key.objectid);
67                         btrfs_release_path(&path);
68                         return ret;
69                 }
70                 read_extent_buffer(path.nodes[0], &ii,
71                         btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
72                         sizeof(ii));
73                 btrfs_release_path(&path);
74                 mtime = btrfs_stack_timespec_sec(&ii.mtime);
75         }
76         ctime_r(&mtime, filetime);
77
78         if (type == BTRFS_FT_SYMLINK) {
79                 target = malloc(fs_info->sectorsize);
80                 if (!target) {
81                         error("Can't alloc memory for symlink %llu",
82                                 key.objectid);
83                         return -ENOMEM;
84                 }
85                 ret = btrfs_readlink(root, key.objectid, target);
86                 if (ret < 0) {
87                         error("Failed to read symlink %llu", key.objectid);
88                         goto out;
89                 }
90                 target[ret] = '\0';
91         }
92
93         if (type < ARRAY_SIZE(dir_item_str) && dir_item_str[type])
94                 printf("<%s> ", dir_item_str[type]);
95         else
96                 printf("?%3u? ", type);
97         if (type == BTRFS_FT_CHRDEV || type == BTRFS_FT_BLKDEV) {
98                 ASSERT(key.type == BTRFS_INODE_ITEM_KEY);
99                 printf("%4llu,%5llu  ", btrfs_stack_inode_rdev(&ii) >> 20,
100                                 btrfs_stack_inode_rdev(&ii) & 0xfffff);
101         } else {
102                 if (key.type == BTRFS_INODE_ITEM_KEY)
103                         printf("%10llu  ", btrfs_stack_inode_size(&ii));
104                 else
105                         printf("%10llu  ", 0ULL);
106         }
107
108         read_extent_buffer(eb, namebuf, (unsigned long)(di + 1),
109                            btrfs_dir_name_len(eb, di));
110         printf("%24.24s  %.*s", filetime, btrfs_dir_name_len(eb, di), namebuf);
111         if (type == BTRFS_FT_SYMLINK)
112                 printf(" -> %s", target ? target : "?");
113         printf("\n");
114 out:
115         free(target);
116         return ret;
117 }
118
119 int btrfs_probe(struct blk_desc *fs_dev_desc,
120                 struct disk_partition *fs_partition)
121 {
122         struct btrfs_fs_info *fs_info;
123         int ret = -1;
124
125         btrfs_hash_init();
126         fs_info = open_ctree_fs_info(fs_dev_desc, fs_partition);
127         if (fs_info) {
128                 current_fs_info = fs_info;
129                 ret = 0;
130         }
131         return ret;
132 }
133
134 int btrfs_ls(const char *path)
135 {
136         struct btrfs_fs_info *fs_info = current_fs_info;
137         struct btrfs_root *root = fs_info->fs_root;
138         u64 ino = BTRFS_FIRST_FREE_OBJECTID;
139         u8 type;
140         int ret;
141
142         ASSERT(fs_info);
143         ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
144                                 path, &root, &ino, &type, 40);
145         if (ret < 0) {
146                 printf("Cannot lookup path %s\n", path);
147                 return ret;
148         }
149
150         if (type != BTRFS_FT_DIR) {
151                 error("Not a directory: %s", path);
152                 return -ENOENT;
153         }
154         ret = btrfs_iter_dir(root, ino, show_dir);
155         if (ret < 0) {
156                 error("An error occurred while listing directory %s", path);
157                 return ret;
158         }
159         return 0;
160 }
161
162 int btrfs_exists(const char *file)
163 {
164         struct btrfs_fs_info *fs_info = current_fs_info;
165         struct btrfs_root *root;
166         u64 ino;
167         u8 type;
168         int ret;
169
170         ASSERT(fs_info);
171
172         ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
173                                 file, &root, &ino, &type, 40);
174         if (ret < 0)
175                 return 0;
176
177         if (type == BTRFS_FT_REG_FILE)
178                 return 1;
179         return 0;
180 }
181
182 int btrfs_size(const char *file, loff_t *size)
183 {
184         struct btrfs_fs_info *fs_info = current_fs_info;
185         struct btrfs_inode_item *ii;
186         struct btrfs_root *root;
187         struct btrfs_path path;
188         struct btrfs_key key;
189         u64 ino;
190         u8 type;
191         int ret;
192
193         ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
194                                 file, &root, &ino, &type, 40);
195         if (ret < 0) {
196                 printf("Cannot lookup file %s\n", file);
197                 return ret;
198         }
199         if (type != BTRFS_FT_REG_FILE) {
200                 printf("Not a regular file: %s\n", file);
201                 return -ENOENT;
202         }
203         btrfs_init_path(&path);
204         key.objectid = ino;
205         key.type = BTRFS_INODE_ITEM_KEY;
206         key.offset = 0;
207
208         ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
209         if (ret < 0) {
210                 printf("Cannot lookup ino %llu\n", ino);
211                 return ret;
212         }
213         if (ret > 0) {
214                 printf("Ino %llu does not exist\n", ino);
215                 ret = -ENOENT;
216                 goto out;
217         }
218         ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
219                             struct btrfs_inode_item);
220         *size = btrfs_inode_size(path.nodes[0], ii);
221 out:
222         btrfs_release_path(&path);
223         return ret;
224 }
225
226 int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
227                loff_t *actread)
228 {
229         struct btrfs_fs_info *fs_info = current_fs_info;
230         struct btrfs_root *root;
231         loff_t real_size = 0;
232         u64 ino;
233         u8 type;
234         int ret;
235
236         ASSERT(fs_info);
237         ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
238                                 file, &root, &ino, &type, 40);
239         if (ret < 0) {
240                 error("Cannot lookup file %s", file);
241                 return ret;
242         }
243
244         if (type != BTRFS_FT_REG_FILE) {
245                 error("Not a regular file: %s", file);
246                 return -EINVAL;
247         }
248
249         if (!len) {
250                 ret = btrfs_size(file, &real_size);
251                 if (ret < 0) {
252                         error("Failed to get inode size: %s", file);
253                         return ret;
254                 }
255                 len = real_size;
256         }
257
258         if (len > real_size - offset)
259                 len = real_size - offset;
260
261         ret = btrfs_file_read(root, ino, offset, len, buf);
262         if (ret < 0) {
263                 error("An error occurred while reading file %s", file);
264                 return ret;
265         }
266
267         *actread = len;
268         return 0;
269 }
270
271 void btrfs_close(void)
272 {
273         if (current_fs_info) {
274                 close_ctree_fs_info(current_fs_info);
275                 current_fs_info = NULL;
276         }
277 }
278
279 int btrfs_uuid(char *uuid_str)
280 {
281 #ifdef CONFIG_LIB_UUID
282         if (current_fs_info)
283                 uuid_bin_to_str(current_fs_info->super_copy->fsid, uuid_str,
284                                 UUID_STR_FORMAT_STD);
285         return 0;
286 #endif
287         return -ENOSYS;
288 }