Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 151