Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1468