Chameleon

Chameleon Svn Source Tree

Root/trunk/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_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_RECOGNIZED0
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 ntfs_find_attr(
110 char *buf,
111 u_int32_t attrType,
112 void **attrData,
113 size_t *attrSize)
114{
115 struct filerec *filerec;
116 struct attr *attr;
117 u_int16_t offset;
118
119 filerec = (struct filerec *) buf;
120 offset = OSReadLittleInt16(&filerec->fr_attroff,0);
121 attr = (struct attr *) (buf + offset);
122
123
124 while (attr->a_hdr.a_type != 0xFFFFFFFF)/* same for big/little endian */
125 {
126 if (OSReadLittleInt32(&attr->a_hdr.a_type,0) == attrType)
127 {
128 if (attr->a_hdr.a_flag != 0)
129 {
130 //verbose("NTFS: attriubte 0x%X is non-resident\n", attrType);
131 return 1;
132 }
133
134 *attrSize = OSReadLittleInt16(&attr->a_r.a_datalen,0);
135 *attrData = buf + offset + OSReadLittleInt16(&attr->a_r.a_dataoff,0);
136 return 0;/* found it! */
137 }
138
139 /* Skip to the next attribute */
140 offset += OSReadLittleInt32(&attr->a_hdr.reclen,0);
141 attr = (struct attr *) (buf + offset);
142 }
143
144 return 1;/* No matching attrType found */
145}
146
147/*
148 * Examine a volume to see if we recognize it as a mountable.
149 */
150void NTFSGetDescription(CICell ih, char *str, long strMaxLen)
151{
152struct bootfile *boot;
153unsigned bytesPerSector;
154unsigned sectorsPerCluster;
155int mftRecordSize;
156u_int64_t totalClusters;
157u_int64_t cluster, mftCluster;
158 //size_t mftOffset;
159long long mftOffset;
160void *nameAttr;
161size_t nameSize;
162char *buf;
163
164buf = (char *)malloc(MAX_CLUSTER_SIZE);
165if (buf == 0)
166{
167goto 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 */
176Seek(ih, 0);
177Read(ih, (long)buf, MAX_BLOCK_SIZE);
178
179boot = (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 */
188if (boot->reserved1[0] != 0xE9 && (boot->reserved1[0] != 0xEB || boot->reserved1[2] != 0x90))
189{
190goto error;
191}
192
193/*
194 * Check the "NTFS " signature.
195 */
196if (memcmp((const char *)boot->bf_sysid, "NTFS ", 8) != 0)
197{
198/*
199 * Check for EXFAT. Finish by jumping to error to free buf,
200 * although if it is EXFAT then it's no an error.
201 */
202EXFATGetDescription(ih, str, strMaxLen);
203goto error;
204}
205
206/*
207 * Make sure the bytes per sector and sectors per cluster are
208 * powers of two, and within reasonable ranges.
209 */
210bytesPerSector = OSReadLittleInt16(&boot->bf_bps,0);
211if ((bytesPerSector & (bytesPerSector-1)) || bytesPerSector < 512 || bytesPerSector > 32768)
212{
213//verbose("NTFS: invalid bytes per sector (%d)\n", bytesPerSector);
214goto error;
215}
216
217sectorsPerCluster = boot->bf_spc;/* Just one byte; no swapping needed */
218if ((sectorsPerCluster & (sectorsPerCluster-1)) || sectorsPerCluster > 128)
219{
220//verbose("NTFS: invalid sectors per cluster (%d)\n", bytesPerSector);
221goto error;
222}
223
224 /*
225 * Calculate the number of clusters from the number of sectors.
226 * Then bounds check the $MFT and $MFTMirr clusters.
227 */
228 totalClusters = OSReadLittleInt64(&boot->bf_spv,0) / sectorsPerCluster;
229 mftCluster = OSReadLittleInt64(&boot->bf_mftcn,0);
230 if (mftCluster > totalClusters)
231 {
232 ////verbose("NTFS: invalid $MFT cluster (%lld)\n", mftCluster);
233 goto error;
234 }
235 cluster = OSReadLittleInt64(&boot->bf_mftmirrcn,0);
236 if (cluster > totalClusters)
237 {
238 //verbose("NTFS: invalid $MFTMirr cluster (%lld)\n", cluster);
239 goto error;
240 }
241
242 /*
243 * Determine the size of an MFT record.
244 */
245 mftRecordSize = (int8_t) boot->bf_mftrecsz;
246 if (mftRecordSize < 0)
247 mftRecordSize = 1 << -mftRecordSize;
248 else
249 mftRecordSize *= bytesPerSector * sectorsPerCluster;
250 //verbose("NTFS: MFT record size = %d\n", mftRecordSize);
251
252 /*
253 * Read the MFT record for $Volume. This assumes the first four
254 * file records in the MFT are contiguous; if they aren't, we
255 * would have to map the $MFT itself.
256 *
257 * This will fail if the device sector size is larger than the
258 * MFT record size, since the $Volume record won't be aligned
259 * on a sector boundary.
260 */
261 mftOffset = mftCluster * sectorsPerCluster * bytesPerSector;
262 mftOffset += mftRecordSize * NTFS_VOLUMEINO;
263
264 Seek(ih, mftOffset);
265 Read(ih, (long)buf, mftRecordSize);
266#if UNUSED
267 if (lseek(fd, mftOffset, SEEK_SET) == -1)
268 {
269 //verbose("NTFS: lseek to $Volume failed: %s\n", strerror(errno));
270 goto error;
271 }
272 if (read(fd, buf, mftRecordSize) != mftRecordSize) {
273 //verbose("NTFS: error reading MFT $Volume record: %s\n", strerror(errno));
274 goto error;
275 }
276#endif
277
278 if (ntfs_fixup(buf, mftRecordSize, NTFS_FILEMAGIC, bytesPerSector) != 0) {
279 //verbose("NTFS: block fixup failed\n");
280 goto error;
281 }
282
283 /*
284 * Loop over the attributes, looking for $VOLUME_NAME (0x60).
285 */
286if(ntfs_find_attr(buf, NTFS_A_VOLUMENAME, &nameAttr, &nameSize) != 0)
287{
288//verbose("NTFS: $VOLUME_NAME attribute not found\n");
289goto error;
290}
291
292str[0] = '\0';
293
294utf_encodestr( nameAttr, nameSize / 2, (u_int8_t *)str, strMaxLen, OSLittleEndian );
295
296free(buf);
297return;
298
299 error:
300if (buf)
301{
302free(buf);
303}
304return;
305}
306
307long NTFSGetUUID(CICell ih, char *uuidStr)
308{
309bool NTFSProbe(const void*);
310
311long long mftOffset;
312
313char sero[20];
314
315const unsigned char bufff[32];
316struct bootfile *boot;
317void *buf = malloc(MAX_BLOCK_SIZE);
318if ( !buf )
319{
320return -1;
321}
322bzero(buf,MAX_BLOCK_SIZE);
323
324/*
325 * Read the boot sector, check signatures, and do some minimal
326 * sanity checking. NOTE: the size of the read below is intended
327 * to be a multiple of all supported block sizes, so we don't
328 * have to determine or change the device's block size.
329 */
330Seek(ih, 0);
331Read(ih, (long)buf, MAX_BLOCK_SIZE);
332
333boot = (struct bootfile *) buf;
334
335// Check for NTFS signature
336if ( memcmp((void*)boot->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) != 0 )
337{
338// If not NTFS, maybe it is EXFAT
339free(buf);
340return EXFATGetUUID(ih, uuidStr);
341}
342
343// Check for non-null volume serial number
344if( !boot->bf_volsn )
345{
346free(buf);
347return -1;
348}
349
350free(buf);
351
352sprintf(sero,"%016llx",boot->bf_volsn);
353
354sprintf(sero,"%c%c%c%c-%c%c%c%c-%c%c%c%c-%c%c%c%c",sero[0],sero[1],sero[2],sero[3],sero[4],sero[5],sero[6],sero[7],sero[8],sero[9],sero[10],sero[11],sero[12],sero[13],sero[14],sero[15]);
355
356verbose("Numero de Serie %s\n " ,sero);
357
358mftOffset = (boot->bf_mftcn * boot->bf_bps * boot->bf_spc);
359
360bzero((void*)bufff,32);
361
362bzero(uuidStr,40);
363
364Seek(ih, mftOffset);
365
366Read(ih, (long)bufff, 5);
367
368if((unsigned char )bufff[4]==0x30) {
369mftOffset = (mftOffset + 3352);
370} else {
371mftOffset = (mftOffset + 3320);
372}
373
374bzero((void*)bufff,32);
375
376Seek(ih, mftOffset);
377
378Read(ih, (long)bufff,16);
379
380snprintf(uuidStr,
381 37,
382 "%02X%02X%02X%02X-"
383 "%02X%02X-"
384 "%02X%02X-"
385
386 "%02X%02X-"
387 "%02X%02X%02X%02X%02X%02X",
388 bufff[3], bufff[2], bufff[1], bufff[0],
389 bufff[5], bufff[4],
390 bufff[7], bufff[6],
391 bufff[8], bufff[9],
392 bufff[10], bufff[11], bufff[12], bufff[13], bufff[14], bufff[15]);
393
394verbose("UUID : %s\n\n" ,uuidStr);
395
396return 0;
397}
398
399bool NTFSProbe(const void *buffer)
400{
401bool result = false;
402
403const struct bootfile *part_bootfile = buffer;// NTFS boot sector structure
404
405// Looking for NTFS signature.
406if (strncmp((const char *)part_bootfile->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) == 0)
407{
408result = true;
409}
410
411// If not NTFS, maybe it is EXFAT
412if (!result)
413{
414result = EXFATProbe(buffer);
415}
416
417return result;
418}
419

Archive Download this file

Revision: 2912