Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 312