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