]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/fdos/vfat.c
* Patch by Daniel Engström, 13 Nov 2002:
[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  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 #include <common.h>
26 #include <config.h>
27
28 #if (CONFIG_COMMANDS & CFG_CMD_FDOS)
29 #include <linux/ctype.h>
30
31 #include "dos.h"
32 #include "fdos.h"
33
34 static int dir_read (Fs_t *fs,
35                      Slot_t *dir,
36                      Directory_t *dirent,
37                      int num,
38                      struct vfat_state *v);
39
40 static int unicode_read (char *in, char *out, int num);
41 static int match (const char *s, const char *p);
42 static unsigned char sum_shortname (char *name);
43 static int check_vfat (struct vfat_state *v, Directory_t *dir);
44 static char *conv_name (char *name, char *ext, char Case, char *ans);
45
46
47 /*-----------------------------------------------------------------------------
48  * clear_vfat -- 
49  *-----------------------------------------------------------------------------
50  */
51 static void clear_vfat (struct vfat_state *v)
52 {
53     v -> subentries = 0;
54     v -> status = 0;
55 }
56
57 /*-----------------------------------------------------------------------------
58  * vfat_lookup -- 
59  *-----------------------------------------------------------------------------
60  */
61 int vfat_lookup (Slot_t *dir,
62                  Fs_t *fs,
63                  Directory_t *dirent,
64                  int *entry,
65                  int *vfat_start,
66                  char *filename, 
67                  int flags,
68                  char *outname,
69                  Slot_t *file)
70 {
71     int found;
72     struct vfat_state vfat;
73     char newfile [VSE_NAMELEN];
74     int vfat_present = 0;
75
76     if (*entry == -1) {
77         return -1;
78     }
79
80     found = 0;
81     clear_vfat (&vfat);
82     while (1) {
83         if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) {
84             if (vfat_start) {
85                 *vfat_start = *entry;
86             }
87             break;
88         }
89         (*entry)++;
90
91         /* Empty slot                                                        */
92         if (dirent -> name[0] == '\0'){
93             if (vfat_start == 0) {
94                 break;
95             }
96             continue;
97         }
98
99         if (dirent -> attr == ATTR_VSE) {
100             /* VSE entry, continue                                           */
101             continue;
102         }
103         if ( (dirent -> name [0] == DELMARK) ||
104              ((dirent -> attr & ATTR_DIRECTORY) != 0 &&
105               (flags & ACCEPT_DIR) == 0) ||
106              ((dirent -> attr & ATTR_VOLUME) != 0 &&
107               (flags & ACCEPT_LABEL) == 0) ||
108              (((dirent -> attr & (ATTR_DIRECTORY | ATTR_VOLUME)) == 0) &&
109               (flags & ACCEPT_PLAIN) == 0)) {
110             clear_vfat (&vfat);
111             continue;
112         }
113
114         vfat_present = check_vfat (&vfat, dirent);
115         if (vfat_start) {
116             *vfat_start = *entry - 1;
117             if (vfat_present) {
118                 *vfat_start -= vfat.subentries;
119             }
120         }
121
122         if (dirent -> attr & ATTR_VOLUME) {
123             strncpy (newfile, dirent -> name, 8);
124             newfile [8] = '\0';
125             strncat (newfile, dirent -> ext, 3);
126             newfile [11] = '\0';
127         }
128         else {
129             conv_name (dirent -> name, dirent -> ext, dirent -> Case, newfile);
130         }
131
132         if (flags & MATCH_ANY) {
133             found = 1;
134             break;
135         }
136
137         if ((vfat_present && match (vfat.name, filename)) ||
138             (match (newfile, filename))) {
139             found = 1;
140             break;
141         }
142         clear_vfat (&vfat);
143     }
144
145     if (found) {
146         if ((flags & DO_OPEN) && file) {
147             if (open_file (file, dirent) < 0) {
148                 return (-1);
149             }
150         }
151         if (outname) {
152             if (vfat_present) {
153                 strcpy (outname, vfat.name);
154             }
155             else {
156                 strcpy (outname, newfile);
157             }
158         }
159         return (0);                    /* File found                         */
160     } else {
161         *entry = -1;
162         return -1;                      /* File not found                    */
163     }
164 }
165
166 /*-----------------------------------------------------------------------------
167  * dir_read -- Read one directory entry
168  *-----------------------------------------------------------------------------
169  */
170 static int dir_read (Fs_t *fs,
171               Slot_t *dir,
172               Directory_t *dirent,
173               int num,
174               struct vfat_state *v)
175 {
176
177     /* read the directory entry                                              */
178     if (read_file (fs,
179                    dir,
180                    (char *)dirent,
181                    num * MDIR_SIZE,
182                    MDIR_SIZE) != MDIR_SIZE) {
183         return (-1);
184     }
185
186     if (v && (dirent -> attr == ATTR_VSE)) {
187         struct vfat_subentry *vse;
188         unsigned char id, last_flag;
189         char *c;
190
191         vse = (struct vfat_subentry *) dirent;
192         id = vse -> id & VSE_MASK;
193         last_flag = (vse -> id & VSE_LAST);
194         if (id > MAX_VFAT_SUBENTRIES) {
195             /* Invalid VSE entry                                             */
196             return (-1);
197         }
198
199
200         /* Decode VSE                                                        */
201         if(v -> sum != vse -> sum) {
202             clear_vfat (v);
203             v -> sum = vse -> sum;
204         }
205
206         
207         v -> status |= 1 << (id - 1);
208         if (last_flag) {
209             v -> subentries = id;
210         }
211
212         c = &(v -> name [VSE_NAMELEN * (id - 1)]);
213         c += unicode_read (vse->text1, c, VSE1SIZE);
214         c += unicode_read (vse->text2, c, VSE2SIZE);
215         c += unicode_read (vse->text3, c, VSE3SIZE);
216                 
217         if (last_flag) {
218             *c = '\0';          /* Null terminate long name                  */
219         }
220         
221     }
222     return (0);
223 }
224
225 /*-----------------------------------------------------------------------------
226  * unicode_read -- 
227  *-----------------------------------------------------------------------------
228  */
229 static int unicode_read (char *in, char *out, int num)
230 {
231     int j;
232     
233     for (j = 0; j < num; ++j) {
234         if (in [1])
235             *out = '_';
236         else
237             *out = in [0];
238         out ++;
239         in += 2;
240     }
241     return num;
242 }
243
244 /*-----------------------------------------------------------------------------
245  * match -- 
246  *-----------------------------------------------------------------------------
247  */
248 static int match (const char *s, const char *p)
249 {
250
251     for (; *p != '\0'; ) {
252         if (toupper (*s) != toupper (*p)) {
253             return (0);
254         }
255         p++;
256         s++;
257     }
258     
259     if (*s != '\0') {
260         return (0);
261     }
262     else {
263         return (1);
264     }
265 }
266 /*-----------------------------------------------------------------------------
267  * sum_shortname -- 
268  *-----------------------------------------------------------------------------
269  */
270 static unsigned char sum_shortname (char *name)
271 {
272     unsigned char sum;
273     int j;
274     
275     for (j = sum = 0; j < 11; ++j) {
276         sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) +
277             (name [j] ? name [j] : ' ');
278     }
279     return (sum);
280 }
281 /*-----------------------------------------------------------------------------
282  * check_vfat -- 
283  * Return 1 if long name is valid, 0 else
284  *-----------------------------------------------------------------------------
285  */
286 static int check_vfat (struct vfat_state *v, Directory_t *dir)
287 {
288     char name[12];
289     
290     if (v -> subentries == 0) {
291         return 0;
292     }
293     
294     strncpy (name, dir -> name, 8);
295     strncpy (name + 8, dir -> ext, 3);
296     name [11] = '\0';
297     
298     if (v -> sum != sum_shortname (name)) {
299         return 0;
300     }
301     
302     if( (v -> status & ((1 << v -> subentries) - 1)) !=
303         (1 << v -> subentries) - 1) {
304         return 0;
305     }
306     v->name [VSE_NAMELEN * v -> subentries] = 0;
307     
308     return 1;
309 }
310 /*-----------------------------------------------------------------------------
311  * conv_name -- 
312  *-----------------------------------------------------------------------------
313  */
314 static char *conv_name (char *name, char *ext, char Case, char *ans)
315 {
316     char tname [9], text [4];
317     int i;
318
319     i = 0;
320     while (i < 8 && name [i] != ' ' && name [i] != '\0') {
321         tname [i] = name [i];
322         i++;
323     }
324     tname [i] = '\0';
325     
326     if (Case & BASECASE) {
327         for (i = 0; i < 8 && tname [i]; i++) {
328             tname [i] = tolower (tname [i]);
329         }
330     }
331
332     i = 0;
333     while (i < 3 && ext [i] != ' ' && ext [i] != '\0') {
334         text [i] = ext [i];
335         i++;
336     }
337     text [i] = '\0';
338
339     if (Case & EXTCASE){
340         for (i = 0; i < 3 && text [i]; i++) {
341             text [i] = tolower (text [i]);
342         }
343     }
344
345     if (*text) {
346         strcpy (ans, tname);
347         strcat (ans, ".");
348         strcat (ans, text);
349     }
350     else {
351         strcpy(ans, tname);
352     }
353     return (ans);
354 }
355
356
357 #endif