Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/Chazileon/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
56#define LABEL_LENGTH11
57#define MAX_DOS_BLOCKSIZE2048
58#define MAX_CACHE_BLOCKSIZE 32768
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;
78static int msdosCacheBlockSize = 0;
79
80#if UNUSED
81/*
82 * Check a volume label.
83 */
84static int
85oklabel(const char *src)
86{
87 int c, i;
88
89 for (i = 0, c = 0; i <= 11; i++) {
90 c = (u_char)*src++;
91 if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
92 break;
93 }
94 return i && !c;
95}
96#endif /* UNUSED */
97
98void MSDOSFree(CICell ih)
99{
100if(msdoscurrent == ih)
101 msdoscurrent = 0;
102 free(ih);
103}
104
105int MSDOSProbe(const void * buffer)
106{
107 union bootsector *bsp;
108 struct bpb33 *b33;
109 struct bpb50 *b50;
110 struct bpb710 *b710;
111 u_int16_t bps;
112 u_int8_tspc;
113
114 bsp = (union bootsector *)buffer;
115 b33 = (struct bpb33 *)bsp->bs33.bsBPB;
116 b50 = (struct bpb50 *)bsp->bs50.bsBPB;
117 b710 = (struct bpb710 *)bsp->bs710.bsBPB;
118
119 /* We only work with 512, 1024, and 2048 byte sectors */
120 bps = OSSwapLittleToHostInt16(b33->bpbBytesPerSec);
121 if ((bps < 0x200) || (bps & (bps - 1)) || (bps > 0x800))
122 return 0;
123
124/* Check to make sure valid sectors per cluster */
125 spc = b33->bpbSecPerClust;
126 if ((spc == 0 ) || (spc & (spc - 1)))
127 return 0;
128
129if (OSSwapLittleToHostInt16(b50->bpbRootDirEnts) == 0) { /* It's FAT32 */
130if (!memcmp(((struct extboot *)bsp->bs710.bsExt)->exFileSysType, "FAT32 ", 8))
131return 32;
132}
133else if (((struct extboot *)bsp->bs50.bsExt)->exBootSignature == EXBOOTSIG) {
134if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT16 ", 8))
135return 16;
136if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT12 ", 8))
137return 12;
138}
139
140return 0;
141}
142
143
144long
145MSDOSInitPartition (CICell ih)
146{
147 union bootsector *bsp;
148 struct bpb33 *b33;
149 struct bpb50 *b50;
150 struct bpb710 *b710;
151 u_int8_tspc;
152 char *buf;
153
154if (msdoscurrent == ih)
155{
156CacheInit(ih, msdosCacheBlockSize);
157return 0;
158}
159
160buf=malloc (512);
161/*
162 * Read the boot sector of the filesystem, and then check the
163 * boot signature. If not a dos boot sector then error out.
164 *
165 * NOTE: 2048 is a maximum sector size in current...
166 */
167 Seek(ih, 0);
168 Read(ih, (long)buf, 512);
169
170 bsp = (union bootsector *)buf;
171 b33 = (struct bpb33 *)bsp->bs33.bsBPB;
172 b50 = (struct bpb50 *)bsp->bs50.bsBPB;
173 b710 = (struct bpb710 *)bsp->bs710.bsBPB;
174
175
176 /* We only work with 512, 1024, and 2048 byte sectors */
177 msdosbps = OSSwapLittleToHostInt16(b33->bpbBytesPerSec);
178 if ((msdosbps < 0x200) || (msdosbps & (msdosbps - 1)) || (msdosbps > 0x800))
179{
180free (buf);
181return -1;
182}
183
184 /* Check to make sure valid sectors per cluster */
185 spc = b33->bpbSecPerClust;
186 if ((spc == 0 ) || (spc & (spc - 1)))
187return -1;
188
189if (OSSwapLittleToHostInt16(b50->bpbRootDirEnts) == 0) { /* It's FAT32 */
190if (memcmp(((struct extboot *)bsp->bs710.bsExt)->exFileSysType, "FAT32 ", 8))
191{
192free (buf);
193return -1;
194}
195msdosressector = OSSwapLittleToHostInt16(b710->bpbResSectors);
196msdosnfats = b710->bpbFATs;
197msdosfatsecs = OSSwapLittleToHostInt16(b710->bpbBigFATsecs);
198msdosrootcluster = OSSwapLittleToHostInt32(b710->bpbRootClust);
199msdosrootDirSectors = 0;
200msdosfatbits = 32;
201}
202else if (((struct extboot *)bsp->bs50.bsExt)->exBootSignature == EXBOOTSIG) {
203if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT16 ", 8))
204msdosfatbits = 16;
205else if (!memcmp((char *)((struct extboot *)bsp->bs50.bsExt)->exFileSysType, "FAT12 ", 8))
206msdosfatbits = 12;
207else
208{
209free (buf);
210return -1;
211}
212
213msdosressector = OSSwapLittleToHostInt16(b33->bpbResSectors);
214msdosnfats = b33->bpbFATs;
215msdosfatsecs = OSSwapLittleToHostInt16(b33->bpbFATsecs);
216msdosrootcluster = 0;
217msdosrootDirSectors = ((OSSwapLittleToHostInt16(b50->bpbRootDirEnts) * sizeof(struct direntry)) +
218 (msdosbps-1)) / msdosbps;
219} else {
220free (buf);
221return -1;
222}
223
224msdosclustersize = msdosbps * spc;
225msdoscurrent = ih;
226
227msdosCacheBlockSize = (msdosclustersize > MAX_CACHE_BLOCKSIZE) ? msdosclustersize : MAX_CACHE_BLOCKSIZE;
228CacheInit(ih, msdosCacheBlockSize);
229free (buf);
230return 0;
231}
232
233static int
234readSectorAligned(CICell ih, off_t readOffset, char *buf, int size)
235{
236 long long sectorOffset = (uint64_t)readOffset / msdosCacheBlockSize * msdosCacheBlockSize;
237 long relOffset = readOffset % msdosCacheBlockSize;
238 char *cacheBuffer;
239
240 cacheBuffer = malloc(msdosCacheBlockSize);
241 CacheRead(ih, cacheBuffer, sectorOffset, msdosCacheBlockSize, true);
242 bcopy(cacheBuffer + relOffset, buf, size);
243 free(cacheBuffer);
244
245 return 0;
246}
247
248static int
249msdosreadcluster (CICell ih, uint8_t *buf, int size, off_t *cluster)
250{
251 off_t readOffset;
252char tmpbuf[8];
253off_t clusn;
254
255switch (msdosfatbits) {
256case 32:
257if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD32)
258return 0;
259clusn = *cluster - CLUST_FIRST;
260break;
261case 16:
262if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD16)
263return 0;
264clusn = *cluster - CLUST_FIRST;
265break;
266case 12:
267if (*cluster < CLUST_FIRST ||*cluster >= CLUST_RSRVD12)
268return 0;
269clusn = *cluster - CLUST_FIRST;
270break;
271default:
272return 0;
273}
274
275/* Find sector where clusters start */
276readOffset = (msdosressector +
277 (msdosnfats * msdosfatsecs)+msdosrootDirSectors)*msdosbps;
278/* Find sector where "cluster" starts */
279readOffset += clusn * msdosclustersize;
280
281/* Read in "cluster" */
282if (buf)
283{
284 readSectorAligned(ih, readOffset, (char *)buf, size);
285}
286
287/* Find first sector of FAT */
288readOffset = msdosressector * msdosbps;
289
290/* Find sector containing "cluster" entry in FAT */
291readOffset += ((uint64_t)*cluster * (uint64_t)msdosfatbits) / 8;
292
293/* Read one sector of the FAT */
294readSectorAligned(ih, readOffset, tmpbuf, 4);
295
296switch (msdosfatbits) {
297case 32:
298*cluster = OSReadLittleInt32(tmpbuf, 0);
299*cluster &= 0x0FFFFFFF;// ignore reserved upper bits
300return 1;
301case 16:
302*cluster = OSReadLittleInt16(tmpbuf, 0);
303return 1;
304case 12:
305*cluster = OSReadLittleInt16(tmpbuf, 0)>>(((uint64_t)*cluster * (uint64_t)msdosfatbits)%8);
306*cluster &= 0xfff;
307return 1;
308default:
309return 0;
310}
311}
312
313struct msdosdirstate
314{
315struct direntry *buf;
316uint8_t vfatchecksum;
317int root16;
318off_t cluster;
319int nument;
320int vfatnumber;
321};
322
323static struct direntry *
324getnextdirent (CICell ih, uint16_t *longname, struct msdosdirstate *st)
325{
326struct direntry *dirp;
327while (1)
328{
329if (st->root16)
330{
331if (st->cluster >= msdosrootDirSectors && st->nument == 0)
332return 0;
333if (st->nument == 0)
334{
335Seek(ih, (msdosressector +
336 (msdosnfats * msdosfatsecs)+st->cluster)*msdosbps);
337Read(ih, (long)st->buf, msdosbps);
338st->cluster++;
339}
340} else if (st->nument == 0 && !msdosreadcluster (ih, (uint8_t *)st->buf, msdosclustersize, &(st->cluster)))
341return 0;
342
343dirp=st->buf+st->nument;
344
345if (dirp->deName[0] == SLOT_EMPTY)
346return 0;
347else if (dirp->deName[0] == SLOT_DELETED)
348st->vfatnumber = 0;
349else if (dirp->deAttributes == ATTR_WIN95)
350{
351struct winentry *wdirp = (struct winentry *)dirp;
352int num;
353if (wdirp->weCnt & 0x80)
354continue;
355num=(wdirp->weCnt&0x3f);
356if (WIN_CHARS * num > WIN_MAXLEN)
357continue;
358if (st->vfatchecksum!=wdirp->weChksum)
359{
360st->vfatnumber = 0;
361st->vfatchecksum = wdirp->weChksum;
362}
363if (st->vfatnumber < num)
364st->vfatnumber = num;
365bcopy (&(wdirp->wePart1),longname+WIN_CHARS*(num-1),sizeof (wdirp->wePart1));
366bcopy (&(wdirp->wePart2),longname+WIN_CHARS*(num-1)+5,sizeof (wdirp->wePart2));
367bcopy (&(wdirp->wePart3),longname+WIN_CHARS*(num-1)+11,sizeof (wdirp->wePart3));
368} else {
369uint8_t labelchecksum;
370int i;
371longname[st->vfatnumber*WIN_CHARS]=0;
372
373labelchecksum=0;
374for(i=0;i<LABEL_LENGTH;i++)
375labelchecksum=(labelchecksum>>1)+(labelchecksum<<7)+dirp->deName[i];
376if (!(labelchecksum==st->vfatchecksum && st->vfatnumber))
377longname[0]=0;
378st->vfatnumber = 0;
379st->vfatchecksum = 0;
380st->vfatnumber = 0;
381st->nument++;
382if ((!st->root16 &&st->nument * sizeof (struct direntry)>=msdosclustersize)
383|| (st->root16 &&st->nument * sizeof (struct direntry)>=msdosbps))
384st->nument = 0;
385return dirp;
386}
387st->nument++;
388if ((!st->root16 &&st->nument * sizeof (struct direntry)>=msdosclustersize)
389|| (st->root16 &&st->nument * sizeof (struct direntry)>=msdosbps))
390st->nument = 0;
391}
392}
393
394static void
395initRoot (struct msdosdirstate *st)
396{
397if (msdosrootDirSectors) {/* FAT12 or FAT16 */
398st->root16 = 1;
399st->vfatchecksum = 0;
400st->nument = 0;
401st->cluster = 0;
402st->vfatnumber = 0;
403} else {/* FAT32 */
404st->root16 = 0;
405st->vfatchecksum = 0;
406st->nument = 0;
407st->cluster = msdosrootcluster;
408st->vfatnumber = 0;
409}
410}
411
412/* First comes lowercase, then uppercase*/
413static uint16_t cp850[128][2]=
414{
415{0x00E7,0x00C7},
416{0x00FC,0x00DC},
417{0x00E9,0x00C9},
418{0x00E2,0x00C2},
419{0x00E4,0x00C4},
420{0x00E0,0x00C0},
421{0x00E5,0x00C5},
422{0x00E7,0x00C7},
423{0x00EA,0x00CA},
424{0x00EB,0x00CB},
425{0x00E8,0x00C8},
426{0x00EF,0x00CF},
427{0x00EE,0x00CE},
428{0x00EC,0x00CC},
429{0x00E4,0x00C4},
430{0x00E5,0x00C5},
431{0x00E9,0x00C9},
432{0x00E6,0x00C6},
433{0x00E6,0x00C6},
434{0x00F4,0x00D4},
435{0x00F6,0x00D6},
436{0x00F2,0x00D2},
437{0x00FB,0x00DB},
438{0x00F9,0x00D9},
439{0x00FF,0x0178},
440{0x00F6,0x00D6},
441{0x00FC,0x00DC},
442{0x00F8,0x00D8},
443{0x00A3,0x00A3},
444{0x00F8,0x00D8},
445{0x00D7,0x00D7},
446{0x0192,0x0191},
447{0x00E1,0x00C1},
448{0x00ED,0x00CD},
449{0x00F3,0x00D3},
450{0x00FA,0x00DA},
451{0x00F1,0x00D1},
452{0x00F1,0x00D1},
453{0x00AA,0x00AA},
454{0x00BA,0x00BA},
455{0x00BF,0x00BF},
456{0x00AE,0x00AE},
457{0x00AC,0x00AC},
458{0x00BD,0x00BD},
459{0x00BC,0x00BC},
460{0x00A1,0x00A1},
461{0x00AB,0x00AB},
462{0x00BB,0x00BB},
463{0x2591,0x2591},
464{0x2592,0x2592},
465{0x2593,0x2593},
466{0x2502,0x2502},
467{0x2524,0x2524},
468{0x00E1,0x00C1},
469{0x00E2,0x00C2},
470{0x00E0,0x00C0},
471{0x00A9,0x00A9},
472{0x2563,0x2563},
473{0x2551,0x2551},
474{0x2557,0x2557},
475{0x255D,0x255D},
476{0x00A2,0x00A2},
477{0x00A5,0x00A5},
478{0x2510,0x2510},
479{0x2514,0x2514},
480{0x2534,0x2534},
481{0x252C,0x252C},
482{0x251C,0x251C},
483{0x2500,0x2500},
484{0x253C,0x253C},
485{0x00E3,0x00C3},
486{0x00E3,0x00C3},
487{0x255A,0x255A},
488{0x2554,0x2554},
489{0x2569,0x2569},
490{0x2566,0x2566},
491{0x2560,0x2560},
492{0x2550,0x2550},
493{0x256C,0x256C},
494{0x00A4,0x00A4},
495{0x00F0,0x00D0},
496{0x00F0,0x00D0},
497{0x00EA,0x00CA},
498{0x00EB,0x00CB},
499{0x00E8,0x00C8},
500{0x0131,0x0049},
501{0x00ED,0x00CD},
502{0x00EE,0x00CE},
503{0x00EF,0x00CF},
504{0x2518,0x2518},
505{0x250C,0x250C},
506{0x2588,0x2588},
507{0x2584,0x2584},
508{0x00A6,0x00A6},
509{0x00EC,0x00CC},
510{0x2580,0x2580},
511{0x00F3,0x00D3},
512{0x00DF,0x00DF},
513{0x00F4,0x00D4},
514{0x00F2,0x00D2},
515{0x00F5,0x00D5},
516{0x00F5,0x00D5},
517{0x00B5,0x00B5},
518{0x00FE,0x00DE},
519{0x00FE,0x00DE},
520{0x00FA,0x00DA},
521{0x00FB,0x00DB},
522{0x00F9,0x00D9},
523{0x00FD,0x00DD},
524{0x00FD,0x00DD},
525{0x00AF,0x00AF},
526{0x00B4,0x00B4},
527{0x00AD,0x00AD},
528{0x00B1,0x00B1},
529{0x2017,0x2017},
530{0x00BE,0x00BE},
531{0x00B6,0x00B6},
532{0x00A7,0x00A7},
533{0x00F7,0x00F7},
534{0x00B8,0x00B8},
535{0x00B0,0x00B0},
536{0x00A8,0x00A8},
537{0x00B7,0x00B7},
538{0x00B9,0x00B9},
539{0x00B3,0x00B3},
540{0x00B2,0x00B2},
541{0x25A0,0x25A0},
542{0x00A0,0x00A0}
543};
544
545static int
546checkname (uint16_t *ucsname, int ucslen, struct direntry *dirp, uint16_t *vfatname)
547{
548uint16_t tmp[15];
549if (vfatname[0])
550{
551int i;
552for (i=0;vfatname[i];i++);
553return !FastUnicodeCompare (ucsname, ucslen, vfatname, i, OSLittleEndian);
554}
555else
556{
557int i, j, k;
558for (i=7;i>=0;i--)
559if (dirp->deName[i]!=' ')
560break;
561j=i+1;
562tmp[i+1]=0;
563for(;i>=0;i--)
564tmp[i]=SWAP_LE16((dirp->deName[i]>=128)?cp850[dirp->deName[i]-128][0]:tolower(dirp->deName[i]));
565for (i=2;i>=0;i--)
566if (dirp->deName[8+i]!=' ')
567break;
568if (i>=0)
569{
570tmp[j++]='.';
571tmp[j+i+1]=0;
572k=j+i+1;
573for(;i>=0;i--)
574tmp[j+i]=SWAP_LE16((dirp->deName[i+8]>=128)?cp850[dirp->deName[i+8]-128][0]:tolower(dirp->deName[i+8]));
575j=k;
576}
577return !FastUnicodeCompare (ucsname, ucslen, tmp, j, OSLittleEndian);
578}
579
580}
581
582static struct direntry *
583getdirpfrompath (CICell ih, char *dirspec, uint8_t *buf)
584{
585struct msdosdirstate st;
586struct direntry *dirp;
587uint8_t * ptr;
588uint8_t *slash;
589char c;
590uint16_tvfatname[WIN_MAXLEN+2*WIN_CHARS];
591uint16_t ucsname[WIN_MAXLEN+1];
592uint16_t ucslen;
593int ucslenhost;
594initRoot (&st);
595st.buf = (struct direntry *)buf;
596ptr=(uint8_t*)dirspec;
597for (slash=ptr;*slash && *slash!='/';slash++);
598c=*slash;
599*slash=0;
600utf_decodestr (ptr, ucsname, &ucslen, WIN_MAXLEN, OSLittleEndian);
601ucslenhost = OSReadLittleInt16 (&ucslen,0);
602ucsname[ucslenhost]=0;
603*slash=c;
604while ((dirp = getnextdirent (ih, vfatname, &st)))
605{
606if (checkname (ucsname, ucslenhost, dirp, vfatname))
607{
608for (;*ptr && *ptr!='/';ptr++);
609if (!*ptr)
610return dirp;
611ptr++;
612if (!*ptr)
613return dirp;
614for (slash=ptr;*slash && *slash!='/';slash++);
615c=*slash;
616*slash=0;
617utf_decodestr (ptr, ucsname, &ucslen, WIN_MAXLEN, OSLittleEndian);
618ucslenhost = OSReadLittleInt16 (&ucslen,0);
619ucsname[ucslenhost]=0;
620*slash=c;
621if (!(dirp->deAttributes & ATTR_DIRECTORY))
622return 0;
623st.root16 = 0;
624st.vfatchecksum = 0;
625st.nument = 0;
626st.cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
627if (msdosfatbits == 32)
628st.cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
629st.vfatnumber = 0;
630}
631}
632return 0;
633}
634
635long MSDOSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex,
636 char ** name, long * flags, long * time,
637 FinderInfo * finderInfo, long * infoValid)
638{
639struct msdosdirstate *st;
640struct direntry *dirp;
641uint16_tvfatname[WIN_MAXLEN+2*WIN_CHARS];
642if (MSDOSInitPartition (ih)<0)
643return -1;
644if (dirPath[0] == '/')
645dirPath++;
646st = (struct msdosdirstate *)(long) *dirIndex;
647if (!st)
648{
649st=malloc (sizeof (*st));
650if (dirPath[0])
651{
652uint8_t *buf=malloc(msdosclustersize);
653dirp = getdirpfrompath (ih, dirPath, buf);
654if (!dirp || !(dirp->deAttributes & ATTR_DIRECTORY))
655{
656free (buf);
657free (st);
658return -1;
659}
660st->buf = (struct direntry *)buf;
661st->root16 = 0;
662st->vfatchecksum = 0;
663st->nument = 0;
664st->cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
665st->vfatnumber = 0;
666if (msdosfatbits == 32)
667st->cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
668}
669else
670initRoot (st);
671*dirIndex = (long long) (long) st;
672}
673while((dirp = getnextdirent (ih, vfatname, st))&& (dirp->deAttributes & ATTR_VOLUME));
674if (!dirp)
675{
676free (st->buf);
677free (st);
678return -1;
679}
680if (vfatname[0])
681{
682int i;
683for (i=0;vfatname[i];i++);
684*name = malloc (256);
685utf_encodestr(vfatname, i, (u_int8_t *)*name, 255, OSLittleEndian );
686}
687else
688{
689int i, j, k;
690uint16_t tmp[13];
691*name = malloc (26);
692for (i=7;i>=0;i--)
693if (dirp->deName[i]!=' ')
694break;
695j=i+1;
696tmp[i+1]=0;
697for(;i>=0;i--)
698tmp[i]=(dirp->deName[i]>=128)?cp850[dirp->deName[i]-128][0]:tolower(dirp->deName[i]);
699for (i=2;i>=0;i--)
700if (dirp->deName[8+i]!=' ')
701break;
702
703if (i>=0)
704{
705tmp[j++]='.';
706tmp[j+i+1]=0;
707k=j+i+1;
708for(;i>=0;i--)
709tmp[j+i]=(dirp->deName[i]>=128)?cp850[dirp->deName[i+8]-128][0]:tolower(dirp->deName[i+8]);
710j=k;
711}
712
713utf_encodestr(tmp, j, (uint8_t*)*name, 25, OSHostByteOrder() );
714}
715if (dirp->deAttributes & ATTR_DIRECTORY)
716*flags = kFileTypeDirectory;
717else
718*flags = kFileTypeFlat;
719
720// Calculate a fake timestamp using modification date and time values.
721*time = (dirp->deMDate & 0x7FFF) << 16 + dirp->deMTime;
722
723if (infoValid)
724*infoValid = 1;
725
726return 0;
727}
728
729long
730MSDOSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length)
731{
732uint8_t *buf;
733off_t cluster;
734uint64_t size;
735uint64_t nskip;
736int toread, wastoread;
737char *ptr = (char *)base;
738struct direntry *dirp;
739int i;
740 char devStr[12];
741
742if (MSDOSInitPartition (ih)<0)
743return -1;
744if (filePath[0] == '/')
745filePath++;
746buf = malloc(msdosclustersize);
747dirp = getdirpfrompath (ih, filePath, buf);
748
749if (!dirp || (dirp->deAttributes & ATTR_DIRECTORY))
750{
751free (buf);
752return -1;
753}
754cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
755if (msdosfatbits == 32)
756cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
757size = (uint32_t)OSReadLittleInt32 ((dirp->deFileSize),0);
758if (size<=offset)
759return -1;
760nskip=offset/msdosclustersize;
761for (i=0;i<nskip;i++)
762msdosreadcluster (ih, 0, 0, &cluster);
763msdosreadcluster (ih, buf, msdosclustersize, &cluster);
764toread=length;
765if (length==0 || length>size-offset)
766toread=size-offset;
767wastoread=toread;
768bcopy (buf+(offset%msdosclustersize),ptr,min(msdosclustersize-(offset%msdosclustersize), toread));
769ptr+=msdosclustersize-(offset%msdosclustersize);
770toread-=msdosclustersize-(offset%msdosclustersize);
771while (toread>0 && msdosreadcluster (ih, (uint8_t *)ptr, min(msdosclustersize,toread), &cluster))
772{
773ptr+=msdosclustersize;
774toread-=msdosclustersize;
775}
776
777 getDeviceDescription(ih, devStr);
778verbose("Read FAT%d file: [%s/%s] %d bytes.\n",
779 msdosfatbits, devStr, filePath, (uint32_t)( toread<0 ) ? wastoread : wastoread-toread);
780free (buf);
781if (toread<0)
782return wastoread;
783else
784return wastoread-toread;
785}
786
787long
788MSDOSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
789{
790uint8_t *buf;
791off_t cluster;
792struct direntry *dirp;
793if (MSDOSInitPartition (ih)<0)
794return -1;
795if (filePath[0] == '/')
796filePath++;
797buf = malloc(msdosclustersize);
798dirp = getdirpfrompath (ih, filePath, buf);
799if (!dirp || (dirp->deAttributes & ATTR_DIRECTORY))
800{
801free (buf);
802return -1;
803}
804cluster = OSReadLittleInt16 ((dirp->deStartCluster),0);
805if (msdosfatbits == 32)
806cluster |= ((uint32_t)OSReadLittleInt16 ((dirp->deHighClust),0)) <<16;
807
808off_t clusn;
809
810switch (msdosfatbits) {
811case 32:
812if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD32)
813return -1;
814clusn = cluster - CLUST_FIRST;
815break;
816case 16:
817if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD16)
818return 0;
819clusn = cluster - CLUST_FIRST;
820break;
821case 12:
822
823if (cluster < CLUST_FIRST ||cluster >= CLUST_RSRVD12)
824return 0;
825clusn = cluster - CLUST_FIRST;
826break;
827default:
828return 0;
829}
830
831*firstBlock = ((msdosressector +
832 (msdosnfats * msdosfatsecs))*msdosbps + clusn * msdosclustersize)/512;
833free (buf);
834return 0;
835}
836
837
838long MSDOSLoadFile(CICell ih, char * filePath)
839{
840 return MSDOSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);
841}
842
843/* Fix up volume label. */
844static void
845fixLabel(uint8_t *label, char *str, long strMaxLen)
846{
847 inti, len;
848uint16_tlabelucs[13];
849 //unsigned charlabelUTF8[LABEL_LENGTH*3];
850
851 /* Convert leading 0x05 to 0xE5 for multibyte languages like Japanese */
852 if (label[0] == 0x05)
853 label[0] = 0xE5;
854
855 /* Remove any trailing spaces */
856 for (i=LABEL_LENGTH-1; i>=0; --i) {
857 if (label[i] == ' ')
858 label[i] = 0;
859 else
860 break;
861 }
862labelucs[i++]=0;
863len=i;
864for (;i>=0;--i)
865labelucs[i]=label[i]>=128?cp850[label[i]-128][1]:(label[i]);
866
867utf_encodestr(labelucs, len, (uint8_t *)str, strMaxLen, OSHostByteOrder() );
868}
869
870
871void
872MSDOSGetDescription(CICell ih, char *str, long strMaxLen)
873{
874 struct direntry *dirp;
875 uint8_t label[LABEL_LENGTH+1];
876uint16_tvfatlabel[WIN_MAXLEN+2*WIN_CHARS];
877struct msdosdirstate st;
878int labelfound = 0;
879
880if (MSDOSInitPartition (ih)<0)
881{
882str[0]=0;
883return;
884}
885
886label[0] = '\0';
887
888initRoot (&st);
889st.buf = malloc(msdosclustersize);
890while ((dirp = getnextdirent (ih, vfatlabel, &st)))
891if (dirp->deAttributes & ATTR_VOLUME) {
892strncpy((char *)label, (char *)dirp->deName, LABEL_LENGTH);
893labelfound = 1;
894break;
895}
896
897free(st.buf);
898
899if (vfatlabel[0] && labelfound)
900{
901int i;
902for (i=0;vfatlabel[i];i++);
903utf_encodestr(vfatlabel, i, (u_int8_t *)str, strMaxLen, OSLittleEndian );
904}
905else if (labelfound)
906fixLabel(label, str, strMaxLen);
907
908 /* else look in the boot blocks */
909 if (!labelfound || str[0] == '\0') {
910char *buf = malloc (512);
911union bootsector *bsp = (union bootsector *)buf;
912Seek(ih, 0);
913Read(ih, (long)buf, 512);
914 if (msdosfatbits == 32) { /* It's FAT32 */
915 strncpy((char *)label, (char *)((struct extboot *)bsp->bs710.bsExt)->exVolumeLabel, LABEL_LENGTH);
916 }
917 else if (msdosfatbits == 16) {
918 strncpy((char *)label, (char *)((struct extboot *)bsp->bs50.bsExt)->exVolumeLabel, LABEL_LENGTH);
919 }
920free (buf);
921fixLabel(label, str, strMaxLen);
922 }
923
924 return;
925}
926
927long
928MSDOSGetUUID(CICell ih, char *uuidStr)
929{
930char *buf = malloc (512);
931union bootsector *bsp = (union bootsector *)buf;
932
933if (MSDOSInitPartition (ih)<0)
934{
935return -1;
936}
937bzero (uuidStr, 16);
938Seek(ih, 0);
939Read(ih, (long)buf, 512);
940if (msdosfatbits == 32) { /* It's FAT32 */
941memcpy(uuidStr+12, (char *)((struct extboot *)bsp->bs710.bsExt)->exVolumeID, 4);
942}
943else if (msdosfatbits == 16) {
944memcpy(uuidStr+12, (char *)((struct extboot *)bsp->bs50.bsExt)->exVolumeID, 4);
945}
946free (buf);
947 return 0;
948
949}
950

Archive Download this file

Revision: 296