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