]>
git.saurik.com Git - apple/boot.git/blob - i386/libsaio/ntfs.c
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2004 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
29 #define BYTE_ORDER_MARK 0xFEFF
31 #include "ntfs_private.h"
33 #define FS_TYPE "ntfs"
34 #define FS_NAME_FILE "NTFS"
36 #define MAX_BLOCK_SIZE 2048
37 #define MAX_CLUSTER_SIZE 32768
39 #define LABEL_LENGTH 1024
40 #define UNKNOWN_LABEL "Untitled NTFS"
42 #define FSUR_IO_FAIL -1
43 #define FSUR_UNRECOGNIZED -1
44 #define FSUR_RECOGNIZED 0
49 * Process per-sector "fixups" that NTFS uses to detect corruption of
50 * multi-sector data structures, like MFT records.
57 u_int32_t bytesPerSector
)
59 struct fixuphdr
*fhp
= (struct fixuphdr
*) buf
;
64 u_int32_t fixup_magic
;
65 u_int16_t fixup_count
;
66 u_int16_t fixup_offset
;
68 fixup_magic
= OSReadLittleInt32(&fhp
->fh_magic
,0);
69 if (fixup_magic
!= magic
) {
70 error("ntfs_fixup: magic doesn't match: %08x != %08x\n",
74 fixup_count
= OSReadLittleInt16(&fhp
->fh_fnum
,0);
75 if ((fixup_count
- 1) * bytesPerSector
!= len
) {
76 error("ntfs_fixup: " \
77 "bad fixups number: %d for %ld bytes block\n",
78 fixup_count
, (long)len
); /* XXX printf kludge */
81 fixup_offset
= OSReadLittleInt16(&fhp
->fh_foff
,0);
82 if (fixup_offset
>= len
) {
83 error("ntfs_fixup: invalid offset: %x", fixup_offset
);
86 fxp
= (u_int16_t
*) (buf
+ fixup_offset
);
87 cfxp
= (u_int16_t
*) (buf
+ bytesPerSector
- 2);
89 for (i
= 1; i
< fixup_count
; i
++, fxp
++) {
91 error("ntfs_fixup: fixup %d doesn't match\n", i
);
95 cfxp
= (u_int16_t
*)(((caddr_t
)cfxp
) + bytesPerSector
);
101 * Find a resident attribute of a given type. Returns a pointer to the
102 * attribute data, and its size in bytes.
111 struct filerec
*filerec
;
115 filerec
= (struct filerec
*) buf
;
116 offset
= OSReadLittleInt16(&filerec
->fr_attroff
,0);
117 attr
= (struct attr
*) (buf
+ offset
);
119 /*¥¥ Should we also check offset < buffer size? */
120 while (attr
->a_hdr
.a_type
!= 0xFFFFFFFF) /* same for big/little endian */
122 if (OSReadLittleInt32(&attr
->a_hdr
.a_type
,0) == attrType
)
124 if (attr
->a_hdr
.a_flag
!= 0)
126 //verbose("NTFS: attriubte 0x%X is non-resident\n", attrType);
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! */
135 /* Skip to the next attribute */
136 offset
+= OSReadLittleInt32(&attr
->a_hdr
.reclen
,0);
137 attr
= (struct attr
*) (buf
+ offset
);
140 return 1; /* No matching attrType found */
144 memcmp(const char *p1
, const char *p2
, int len
)
154 * Examine a volume to see if we recognize it as a mountable.
157 NTFSGetDescription(CICell ih
, char *str
, long strMaxLen
)
159 struct bootfile
*boot
;
160 unsigned bytesPerSector
;
161 unsigned sectorsPerCluster
;
163 u_int64_t totalClusters
;
164 u_int64_t cluster
, mftCluster
;
170 buf
= (char *)malloc(MAX_CLUSTER_SIZE
);
176 * Read the boot sector, check signatures, and do some minimal
177 * sanity checking. NOTE: the size of the read below is intended
178 * to be a multiple of all supported block sizes, so we don't
179 * have to determine or change the device's block size.
182 Read(ih
, (long)buf
, MAX_BLOCK_SIZE
);
184 boot
= (struct bootfile
*) buf
;
187 * The first three bytes are an Intel x86 jump instruction. I assume it
188 * can be the same forms as DOS FAT:
191 * where 0x?? means any byte value is OK.
193 if (boot
->reserved1
[0] != 0xE9
194 && (boot
->reserved1
[0] != 0xEB || boot
->reserved1
[2] != 0x90))
200 * Check the "NTFS " signature.
202 if (memcmp((const char *)boot
->bf_sysid
, "NTFS ", 8) != 0)
208 * Make sure the bytes per sector and sectors per cluster are
209 * powers of two, and within reasonable ranges.
211 bytesPerSector
= OSReadLittleInt16(&boot
->bf_bps
,0);
212 if ((bytesPerSector
& (bytesPerSector
-1)) || bytesPerSector
< 512 || bytesPerSector
> 32768)
214 //verbose("NTFS: invalid bytes per sector (%d)\n", bytesPerSector);
218 sectorsPerCluster
= boot
->bf_spc
; /* Just one byte; no swapping needed */
219 if ((sectorsPerCluster
& (sectorsPerCluster
-1)) || sectorsPerCluster
> 128)
221 //verbose("NTFS: invalid sectors per cluster (%d)\n", bytesPerSector);
226 * Calculate the number of clusters from the number of sectors.
227 * Then bounds check the $MFT and $MFTMirr clusters.
229 totalClusters
= OSReadLittleInt64(&boot
->bf_spv
,0) / sectorsPerCluster
;
230 mftCluster
= OSReadLittleInt64(&boot
->bf_mftcn
,0);
231 if (mftCluster
> totalClusters
)
233 ////verbose("NTFS: invalid $MFT cluster (%lld)\n", mftCluster);
236 cluster
= OSReadLittleInt64(&boot
->bf_mftmirrcn
,0);
237 if (cluster
> totalClusters
)
239 //verbose("NTFS: invalid $MFTMirr cluster (%lld)\n", cluster);
244 * Determine the size of an MFT record.
246 mftRecordSize
= (int8_t) boot
->bf_mftrecsz
;
247 if (mftRecordSize
< 0)
248 mftRecordSize
= 1 << -mftRecordSize
;
250 mftRecordSize
*= bytesPerSector
* sectorsPerCluster
;
251 //verbose("NTFS: MFT record size = %d\n", mftRecordSize);
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.
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.
262 mftOffset
= mftCluster
* sectorsPerCluster
* bytesPerSector
;
263 mftOffset
+= mftRecordSize
* NTFS_VOLUMEINO
;
266 Read(ih
, (long)buf
, mftRecordSize
);
268 if (lseek(fd
, mftOffset
, SEEK_SET
) == -1)
270 //verbose("NTFS: lseek to $Volume failed: %s\n", strerror(errno));
273 if (read(fd
, buf
, mftRecordSize
) != mftRecordSize
)
275 //verbose("NTFS: error reading MFT $Volume record: %s\n",
281 if (ntfs_fixup(buf
, mftRecordSize
, NTFS_FILEMAGIC
, bytesPerSector
) != 0)
283 //verbose("NTFS: block fixup failed\n");
288 * Loop over the attributes, looking for $VOLUME_NAME (0x60).
290 if(ntfs_find_attr(buf
, NTFS_A_VOLUMENAME
, &nameAttr
, &nameSize
) != 0)
292 //verbose("NTFS: $VOLUME_NAME attribute not found\n");
298 utf_encodestr( nameAttr
, nameSize
/ 2, (u_int8_t
*)str
, strMaxLen
, OSLittleEndian
);