Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 515