Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 962