Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2004