blob: 46a464b293f44a50ec5a4f86b8ebb88af50f561f [file] [log] [blame]
wdenk591dda52002-11-18 00:14:45 +00001/*
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
34static int dir_read (Fs_t *fs,
wdenk57b2d802003-06-27 21:31:46 +000035 Slot_t *dir,
36 Directory_t *dirent,
37 int num,
38 struct vfat_state *v);
wdenk591dda52002-11-18 00:14:45 +000039
40static int unicode_read (char *in, char *out, int num);
41static int match (const char *s, const char *p);
42static unsigned char sum_shortname (char *name);
43static int check_vfat (struct vfat_state *v, Directory_t *dir);
44static char *conv_name (char *name, char *ext, char Case, char *ans);
45
46
47/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +000048 * clear_vfat --
wdenk591dda52002-11-18 00:14:45 +000049 *-----------------------------------------------------------------------------
50 */
51static void clear_vfat (struct vfat_state *v)
52{
53 v -> subentries = 0;
54 v -> status = 0;
55}
56
57/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +000058 * vfat_lookup --
wdenk591dda52002-11-18 00:14:45 +000059 *-----------------------------------------------------------------------------
60 */
61int vfat_lookup (Slot_t *dir,
wdenk57b2d802003-06-27 21:31:46 +000062 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)
wdenk591dda52002-11-18 00:14:45 +000070{
71 int found;
72 struct vfat_state vfat;
73 char newfile [VSE_NAMELEN];
74 int vfat_present = 0;
75
76 if (*entry == -1) {
wdenk57b2d802003-06-27 21:31:46 +000077 return -1;
wdenk591dda52002-11-18 00:14:45 +000078 }
79
80 found = 0;
81 clear_vfat (&vfat);
82 while (1) {
wdenk57b2d802003-06-27 21:31:46 +000083 if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) {
84 if (vfat_start) {
85 *vfat_start = *entry;
86 }
87 break;
88 }
89 (*entry)++;
wdenk591dda52002-11-18 00:14:45 +000090
wdenk57b2d802003-06-27 21:31:46 +000091 /* Empty slot */
92 if (dirent -> name[0] == '\0'){
93 if (vfat_start == 0) {
94 break;
95 }
96 continue;
97 }
wdenk591dda52002-11-18 00:14:45 +000098
wdenk57b2d802003-06-27 21:31:46 +000099 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 }
wdenk591dda52002-11-18 00:14:45 +0000113
wdenk57b2d802003-06-27 21:31:46 +0000114 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 }
wdenk591dda52002-11-18 00:14:45 +0000121
wdenk57b2d802003-06-27 21:31:46 +0000122 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 }
wdenk591dda52002-11-18 00:14:45 +0000131
wdenk57b2d802003-06-27 21:31:46 +0000132 if (flags & MATCH_ANY) {
133 found = 1;
134 break;
135 }
wdenk591dda52002-11-18 00:14:45 +0000136
wdenk57b2d802003-06-27 21:31:46 +0000137 if ((vfat_present && match (vfat.name, filename)) ||
138 (match (newfile, filename))) {
139 found = 1;
140 break;
141 }
142 clear_vfat (&vfat);
wdenk591dda52002-11-18 00:14:45 +0000143 }
144
145 if (found) {
wdenk57b2d802003-06-27 21:31:46 +0000146 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 */
wdenk591dda52002-11-18 00:14:45 +0000160 } else {
wdenk57b2d802003-06-27 21:31:46 +0000161 *entry = -1;
162 return -1; /* File not found */
wdenk591dda52002-11-18 00:14:45 +0000163 }
164}
165
166/*-----------------------------------------------------------------------------
167 * dir_read -- Read one directory entry
168 *-----------------------------------------------------------------------------
169 */
170static int dir_read (Fs_t *fs,
wdenk57b2d802003-06-27 21:31:46 +0000171 Slot_t *dir,
172 Directory_t *dirent,
173 int num,
174 struct vfat_state *v)
wdenk591dda52002-11-18 00:14:45 +0000175{
176
177 /* read the directory entry */
178 if (read_file (fs,
wdenk57b2d802003-06-27 21:31:46 +0000179 dir,
180 (char *)dirent,
181 num * MDIR_SIZE,
182 MDIR_SIZE) != MDIR_SIZE) {
183 return (-1);
wdenk591dda52002-11-18 00:14:45 +0000184 }
185
186 if (v && (dirent -> attr == ATTR_VSE)) {
wdenk57b2d802003-06-27 21:31:46 +0000187 struct vfat_subentry *vse;
188 unsigned char id, last_flag;
189 char *c;
wdenk591dda52002-11-18 00:14:45 +0000190
wdenk57b2d802003-06-27 21:31:46 +0000191 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 }
wdenk591dda52002-11-18 00:14:45 +0000198
199
wdenk57b2d802003-06-27 21:31:46 +0000200 /* Decode VSE */
201 if(v -> sum != vse -> sum) {
202 clear_vfat (v);
203 v -> sum = vse -> sum;
204 }
wdenk591dda52002-11-18 00:14:45 +0000205
wdenk591dda52002-11-18 00:14:45 +0000206
wdenk57b2d802003-06-27 21:31:46 +0000207 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
wdenk591dda52002-11-18 00:14:45 +0000221 }
222 return (0);
223}
224
225/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +0000226 * unicode_read --
wdenk591dda52002-11-18 00:14:45 +0000227 *-----------------------------------------------------------------------------
228 */
229static int unicode_read (char *in, char *out, int num)
230{
231 int j;
wdenk57b2d802003-06-27 21:31:46 +0000232
wdenk591dda52002-11-18 00:14:45 +0000233 for (j = 0; j < num; ++j) {
wdenk57b2d802003-06-27 21:31:46 +0000234 if (in [1])
235 *out = '_';
236 else
237 *out = in [0];
238 out ++;
239 in += 2;
wdenk591dda52002-11-18 00:14:45 +0000240 }
241 return num;
242}
243
244/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +0000245 * match --
wdenk591dda52002-11-18 00:14:45 +0000246 *-----------------------------------------------------------------------------
247 */
248static int match (const char *s, const char *p)
249{
250
251 for (; *p != '\0'; ) {
wdenk57b2d802003-06-27 21:31:46 +0000252 if (toupper (*s) != toupper (*p)) {
253 return (0);
254 }
255 p++;
256 s++;
wdenk591dda52002-11-18 00:14:45 +0000257 }
wdenk57b2d802003-06-27 21:31:46 +0000258
wdenk591dda52002-11-18 00:14:45 +0000259 if (*s != '\0') {
wdenk57b2d802003-06-27 21:31:46 +0000260 return (0);
wdenk591dda52002-11-18 00:14:45 +0000261 }
262 else {
wdenk57b2d802003-06-27 21:31:46 +0000263 return (1);
wdenk591dda52002-11-18 00:14:45 +0000264 }
265}
266/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +0000267 * sum_shortname --
wdenk591dda52002-11-18 00:14:45 +0000268 *-----------------------------------------------------------------------------
269 */
270static unsigned char sum_shortname (char *name)
271{
272 unsigned char sum;
273 int j;
wdenk57b2d802003-06-27 21:31:46 +0000274
wdenk591dda52002-11-18 00:14:45 +0000275 for (j = sum = 0; j < 11; ++j) {
wdenk57b2d802003-06-27 21:31:46 +0000276 sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) +
277 (name [j] ? name [j] : ' ');
wdenk591dda52002-11-18 00:14:45 +0000278 }
279 return (sum);
280}
281/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +0000282 * check_vfat --
wdenk591dda52002-11-18 00:14:45 +0000283 * Return 1 if long name is valid, 0 else
284 *-----------------------------------------------------------------------------
285 */
286static int check_vfat (struct vfat_state *v, Directory_t *dir)
287{
288 char name[12];
wdenk57b2d802003-06-27 21:31:46 +0000289
wdenk591dda52002-11-18 00:14:45 +0000290 if (v -> subentries == 0) {
wdenk57b2d802003-06-27 21:31:46 +0000291 return 0;
wdenk591dda52002-11-18 00:14:45 +0000292 }
wdenk57b2d802003-06-27 21:31:46 +0000293
wdenk591dda52002-11-18 00:14:45 +0000294 strncpy (name, dir -> name, 8);
295 strncpy (name + 8, dir -> ext, 3);
296 name [11] = '\0';
wdenk57b2d802003-06-27 21:31:46 +0000297
wdenk591dda52002-11-18 00:14:45 +0000298 if (v -> sum != sum_shortname (name)) {
wdenk57b2d802003-06-27 21:31:46 +0000299 return 0;
wdenk591dda52002-11-18 00:14:45 +0000300 }
wdenk57b2d802003-06-27 21:31:46 +0000301
wdenk591dda52002-11-18 00:14:45 +0000302 if( (v -> status & ((1 << v -> subentries) - 1)) !=
wdenk57b2d802003-06-27 21:31:46 +0000303 (1 << v -> subentries) - 1) {
304 return 0;
wdenk591dda52002-11-18 00:14:45 +0000305 }
306 v->name [VSE_NAMELEN * v -> subentries] = 0;
wdenk57b2d802003-06-27 21:31:46 +0000307
wdenk591dda52002-11-18 00:14:45 +0000308 return 1;
309}
310/*-----------------------------------------------------------------------------
wdenk57b2d802003-06-27 21:31:46 +0000311 * conv_name --
wdenk591dda52002-11-18 00:14:45 +0000312 *-----------------------------------------------------------------------------
313 */
314static 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') {
wdenk57b2d802003-06-27 21:31:46 +0000321 tname [i] = name [i];
322 i++;
wdenk591dda52002-11-18 00:14:45 +0000323 }
324 tname [i] = '\0';
wdenk57b2d802003-06-27 21:31:46 +0000325
wdenk591dda52002-11-18 00:14:45 +0000326 if (Case & BASECASE) {
wdenk57b2d802003-06-27 21:31:46 +0000327 for (i = 0; i < 8 && tname [i]; i++) {
328 tname [i] = tolower (tname [i]);
329 }
wdenk591dda52002-11-18 00:14:45 +0000330 }
331
332 i = 0;
333 while (i < 3 && ext [i] != ' ' && ext [i] != '\0') {
wdenk57b2d802003-06-27 21:31:46 +0000334 text [i] = ext [i];
335 i++;
wdenk591dda52002-11-18 00:14:45 +0000336 }
337 text [i] = '\0';
338
339 if (Case & EXTCASE){
wdenk57b2d802003-06-27 21:31:46 +0000340 for (i = 0; i < 3 && text [i]; i++) {
341 text [i] = tolower (text [i]);
342 }
wdenk591dda52002-11-18 00:14:45 +0000343 }
344
345 if (*text) {
wdenk57b2d802003-06-27 21:31:46 +0000346 strcpy (ans, tname);
347 strcat (ans, ".");
348 strcat (ans, text);
wdenk591dda52002-11-18 00:14:45 +0000349 }
350 else {
wdenk57b2d802003-06-27 21:31:46 +0000351 strcpy(ans, tname);
wdenk591dda52002-11-18 00:14:45 +0000352 }
353 return (ans);
354}
355
356
357#endif