Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: HEAD