Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1055