Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/libsaio/msdos.c

1/*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 2.0 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1998 Robert Nordier
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in
33 * the documentation and/or other materials provided with the
34 * distribution.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
37 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
40 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
42 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
43 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
44 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
46 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 */
48
49#define tolower(c) (((c)>='A' && c<='Z')?((c) | 0x20):(c))
50#include "libsaio.h"
51#include "sl.h"
52
53#include "msdos_private.h"
54#include "msdos.h"
55#include "platform.h"
56
57#define LABEL_LENGTH11
58#define MSDOS_CACHE_BLOCKSIZE BPS
59
60#defineCLUST_FIRST2/* reserved cluster range */
61#defineCLUST_RSRVD320x0ffffff8/* reserved cluster range */
62#defineCLUST_RSRVD160xfff8/* reserved cluster range */
63#defineCLUST_RSRVD120xff8/* reserved cluster range */
64
65
66//#define false 0
67#define true 1
68
69static int msdosressector=0;
70static int msdosnfats = 0;
71static int msdosfatsecs = 0;
72static int msdosbps = 0;
73static int msdosclustersize = 0;
74static int msdosrootDirSectors = 0;
75static CICell msdoscurrent = 0;
76static int msdosrootcluster = 0;
77static int msdosfatbits = 0;
78struct msdosdirstate
79{
80struct direntry *buf;
81uint8_t vfatchecksum;
82int root16;
83off_t cluster;
84int nument;
85int vfatnumber;
86};
87
88static int
89readSector(CICell ih, off_t readOffset, char *buf, int size);
90static int
91msdosreadcluster (CICell ih, uint8_t *buf, int size, off_t *cluster);
92static struct direntry *
93getnextdirent (CICell ih, uint16_t *longname, struct msdosdirstate *st);
94static void
95initRoot (struct msdosdirstate *st);
96static int
97checkname (uint16_t *ucsname, int ucslen, struct direntry *dirp, uint16_t *vfatname);
98static struct direntry *
99getdirpfrompath (CICell ih, char *dirspec, uint8_t *buf);
100static void
101fixLabel(uint8_t *label, char *str, long strMaxLen);
102
103#if UNUSED
104/*
105 * Check a volume label.
106 */
107static int
108oklabel(const char *src);
109static int
110oklabel(const char *src)
111{
112 int c, i;
113
114 for (i = 0, c = 0; i <= 11; i++) {
115 c = (u_char)*src++;
116 if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
117 break;
118 }
119 return i && !c;
120}
121#endif /* UNUSED */
122
123void MSDOSFree(CICell ih)
124{
125if(msdoscurrent == ih)
126 msdoscurrent = 0;
127 free(ih);
128}
129
130int MSDOSProbe(const void * buffer)
131{
132 union bootsector *bsp;
133 struct bpb33 *b33;
134 struct bpb50 *b50;
135 //struct bpb710 *b710;
136 u_int16_t bps;
137 u_int8_tspc;
138
139 bsp = (union bootsector *)buffer;
140 b33 = (struct bpb33 *)bsp->bs33.bsBPB;
141 b50 = (struct bpb50 *)bsp->bs50.bsBPB;
142 //b710 = (struct bpb710 *)bsp->bs710.bsBPB;
143
144 /* We only work with 512, 1024, and 2048 byte sectors */
145 bps = OSSwapLittleToHostInt16(b33->bpbBytesPerSec);
146 if ((bps < 0x200) || (bps & (bps - 1)) || (bps > 0x800))
147 return 0;
148
149/* Check to make sure valid sectors per cluster */
150 spc = b33->bpbSecPerClust;
151 if ((spc == 0 ) || (spc & (spc - 1)))
152 return 0;
153
154if (OSSwapLittleToHostInt16(b50->bpbRootDirEnts) == 0) { /* It's FAT32 */
155if (!memcmp(((struct extboot *)bsp->bs710.bsExt)->exFileSysType, "FAT32 ", 8))
156return 32;
157}
158else if (((struct extboot *)bsp->bs50.bsExt)->exBootSignature == EXBOOTSIG) {
159if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT16 ", 8))
160return 16;
161if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT12 ", 8))
162return 12;
163}
164
165return 0;
166}
167
168
169long
170MSDOSInitPartition (CICell ih)
171{
172 union bootsector *bsp;
173 struct bpb33 *b33;
174 struct bpb50 *b50;
175 struct bpb710 *b710;
176 u_int8_tspc;
177 char *buf;
178
179if (msdoscurrent == ih)
180{
181CacheInit(ih, MSDOS_CACHE_BLOCKSIZE);
182return 0;
183}
184
185buf=malloc (512);
186 if (!buf)
187 {
188 return -1;
189 }
190/*
191 * Read the boot sector of the filesystem, and then check the
192 * boot signature. If not a dos boot sector then error out.
193 *
194 * NOTE: 2048 is a maximum sector size in current...
195 */
196 Seek(ih, 0);
197 Read(ih, (long)buf, 512);
198
199 bsp = (union bootsector *)buf;
200 b33 = (struct bpb33 *)bsp->bs33.bsBPB;
201 b50 = (struct bpb50 *)bsp->bs50.bsBPB;
202 b710 = (struct bpb710 *)bsp->bs710.bsBPB;
203
204
205 /* We only work with 512, 1024, and 2048 byte sectors */
206 msdosbps = OSSwapLittleToHostInt16(b33->bpbBytesPerSec);
207 if ((msdosbps < 0x200) || (msdosbps & (msdosbps - 1)) || (msdosbps > 0x800))
208{
209free (buf);
210return -1;
211}
212
213 /* Check to make sure valid sectors per cluster */
214 spc = b33->bpbSecPerClust;
215 if ((spc == 0 ) || (spc & (spc - 1)))
216 {
217 free (buf);
218return -1;
219}
220if (OSSwapLittleToHostInt16(b50->bpbRootDirEnts) == 0) { /* It's FAT32 */
221if (memcmp(((struct extboot *)bsp->bs710.bsExt)->exFileSysType, "FAT32 ", 8))
222{
223free (buf);
224return -1;
225}
226msdosressector = OSSwapLittleToHostInt16(b710->bpbResSectors);
227msdosnfats = b710->bpbFATs;
228msdosfatsecs = OSSwapLittleToHostInt16(b710->bpbBigFATsecs);
229msdosrootcluster = OSSwapLittleToHostInt32(b710->bpbRootClust);
230msdosrootDirSectors = 0;
231msdosfatbits = 32;
232}
233else if (((struct extboot *)bsp->bs50.bsExt)->exBootSignature == EXBOOTSIG) {
234if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT16 ", 8))
235msdosfatbits = 16;
236else if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT12 ", 8))
237msdosfatbits = 12;
238else
239{
240free (buf);
241return -1;
242}
243
244msdosressector = OSSwapLittleToHostInt16(b33->bpbResSectors);
245msdosnfats = b33->bpbFATs;
246msdosfatsecs = OSSwapLittleToHostInt16(b33->bpbFATsecs);
247msdosrootcluster = 0;
248msdosrootDirSectors = ((OSSwapLittleToHostInt16(b50->bpbRootDirEnts) * sizeof(struct direntry)) +
249 (msdosbps-1)) / msdosbps;
250} else {
251free (buf);
252return -1;
253}
254
255msdosclustersize = msdosbps * spc;
256msdoscurrent = ih;
257
258CacheInit(ih, MSDOS_CACHE_BLOCKSIZE);
259free (buf);
260return 0;
261}
262
263static int
264readSector(CICell ih, off_t readOffset, char *buf, int size)
265{
266 // Caching only FAT entries (4 bytes) by utlizing the cache with sector aligned read requests.
267if (size < BPS)
268{
269long long sectorOffset = (uint64_t)readOffset / BPS * BPS;
270long relOffset = readOffset % BPS;
271char *cacheBuffer;
272
273cacheBuffer = malloc(MSDOS_CACHE_BLOCKSIZE);
274 if (!cacheBuffer)
275 {
276 return -1;
277 }
278CacheRead(ih, cacheBuffer, sectorOffset, MSDOS_CACHE_BLOCKSIZE, true);
279bcopy(cacheBuffer + relOffset, buf, size);
280free(cacheBuffer);
281}
282else
283{
284Seek(ih, readOffset);
285Read(ih, (long)buf, size);
286}
287
288return 0;
289}
290
291static int
292msdosreadcluster (CICell ih, uint8_t *buf, int size, off_t *cluster)
293{
294 off_t readOffset;
295char tmpbuf[8];
296off_t clusn;
297
298switch (msdosfatbits) {
299case 32:
300if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD32)
301return 0;
302clusn = *cluster - CLUST_FIRST;
303break;
304case 16:
305if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD16)
306return 0;
307clusn = *cluster - CLUST_FIRST;
308break;
309case 12:
310if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD12)
311return 0;
312clusn = *cluster - CLUST_FIRST;
313break;
314default:
315return 0;
316}
317
318/* Find sector where clusters start */
319readOffset = (msdosressector +
320 (msdosnfats * msdosfatsecs)+msdosrootDirSectors)*msdosbps;
321/* Find sector where "cluster" starts */
322readOffset += clusn * msdosclustersize;
323
324/* Read in "cluster" */
325if (buf)
326{
327Seek(ih, readOffset);
328Read(ih, (long)buf, size);
329}
330
331/* Find first sector of FAT */
332readOffset = msdosressector * msdosbps;
333
334/* Find sector containing "cluster" entry in FAT */
335readOffset += ((uint64_t)*cluster * (uint64_t)msdosfatbits) / 8;
336
337/* Read one sector of the FAT */
338if (readSector(ih, readOffset, tmpbuf, 4) != 0) return 0;
339
340switch (msdosfatbits) {
341case 32:
342*cluster = OSReadLittleInt32(tmpbuf, 0);
343*cluster &= 0x0FFFFFFF;// ignore reserved upper bits
344return 1;
345case 16:
346*cluster = OSReadLittleInt16(tmpbuf, 0);
347return 1;
348case 12:
349*cluster = OSReadLittleInt16(tmpbuf, 0)>>(((uint64_t)*cluster * (uint64_t)msdosfatbits)%8);
350*cluster &= 0xfff;
351return 1;
352default:
353return 0;
354}
355}
356
357static struct direntry *
358getnextdirent (CICell ih, uint16_t *longname, struct msdosdirstate *st)
359{
360struct direntry *dirp;
361while (1)
362{
363if (st->root16)
364{
365if (st->cluster >= msdosrootDirSectors && st->nument == 0)
366return 0;
367if (st->nument == 0)
368{
369Seek(ih, (msdosressector +
370 (msdosnfats * msdosfatsecs)+st->cluster)*msdosbps);
371Read(ih, (long)st->buf, msdosbps);
372st->cluster++;
373}
374} else if (st->nument == 0 && !msdosreadcluster (ih, (uint8_t *)st->buf, msdosclustersize, &(st->cluster)))
375return 0;
376
377dirp=st->buf+st->nument;
378
379if (dirp->deName[0] == SLOT_EMPTY)
380return 0;
381else if (dirp->deName[0] == SLOT_DELETED)
382st->vfatnumber = 0;
383else if (dirp->deAttributes == ATTR_WIN95)
384{
385struct winentry *wdirp = (struct winentry *)dirp;
386int num;
387if (wdirp->weCnt & 0x80)
388continue;
389num=(wdirp->weCnt&0x3f);
390if (WIN_CHARS * num > WIN_MAXLEN)
391continue;
392if (st->vfatchecksum!=wdirp->weChksum)
393{
394st->vfatnumber = 0;
395st->vfatchecksum = wdirp->weChksum;
396}
397if (st->vfatnumber < num)
398st->vfatnumber = num;
399bcopy (&(wdirp->wePart1),longname+WIN_CHARS*(num-1),sizeof (wdirp->wePart1));
400bcopy (&(wdirp->wePart2),longname+WIN_CHARS*(num-1)+5,sizeof (wdirp->wePart2));
401bcopy (&(wdirp->wePart3),longname+WIN_CHARS*(num-1)+11,sizeof (wdirp->wePart3));
402} else {
403uint8_t labelchecksum;
404int i;
405longname[st->vfatnumber*WIN_CHARS]=0;
406
407labelchecksum=0;
408for(i=0;i<LABEL_LENGTH;i++)
409labelchecksum=(labelchecksum>>1)+(labelchecksum<<7)+dirp->deName[i];
410if (!(labelchecksum==st->vfatchecksum && st->vfatnumber))
411longname[0]=0;
412st->vfatnumber = 0;
413st->vfatchecksum = 0;
414st->vfatnumber = 0;
415st->nument++;
416if (((int)(!st->root16 &&st->nument * sizeof (struct direntry))>=msdosclustersize)
417|| ((int)(st->root16 &&st->nument * sizeof (struct direntry))>=msdosbps))
418st->nument = 0;
419return dirp;
420}
421st->nument++;
422if (((int)(!st->root16 &&st->nument * sizeof (struct direntry))>=msdosclustersize)
423|| ((int)(st->root16 &&st->nument * sizeof (struct direntry))>=msdosbps))
424st->nument = 0;
425}
426}
427
428static void
429initRoot (struct msdosdirstate *st)
430{
431if (msdosrootDirSectors) {/* FAT12 or FAT16 */
432st->root16 = 1;
433st->vfatchecksum = 0;
434st->nument = 0;
435st->cluster = 0;
436st->vfatnumber = 0;
437} else {/* FAT32 */
438st->root16 = 0;
439st->vfatchecksum = 0;
440st->nument = 0;
441st->cluster = msdosrootcluster;
442st->vfatnumber = 0;
443}
444}
445
446/* First comes lowercase, then uppercase*/
447static uint16_t cp850[128][2]=
448{
449{0x00E7,0x00C7},
450{0x00FC,0x00DC},
451{0x00E9,0x00C9},
452{0x00E2,0x00C2},
453{0x00E4,0x00C4},
454{0x00E0,0x00C0},
455{0x00E5,0x00C5},
456{0x00E7,0x00C7},
457{0x00EA,0x00CA},
458{0x00EB,0x00CB},
459{0x00E8,0x00C8},
460{0x00EF,0x00CF},
461{0x00EE,0x00CE},
462{0x00EC,0x00CC},
463{0x00E4,0x00C4},
464{0x00E5,0x00C5},
465{0x00E9,0x00C9},
466{0x00E6,0x00C6},
467{0x00E6,0x00C6},
468{0x00F4,0x00D4},
469{0x00F6,0x00D6},
470{0x00F2,0x00D2},
471{0x00FB,0x00DB},
472{0x00F9,0x00D9},
473{0x00FF,0x0178},
474{0x00F6,0x00D6},
475{0x00FC,0x00DC},
476{0x00F8,0x00D8},
477{0x00A3,0x00A3},
478{0x00F8,0x00D8},
479{0x00D7,0x00D7},
480{0x0192,0x0191},
481{0x00E1,0x00C1},
482{0x00ED,0x00CD},
483{0x00F3,0x00D3},
484{0x00FA,0x00DA},
485{0x00F1,0x00D1},
486{0x00F1,0x00D1},
487{0x00AA,0x00AA},
488{0x00BA,0x00BA},
489{0x00BF,0x00BF},
490{0x00AE,0x00AE},
491{0x00AC,0x00AC},
492{0x00BD,0x00BD},
493{0x00BC,0x00BC},
494{0x00A1,0x00A1},
495{0x00AB,0x00AB},
496{0x00BB,0x00BB},
497{0x2591,0x2591},
498{0x2592,0x2592},
499{0x2593,0x2593},
500{0x2502,0x2502},
501{0x2524,0x2524},
502{0x00E1,0x00C1},
503{0x00E2,0x00C2},
504{0x00E0,0x00C0},
505{0x00A9,0x00A9},
506{0x2563,0x2563},
507{0x2551,0x2551},
508{0x2557,0x2557},
509{0x255D,0x255D},
510{0x00A2,0x00A2},
511{0x00A5,0x00A5},
512{0x2510,0x2510},
513{0x2514,0x2514},
514{0x2534,0x2534},
515{0x252C,0x252C},
516{0x251C,0x251C},
517{0x2500,0x2500},
518{0x253C,0x253C},
519{0x00E3,0x00C3},
520{0x00E3,0x00C3},
521{0x255A,0x255A},
522{0x2554,0x2554},
523{0x2569,0x2569},
524{0x2566,0x2566},
525{0x2560,0x2560},
526{0x2550,0x2550},
527{0x256C,0x256C},
528{0x00A4,0x00A4},
529{0x00F0,0x00D0},
530{0x00F0,0x00D0},
531{0x00EA,0x00CA},
532{0x00EB,0x00CB},
533{0x00E8,0x00C8},
534{0x0131,0x0049},
535{0x00ED,0x00CD},
536{0x00EE,0x00CE},
537{0x00EF,0x00CF},
538{0x2518,0x2518},
539{0x250C,0x250C},
540{0x2588,0x2588},
541{0x2584,0x2584},
542{0x00A6,0x00A6},
543{0x00EC,0x00CC},
544{0x2580,0x2580},
545{0x00F3,0x00D3},
546{0x00DF,0x00DF},
547{0x00F4,0x00D4},
548{0x00F2,0x00D2},
549{0x00F5,0x00D5},
550{0x00F5,0x00D5},
551{0x00B5,0x00B5},
552{0x00FE,0x00DE},
553{0x00FE,0x00DE},
554{0x00FA,0x00DA},
555{0x00FB,0x00DB},
556{0x00F9,0x00D9},
557{0x00FD,0x00DD},
558{0x00FD,0x00DD},
559{0x00AF,0x00AF},
560{0x00B4,0x00B4},
561{0x00AD,0x00AD},
562{0x00B1,0x00B1},
563{0x2017,0x2017},
564{0x00BE,0x00BE},
565{0x00B6,0x00B6},
566{0x00A7,0x00A7},
567{0x00F7,0x00F7},
568{0x00B8,0x00B8},
569{0x00B0,0x00B0},
570{0x00A8,0x00A8},
571{0x00B7,0x00B7},
572{0x00B9,0x00B9},
573{0x00B3,0x00B3},
574{0x00B2,0x00B2},
575{0x25A0,0x25A0},
576{0x00A0,0x00A0}
577};
578
579static int
580checkname (uint16_t *ucsname, int ucslen, struct direntry *dirp, uint16_t *vfatname)
581{
582uint16_t tmp[15];
583if (vfatname[0])
584{
585int i;
586for (i=0;vfatname[i];i++);
587return !FastUnicodeCompare (ucsname, ucslen, vfatname, i, OSLittleEndian);
588}
589else
590{
591int i, j, k;
592for (i=7;i>=0;i--)
593if (dirp->deName[i]!=' ')
594break;
595j=i+1;
596tmp[i+1]=0;
597for(;i>=0;i--)
598tmp[i]=SWAP_LE16((dirp->deName[i]>=128)?cp850[dirp->deName[i]-128][0]:tolower(dirp->deName[i]));
599for (i=2;i>=0;i--)
600if (dirp->deName[8+i]!=' ')
601break;
602if (i>=0)
603{
604tmp[j++]='.';
605tmp[j+i+1]=0;
606k=j+i+1;
607for(;i>=0;i--)
608tmp[j+i]=SWAP_LE16((dirp->deName[i+8]>=128)?cp850[dirp->deName[i+8]-128][0]:tolower(dirp->deName[i+8]));
609j=k;
610}
611return !FastUnicodeCompare (ucsname, ucslen, tmp, j, OSLittleEndian);
612}
613
614}
615
616static struct direntry *
617getdirpfrompath (CICell ih, char *dirspec, uint8_t *buf)
618{
619struct msdosdirstate st;
620struct direntry *dirp;
621uint8_t * ptr;
622uint8_t *slash;
623char c;
624uint16_tvfatname[WIN_MAXLEN+2*WIN_CHARS];
625uint16_t ucsname[WIN_MAXLEN+1];
626uint16_t ucslen;
627int ucslenhost;
628initRoot (&st);
629st.buf = (struct direntry *)buf;
630ptr=(uint8_t*)dirspec;
631for (slash=ptr;*slash && *slash!='/';slash++);
632c=*slash;
633*slash=0;
634utf_decodestr (ptr, ucsname, &ucslen, WIN_MAXLEN, OSLittleEndian);
635ucslenhost = OSReadLittleInt16 (&ucslen,0);
636ucsname[ucslenhost]=0;
637*slash=c;
638while ((dirp = getnextdirent (ih, vfatname, &st)))
639{
640if (checkname (ucsname, ucslenhost, dirp, vfatname))
641{
642for (;*ptr && *ptr!='/';ptr++);
643if (!*ptr)
644return dirp;
645ptr++;
646if (!*ptr)
647return dirp;
648for (slash=ptr;*slash && *slash!='/';slash++);
649c=*slash;
650*slash=0;
651utf_decodestr (ptr, ucsname, &ucslen, WIN_MAXLEN, OSLittleEndian);
652ucslenhost = OSReadLittleInt16 (&ucslen,0);
653ucsname[ucslenhost]=0;
654*slash=c;
655if (!(dirp->deAttributes & ATTR_DIRECTORY))
656return 0;
657st.root16 = 0;
658st.vfatchecksum = 0;
659st.nument = 0;
660st.cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
661if (msdosfatbits == 32)
662st.cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
663st.vfatnumber = 0;
664}
665}
666return 0;
667}
668
669long MSDOSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex,
670 char ** name, long * flags, long * time,
671 FinderInfo * finderInfo, long * infoValid)
672{
673struct msdosdirstate *st;
674struct direntry *dirp;
675uint16_tvfatname[WIN_MAXLEN+2*WIN_CHARS];
676if (MSDOSInitPartition (ih)<0)
677return -1;
678if (dirPath[0] == '/')
679dirPath++;
680st = (struct msdosdirstate *)(long) *dirIndex;
681if (!st)
682{
683st=malloc (sizeof (struct msdosdirstate));
684 if (!st)
685 {
686 return -1;
687 }
688if (dirPath[0])
689{
690uint8_t *buf=malloc(msdosclustersize);
691 if (!buf)
692 {
693 free (st);
694 return -1;
695 }
696dirp = getdirpfrompath (ih, dirPath, buf);
697if (!dirp || !(dirp->deAttributes & ATTR_DIRECTORY))
698{
699free (buf);
700free (st);
701return -1;
702}
703st->buf = (struct direntry *)buf;
704st->root16 = 0;
705st->vfatchecksum = 0;
706st->nument = 0;
707st->cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
708st->vfatnumber = 0;
709if (msdosfatbits == 32)
710st->cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
711}
712else
713initRoot (st);
714*dirIndex = (long long) (long) st;
715}
716while((dirp = getnextdirent (ih, vfatname, st))&& (dirp->deAttributes & ATTR_VOLUME));
717if (!dirp)
718{
719free (st->buf);
720free (st);
721return -1;
722}
723if (vfatname[0])
724{
725int i;
726for (i=0;vfatname[i];i++);
727*name = malloc (256);
728 if (!*name)
729 {
730 free (st->buf);
731 free (st);
732 return -1;
733 }
734utf_encodestr(vfatname, i, (u_int8_t *)*name, 255, OSLittleEndian );
735}
736else
737{
738int i, j, k;
739uint16_t tmp[13];
740*name = malloc (26);
741 if (!*name)
742 {
743 free (st->buf);
744 free (st);
745 return -1;
746 }
747for (i=7;i>=0;i--)
748if (dirp->deName[i]!=' ')
749break;
750j=i+1;
751tmp[i+1]=0;
752for(;i>=0;i--)
753tmp[i]=(dirp->deName[i]>=128)?cp850[dirp->deName[i]-128][0]:tolower(dirp->deName[i]);
754for (i=2;i>=0;i--)
755if (dirp->deName[8+i]!=' ')
756break;
757
758if (i>=0)
759{
760tmp[j++]='.';
761tmp[j+i+1]=0;
762k=j+i+1;
763for(;i>=0;i--)
764tmp[j+i]=(dirp->deName[i]>=128)?cp850[dirp->deName[i+8]-128][0]:tolower(dirp->deName[i+8]);
765j=k;
766}
767
768utf_encodestr(tmp, j, (uint8_t*)*name, 25, OSHostByteOrder() );
769}
770if (dirp->deAttributes & ATTR_DIRECTORY)
771*flags = kFileTypeDirectory;
772else
773*flags = kFileTypeFlat;
774
775// Calculate a fake timestamp using modification date and time values.
776*time = (dirp->deMDate & 0x7FFF) << 16 + dirp->deMTime;
777
778if (infoValid)
779*infoValid = 1;
780
781return 0;
782}
783
784long
785MSDOSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length)
786{
787uint8_t *buf;
788off_t cluster;
789uint64_t size;
790uint64_t nskip;
791int toread, wastoread;
792char *ptr = (char *)base;
793struct direntry *dirp;
794uint64_t i;
795 char devStr[12];
796
797if (MSDOSInitPartition (ih)<0)
798return -1;
799if (filePath[0] == '/')
800filePath++;
801buf = malloc(msdosclustersize);
802 if (!buf) {
803 return -1;
804 }
805dirp = getdirpfrompath (ih, filePath, buf);
806
807if (!dirp || (dirp->deAttributes & ATTR_DIRECTORY))
808{
809free (buf);
810return -1;
811}
812cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
813if (msdosfatbits == 32)
814cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
815size = (uint32_t)OSReadLittleInt32 ((dirp->deFileSize),0);
816if (size<=offset)
817 {
818 free (buf);
819return -1;
820 }
821nskip=offset/msdosclustersize;
822for (i=0;i<nskip;i++)
823msdosreadcluster (ih, 0, 0, &cluster);
824msdosreadcluster (ih, buf, msdosclustersize, &cluster);
825toread=length;
826if (length==0 || length>size-offset)
827toread=size-offset;
828wastoread=toread;
829bcopy (buf+(offset%msdosclustersize),ptr,min((msdosclustersize-(offset%msdosclustersize)),(unsigned)toread));
830ptr+=msdosclustersize-(offset%msdosclustersize);
831toread-=msdosclustersize-(offset%msdosclustersize);
832while (toread>0 && msdosreadcluster (ih, (uint8_t *)ptr, min(msdosclustersize,toread), &cluster))
833{
834ptr+=msdosclustersize;
835toread-=msdosclustersize;
836}
837
838 getDeviceDescription(ih, devStr);
839verbose("Read FAT%d file: [%s/%s] %d bytes.\n",
840 msdosfatbits, devStr, filePath, (uint32_t)( toread<0 ) ? wastoread : wastoread-toread);
841free (buf);
842if (toread<0)
843return wastoread;
844else
845return wastoread-toread;
846}
847
848long
849MSDOSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
850{
851uint8_t *buf;
852off_t cluster;
853struct direntry *dirp;
854if (MSDOSInitPartition (ih)<0)
855return -1;
856if (filePath[0] == '/')
857filePath++;
858buf = malloc(msdosclustersize);
859 if (!buf) {
860 return -1;
861 }
862dirp = getdirpfrompath (ih, filePath, buf);
863if (!dirp || (dirp->deAttributes & ATTR_DIRECTORY))
864{
865free (buf);
866return -1;
867}
868cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
869if (msdosfatbits == 32)
870cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
871
872off_t clusn;
873
874switch (msdosfatbits) {
875case 32:
876if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD32)
877return -1;
878clusn = cluster - CLUST_FIRST;
879break;
880case 16:
881if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD16)
882return 0;
883clusn = cluster - CLUST_FIRST;
884break;
885case 12:
886
887if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD12)
888return 0;
889clusn = cluster - CLUST_FIRST;
890break;
891default:
892return 0;
893}
894
895*firstBlock = ((msdosressector +
896 (msdosnfats * msdosfatsecs))*msdosbps + clusn * msdosclustersize)/512;
897free (buf);
898return 0;
899}
900
901
902long MSDOSLoadFile(CICell ih, char * filePath)
903{
904return MSDOSReadFile(ih, filePath, (void *)(uint32_t)get_env(envgFSLoadAddress), 0, 0);
905
906}
907
908/* Fix up volume label. */
909static void
910fixLabel(uint8_t *label, char *str, long strMaxLen)
911{
912 inti, len;
913uint16_tlabelucs[13];
914 //unsigned charlabelUTF8[LABEL_LENGTH*3];
915
916 /* Convert leading 0x05 to 0xE5 for multibyte languages like Japanese */
917 if (label[0] == 0x05)
918 label[0] = 0xE5;
919
920 /* Remove any trailing spaces */
921 for (i=LABEL_LENGTH-1; i>=0; --i) {
922 if (label[i] == ' ')
923 label[i] = 0;
924 else
925 break;
926 }
927labelucs[i++]=0;
928len=i;
929for (;i>=0;--i)
930labelucs[i]=label[i]>=128?cp850[label[i]-128][1]:(label[i]);
931
932utf_encodestr(labelucs, len, (uint8_t *)str, strMaxLen, OSHostByteOrder() );
933}
934
935
936void
937MSDOSGetDescription(CICell ih, char *str, long strMaxLen)
938{
939 struct direntry *dirp;
940 uint8_t label[LABEL_LENGTH+1];
941uint16_tvfatlabel[WIN_MAXLEN+2*WIN_CHARS];
942struct msdosdirstate st;
943int labelfound = 0;
944
945if (MSDOSInitPartition (ih)<0)
946{
947str[0]=0;
948return;
949}
950
951 bzero(label,sizeof(label));
952bzero(vfatlabel,sizeof(vfatlabel));
953
954label[0] = '\0';
955
956initRoot (&st);
957st.buf = malloc(msdosclustersize);
958 if (!st.buf) {
959 return;
960 }
961while ((dirp = getnextdirent (ih, vfatlabel, &st)))
962if (dirp->deAttributes & ATTR_VOLUME) {
963strncpy((char *)label, (char *)dirp->deName, LABEL_LENGTH);
964labelfound = 1;
965break;
966}
967
968free(st.buf);
969
970if (vfatlabel[0] && labelfound)
971{
972int i;
973for (i=0;vfatlabel[i];i++);
974utf_encodestr(vfatlabel, i, (u_int8_t *)str, strMaxLen, OSLittleEndian );
975}
976else if (labelfound)
977fixLabel(label, str, strMaxLen);
978
979 /* else look in the boot blocks */
980 if (!labelfound || str[0] == '\0') {
981char *buf = malloc (512);
982 if (!buf) {
983 return;
984 }
985union bootsector *bsp = (union bootsector *)buf;
986Seek(ih, 0);
987Read(ih, (long)buf, 512);
988 if (msdosfatbits == 32) { /* It's FAT32 */
989 strncpy((char *)label, (char *)((struct extboot *)bsp->bs710.bsExt)->exVolumeLabel, LABEL_LENGTH);
990 }
991 else if (msdosfatbits == 16) {
992 strncpy((char *)label, (char *)((struct extboot *)bsp->bs50.bsExt)->exVolumeLabel, LABEL_LENGTH);
993 }
994free (buf);
995fixLabel(label, str, strMaxLen);
996 }
997
998 return;
999}
1000
1001long
1002MSDOSGetUUID(CICell ih, char *uuidStr)
1003{
1004char *buf = malloc (512);
1005 if (!buf) {
1006 return -1;
1007 }
1008union bootsector *bsp = (union bootsector *)buf;
1009
1010if (MSDOSInitPartition (ih)<0)
1011{
1012 free (buf);
1013return -1;
1014}
1015bzero (uuidStr, 16);
1016Seek(ih, 0);
1017Read(ih, (long)buf, 512);
1018if (msdosfatbits == 32) { /* It's FAT32 */
1019memcpy(uuidStr+12, (char *)((struct extboot *)bsp->bs710.bsExt)->exVolumeID, 4);
1020}
1021else if (msdosfatbits == 16) {
1022memcpy(uuidStr+12, (char *)((struct extboot *)bsp->bs50.bsExt)->exVolumeID, 4);
1023}
1024free (buf);
1025 return 0;
1026
1027}
1028

Archive Download this file

Revision: 1984