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

Archive Download this file

Revision: 2182