Chameleon

Chameleon Svn Source Tree

Root/branches/Bungo/i386/libsaio/exfat.c

1/*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2004 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * dmazar, 14/7/2011
27 * support for EXFAT volume label reading
28 * EXFAT info from: http://www.ntfs.com/exfat-overview.htm
29 *
30 * EXFAT shares partition type with NTFS (0x7) and easiest way of
31 * adding it was through ntfs.c module. All functions here are called
32 * from similar ntfs.c funcs as fallback (if not NTFS, maybe it's EXFAT).
33 */
34
35#include "libsaio.h"
36#include "sl.h"
37
38#ifndef DEBUG_EXFAT
39#define DEBUG_EXFAT 0
40#endif
41
42#if DEBUG_EXFAT
43#define DBG(x...)printf(x)
44#else
45#define DBG(x...)msglog(x)
46#endif
47
48#defineEXFAT_BBID"EXFAT "
49#defineEXFAT_BBIDLEN8
50
51#define MAX_BLOCK_SIZE4096
52#define MAX_CLUSTER_SIZE32 * 1024 * 1024
53
54#define ERROR -1
55
56
57/*
58 * boot sector of the partition
59 * http://www.ntfs.com/exfat-boot-sector.htm
60 */
61struct exfatbootfile {
62u_int8_t reserved1[3];/* JumpBoot: 0xEB7690 */
63u_int8_t bf_sysid[8];/* FileSystemName: 'EXFAT ' */
64u_int8_t reserved2[53];/* MustBeZero */
65u_int64_t bf_prtoff;/* PartitionOffset: In sectors; if 0, shall be ignored */
66u_int64_t bf_vollen;/* VolumeLength: Size of exFAT volume in sectors */
67u_int32_t bf_fatoff;/* FatOffset: In sectors */
68u_int32_t bf_fatlen;/* FatLength: In sectors. May exceed the required space in order to align the second FAT */
69u_int32_t bf_cloff;/* ClusterHeapOffset: In sectors. */
70u_int32_t bf_clcnt;/* ClusterCount: 2^32-11 is the maximum number of clusters could be described. */
71u_int32_t bf_rdircl;/* RootDirectoryCluster. */
72u_int32_t bf_volsn;/* VolumeSerialNumber. */
73u_int16_t bf_fsrev;/* FileSystemRevision: as MAJOR.minor, major revision is high byte, minor is low byte; currently 01.00. */
74u_int16_t bf_volflags;/* VolumeFlags. */
75u_int8_t bf_bpss;/* BytesPerSectorShift: Power of 2. Minimum 9 (512 bytes per sector), maximum 12 (4096 bytes per sector) */
76
77u_int8_t bf_nfats;/* NumberOfFats: 2 is for TexFAT only */
78u_int8_t bf_drvs;/* DriveSelect: Extended INT 13h drive number; typically 0x80 */
79
80u_int8_t reserved3[7];/* Reserved */
81u_int8_t bootcode[390];/* BootCode */
82u_int16_t bf_bsig;/* BootSignature: 0xAA55 */
83};
84
85struct direntry_label {
86u_int8_t type;/* EntryType: 0x83 (or 0x03 if label is empty) */
87u_int8_t llen;/* CharacterCount: Length in Unicode characters (max 11) */
88u_int16_t label[11];/* VolumeLabel: Unicode characters (max 11) */
89u_int8_t reserved1[8];/* Reserved */
90};
91
92
93/**
94 * Reads volume label into str.
95 * Reads boot sector, performs dome checking, loads root dir
96 * and parses volume label.
97 */
98void
99EXFATGetDescription(CICell ih, char *str, long strMaxLen)
100{
101 struct exfatbootfile *boot;
102 u_int32_t bytesPerSector = 0;
103 u_int32_t sectorsPerCluster = 0;
104 long long rdirOffset = 0;
105 char *buf = NULL;
106 struct direntry_label *dire = NULL;
107 int loopControl = 0;
108
109 //verbose("EXFAT: start %x:%x\n", ih->biosdev, ih->part_no);
110
111 buf = (char *)malloc(MAX_BLOCK_SIZE);
112 if (buf == 0)
113 {
114 goto error;
115 }
116
117 /*
118 * Read the boot sector, check signatures, and do some minimal
119 * sanity checking. NOTE: the size of the read below is intended
120 * to be a multiple of all supported block sizes, so we don't
121 * have to determine or change the device's block size.
122 */
123 Seek(ih, 0);
124 Read(ih, (long)buf, MAX_BLOCK_SIZE);
125
126 // take our boot structure
127 boot = (struct exfatbootfile *) buf;
128
129 /*
130 * The first three bytes are an Intel x86 jump instruction. I assume it
131 * can be the same forms as DOS FAT:
132 * 0xE9 0x?? 0x??
133 * 0xEC 0x?? 0x90
134 * where 0x?? means any byte value is OK.
135 */
136 if (boot->reserved1[0] != 0xE9 && (boot->reserved1[0] != 0xEB || boot->reserved1[2] != 0x90))
137 {
138 goto error;
139 }
140
141 // Check the "EXFAT " signature.
142 if (memcmp((const char *)boot->bf_sysid, EXFAT_BBID, EXFAT_BBIDLEN) != 0)
143 {
144 goto error;
145 }
146
147 /*
148 * Make sure the bytes per sector and sectors per cluster are
149 * powers of two, and within reasonable ranges.
150 */
151 bytesPerSector = 1 << boot->bf_bpss;/* Just one byte; no swapping needed */
152 //verbose("EXFAT: bpss=%d, bytesPerSector=%d\n", boot->bf_bpss, bytesPerSector);
153 if (boot->bf_bpss < 9 || boot->bf_bpss > 12)
154 {
155 verbose("EXFAT: invalid bytes per sector shift(%d)\n", boot->bf_bpss);
156 goto error;
157 }
158
159 sectorsPerCluster = 1 << boot->bf_spcs;/* Just one byte; no swapping needed */
160 //verbose("EXFAT: spcs=%d, sectorsPerCluster=%d\n", boot->bf_spcs, sectorsPerCluster);
161 if (boot->bf_spcs > (25 - boot->bf_bpss))
162 {
163 verbose("EXFAT: invalid sectors per cluster shift (%d)\n", boot->bf_spcs);
164 goto error;
165 }
166
167 // calculate root dir cluster offset
168 rdirOffset = boot->bf_cloff + (boot->bf_rdircl - 2) * sectorsPerCluster;
169 //verbose("EXFAT: rdirOffset=%d\n", rdirOffset);
170
171 // load MAX_BLOCK_SIZE bytes of root dir
172 Seek(ih, rdirOffset * bytesPerSector);
173 Read(ih, (long)buf, MAX_BLOCK_SIZE);
174 //verbose("buf 0 1 2 = %x %x %x\n", 0x00ff & buf[0], 0x00ff & buf[1], 0x00ff & buf[2]);
175
176 str[0] = '\0';
177
178 /*
179 * Search for volume label dir entry (type 0x83), convert from unicode and put to str.
180 * Set loopControl var to avoid searching outside of buf.
181 */
182 loopControl = MAX_BLOCK_SIZE / sizeof(struct direntry_label);
183 dire = (struct direntry_label *)buf;
184 while (loopControl && dire->type && dire->type != 0x83)
185 {
186 dire++;
187 loopControl--;
188 }
189 if (dire->type == 0x83 && dire->llen > 0 && dire->llen <= 11)
190 {
191 utf_encodestr( dire->label, (int)dire->llen, (u_int8_t *)str, strMaxLen, OSLittleEndian );
192 }
193 //verbose("EXFAT: label=%s\n", str);
194/*
195 free(buf);
196#if DEBUG_EXFAT
197 pause("");
198#endif
199 return;
200*/
201 error:
202 if (buf) free(buf);
203#if DEBUG_EXFAT
204 pause("");
205#endif
206 return;
207}
208
209/**
210 * Sets UUID to uuidStr.
211 * Reads the boot sector, does some checking, generates UUID
212 * (like the one you get on Windows???)
213 */
214long EXFATGetUUID(CICell ih, char *uuidStr)
215{
216 struct exfatbootfile *boot;
217 void *buf = malloc(MAX_BLOCK_SIZE);
218 if ( !buf )
219 return -1;
220
221 /*
222 * Read the boot sector, check signatures, and do some minimal
223 * sanity checking. NOTE: the size of the read below is intended
224 * to be a multiple of all supported block sizes, so we don't
225 * have to determine or change the device's block size.
226 */
227 Seek(ih, 0);
228 Read(ih, (long)buf, MAX_BLOCK_SIZE);
229
230 boot = (struct exfatbootfile *) buf;
231
232 /*
233 * Check the "EXFAT " signature.
234 */
235 if (memcmp((const char *)boot->bf_sysid, EXFAT_BBID, EXFAT_BBIDLEN) != 0)
236 return -1;
237
238 // Check for non-null volume serial number
239 if( !boot->bf_volsn )
240 return -1;
241
242 // Use UUID like the one you get on Windows
243 sprintf(uuidStr, "%04X-%04X", (unsigned short)(boot->bf_volsn >> 16) & 0xFFFF,
244 (unsigned short)boot->bf_volsn & 0xFFFF);
245
246 //verbose("EXFATGetUUID: %x:%x = %s\n", ih->biosdev, ih->part_no, uuidStr);
247 return 0;
248}
249
250/**
251 * Returns true if given buffer is the boot rec of the EXFAT volume.
252 */
253bool EXFATProbe(const void *buffer)
254{
255 bool result = false;
256
257 // boot sector structure
258 const struct exfatbootfile*boot = buffer;
259
260 // Looking for EXFAT signature.
261 if (memcmp((const char *)boot->bf_sysid, EXFAT_BBID, EXFAT_BBIDLEN) == 0)
262 result = true;
263
264 //verbose("EXFATProbe: %d\n", result ? 1 : 0);
265 return result;
266}
267

Archive Download this file

Revision: 2531