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