Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2531