2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * fs.c - Generic access to the file system modules.
25 * Copyright (c) 1999-2004 Apple Computer, Inc.
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
);
52 FSGetDirEntry getDirEntry
;
56 typedef struct PartInfo PartInfo
, *PartInfoPtr
;
58 #define kNumPartInfos (16)
59 static PartInfo gParts
[kNumPartInfos
];
60 static char gMakeDirSpec
[1024];
62 // Private function prototypes
63 long LookupPartition(char *devSpec
);
68 long LoadFile(char *fileSpec
)
73 long ret
, length
, partIndex
;
75 ret
= ConvertFileSpec(fileSpec
, devSpec
, &filePath
);
76 if ((ret
== -1) || (filePath
== NULL
)) return -1;
78 // Get the partition index for devSpec.
79 partIndex
= LookupPartition(devSpec
);
80 if (partIndex
== -1) return -1;
82 loadFile
= gParts
[partIndex
].loadFile
;
83 length
= loadFile(gParts
[partIndex
].partIH
, filePath
);
85 // if (length == 0) return -1;
90 long LoadThinFatFile(char *fileSpec
, void **binary
)
96 long ret
, length
, length2
, partIndex
;
98 ret
= ConvertFileSpec(fileSpec
, devSpec
, &filePath
);
99 if ((ret
== -1) || (filePath
== NULL
)) return -1;
101 // Get the partition index for devSpec.
102 partIndex
= LookupPartition(devSpec
);
103 if (partIndex
== -1) return -1;
105 *binary
= (void *)kLoadAddr
;
107 readFile
= gParts
[partIndex
].readFile
;
109 if (readFile
!= NULL
) {
110 // Read the first 4096 bytes (fat header)
111 length
= readFile(gParts
[partIndex
].partIH
, filePath
, *binary
, 0, 0x1000);
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
;
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;
126 loadFile
= gParts
[partIndex
].loadFile
;
127 length
= loadFile(gParts
[partIndex
].partIH
, filePath
);
129 ThinFatBinary(binary
, &length
);
136 long GetFSUUID(char *spec
, char *uuidStr
)
138 long rval
= -1, partIndex
;
143 if(ConvertFileSpec(spec
, devSpec
, NULL
)) break;
145 // Get the partition index
146 partIndex
= LookupPartition(devSpec
);
147 if (partIndex
== -1) break;
149 getUUID
= gParts
[partIndex
].getUUID
;
151 rval
= getUUID(gParts
[partIndex
].partIH
, uuidStr
);
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};
161 // filesystem-specific getUUID functions call this shared string generator
162 long CreateUUIDString(uint8_t uubytes
[], int nbytes
, char *uuidStr
)
164 unsigned fmtbase
, fmtidx
, i
;
165 uint8_t uuidfmt
[] = { 4, 2, 2, 2, 6 };
168 uint8_t mdresult
[16];
170 bzero(mdresult
, sizeof(mdresult
));
172 // just like AppleFileSystemDriver
174 MD5Update(&md5c
, kFSUUIDNamespaceSHA1
, sizeof(kFSUUIDNamespaceSHA1
));
175 MD5Update(&md5c
, uubytes
, nbytes
);
176 MD5Final(mdresult
, &md5c
);
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 );
184 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
186 for(fmtidx
= 0; fmtidx
< sizeof(uuidfmt
); fmtidx
++) {
187 for(i
=0; i
< uuidfmt
[fmtidx
]; i
++) {
188 uint8_t byte
= mdresult
[fmtbase
+i
];
192 *p
= nib
+ '0'; // 0x4 -> '4'
193 if(*p
> '9') *p
= (nib
- 9 + ('A'-1)); // 0xB -> 'B'
197 *p
= nib
+ '0'; // 0x4 -> '4'
198 if(*p
> '9') *p
= (nib
- 9 + ('A'-1)); // 0xB -> 'B'
203 if(fmtidx
< sizeof(uuidfmt
)-1)
212 long GetFileInfo(char *dirSpec
, char *name
, long *flags
, long *time
)
222 for (idx
= len
; idx
&& (name
[idx
] != '\\'); idx
--) {}
224 strncpy(gMakeDirSpec
, name
, idx
);
226 dirSpec
= gMakeDirSpec
;
230 ret
= GetDirEntry(dirSpec
, &index
, &curName
, flags
, time
);
231 if (ret
== -1) break;
233 if (!strcmp(name
, curName
)) break;
239 long GetDirEntry(char *dirSpec
, long *dirIndex
, char **name
,
240 long *flags
, long *time
)
244 FSGetDirEntry getDirEntry
;
247 ret
= ConvertFileSpec(dirSpec
, devSpec
, &dirPath
);
248 if ((ret
== -1) || (dirPath
== NULL
)) return -1;
250 // Get the partition index for devSpec.
251 partIndex
= LookupPartition(devSpec
);
252 if (partIndex
== -1) return -1;
254 getDirEntry
= gParts
[partIndex
].getDirEntry
;
255 ret
= getDirEntry(gParts
[partIndex
].partIH
, dirPath
,
256 dirIndex
, name
, flags
, time
);
261 long DumpDir(char *dirSpec
)
263 long ret
, flags
, time
, index
= 0;
266 printf("DumpDir on [%s]\n", dirSpec
);
269 ret
= GetDirEntry(dirSpec
, &index
, &name
, &flags
, &time
);
270 if (ret
== -1) break;
272 printf("%x %x [%s]\n", flags
, time
, name
);
281 long LookupPartition(char *devSpec
)
284 long partIndex
, partType
;
287 // See if the devSpec has already been opened.
288 for (partIndex
= 0; partIndex
< kNumPartInfos
; partIndex
++) {
289 if (!strcmp(gParts
[partIndex
].partName
, devSpec
)) break;
292 // If it has not been opened, do so now.
293 if (partIndex
== kNumPartInfos
) {
295 for (partIndex
= 0; partIndex
< kNumPartInfos
; partIndex
++) {
296 if (gParts
[partIndex
].partIH
== 0) break;
298 // No free slots, so return error.
299 if (partIndex
== kNumPartInfos
) return -1;
301 deviceType
= GetDeviceType(devSpec
);
302 switch (deviceType
) {
303 case kNetworkDeviceType
:
304 partIH
= NetInitPartition(devSpec
);
305 if (partIH
== 0) return -1;
309 case kBlockDeviceType
:
310 printf("Opening partition [%s]...\n", devSpec
);
311 partIH
= Open(devSpec
);
313 printf("Failed to open partition [%s].\n", devSpec
);
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
;
328 gParts
[partIndex
].partIH
= partIH
;
329 gParts
[partIndex
].partType
= partType
;
330 strcpy(gParts
[partIndex
].partName
, devSpec
);
334 gParts
[partIndex
].loadFile
= NetLoadFile
;
335 gParts
[partIndex
].readFile
= NULL
;
336 gParts
[partIndex
].getDirEntry
= NetGetDirEntry
;
337 gParts
[partIndex
].getUUID
= NULL
;
341 gParts
[partIndex
].loadFile
= HFSLoadFile
;
342 gParts
[partIndex
].readFile
= HFSReadFile
;
343 gParts
[partIndex
].getDirEntry
= HFSGetDirEntry
;
344 gParts
[partIndex
].getUUID
= HFSGetUUID
;
348 gParts
[partIndex
].loadFile
= UFSLoadFile
;
349 gParts
[partIndex
].readFile
= UFSReadFile
;
350 gParts
[partIndex
].getDirEntry
= UFSGetDirEntry
;
351 gParts
[partIndex
].getUUID
= UFSGetUUID
;
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