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

Archive Download this file

Revision: 2323