]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/fs.c
fs: add filesystem switch libary, implement ls and fsload commands
[karo-tx-uboot.git] / fs / fs.c
1 /*
2  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <config.h>
18 #include <common.h>
19 #include <part.h>
20 #include <ext4fs.h>
21 #include <fat.h>
22 #include <fs.h>
23
24 static block_dev_desc_t *fs_dev_desc;
25 static disk_partition_t fs_partition;
26 static int fs_type = FS_TYPE_ANY;
27
28 static inline int fs_ls_unsupported(const char *dirname)
29 {
30         printf("** Unrecognized filesystem type **\n");
31         return -1;
32 }
33
34 static inline int fs_read_unsupported(const char *filename, ulong addr,
35                                       int offset, int len)
36 {
37         printf("** Unrecognized filesystem type **\n");
38         return -1;
39 }
40
41 #ifdef CONFIG_FS_FAT
42 static int fs_probe_fat(void)
43 {
44         return fat_set_blk_dev(fs_dev_desc, &fs_partition);
45 }
46
47 static void fs_close_fat(void)
48 {
49 }
50
51 #define fs_ls_fat file_fat_ls
52
53 static int fs_read_fat(const char *filename, ulong addr, int offset, int len)
54 {
55         int len_read;
56
57         len_read = file_fat_read_at(filename, offset,
58                                     (unsigned char *)addr, len);
59         if (len_read == -1) {
60                 printf("** Unable to read file %s **\n", filename);
61                 return -1;
62         }
63
64         return len_read;
65 }
66 #else
67 static inline int fs_probe_fat(void)
68 {
69         return -1;
70 }
71
72 static inline void fs_close_fat(void)
73 {
74 }
75
76 #define fs_ls_fat fs_ls_unsupported
77 #define fs_read_fat fs_read_unsupported
78 #endif
79
80 #ifdef CONFIG_FS_EXT4
81 static int fs_probe_ext(void)
82 {
83         ext4fs_set_blk_dev(fs_dev_desc, &fs_partition);
84
85         if (!ext4fs_mount(fs_partition.size)) {
86                 ext4fs_close();
87                 return -1;
88         }
89
90         return 0;
91 }
92
93 static void fs_close_ext(void)
94 {
95         ext4fs_close();
96 }
97
98 #define fs_ls_ext ext4fs_ls
99
100 static int fs_read_ext(const char *filename, ulong addr, int offset, int len)
101 {
102         int file_len;
103         int len_read;
104
105         if (offset != 0) {
106                 printf("** Cannot support non-zero offset **\n");
107                 return -1;
108         }
109
110         file_len = ext4fs_open(filename);
111         if (file_len < 0) {
112                 printf("** File not found %s **\n", filename);
113                 ext4fs_close();
114                 return -1;
115         }
116
117         if (len == 0)
118                 len = file_len;
119
120         len_read = ext4fs_read((char *)addr, len);
121         ext4fs_close();
122
123         if (len_read != len) {
124                 printf("** Unable to read file %s **\n", filename);
125                 return -1;
126         }
127
128         return len_read;
129 }
130 #else
131 static inline int fs_probe_ext(void)
132 {
133         return -1;
134 }
135
136 static inline void fs_close_ext(void)
137 {
138 }
139
140 #define fs_ls_ext fs_ls_unsupported
141 #define fs_read_ext fs_read_unsupported
142 #endif
143
144 static const struct {
145         int fstype;
146         int (*probe)(void);
147 } fstypes[] = {
148         {
149                 .fstype = FS_TYPE_FAT,
150                 .probe = fs_probe_fat,
151         },
152         {
153                 .fstype = FS_TYPE_EXT,
154                 .probe = fs_probe_ext,
155         },
156 };
157
158 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
159 {
160         int part, i;
161
162         part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
163                                         &fs_partition, 1);
164         if (part < 0)
165                 return -1;
166
167         for (i = 0; i < ARRAY_SIZE(fstypes); i++) {
168                 if ((fstype != FS_TYPE_ANY) && (fstype != fstypes[i].fstype))
169                         continue;
170
171                 if (!fstypes[i].probe()) {
172                         fs_type = fstypes[i].fstype;
173                         return 0;
174                 }
175         }
176
177         printf("** Unrecognized filesystem type **\n");
178         return -1;
179 }
180
181 static void fs_close(void)
182 {
183         switch (fs_type) {
184         case FS_TYPE_FAT:
185                 fs_close_fat();
186                 break;
187         case FS_TYPE_EXT:
188                 fs_close_ext();
189                 break;
190         default:
191                 break;
192         }
193
194         fs_type = FS_TYPE_ANY;
195 }
196
197 int fs_ls(const char *dirname)
198 {
199         int ret;
200
201         switch (fs_type) {
202         case FS_TYPE_FAT:
203                 ret = fs_ls_fat(dirname);
204                 break;
205         case FS_TYPE_EXT:
206                 ret = fs_ls_ext(dirname);
207                 break;
208         default:
209                 ret = fs_ls_unsupported(dirname);
210                 break;
211         }
212
213         fs_close();
214
215         return ret;
216 }
217
218 int fs_read(const char *filename, ulong addr, int offset, int len)
219 {
220         int ret;
221
222         switch (fs_type) {
223         case FS_TYPE_FAT:
224                 ret = fs_read_fat(filename, addr, offset, len);
225                 break;
226         case FS_TYPE_EXT:
227                 ret = fs_read_ext(filename, addr, offset, len);
228                 break;
229         default:
230                 ret = fs_read_unsupported(filename, addr, offset, len);
231                 break;
232         }
233
234         fs_close();
235
236         return ret;
237 }
238
239 int do_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
240                 int fstype)
241 {
242         unsigned long addr;
243         const char *addr_str;
244         const char *filename;
245         unsigned long bytes;
246         unsigned long pos;
247         int len_read;
248         char buf[12];
249
250         if (argc < 5)
251                 return CMD_RET_USAGE;
252
253         if (fs_set_blk_dev(argv[1], argv[2], fstype))
254                 return 1;
255
256         if (argc >= 4) {
257                 addr = simple_strtoul(argv[3], NULL, 0);
258         } else {
259                 addr_str = getenv("loadaddr");
260                 if (addr_str != NULL)
261                         addr = simple_strtoul(addr_str, NULL, 16);
262                 else
263                         addr = CONFIG_SYS_LOAD_ADDR;
264         }
265         if (argc >= 5) {
266                 filename = argv[4];
267         } else {
268                 filename = getenv("bootfile");
269                 if (!filename) {
270                         puts("** No boot file defined **\n");
271                         return 1;
272                 }
273         }
274         if (argc >= 6)
275                 bytes = simple_strtoul(argv[5], NULL, 0);
276         else
277                 bytes = 0;
278         if (argc >= 7)
279                 pos = simple_strtoul(argv[6], NULL, 0);
280         else
281                 pos = 0;
282
283         len_read = fs_read(filename, addr, pos, bytes);
284         if (len_read <= 0)
285                 return 1;
286
287         printf("%d bytes read\n", len_read);
288
289         sprintf(buf, "0x%x", len_read);
290         setenv("filesize", buf);
291
292         return 0;
293 }
294
295 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
296         int fstype)
297 {
298         if (argc < 2)
299                 return CMD_RET_USAGE;
300
301         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
302                 return 1;
303
304         if (fs_ls(argc == 4 ? argv[3] : "/"))
305                 return 1;
306
307         return 0;
308 }