Chameleon

Chameleon Svn Source Tree

Root/tags/2.1/i386/libsaio/ntfs.c

Source at commit 2381 created 10 years 21 days ago.
By ifabio, Apply patch: (Credits to Thomas Jansen aka tja) - Reading options from all devices during boot. The options for the boot menu are only read from the devices rd(0,0) or bt(0,0). Consequently, boot menu options (e.g. "Quiet Boot", "Timeout", etc.) in plists on other devices (like most users have) are ignored. This patch extends the list of paths to search for the options plist on all devices that can be found.
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#include "libsaio.h"
27#include "sl.h"
28
29/*
30 * dmazar, 14/7/2011 - support for EXFAT volume label reading
31 */
32#include "exfat.h"
33
34#define BYTE_ORDER_MARK0xFEFF
35
36#include "ntfs_private.h"
37
38#define FS_TYPE"ntfs"
39#define FS_NAME_FILE"NTFS"
40
41#define MAX_BLOCK_SIZE2048
42#define MAX_CLUSTER_SIZE32768
43
44#define LABEL_LENGTH1024
45#define UNKNOWN_LABEL"Untitled NTFS"
46
47#define FSUR_IO_FAIL -1
48#define FSUR_UNRECOGNIZED -1
49#define FSUR_RECOGNIZED 0
50
51#define ERROR -1
52
53/*
54 * Process per-sector "fixups" that NTFS uses to detect corruption of
55 * multi-sector data structures, like MFT records.
56 */
57static int
58ntfs_fixup(
59 char *buf,
60 size_t len,
61 u_int32_t magic,
62 u_int32_t bytesPerSector)
63{
64struct fixuphdr *fhp = (struct fixuphdr *) buf;
65int i;
66u_int16_t fixup;
67u_int16_t *fxp;
68u_int16_t *cfxp;
69 u_int32_tfixup_magic;
70 u_int16_tfixup_count;
71 u_int16_tfixup_offset;
72
73 fixup_magic = OSReadLittleInt32(&fhp->fh_magic,0);
74if (fixup_magic != magic) {
75error("ntfs_fixup: magic doesn't match: %08x != %08x\n",
76 fixup_magic, magic);
77return (ERROR);
78}
79 fixup_count = OSReadLittleInt16(&fhp->fh_fnum,0);
80if ((fixup_count - 1) * bytesPerSector != len) {
81error("ntfs_fixup: " \
82 "bad fixups number: %d for %ld bytes block\n",
83 fixup_count, (long)len);/* XXX printf kludge */
84return (ERROR);
85}
86 fixup_offset = OSReadLittleInt16(&fhp->fh_foff,0);
87if (fixup_offset >= len) {
88error("ntfs_fixup: invalid offset: %x", fixup_offset);
89return (ERROR);
90}
91fxp = (u_int16_t *) (buf + fixup_offset);
92cfxp = (u_int16_t *) (buf + bytesPerSector - 2);
93fixup = *fxp++;
94for (i = 1; i < fixup_count; i++, fxp++) {
95if (*cfxp != fixup) {
96error("ntfs_fixup: fixup %d doesn't match\n", i);
97return (ERROR);
98}
99*cfxp = *fxp;
100 cfxp = (u_int16_t *)(((caddr_t)cfxp) + bytesPerSector);
101}
102return (0);
103}
104
105/*
106 * Find a resident attribute of a given type. Returns a pointer to the
107 * attribute data, and its size in bytes.
108 */
109static int
110ntfs_find_attr(
111 char *buf,
112 u_int32_t attrType,
113 void **attrData,
114 size_t *attrSize)
115{
116 struct filerec *filerec;
117 struct attr *attr;
118 u_int16_t offset;
119
120 filerec = (struct filerec *) buf;
121 offset = OSReadLittleInt16(&filerec->fr_attroff,0);
122 attr = (struct attr *) (buf + offset);
123
124
125 while (attr->a_hdr.a_type != 0xFFFFFFFF)/* same for big/little endian */
126 {
127 if (OSReadLittleInt32(&attr->a_hdr.a_type,0) == attrType)
128 {
129 if (attr->a_hdr.a_flag != 0)
130 {
131 //verbose("NTFS: attriubte 0x%X is non-resident\n", attrType);
132 return 1;
133 }
134
135 *attrSize = OSReadLittleInt16(&attr->a_r.a_datalen,0);
136 *attrData = buf + offset + OSReadLittleInt16(&attr->a_r.a_dataoff,0);
137 return 0;/* found it! */
138 }
139
140 /* Skip to the next attribute */
141 offset += OSReadLittleInt32(&attr->a_hdr.reclen,0);
142 attr = (struct attr *) (buf + offset);
143 }
144
145 return 1;/* No matching attrType found */
146}
147
148/*
149 * Examine a volume to see if we recognize it as a mountable.
150 */
151void
152NTFSGetDescription(CICell ih, char *str, long strMaxLen)
153{
154 struct bootfile *boot;
155 unsigned bytesPerSector;
156 unsigned sectorsPerCluster;
157 int mftRecordSize;
158 u_int64_t totalClusters;
159 u_int64_t cluster, mftCluster;
160 size_t mftOffset;
161 void *nameAttr;
162 size_t nameSize;
163 char *buf;
164
165 buf = (char *)malloc(MAX_CLUSTER_SIZE);
166 if (buf == 0) {
167 goto error;
168 }
169
170 /*
171 * Read the boot sector, check signatures, and do some minimal
172 * sanity checking. NOTE: the size of the read below is intended
173 * to be a multiple of all supported block sizes, so we don't
174 * have to determine or change the device's block size.
175 */
176 Seek(ih, 0);
177 Read(ih, (long)buf, MAX_BLOCK_SIZE);
178
179 boot = (struct bootfile *) buf;
180
181 /*
182 * The first three bytes are an Intel x86 jump instruction. I assume it
183 * can be the same forms as DOS FAT:
184 * 0xE9 0x?? 0x??
185 * 0xEC 0x?? 0x90
186 * where 0x?? means any byte value is OK.
187 */
188 if (boot->reserved1[0] != 0xE9
189 && (boot->reserved1[0] != 0xEB || boot->reserved1[2] != 0x90))
190 {
191 goto error;
192 }
193
194 /*
195 * Check the "NTFS " signature.
196 */
197 if (memcmp((const char *)boot->bf_sysid, "NTFS ", 8) != 0)
198 {
199 /*
200 * Check for EXFAT. Finish by jumping to error to free buf,
201 * although if it is EXFAT then it's no an error.
202 */
203 EXFATGetDescription(ih, str, strMaxLen);
204 goto error;
205 }
206
207 /*
208 * Make sure the bytes per sector and sectors per cluster are
209 * powers of two, and within reasonable ranges.
210 */
211 bytesPerSector = OSReadLittleInt16(&boot->bf_bps,0);
212 if ((bytesPerSector & (bytesPerSector-1)) || bytesPerSector < 512 || bytesPerSector > 32768)
213 {
214 //verbose("NTFS: invalid bytes per sector (%d)\n", bytesPerSector);
215 goto error;
216 }
217
218 sectorsPerCluster = boot->bf_spc;/* Just one byte; no swapping needed */
219 if ((sectorsPerCluster & (sectorsPerCluster-1)) || sectorsPerCluster > 128)
220 {
221 //verbose("NTFS: invalid sectors per cluster (%d)\n", bytesPerSector);
222 goto error;
223 }
224
225 /*
226 * Calculate the number of clusters from the number of sectors.
227 * Then bounds check the $MFT and $MFTMirr clusters.
228 */
229 totalClusters = OSReadLittleInt64(&boot->bf_spv,0) / sectorsPerCluster;
230 mftCluster = OSReadLittleInt64(&boot->bf_mftcn,0);
231 if (mftCluster > totalClusters)
232 {
233 ////verbose("NTFS: invalid $MFT cluster (%lld)\n", mftCluster);
234 goto error;
235 }
236 cluster = OSReadLittleInt64(&boot->bf_mftmirrcn,0);
237 if (cluster > totalClusters)
238 {
239 //verbose("NTFS: invalid $MFTMirr cluster (%lld)\n", cluster);
240 goto error;
241 }
242
243 /*
244 * Determine the size of an MFT record.
245 */
246 mftRecordSize = (int8_t) boot->bf_mftrecsz;
247 if (mftRecordSize < 0)
248 mftRecordSize = 1 << -mftRecordSize;
249 else
250 mftRecordSize *= bytesPerSector * sectorsPerCluster;
251 //verbose("NTFS: MFT record size = %d\n", mftRecordSize);
252
253 /*
254 * Read the MFT record for $Volume. This assumes the first four
255 * file records in the MFT are contiguous; if they aren't, we
256 * would have to map the $MFT itself.
257 *
258 * This will fail if the device sector size is larger than the
259 * MFT record size, since the $Volume record won't be aligned
260 * on a sector boundary.
261 */
262 mftOffset = mftCluster * sectorsPerCluster * bytesPerSector;
263 mftOffset += mftRecordSize * NTFS_VOLUMEINO;
264
265 Seek(ih, mftOffset);
266 Read(ih, (long)buf, mftRecordSize);
267#if UNUSED
268 if (lseek(fd, mftOffset, SEEK_SET) == -1)
269 {
270 //verbose("NTFS: lseek to $Volume failed: %s\n", strerror(errno));
271 goto error;
272 }
273 if (read(fd, buf, mftRecordSize) != mftRecordSize)
274 {
275 //verbose("NTFS: error reading MFT $Volume record: %s\n",
276 strerror(errno));
277 goto error;
278 }
279#endif
280
281 if (ntfs_fixup(buf, mftRecordSize, NTFS_FILEMAGIC, bytesPerSector) != 0)
282 {
283 //verbose("NTFS: block fixup failed\n");
284 goto error;
285 }
286
287 /*
288 * Loop over the attributes, looking for $VOLUME_NAME (0x60).
289 */
290 if(ntfs_find_attr(buf, NTFS_A_VOLUMENAME, &nameAttr, &nameSize) != 0)
291 {
292 //verbose("NTFS: $VOLUME_NAME attribute not found\n");
293 goto error;
294 }
295
296 str[0] = '\0';
297
298 utf_encodestr( nameAttr, nameSize / 2, (u_int8_t *)str, strMaxLen, OSLittleEndian );
299
300 free(buf);
301 return;
302
303 error:
304 if (buf) free(buf);
305 return;
306}
307
308long NTFSGetUUID(CICell ih, char *uuidStr)
309{
310bool NTFSProbe(const void*);
311
312struct bootfile *boot;
313void *buf = malloc(MAX_BLOCK_SIZE);
314if ( !buf )
315return -1;
316
317/*
318 * Read the boot sector, check signatures, and do some minimal
319 * sanity checking. NOTE: the size of the read below is intended
320 * to be a multiple of all supported block sizes, so we don't
321 * have to determine or change the device's block size.
322 */
323Seek(ih, 0);
324Read(ih, (long)buf, MAX_BLOCK_SIZE);
325
326boot = (struct bootfile *) buf;
327
328// Check for NTFS signature
329if ( memcmp((void*)boot->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) != 0 ) {
330// If not NTFS, maybe it is EXFAT
331return EXFATGetUUID(ih, uuidStr);
332}
333
334// Check for non-null volume serial number
335if( !boot->bf_volsn )
336return -1;
337
338// Use UUID like the one you get on Windows
339sprintf(uuidStr, "%04X-%04X",(unsigned short)(boot->bf_volsn >> 16) & 0xFFFF,
340(unsigned short)boot->bf_volsn & 0xFFFF);
341
342return 0;
343}
344
345bool NTFSProbe(const void * buffer)
346{
347bool result = false;
348
349const struct bootfile* part_bootfile = buffer;// NTFS boot sector structure
350
351// Looking for NTFS signature.
352if (strncmp((const char *)part_bootfile->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) == 0)
353result = true;
354
355// If not NTFS, maybe it is EXFAT
356if (!result)
357result = EXFATProbe(buffer);
358
359return result;
360}
361

Archive Download this file

Revision: 2381