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

Archive Download this file

Revision: 2504