]>
Commit | Line | Data |
---|---|---|
04fee52e | 1 | /* |
873b6fa6 | 2 | * Copyright (c) 2000-2007 Apple Inc. All rights reserved. |
04fee52e | 3 | * |
873b6fa6 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
04fee52e | 5 | * |
873b6fa6 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
04fee52e | 14 | * |
873b6fa6 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
04fee52e A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
873b6fa6 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
04fee52e | 25 | * |
873b6fa6 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
04fee52e | 27 | */ |
873b6fa6 | 28 | |
04fee52e A |
29 | /* |
30 | * fs.c - Generic access to the file system modules. | |
31 | * | |
8be739c0 | 32 | * Copyright (c) 1999-2004 Apple Computer, Inc. |
04fee52e A |
33 | * |
34 | * DRI: Josh de Cesare | |
35 | */ | |
36 | ||
37 | #include <sl.h> | |
873b6fa6 | 38 | #include "md5.h" |
04fee52e A |
39 | |
40 | typedef long (* FSLoadFile)(CICell ih, char *filePath); | |
8be739c0 A |
41 | typedef long (* FSReadFile)(CICell ih, char *filePath, |
42 | void *base, unsigned long offset, | |
43 | unsigned long length); | |
04fee52e | 44 | typedef long (* FSGetDirEntry)(CICell ih, char *dirPath, |
873b6fa6 | 45 | unsigned long *dirIndex, char **name, |
04fee52e | 46 | long *flags, long *time); |
8be739c0 | 47 | typedef long (* FSGetUUID)(CICell ih, char *uuidStr); |
04fee52e A |
48 | |
49 | #define kPartNet (0) | |
50 | #define kPartHFS (1) | |
51 | #define kPartUFS (2) | |
52 | #define kPartExt2 (3) | |
53 | ||
54 | struct PartInfo { | |
55 | long partType; | |
56 | CICell partIH; | |
57 | FSLoadFile loadFile; | |
8be739c0 | 58 | FSReadFile readFile; |
04fee52e | 59 | FSGetDirEntry getDirEntry; |
8be739c0 | 60 | FSGetUUID getUUID; |
04fee52e A |
61 | char partName[1024]; |
62 | }; | |
63 | typedef struct PartInfo PartInfo, *PartInfoPtr; | |
64 | ||
65 | #define kNumPartInfos (16) | |
66 | static PartInfo gParts[kNumPartInfos]; | |
b1faa321 | 67 | static char gMakeDirSpec[1024]; |
04fee52e A |
68 | |
69 | // Private function prototypes | |
70 | long LookupPartition(char *devSpec); | |
71 | ||
72 | ||
73 | // Public functions | |
74 | ||
75 | long LoadFile(char *fileSpec) | |
76 | { | |
77 | char devSpec[256]; | |
78 | char *filePath; | |
79 | FSLoadFile loadFile; | |
80 | long ret, length, partIndex; | |
81 | ||
82 | ret = ConvertFileSpec(fileSpec, devSpec, &filePath); | |
83 | if ((ret == -1) || (filePath == NULL)) return -1; | |
84 | ||
85 | // Get the partition index for devSpec. | |
86 | partIndex = LookupPartition(devSpec); | |
87 | if (partIndex == -1) return -1; | |
88 | ||
89 | loadFile = gParts[partIndex].loadFile; | |
90 | length = loadFile(gParts[partIndex].partIH, filePath); | |
91 | ||
92 | // if (length == 0) return -1; | |
93 | ||
94 | return length; | |
95 | } | |
96 | ||
8be739c0 A |
97 | long LoadThinFatFile(char *fileSpec, void **binary) |
98 | { | |
99 | char devSpec[256]; | |
100 | char *filePath; | |
101 | FSLoadFile loadFile; | |
102 | FSReadFile readFile; | |
103 | long ret, length, length2, partIndex; | |
104 | ||
105 | ret = ConvertFileSpec(fileSpec, devSpec, &filePath); | |
106 | if ((ret == -1) || (filePath == NULL)) return -1; | |
107 | ||
108 | // Get the partition index for devSpec. | |
109 | partIndex = LookupPartition(devSpec); | |
110 | if (partIndex == -1) return -1; | |
111 | ||
112 | *binary = (void *)kLoadAddr; | |
113 | ||
114 | readFile = gParts[partIndex].readFile; | |
115 | ||
116 | if (readFile != NULL) { | |
117 | // Read the first 4096 bytes (fat header) | |
118 | length = readFile(gParts[partIndex].partIH, filePath, *binary, 0, 0x1000); | |
119 | if (length > 0) { | |
120 | if (ThinFatBinary(binary, &length) == 0) { | |
121 | // We found a fat binary; read only the thin part | |
122 | length = readFile(gParts[partIndex].partIH, filePath, | |
123 | (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length); | |
124 | *binary = (void *)kLoadAddr; | |
125 | } else { | |
126 | // Not a fat binary; read the rest of the file | |
127 | length2 = readFile(gParts[partIndex].partIH, filePath, (void *)(kLoadAddr + length), length, 0); | |
128 | if (length2 == -1) return -1; | |
129 | length += length2; | |
130 | } | |
131 | } | |
132 | } else { | |
133 | loadFile = gParts[partIndex].loadFile; | |
134 | length = loadFile(gParts[partIndex].partIH, filePath); | |
135 | if (length > 0) { | |
136 | ThinFatBinary(binary, &length); | |
137 | } | |
138 | } | |
139 | ||
140 | return length; | |
141 | } | |
142 | ||
143 | long GetFSUUID(char *spec, char *uuidStr) | |
144 | { | |
145 | long rval = -1, partIndex; | |
146 | FSGetUUID getUUID; | |
147 | char devSpec[256]; | |
148 | ||
149 | do { | |
150 | if(ConvertFileSpec(spec, devSpec, NULL)) break; | |
151 | ||
152 | // Get the partition index | |
153 | partIndex = LookupPartition(devSpec); | |
154 | if (partIndex == -1) break; | |
155 | ||
156 | getUUID = gParts[partIndex].getUUID; | |
157 | if(getUUID) | |
158 | rval = getUUID(gParts[partIndex].partIH, uuidStr); | |
159 | } while(0); | |
160 | ||
161 | return rval; | |
162 | } | |
163 | ||
164 | ||
165 | // from our uuid/namespace.h (UFS and HFS uuids can live in the same space?) | |
873b6fa6 | 166 | static unsigned char kFSUUIDNamespaceSHA1[] = {0xB3,0xE2,0x0F,0x39,0xF2,0x92,0x11,0xD6,0x97,0xA4,0x00,0x30,0x65,0x43,0xEC,0xAC}; |
8be739c0 A |
167 | |
168 | // filesystem-specific getUUID functions call this shared string generator | |
169 | long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr) | |
170 | { | |
171 | unsigned fmtbase, fmtidx, i; | |
172 | uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 }; | |
173 | char *p = uuidStr; | |
174 | MD5_CTX md5c; | |
175 | uint8_t mdresult[16]; | |
176 | ||
177 | bzero(mdresult, sizeof(mdresult)); | |
178 | ||
179 | // just like AppleFileSystemDriver | |
180 | MD5Init(&md5c); | |
181 | MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1)); | |
182 | MD5Update(&md5c, uubytes, nbytes); | |
183 | MD5Final(mdresult, &md5c); | |
184 | ||
185 | // this UUID has been made version 3 style (i.e. via namespace) | |
186 | // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte) | |
187 | mdresult[6] = 0x30 | ( mdresult[6] & 0x0F ); | |
188 | mdresult[8] = 0x80 | ( mdresult[8] & 0x3F ); | |
189 | ||
190 | ||
191 | // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292 | |
192 | i = 0; fmtbase = 0; | |
193 | for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) { | |
194 | for(i=0; i < uuidfmt[fmtidx]; i++) { | |
195 | uint8_t byte = mdresult[fmtbase+i]; | |
196 | char nib; | |
197 | ||
198 | nib = byte >> 4; | |
199 | *p = nib + '0'; // 0x4 -> '4' | |
200 | if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B' | |
201 | p++; | |
202 | ||
203 | nib = byte & 0xf; | |
204 | *p = nib + '0'; // 0x4 -> '4' | |
205 | if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B' | |
206 | p++; | |
207 | ||
208 | } | |
209 | fmtbase += i; | |
210 | if(fmtidx < sizeof(uuidfmt)-1) | |
211 | *(p++) = '-'; | |
212 | else | |
213 | *p = '\0'; | |
214 | } | |
215 | ||
216 | return 0; | |
217 | } | |
218 | ||
04fee52e A |
219 | long GetFileInfo(char *dirSpec, char *name, long *flags, long *time) |
220 | { | |
873b6fa6 A |
221 | long ret; |
222 | unsigned long index = 0; | |
04fee52e | 223 | char *curName; |
b1faa321 A |
224 | |
225 | if (!dirSpec) { | |
226 | long idx, len; | |
227 | ||
228 | len = strlen(name); | |
229 | ||
230 | for (idx = len; idx && (name[idx] != '\\'); idx--) {} | |
231 | idx++; | |
232 | strncpy(gMakeDirSpec, name, idx); | |
233 | name += idx; | |
234 | dirSpec = gMakeDirSpec; | |
235 | } | |
04fee52e A |
236 | |
237 | while (1) { | |
238 | ret = GetDirEntry(dirSpec, &index, &curName, flags, time); | |
239 | if (ret == -1) break; | |
240 | ||
241 | if (!strcmp(name, curName)) break; | |
242 | } | |
243 | ||
244 | return ret; | |
245 | } | |
246 | ||
873b6fa6 | 247 | long GetDirEntry(char *dirSpec, unsigned long *dirIndex, char **name, |
04fee52e A |
248 | long *flags, long *time) |
249 | { | |
250 | char devSpec[256]; | |
251 | char *dirPath; | |
252 | FSGetDirEntry getDirEntry; | |
253 | long ret, partIndex; | |
254 | ||
255 | ret = ConvertFileSpec(dirSpec, devSpec, &dirPath); | |
256 | if ((ret == -1) || (dirPath == NULL)) return -1; | |
257 | ||
258 | // Get the partition index for devSpec. | |
259 | partIndex = LookupPartition(devSpec); | |
260 | if (partIndex == -1) return -1; | |
261 | ||
262 | getDirEntry = gParts[partIndex].getDirEntry; | |
263 | ret = getDirEntry(gParts[partIndex].partIH, dirPath, | |
264 | dirIndex, name, flags, time); | |
265 | ||
266 | return ret; | |
267 | } | |
268 | ||
269 | long DumpDir(char *dirSpec) | |
270 | { | |
873b6fa6 A |
271 | long ret, flags, time; |
272 | unsigned long index = 0; | |
04fee52e A |
273 | char *name; |
274 | ||
275 | printf("DumpDir on [%s]\n", dirSpec); | |
276 | ||
277 | while (1) { | |
278 | ret = GetDirEntry(dirSpec, &index, &name, &flags, &time); | |
279 | if (ret == -1) break; | |
280 | ||
281 | printf("%x %x [%s]\n", flags, time, name); | |
282 | } | |
283 | ||
284 | return 0; | |
285 | } | |
286 | ||
287 | ||
288 | // Private functions | |
289 | ||
290 | long LookupPartition(char *devSpec) | |
291 | { | |
292 | CICell partIH; | |
293 | long partIndex, partType; | |
294 | long deviceType; | |
295 | ||
296 | // See if the devSpec has already been opened. | |
297 | for (partIndex = 0; partIndex < kNumPartInfos; partIndex++) { | |
298 | if (!strcmp(gParts[partIndex].partName, devSpec)) break; | |
299 | } | |
300 | ||
301 | // If it has not been opened, do so now. | |
302 | if (partIndex == kNumPartInfos) { | |
303 | // Find a free slot. | |
304 | for (partIndex = 0; partIndex < kNumPartInfos; partIndex++) { | |
305 | if (gParts[partIndex].partIH == 0) break; | |
306 | } | |
307 | // No free slots, so return error. | |
308 | if (partIndex == kNumPartInfos) return -1; | |
309 | ||
310 | deviceType = GetDeviceType(devSpec); | |
311 | switch (deviceType) { | |
312 | case kNetworkDeviceType : | |
313 | partIH = NetInitPartition(devSpec); | |
314 | if (partIH == 0) return -1; | |
315 | partType = kPartNet; | |
316 | break; | |
317 | ||
318 | case kBlockDeviceType : | |
319 | printf("Opening partition [%s]...\n", devSpec); | |
320 | partIH = Open(devSpec); | |
321 | if (partIH == 0) { | |
322 | printf("Failed to open partition [%s].\n", devSpec); | |
323 | return -1; | |
324 | } | |
325 | ||
326 | // Find out what kind of partition it is. | |
327 | if (HFSInitPartition(partIH) != -1) partType = kPartHFS; | |
328 | else if (UFSInitPartition(partIH) != -1) partType = kPartUFS; | |
329 | else if (Ext2InitPartition(partIH) != -1) partType = kPartExt2; | |
330 | else return -1; | |
331 | break; | |
332 | ||
333 | default : | |
334 | return -1; | |
335 | } | |
336 | ||
337 | gParts[partIndex].partIH = partIH; | |
338 | gParts[partIndex].partType = partType; | |
339 | strcpy(gParts[partIndex].partName, devSpec); | |
340 | ||
341 | switch (partType) { | |
342 | case kPartNet: | |
343 | gParts[partIndex].loadFile = NetLoadFile; | |
8be739c0 | 344 | gParts[partIndex].readFile = NULL; |
04fee52e | 345 | gParts[partIndex].getDirEntry = NetGetDirEntry; |
8be739c0 | 346 | gParts[partIndex].getUUID = NULL; |
04fee52e A |
347 | break; |
348 | ||
349 | case kPartHFS: | |
350 | gParts[partIndex].loadFile = HFSLoadFile; | |
8be739c0 | 351 | gParts[partIndex].readFile = HFSReadFile; |
04fee52e | 352 | gParts[partIndex].getDirEntry = HFSGetDirEntry; |
8be739c0 | 353 | gParts[partIndex].getUUID = HFSGetUUID; |
04fee52e A |
354 | break; |
355 | ||
356 | case kPartUFS: | |
357 | gParts[partIndex].loadFile = UFSLoadFile; | |
8be739c0 | 358 | gParts[partIndex].readFile = UFSReadFile; |
04fee52e | 359 | gParts[partIndex].getDirEntry = UFSGetDirEntry; |
8be739c0 | 360 | gParts[partIndex].getUUID = UFSGetUUID; |
04fee52e A |
361 | break; |
362 | ||
363 | case kPartExt2: | |
364 | gParts[partIndex].loadFile = Ext2LoadFile; | |
8be739c0 | 365 | gParts[partIndex].readFile = NULL; |
04fee52e | 366 | gParts[partIndex].getDirEntry = Ext2GetDirEntry; |
8be739c0 A |
367 | gParts[partIndex].getUUID = NULL; |
368 | // Ext2GetUUID exists, but there's no kernel support | |
04fee52e A |
369 | break; |
370 | } | |
371 | } | |
372 | ||
373 | return partIndex; | |
374 | } |