Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/libsaio/ntfs.c

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

Archive Download this file

Revision: 536