1
2
3
4
5
6
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
16static int dir_read (Fs_t *fs,
17 Slot_t *dir,
18 Directory_t *dirent,
19 int num,
20 struct vfat_state *v);
21
22static int unicode_read (char *in, char *out, int num);
23static int match (const char *s, const char *p);
24static unsigned char sum_shortname (char *name);
25static int check_vfat (struct vfat_state *v, Directory_t *dir);
26static char *conv_name (char *name, char *ext, char Case, char *ans);
27
28
29
30
31
32
33static void clear_vfat (struct vfat_state *v)
34{
35 v -> subentries = 0;
36 v -> status = 0;
37}
38
39
40
41
42
43int 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
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
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);
142 } else {
143 *entry = -1;
144 return -1;
145 }
146}
147
148
149
150
151
152static 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
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
178 return (-1);
179 }
180
181
182
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';
201 }
202
203 }
204 return (0);
205}
206
207
208
209
210
211static 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
228
229
230static 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
250
251
252static 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
265
266
267
268static 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
294
295
296static 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}
337