lib/vsprintf.c: don't special-case pointers to address null
[oweals/u-boot.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 DECLARE_GLOBAL_DATA_PTR;
25
26 static block_dev_desc_t *fs_dev_desc;
27 static disk_partition_t fs_partition;
28 static int fs_type = FS_TYPE_ANY;
29
30 static inline int fs_ls_unsupported(const char *dirname)
31 {
32         printf("** Unrecognized filesystem type **\n");
33         return -1;
34 }
35
36 static inline int fs_read_unsupported(const char *filename, ulong addr,
37                                       int offset, int len)
38 {
39         printf("** Unrecognized filesystem type **\n");
40         return -1;
41 }
42
43 #ifdef CONFIG_FS_FAT
44 static int fs_probe_fat(void)
45 {
46         return fat_set_blk_dev(fs_dev_desc, &fs_partition);
47 }
48
49 static void fs_close_fat(void)
50 {
51 }
52
53 #define fs_ls_fat file_fat_ls
54
55 static int fs_read_fat(const char *filename, ulong addr, int offset, int len)
56 {
57         int len_read;
58
59         len_read = file_fat_read_at(filename, offset,
60                                     (unsigned char *)addr, len);
61         if (len_read == -1) {
62                 printf("** Unable to read file %s **\n", filename);
63                 return -1;
64         }
65
66         return len_read;
67 }
68 #else
69 static inline int fs_probe_fat(void)
70 {
71         return -1;
72 }
73
74 static inline void fs_close_fat(void)
75 {
76 }
77
78 #define fs_ls_fat fs_ls_unsupported
79 #define fs_read_fat fs_read_unsupported
80 #endif
81
82 #ifdef CONFIG_FS_EXT4
83 static int fs_probe_ext(void)
84 {
85         ext4fs_set_blk_dev(fs_dev_desc, &fs_partition);
86
87         if (!ext4fs_mount(fs_partition.size)) {
88                 ext4fs_close();
89                 return -1;
90         }
91
92         return 0;
93 }
94
95 static void fs_close_ext(void)
96 {
97         ext4fs_close();
98 }
99
100 #define fs_ls_ext ext4fs_ls
101
102 static int fs_read_ext(const char *filename, ulong addr, int offset, int len)
103 {
104         int file_len;
105         int len_read;
106
107         if (offset != 0) {
108                 printf("** Cannot support non-zero offset **\n");
109                 return -1;
110         }
111
112         file_len = ext4fs_open(filename);
113         if (file_len < 0) {
114                 printf("** File not found %s **\n", filename);
115                 ext4fs_close();
116                 return -1;
117         }
118
119         if (len == 0)
120                 len = file_len;
121
122         len_read = ext4fs_read((char *)addr, len);
123         ext4fs_close();
124
125         if (len_read != len) {
126                 printf("** Unable to read file %s **\n", filename);
127                 return -1;
128         }
129
130         return len_read;
131 }
132 #else
133 static inline int fs_probe_ext(void)
134 {
135         return -1;
136 }
137
138 static inline void fs_close_ext(void)
139 {
140 }
141
142 #define fs_ls_ext fs_ls_unsupported
143 #define fs_read_ext fs_read_unsupported
144 #endif
145
146 static struct {
147         int fstype;
148         int (*probe)(void);
149 } fstypes[] = {
150         {
151                 .fstype = FS_TYPE_FAT,
152                 .probe = fs_probe_fat,
153         },
154         {
155                 .fstype = FS_TYPE_EXT,
156                 .probe = fs_probe_ext,
157         },
158 };
159
160 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
161 {
162         int part, i;
163 #ifdef CONFIG_NEEDS_MANUAL_RELOC
164         static int relocated;
165
166         if (!relocated) {
167                 for (i = 0; i < ARRAY_SIZE(fstypes); i++)
168                         fstypes[i].probe += gd->reloc_off;
169                 relocated = 1;
170         }
171 #endif
172
173         part = get_device_and_partition(ifname, dev_part_str, &fs_dev_desc,
174                                         &fs_partition, 1);
175         if (part < 0)
176                 return -1;
177
178         for (i = 0; i < ARRAY_SIZE(fstypes); i++) {
179                 if ((fstype != FS_TYPE_ANY) && (fstype != fstypes[i].fstype))
180                         continue;
181
182                 if (!fstypes[i].probe()) {
183                         fs_type = fstypes[i].fstype;
184                         return 0;
185                 }
186         }
187
188         printf("** Unrecognized filesystem type **\n");
189         return -1;
190 }
191
192 static void fs_close(void)
193 {
194         switch (fs_type) {
195         case FS_TYPE_FAT:
196                 fs_close_fat();
197                 break;
198         case FS_TYPE_EXT:
199                 fs_close_ext();
200                 break;
201         default:
202                 break;
203         }
204
205         fs_type = FS_TYPE_ANY;
206 }
207
208 int fs_ls(const char *dirname)
209 {
210         int ret;
211
212         switch (fs_type) {
213         case FS_TYPE_FAT:
214                 ret = fs_ls_fat(dirname);
215                 break;
216         case FS_TYPE_EXT:
217                 ret = fs_ls_ext(dirname);
218                 break;
219         default:
220                 ret = fs_ls_unsupported(dirname);
221                 break;
222         }
223
224         fs_close();
225
226         return ret;
227 }
228
229 int fs_read(const char *filename, ulong addr, int offset, int len)
230 {
231         int ret;
232
233         switch (fs_type) {
234         case FS_TYPE_FAT:
235                 ret = fs_read_fat(filename, addr, offset, len);
236                 break;
237         case FS_TYPE_EXT:
238                 ret = fs_read_ext(filename, addr, offset, len);
239                 break;
240         default:
241                 ret = fs_read_unsupported(filename, addr, offset, len);
242                 break;
243         }
244
245         fs_close();
246
247         return ret;
248 }
249
250 int do_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
251                 int fstype)
252 {
253         unsigned long addr;
254         const char *addr_str;
255         const char *filename;
256         unsigned long bytes;
257         unsigned long pos;
258         int len_read;
259         char buf[12];
260
261         if (argc < 5)
262                 return CMD_RET_USAGE;
263
264         if (fs_set_blk_dev(argv[1], argv[2], fstype))
265                 return 1;
266
267         if (argc >= 4) {
268                 addr = simple_strtoul(argv[3], NULL, 0);
269         } else {
270                 addr_str = getenv("loadaddr");
271                 if (addr_str != NULL)
272                         addr = simple_strtoul(addr_str, NULL, 16);
273                 else
274                         addr = CONFIG_SYS_LOAD_ADDR;
275         }
276         if (argc >= 5) {
277                 filename = argv[4];
278         } else {
279                 filename = getenv("bootfile");
280                 if (!filename) {
281                         puts("** No boot file defined **\n");
282                         return 1;
283                 }
284         }
285         if (argc >= 6)
286                 bytes = simple_strtoul(argv[5], NULL, 0);
287         else
288                 bytes = 0;
289         if (argc >= 7)
290                 pos = simple_strtoul(argv[6], NULL, 0);
291         else
292                 pos = 0;
293
294         len_read = fs_read(filename, addr, pos, bytes);
295         if (len_read <= 0)
296                 return 1;
297
298         printf("%d bytes read\n", len_read);
299
300         sprintf(buf, "0x%x", len_read);
301         setenv("filesize", buf);
302
303         return 0;
304 }
305
306 int do_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
307         int fstype)
308 {
309         if (argc < 2)
310                 return CMD_RET_USAGE;
311
312         if (fs_set_blk_dev(argv[1], (argc >= 3) ? argv[2] : NULL, fstype))
313                 return 1;
314
315         if (fs_ls(argc == 4 ? argv[3] : "/"))
316                 return 1;
317
318         return 0;
319 }