2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1998 Robert Nordier
24 * All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
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
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.
52 #include "msdos_private.h"
55 #define LABEL_LENGTH 11
56 #define MAX_DOS_BLOCKSIZE 2048
58 #define CLUST_FIRST 2 /* first legal cluster number */
59 #define CLUST_RSRVD 0xfffffff6 /* reserved cluster range */
66 #define DLOG(x) { outb(0x80, (x)); getc(); }
73 * Check a volume label.
76 oklabel(const char *src
)
80 for (i
= 0, c
= 0; i
<= 11; i
++) {
82 if (c
< ' ' + !i
|| strchr("\"*+,./:;<=>?[\\]|", c
))
89 /* Fix up volume label. */
91 fixLabel(char *label
, char *str
, long strMaxLen
)
94 //unsigned char labelUTF8[LABEL_LENGTH*3];
96 /* Convert leading 0x05 to 0xE5 for multibyte languages like Japanese */
101 /* Check for illegal characters */
106 /* Remove any trailing spaces */
107 for (i
=LABEL_LENGTH
-1; i
>=0; --i
) {
114 /* TODO: Convert it to UTF-8 from DOSLatin1 encoding */
115 strncpy(str
, label
, strMaxLen
);
120 MSDOSGetDescription(CICell ih
, char *str
, long strMaxLen
)
122 struct direntry
*dirp
;
123 union bootsector
*bsp
;
132 char label
[LABEL_LENGTH
+1];
135 buf
= (char *)malloc(MAX_DOS_BLOCKSIZE
);
136 if (buf
== 0) goto error
;
140 * Read the boot sector of the filesystem, and then check the
141 * boot signature. If not a dos boot sector then error out.
143 * NOTE: 2048 is a maximum sector size in current...
146 Read(ih
, (long)buf
, MAX_DOS_BLOCKSIZE
);
149 bsp
= (union bootsector
*)buf
;
150 b33
= (struct bpb33
*)bsp
->bs33
.bsBPB
;
151 b50
= (struct bpb50
*)bsp
->bs50
.bsBPB
;
152 b710
= (struct bpb710
*)bsp
->bs710
.bsBPB
;
157 * The first three bytes are an Intel x86 jump instruction. It should be one
158 * of the following forms:
161 * where 0x?? means any byte value is OK.
163 if (bsp
->bs50
.bsJump
[0] != 0xE9
164 && (bsp
->bs50
.bsJump
[0] != 0xEB || bsp
->bs50
.bsJump
[2] != 0x90)) {
169 /* It is possible that the above check could match a partition table, or some */
170 /* non-FAT disk meant to boot a PC. Check some more fields for sensible values. */
172 /* We only work with 512, 1024, and 2048 byte sectors */
173 bps
= OSSwapLittleToHostInt16(b33
->bpbBytesPerSec
);
174 if ((bps
< 0x200) || (bps
& (bps
- 1)) || (bps
> 0x800)) {
179 /* Check to make sure valid sectors per cluster */
180 spc
= b33
->bpbSecPerClust
;
181 if ((spc
== 0 ) || (spc
& (spc
- 1))) {
186 /* we know this disk, find the volume label */
187 /* First, find the root directory */
190 rootDirSectors
= ((OSSwapLittleToHostInt16(b50
->bpbRootDirEnts
) * sizeof(struct direntry
)) +
195 if (rootDirSectors
) { /* FAT12 or FAT16 */
196 int firstRootDirSecNum
;
197 u_int8_t
*rootDirBuffer
;
200 rootDirBuffer
= (u_int8_t
*)malloc(MAX_DOS_BLOCKSIZE
);
203 firstRootDirSecNum
= OSSwapLittleToHostInt16(b33
->bpbResSectors
) +
204 (b33
->bpbFATs
* OSSwapLittleToHostInt16(b33
->bpbFATsecs
));
205 for (i
=0; i
< rootDirSectors
; i
++) {
206 Seek(ih
, (firstRootDirSecNum
+i
)*bps
);
207 Read(ih
, (long)rootDirBuffer
, bps
);
208 dirp
= (struct direntry
*)rootDirBuffer
;
209 for (j
=0; j
<bps
; j
+=sizeof(struct direntry
), dirp
++) {
210 if (dirp
->deName
[0] == SLOT_EMPTY
) {
214 else if (dirp
->deName
[0] == SLOT_DELETED
)
216 else if (dirp
->deAttributes
== ATTR_WIN95
)
218 else if (dirp
->deAttributes
& ATTR_VOLUME
) {
219 strncpy(label
, (char *)dirp
->deName
, LABEL_LENGTH
);
224 if (finished
== true) {
233 u_int32_t bytesPerCluster
;
234 u_int8_t
*rootDirBuffer
;
238 bytesPerCluster
= bps
* spc
;
239 rootDirBuffer
= malloc(bytesPerCluster
);
240 cluster
= OSSwapLittleToHostInt32(b710
->bpbRootClust
);
244 while (!finished
&& cluster
>= CLUST_FIRST
&& cluster
< CLUST_RSRVD
) {
247 /* Find sector where clusters start */
248 readOffset
= OSSwapLittleToHostInt16(b710
->bpbResSectors
) +
249 (b710
->bpbFATs
* OSSwapLittleToHostInt16(b710
->bpbBigFATsecs
));
250 /* Find sector where "cluster" starts */
251 readOffset
+= ((off_t
) cluster
- CLUST_FIRST
) * (off_t
) spc
;
252 /* Convert to byte offset */
253 readOffset
*= (off_t
) bps
;
256 /* Read in "cluster" */
257 Seek(ih
, readOffset
);
258 Read(ih
, (long)rootDirBuffer
, bytesPerCluster
);
259 dirp
= (struct direntry
*) rootDirBuffer
;
262 /* Examine each directory entry in this cluster */
263 for (i
=0; i
< bytesPerCluster
; i
+= sizeof(struct direntry
), dirp
++) {
266 if (dirp
->deName
[0] == SLOT_EMPTY
) {
267 finished
= true; // Reached end of directory (never used entry)
270 else if (dirp
->deName
[0] == SLOT_DELETED
)
272 else if (dirp
->deAttributes
== ATTR_WIN95
)
274 else if (dirp
->deAttributes
& ATTR_VOLUME
) {
276 strncpy(label
, (char *)dirp
->deName
, LABEL_LENGTH
);
286 /* Find next cluster in the chain by reading the FAT */
288 /* Find first sector of FAT */
289 readOffset
= OSSwapLittleToHostInt16(b710
->bpbResSectors
);
290 /* Find sector containing "cluster" entry in FAT */
291 readOffset
+= (cluster
* 4) / bps
;
292 /* Convert to byte offset */
296 /* Read one sector of the FAT */
297 Seek(ih
, readOffset
);
298 Read(ih
, (long)rootDirBuffer
, bps
);
301 cluster
= OSReadLittleInt32(rootDirBuffer
+ ((cluster
* 4) % bps
), 0);
302 cluster
&= 0x0FFFFFFF; // ignore reserved upper bits
307 } /* rootDirSectors */
310 /* else look in the boot blocks */
311 if (str
[0] == '\0') {
312 if (OSSwapLittleToHostInt16(b50
->bpbRootDirEnts
) == 0) { /* It's FAT32 */
313 strncpy(label
, (char *)((struct extboot
*)bsp
->bs710
.bsExt
)->exVolumeLabel
, LABEL_LENGTH
);
315 else if (((struct extboot
*)bsp
->bs50
.bsExt
)->exBootSignature
== EXBOOTSIG
) {
316 strncpy(label
, (char *)((struct extboot
*)bsp
->bs50
.bsExt
)->exVolumeLabel
, LABEL_LENGTH
);
320 fixLabel(label
, str
, strMaxLen
);