]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/fdos/vfat.c
Merge branch 'master' of git://git.denx.de/u-boot-nds32
[karo-tx-uboot.git] / fs / fdos / vfat.c
1 /*
2  * (C) Copyright 2002
3  * Stäubli Faverges - <www.staubli.com>
4  * Pierre AUBERT  p.aubert@staubli.com
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  */
8
9 #include <common.h>
10 #include <config.h>
11 #include <linux/ctype.h>
12
13 #include "dos.h"
14 #include "fdos.h"
15
16 static int dir_read (Fs_t *fs,
17                      Slot_t *dir,
18                      Directory_t *dirent,
19                      int num,
20                      struct vfat_state *v);
21
22 static int unicode_read (char *in, char *out, int num);
23 static int match (const char *s, const char *p);
24 static unsigned char sum_shortname (char *name);
25 static int check_vfat (struct vfat_state *v, Directory_t *dir);
26 static char *conv_name (char *name, char *ext, char Case, char *ans);
27
28
29 /*-----------------------------------------------------------------------------
30  * clear_vfat --
31  *-----------------------------------------------------------------------------
32  */
33 static void clear_vfat (struct vfat_state *v)
34 {
35     v -> subentries = 0;
36     v -> status = 0;
37 }
38
39 /*-----------------------------------------------------------------------------
40  * vfat_lookup --
41  *-----------------------------------------------------------------------------
42  */
43 int vfat_lookup (Slot_t *dir,
44                  Fs_t *fs,
45                  Directory_t *dirent,
46                  int *entry,
47                  int *vfat_start,
48                  char *filename,
49                  int flags,
50                  char *outname,
51                  Slot_t *file)
52 {
53     int found;
54     struct vfat_state vfat;
55     char newfile [VSE_NAMELEN];
56     int vfat_present = 0;
57
58     if (*entry == -1) {
59         return -1;
60     }
61
62     found = 0;
63     clear_vfat (&vfat);
64     while (1) {
65         if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) {
66             if (vfat_start) {
67                 *vfat_start = *entry;
68             }
69             break;
70         }
71         (*entry)++;
72
73         /* Empty slot                                                        */
74         if (dirent -> name[0] == '\0'){
75             if (vfat_start == 0) {
76                 break;
77             }
78             continue;
79         }
80
81         if (dirent -> attr == ATTR_VSE) {
82             /* VSE entry, continue                                           */
83             continue;
84         }
85         if ( (dirent -> name [0] == DELMARK) ||
86              ((dirent -> attr & ATTR_DIRECTORY) != 0 &&
87               (flags & ACCEPT_DIR) == 0) ||
88              ((dirent -> attr & ATTR_VOLUME) != 0 &&
89               (flags & ACCEPT_LABEL) == 0) ||
90              (((dirent -> attr & (ATTR_DIRECTORY | ATTR_VOLUME)) == 0) &&
91               (flags & ACCEPT_PLAIN) == 0)) {
92             clear_vfat (&vfat);
93             continue;
94         }
95
96         vfat_present = check_vfat (&vfat, dirent);
97         if (vfat_start) {
98             *vfat_start = *entry - 1;
99             if (vfat_present) {
100                 *vfat_start -= vfat.subentries;
101             }
102         }
103
104         if (dirent -> attr & ATTR_VOLUME) {
105             strncpy (newfile, dirent -> name, 8);
106             newfile [8] = '\0';
107             strncat (newfile, dirent -> ext, 3);
108             newfile [11] = '\0';
109         }
110         else {
111             conv_name (dirent -> name, dirent -> ext, dirent -> Case, newfile);
112         }
113
114         if (flags & MATCH_ANY) {
115             found = 1;
116             break;
117         }
118
119         if ((vfat_present && match (vfat.name, filename)) ||
120             (match (newfile, filename))) {
121             found = 1;
122             break;
123         }
124         clear_vfat (&vfat);
125     }
126
127     if (found) {
128         if ((flags & DO_OPEN) && file) {
129             if (open_file (file, dirent) < 0) {
130                 return (-1);
131             }
132         }
133         if (outname) {
134             if (vfat_present) {
135                 strcpy (outname, vfat.name);
136             }
137             else {
138                 strcpy (outname, newfile);
139             }
140         }
141         return (0);                    /* File found                         */
142     } else {
143         *entry = -1;
144         return -1;                      /* File not found                    */
145     }
146 }
147
148 /*-----------------------------------------------------------------------------
149  * dir_read -- Read one directory entry
150  *-----------------------------------------------------------------------------
151  */
152 static int dir_read (Fs_t *fs,
153               Slot_t *dir,
154               Directory_t *dirent,
155               int num,
156               struct vfat_state *v)
157 {
158
159     /* read the directory entry                                              */
160     if (read_file (fs,
161                    dir,
162                    (char *)dirent,
163                    num * MDIR_SIZE,
164                    MDIR_SIZE) != MDIR_SIZE) {
165         return (-1);
166     }
167
168     if (v && (dirent -> attr == ATTR_VSE)) {
169         struct vfat_subentry *vse;
170         unsigned char id, last_flag;
171         char *c;
172
173         vse = (struct vfat_subentry *) dirent;
174         id = vse -> id & VSE_MASK;
175         last_flag = (vse -> id & VSE_LAST);
176         if (id > MAX_VFAT_SUBENTRIES) {
177             /* Invalid VSE entry                                             */
178             return (-1);
179         }
180
181
182         /* Decode VSE                                                        */
183         if(v -> sum != vse -> sum) {
184             clear_vfat (v);
185             v -> sum = vse -> sum;
186         }
187
188
189         v -> status |= 1 << (id - 1);
190         if (last_flag) {
191             v -> subentries = id;
192         }
193
194         c = &(v -> name [VSE_NAMELEN * (id - 1)]);
195         c += unicode_read (vse->text1, c, VSE1SIZE);
196         c += unicode_read (vse->text2, c, VSE2SIZE);
197         c += unicode_read (vse->text3, c, VSE3SIZE);
198
199         if (last_flag) {
200             *c = '\0';          /* Null terminate long name                  */
201         }
202
203     }
204     return (0);
205 }
206
207 /*-----------------------------------------------------------------------------
208  * unicode_read --
209  *-----------------------------------------------------------------------------
210  */
211 static int unicode_read (char *in, char *out, int num)
212 {
213     int j;
214
215     for (j = 0; j < num; ++j) {
216         if (in [1])
217             *out = '_';
218         else
219             *out = in [0];
220         out ++;
221         in += 2;
222     }
223     return num;
224 }
225
226 /*-----------------------------------------------------------------------------
227  * match --
228  *-----------------------------------------------------------------------------
229  */
230 static int match (const char *s, const char *p)
231 {
232
233     for (; *p != '\0'; ) {
234         if (toupper (*s) != toupper (*p)) {
235             return (0);
236         }
237         p++;
238         s++;
239     }
240
241     if (*s != '\0') {
242         return (0);
243     }
244     else {
245         return (1);
246     }
247 }
248 /*-----------------------------------------------------------------------------
249  * sum_shortname --
250  *-----------------------------------------------------------------------------
251  */
252 static unsigned char sum_shortname (char *name)
253 {
254     unsigned char sum;
255     int j;
256
257     for (j = sum = 0; j < 11; ++j) {
258         sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) +
259             (name [j] ? name [j] : ' ');
260     }
261     return (sum);
262 }
263 /*-----------------------------------------------------------------------------
264  * check_vfat --
265  * Return 1 if long name is valid, 0 else
266  *-----------------------------------------------------------------------------
267  */
268 static int check_vfat (struct vfat_state *v, Directory_t *dir)
269 {
270     char name[12];
271
272     if (v -> subentries == 0) {
273         return 0;
274     }
275
276     strncpy (name, dir -> name, 8);
277     strncpy (name + 8, dir -> ext, 3);
278     name [11] = '\0';
279
280     if (v -> sum != sum_shortname (name)) {
281         return 0;
282     }
283
284     if( (v -> status & ((1 << v -> subentries) - 1)) !=
285         (1 << v -> subentries) - 1) {
286         return 0;
287     }
288     v->name [VSE_NAMELEN * v -> subentries] = 0;
289
290     return 1;
291 }
292 /*-----------------------------------------------------------------------------
293  * conv_name --
294  *-----------------------------------------------------------------------------
295  */
296 static char *conv_name (char *name, char *ext, char Case, char *ans)
297 {
298     char tname [9], text [4];
299     int i;
300
301     i = 0;
302     while (i < 8 && name [i] != ' ' && name [i] != '\0') {
303         tname [i] = name [i];
304         i++;
305     }
306     tname [i] = '\0';
307
308     if (Case & BASECASE) {
309         for (i = 0; i < 8 && tname [i]; i++) {
310             tname [i] = tolower (tname [i]);
311         }
312     }
313
314     i = 0;
315     while (i < 3 && ext [i] != ' ' && ext [i] != '\0') {
316         text [i] = ext [i];
317         i++;
318     }
319     text [i] = '\0';
320
321     if (Case & EXTCASE){
322         for (i = 0; i < 3 && text [i]; i++) {
323             text [i] = tolower (text [i]);
324         }
325     }
326
327     if (*text) {
328         strcpy (ans, tname);
329         strcat (ans, ".");
330         strcat (ans, text);
331     }
332     else {
333         strcpy(ans, tname);
334     }
335     return (ans);
336 }