Root/
Source at commit 2381 created 10 years 21 days ago. By ifabio, Apply patch: (Credits to Thomas Jansen aka tja) - Reading options from all devices during boot. The options for the boot menu are only read from the devices rd(0,0) or bt(0,0). Consequently, boot menu options (e.g. "Quiet Boot", "Timeout", etc.) in plists on other devices (like most users have) are ignored. This patch extends the list of paths to search for the options plist on all devices that can be found. | |
---|---|
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_SIZE␉␉2048␊ |
42 | #define MAX_CLUSTER_SIZE␉32768␊ |
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 | */␊ |
57 | static int␊ |
58 | ntfs_fixup(␊ |
59 | char *buf,␊ |
60 | size_t len,␊ |
61 | u_int32_t magic,␊ |
62 | u_int32_t bytesPerSector)␊ |
63 | {␊ |
64 | ␉struct fixuphdr *fhp = (struct fixuphdr *) buf;␊ |
65 | ␉int i;␊ |
66 | ␉u_int16_t fixup;␊ |
67 | ␉u_int16_t *fxp;␊ |
68 | ␉u_int16_t *cfxp;␊ |
69 | u_int32_t␉fixup_magic;␊ |
70 | u_int16_t␉fixup_count;␊ |
71 | u_int16_t␉fixup_offset;␊ |
72 | ␊ |
73 | fixup_magic = OSReadLittleInt32(&fhp->fh_magic,0);␊ |
74 | ␉if (fixup_magic != magic) {␊ |
75 | ␉␉error("ntfs_fixup: magic doesn't match: %08x != %08x\n",␊ |
76 | ␉␉ fixup_magic, magic);␊ |
77 | ␉␉return (ERROR);␊ |
78 | ␉}␊ |
79 | fixup_count = OSReadLittleInt16(&fhp->fh_fnum,0);␊ |
80 | ␉if ((fixup_count - 1) * bytesPerSector != len) {␊ |
81 | ␉␉error("ntfs_fixup: " \␊ |
82 | ␉␉ "bad fixups number: %d for %ld bytes block\n", ␊ |
83 | ␉␉ fixup_count, (long)len);␉/* XXX printf kludge */␊ |
84 | ␉␉return (ERROR);␊ |
85 | ␉}␊ |
86 | fixup_offset = OSReadLittleInt16(&fhp->fh_foff,0);␊ |
87 | ␉if (fixup_offset >= len) {␊ |
88 | ␉␉error("ntfs_fixup: invalid offset: %x", fixup_offset);␊ |
89 | ␉␉return (ERROR);␊ |
90 | ␉}␊ |
91 | ␉fxp = (u_int16_t *) (buf + fixup_offset);␊ |
92 | ␉cfxp = (u_int16_t *) (buf + bytesPerSector - 2);␊ |
93 | ␉fixup = *fxp++;␊ |
94 | ␉for (i = 1; i < fixup_count; i++, fxp++) {␊ |
95 | ␉␉if (*cfxp != fixup) {␊ |
96 | ␉␉␉error("ntfs_fixup: fixup %d doesn't match\n", i);␊ |
97 | ␉␉␉return (ERROR);␊ |
98 | ␉␉}␊ |
99 | ␉␉*cfxp = *fxp;␊ |
100 | cfxp = (u_int16_t *)(((caddr_t)cfxp) + bytesPerSector);␊ |
101 | ␉}␊ |
102 | ␉return (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 | */␊ |
109 | static int␊ |
110 | ntfs_find_attr(␊ |
111 | char *buf,␊ |
112 | u_int32_t attrType,␊ |
113 | void **attrData,␊ |
114 | size_t *attrSize)␊ |
115 | {␊ |
116 | struct filerec *filerec;␊ |
117 | struct attr *attr;␊ |
118 | u_int16_t offset;␊ |
119 | ␊ |
120 | filerec = (struct filerec *) buf;␊ |
121 | offset = OSReadLittleInt16(&filerec->fr_attroff,0);␊ |
122 | attr = (struct attr *) (buf + offset);␊ |
123 | ␊ |
124 | |
125 | while (attr->a_hdr.a_type != 0xFFFFFFFF)␉/* same for big/little endian */␊ |
126 | {␊ |
127 | if (OSReadLittleInt32(&attr->a_hdr.a_type,0) == attrType)␊ |
128 | {␊ |
129 | if (attr->a_hdr.a_flag != 0)␊ |
130 | {␊ |
131 | //verbose("NTFS: attriubte 0x%X is non-resident\n", attrType);␊ |
132 | return 1;␊ |
133 | }␊ |
134 | ␊ |
135 | *attrSize = OSReadLittleInt16(&attr->a_r.a_datalen,0);␊ |
136 | *attrData = buf + offset + OSReadLittleInt16(&attr->a_r.a_dataoff,0);␊ |
137 | return 0;␉/* found it! */␊ |
138 | }␊ |
139 | ␊ |
140 | /* Skip to the next attribute */␊ |
141 | offset += OSReadLittleInt32(&attr->a_hdr.reclen,0);␊ |
142 | attr = (struct attr *) (buf + offset);␊ |
143 | }␊ |
144 | ␊ |
145 | return 1;␉/* No matching attrType found */␊ |
146 | }␊ |
147 | ␊ |
148 | /*␊ |
149 | * Examine a volume to see if we recognize it as a mountable.␊ |
150 | */␊ |
151 | void␊ |
152 | NTFSGetDescription(CICell ih, char *str, long strMaxLen)␊ |
153 | {␊ |
154 | struct bootfile *boot;␊ |
155 | unsigned bytesPerSector;␊ |
156 | unsigned sectorsPerCluster;␊ |
157 | int mftRecordSize;␊ |
158 | u_int64_t totalClusters;␊ |
159 | u_int64_t cluster, mftCluster;␊ |
160 | size_t mftOffset;␊ |
161 | void *nameAttr;␊ |
162 | size_t nameSize;␊ |
163 | char *buf;␊ |
164 | ␊ |
165 | buf = (char *)malloc(MAX_CLUSTER_SIZE);␊ |
166 | if (buf == 0) {␊ |
167 | goto 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 | */␊ |
176 | Seek(ih, 0);␊ |
177 | Read(ih, (long)buf, MAX_BLOCK_SIZE);␊ |
178 | ␊ |
179 | boot = (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 | */␊ |
188 | if (boot->reserved1[0] != 0xE9␊ |
189 | && (boot->reserved1[0] != 0xEB || boot->reserved1[2] != 0x90))␊ |
190 | {␊ |
191 | goto error;␊ |
192 | }␊ |
193 | ␊ |
194 | /*␊ |
195 | * Check the "NTFS " signature.␊ |
196 | */␊ |
197 | if (memcmp((const char *)boot->bf_sysid, "NTFS ", 8) != 0)␊ |
198 | {␊ |
199 | /*␊ |
200 | * Check for EXFAT. Finish by jumping to error to free buf,␊ |
201 | * although if it is EXFAT then it's no an error.␊ |
202 | */␊ |
203 | EXFATGetDescription(ih, str, strMaxLen);␊ |
204 | goto error;␊ |
205 | }␊ |
206 | ␊ |
207 | /*␊ |
208 | * Make sure the bytes per sector and sectors per cluster are␊ |
209 | * powers of two, and within reasonable ranges.␊ |
210 | */␊ |
211 | bytesPerSector = OSReadLittleInt16(&boot->bf_bps,0);␊ |
212 | if ((bytesPerSector & (bytesPerSector-1)) || bytesPerSector < 512 || bytesPerSector > 32768)␊ |
213 | {␊ |
214 | //verbose("NTFS: invalid bytes per sector (%d)\n", bytesPerSector);␊ |
215 | goto error;␊ |
216 | }␊ |
217 | ␊ |
218 | sectorsPerCluster = boot->bf_spc;␉/* Just one byte; no swapping needed */␊ |
219 | if ((sectorsPerCluster & (sectorsPerCluster-1)) || sectorsPerCluster > 128)␊ |
220 | {␊ |
221 | //verbose("NTFS: invalid sectors per cluster (%d)\n", bytesPerSector);␊ |
222 | goto error;␊ |
223 | }␊ |
224 | ␊ |
225 | /*␊ |
226 | * Calculate the number of clusters from the number of sectors.␊ |
227 | * Then bounds check the $MFT and $MFTMirr clusters.␊ |
228 | */␊ |
229 | totalClusters = OSReadLittleInt64(&boot->bf_spv,0) / sectorsPerCluster;␊ |
230 | mftCluster = OSReadLittleInt64(&boot->bf_mftcn,0);␊ |
231 | if (mftCluster > totalClusters)␊ |
232 | {␊ |
233 | ////verbose("NTFS: invalid $MFT cluster (%lld)\n", mftCluster);␊ |
234 | goto error;␊ |
235 | }␊ |
236 | cluster = OSReadLittleInt64(&boot->bf_mftmirrcn,0);␊ |
237 | if (cluster > totalClusters)␊ |
238 | {␊ |
239 | //verbose("NTFS: invalid $MFTMirr cluster (%lld)\n", cluster);␊ |
240 | goto error;␊ |
241 | }␊ |
242 | ␊ |
243 | /*␊ |
244 | * Determine the size of an MFT record.␊ |
245 | */␊ |
246 | mftRecordSize = (int8_t) boot->bf_mftrecsz;␊ |
247 | if (mftRecordSize < 0)␊ |
248 | mftRecordSize = 1 << -mftRecordSize;␊ |
249 | else␊ |
250 | mftRecordSize *= bytesPerSector * sectorsPerCluster;␊ |
251 | //verbose("NTFS: MFT record size = %d\n", mftRecordSize);␊ |
252 | ␊ |
253 | /*␊ |
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.␊ |
257 | *␊ |
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.␊ |
261 | */␊ |
262 | mftOffset = mftCluster * sectorsPerCluster * bytesPerSector;␊ |
263 | mftOffset += mftRecordSize * NTFS_VOLUMEINO;␊ |
264 | ␊ |
265 | Seek(ih, mftOffset);␊ |
266 | Read(ih, (long)buf, mftRecordSize);␊ |
267 | #if UNUSED␊ |
268 | if (lseek(fd, mftOffset, SEEK_SET) == -1)␊ |
269 | {␊ |
270 | //verbose("NTFS: lseek to $Volume failed: %s\n", strerror(errno));␊ |
271 | goto error;␊ |
272 | }␊ |
273 | if (read(fd, buf, mftRecordSize) != mftRecordSize)␊ |
274 | {␊ |
275 | //verbose("NTFS: error reading MFT $Volume record: %s\n",␊ |
276 | strerror(errno));␊ |
277 | goto error;␊ |
278 | }␊ |
279 | #endif␊ |
280 | ␊ |
281 | if (ntfs_fixup(buf, mftRecordSize, NTFS_FILEMAGIC, bytesPerSector) != 0)␊ |
282 | {␊ |
283 | //verbose("NTFS: block fixup failed\n");␊ |
284 | goto error;␊ |
285 | }␊ |
286 | ␊ |
287 | /*␊ |
288 | * Loop over the attributes, looking for $VOLUME_NAME (0x60).␊ |
289 | */␊ |
290 | if(ntfs_find_attr(buf, NTFS_A_VOLUMENAME, &nameAttr, &nameSize) != 0)␊ |
291 | {␊ |
292 | //verbose("NTFS: $VOLUME_NAME attribute not found\n");␊ |
293 | goto error;␊ |
294 | }␊ |
295 | ␊ |
296 | str[0] = '\0';␊ |
297 | ␊ |
298 | utf_encodestr( nameAttr, nameSize / 2, (u_int8_t *)str, strMaxLen, OSLittleEndian );␊ |
299 | ␊ |
300 | free(buf);␊ |
301 | return;␊ |
302 | ␊ |
303 | error:␊ |
304 | if (buf) free(buf);␊ |
305 | return;␊ |
306 | }␊ |
307 | ␊ |
308 | long NTFSGetUUID(CICell ih, char *uuidStr)␊ |
309 | {␊ |
310 | ␉bool NTFSProbe(const void*);␊ |
311 | ␊ |
312 | ␉struct bootfile *boot;␊ |
313 | ␉void *buf = malloc(MAX_BLOCK_SIZE);␊ |
314 | ␉if ( !buf )␊ |
315 | ␉␉return -1;␊ |
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 | ␉ */␊ |
323 | ␉Seek(ih, 0);␊ |
324 | ␉Read(ih, (long)buf, MAX_BLOCK_SIZE);␊ |
325 | ␊ |
326 | ␉boot = (struct bootfile *) buf;␊ |
327 | ␊ |
328 | ␉// Check for NTFS signature␊ |
329 | ␉if ( memcmp((void*)boot->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) != 0 ) {␊ |
330 | ␉␉// If not NTFS, maybe it is EXFAT␊ |
331 | ␉␉return EXFATGetUUID(ih, uuidStr);␊ |
332 | ␉}␊ |
333 | ␊ |
334 | ␉// Check for non-null volume serial number␊ |
335 | ␉if( !boot->bf_volsn )␊ |
336 | ␉␉return -1;␊ |
337 | ␊ |
338 | ␉// Use UUID like the one you get on Windows␊ |
339 | ␉sprintf(uuidStr, "%04X-%04X",␉(unsigned short)(boot->bf_volsn >> 16) & 0xFFFF,␊ |
340 | ␉␉␉␉␉␉␉␉␉(unsigned short)boot->bf_volsn & 0xFFFF);␊ |
341 | ␊ |
342 | ␉return 0;␊ |
343 | } ␊ |
344 | ␊ |
345 | bool NTFSProbe(const void * buffer)␊ |
346 | {␊ |
347 | ␉bool result = false;␊ |
348 | ␉␊ |
349 | ␉const struct bootfile␉* part_bootfile = buffer;␉␉␉// NTFS boot sector structure␊ |
350 | ␉␊ |
351 | ␉// Looking for NTFS signature.␊ |
352 | ␉if (strncmp((const char *)part_bootfile->bf_sysid, NTFS_BBID, NTFS_BBIDLEN) == 0)␊ |
353 | ␉␉result = true;␊ |
354 | ␉␊ |
355 | ␉// If not NTFS, maybe it is EXFAT␊ |
356 | ␉if (!result)␊ |
357 | ␉␉result = EXFATProbe(buffer);␊ |
358 | ␉␊ |
359 | ␉return result;␊ |
360 | }␊ |
361 |