1 |
/* |
2 |
* PearPC |
3 |
* hfsplus.cc |
4 |
* |
5 |
* Copyright (C) 2004 Stefan Weyergraf |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License version 2 as |
9 |
* published by the Free Software Foundation. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 |
*/ |
20 |
|
21 |
#include <string.h> |
22 |
|
23 |
#include "debug/tracers.h" |
24 |
#include "hfsplus.h" |
25 |
#include "tools/endianess.h" |
26 |
#include "tools/except.h" |
27 |
#include "tools/snprintf.h" |
28 |
|
29 |
#include "hfs.h" |
30 |
|
31 |
extern "C" { |
32 |
#include "hfsplus/libhfsp.h" |
33 |
#include "hfsplus/volume.h" |
34 |
#include "hfsplus/btree.h" |
35 |
#include "hfsplus/blockiter.h" |
36 |
#include "hfsplus/record.h" |
37 |
#include "hfsplus/unicode.h" |
38 |
#include "hfsplus/os.h" |
39 |
} |
40 |
|
41 |
typedef uint32 HFSCatalogNodeID; |
42 |
|
43 |
struct HFSPlusExtentDescriptor { |
44 |
uint32 startBlock; |
45 |
uint32 blockCount; |
46 |
} PACKED; |
47 |
|
48 |
struct HFSPlusForkData { |
49 |
uint64 logicalSize; |
50 |
uint32 clumpSize; |
51 |
uint32 totalBlocks; |
52 |
HFSPlusExtentDescriptor extents[8]; |
53 |
} PACKED; |
54 |
|
55 |
struct HFSPlusVolumeHeader { |
56 |
uint16 signature; |
57 |
uint16 version; |
58 |
uint32 attributes; |
59 |
uint32 lastMountedVersion; |
60 |
uint32 journalInfoBlock; |
61 |
|
62 |
uint32 createDate; |
63 |
uint32 modifyDate; |
64 |
uint32 backupDate; |
65 |
uint32 checkedDate; |
66 |
|
67 |
uint32 fileCount; |
68 |
uint32 folderCount; |
69 |
|
70 |
uint32 blockSize; |
71 |
uint32 totalBlocks; |
72 |
uint32 freeBlocks; |
73 |
|
74 |
uint32 nextAllocation; |
75 |
uint32 rsrcClumpSize; |
76 |
uint32 dataClumpSize; |
77 |
HFSCatalogNodeID nextCatalogID; |
78 |
|
79 |
uint32 writeCount; |
80 |
uint64 encodingsBitmap; |
81 |
|
82 |
uint32 finderInfo[8]; |
83 |
|
84 |
HFSPlusForkData allocationFile; |
85 |
HFSPlusForkData extentsFile; |
86 |
HFSPlusForkData catalogFile; |
87 |
HFSPlusForkData attributesFile; |
88 |
HFSPlusForkData startupFile; |
89 |
} PACKED; |
90 |
|
91 |
byte HFSPlusVolumeHeader_struct[]= { |
92 |
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, |
93 |
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, |
94 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
95 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
96 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
97 |
|
98 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
99 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
100 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
101 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
102 |
|
103 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
104 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
105 |
|
106 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
107 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
108 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
109 |
|
110 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
111 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
112 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
113 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
114 |
|
115 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
116 |
STRUCT_ENDIAN_64 | STRUCT_ENDIAN_HOST, |
117 |
|
118 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
119 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
120 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
121 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
122 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
123 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
124 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
125 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
126 |
// 5x forkdata |
127 |
// 1. |
128 |
STRUCT_ENDIAN_64 | STRUCT_ENDIAN_HOST, |
129 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
130 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
131 |
|
132 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
133 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
134 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
135 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
136 |
|
137 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
138 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
139 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
140 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
141 |
|
142 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
143 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
144 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
145 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
146 |
|
147 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
148 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
149 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
150 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
151 |
// 2. |
152 |
STRUCT_ENDIAN_64 | STRUCT_ENDIAN_HOST, |
153 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
154 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
155 |
|
156 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
157 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
158 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
159 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
160 |
|
161 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
162 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
163 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
164 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
165 |
|
166 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
167 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
168 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
169 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
170 |
|
171 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
172 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
173 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
174 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
175 |
// 3. |
176 |
STRUCT_ENDIAN_64 | STRUCT_ENDIAN_HOST, |
177 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
178 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
179 |
|
180 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
181 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
182 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
183 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
184 |
|
185 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
186 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
187 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
188 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
189 |
|
190 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
191 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
192 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
193 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
194 |
|
195 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
196 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
197 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
198 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
199 |
// 4. |
200 |
STRUCT_ENDIAN_64 | STRUCT_ENDIAN_HOST, |
201 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
202 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
203 |
|
204 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
205 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
206 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
207 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
208 |
|
209 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
210 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
211 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
212 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
213 |
|
214 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
215 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
216 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
217 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
218 |
|
219 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
220 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
221 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
222 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
223 |
// 5. |
224 |
STRUCT_ENDIAN_64 | STRUCT_ENDIAN_HOST, |
225 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
226 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
227 |
|
228 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
229 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
230 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
231 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
232 |
|
233 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
234 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
235 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
236 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
237 |
|
238 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
239 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
240 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
241 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
242 |
|
243 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
244 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
245 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
246 |
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
247 |
|
248 |
0, |
249 |
}; |
250 |
|
251 |
/* |
252 |
* |
253 |
*/ |
254 |
static bool doTryBootHFSPlus(File *aDevice, uint aDeviceBlocksize, FileOfs start, PartitionEntry *partEnt); |
255 |
|
256 |
bool tryBootHFSPlus(File *aDevice, uint aDeviceBlocksize, FileOfs start, PartitionEntry *partEnt) |
257 |
{ |
258 |
IO_PROM_FS_TRACE("trying to boot from HFS+ volume\n"); |
259 |
return doTryBootHFSPlus(aDevice, aDeviceBlocksize, start, partEnt); |
260 |
/* |
261 |
// HFS+ |
262 |
HFSPlusVolumeHeader HP_VH; |
263 |
aDevice->seek(start+0x400); |
264 |
if (aDevice->read((byte*)&HP_VH, sizeof HP_VH) == sizeof HP_VH) { |
265 |
createHostStructx(&HP_VH, sizeof HP_VH, HFSPlusVolumeHeader_struct, big_endian); |
266 |
if ((HP_VH.signature == HFSPlusSigWord) || (HP_VH.signature == HFSXSigWord)) { |
267 |
IO_PROM_FS_TRACE("contains HFS+/HFSX volume (startup file size %08x, total blocks %d)\n", HP_VH.startupFile.logicalSize, HP_VH.startupFile.totalBlocks); |
268 |
IO_PROM_FS_TRACE("finderinfo[0]=%08x\n", HP_VH.finderInfo[0]); |
269 |
return doTryBootHFSPlus(aDevice, aDeviceBlocksize, start, partEnt); |
270 |
} |
271 |
} |
272 |
return false; |
273 |
*/ |
274 |
} |
275 |
|
276 |
static int my_ffs(uint64 f) |
277 |
{ |
278 |
for(int i=1; i<64; i++) { |
279 |
if (f&1) return i; |
280 |
f >>= 1; |
281 |
} |
282 |
return 0; |
283 |
} |
284 |
|
285 |
struct HFSPlusInstantiateBootFilePrivData { |
286 |
int mPartNum; |
287 |
}; |
288 |
|
289 |
static File *HFSPlusInstantiateBootFile(File *aDevice, void *priv) |
290 |
{ |
291 |
HFSPlusInstantiateBootFilePrivData *p = (HFSPlusInstantiateBootFilePrivData*)priv; |
292 |
HFSPlusFileSystem *fs = new HFSPlusFileSystem(aDevice, p->mPartNum); |
293 |
File *f = fs->openBootFile(); |
294 |
if (!f) delete fs; // otherwise fs is owned by f |
295 |
return f; |
296 |
} |
297 |
|
298 |
static FileSystem *HFSPlusInstantiateFileSystem(File *aDevice, int partnum) |
299 |
{ |
300 |
return new HFSPlusFileSystem(aDevice, partnum); |
301 |
} |
302 |
|
303 |
static bool doTryBootHFSPlus(File *aDevice, uint aDeviceBlocksize, FileOfs start, PartitionEntry *partEnt) |
304 |
{ |
305 |
if (partEnt->mPartNum <= 0) return false; |
306 |
hfsplus_devicehandle_s dh; |
307 |
dh.mDevice = aDevice; |
308 |
dh.mStart = 0; |
309 |
volume vol; |
310 |
ht_printf("start: %qd\n", start); |
311 |
if (volume_open(&vol, &dh, partEnt->mPartNum-1, HFSP_MODE_RDONLY) == 0) { |
312 |
volume_close(&vol); |
313 |
HFSPlusInstantiateBootFilePrivData *priv = (HFSPlusInstantiateBootFilePrivData*) |
314 |
malloc(sizeof (HFSPlusInstantiateBootFilePrivData)); |
315 |
priv->mPartNum = partEnt->mPartNum; |
316 |
partEnt->mInstantiateBootFilePrivData = priv; |
317 |
partEnt->mInstantiateBootFile = HFSPlusInstantiateBootFile; |
318 |
partEnt->mInstantiateFileSystem = HFSPlusInstantiateFileSystem; |
319 |
partEnt->mBootMethod = BM_chrp; |
320 |
return true; |
321 |
} else IO_PROM_FS_TRACE("couldn't mount HFS+ partition.\n"); |
322 |
return false; |
323 |
} |
324 |
|
325 |
/***/ |
326 |
class HFSPlusFile: public File { |
327 |
protected: |
328 |
byte *block; |
329 |
int blocksize; |
330 |
int blocksize_bits; |
331 |
int blockfill; |
332 |
int blockpos; |
333 |
FileOfs blockofs; |
334 |
blockiter it; |
335 |
volume * vol; |
336 |
hfsp_cat_file mFile; |
337 |
FileOfs mCurOfs; |
338 |
FileSystem * mFS; |
339 |
bool mOwnFS; |
340 |
public: |
341 |
|
342 |
HFSPlusFile(volume *aVol, hfsp_cat_file aFile, FileSystem *fs, bool own_fs) |
343 |
{ |
344 |
vol = aVol; |
345 |
mFile = aFile; |
346 |
mOwnFS = own_fs; |
347 |
mFS = fs; |
348 |
|
349 |
blockiter_init(&it, vol, &mFile.data_fork, HFSP_EXTENT_DATA, mFile.id); |
350 |
blockpos = 0; |
351 |
blockfill = 0; |
352 |
blockofs = 0; |
353 |
|
354 |
block = (byte*)malloc(vol->vol.blocksize); |
355 |
blocksize = vol->vol.blocksize; |
356 |
blocksize_bits = my_ffs(vol->vol.blocksize)-1; |
357 |
if (vol->vol.blocksize != (1 << blocksize_bits)) |
358 |
throw MsgfException("invalid blocksize: %d (not a power of 2)", |
359 |
vol->vol.blocksize); |
360 |
} |
361 |
|
362 |
virtual ~HFSPlusFile() |
363 |
{ |
364 |
if (mOwnFS) delete mFS; |
365 |
} |
366 |
|
367 |
virtual FileOfs getSize() const |
368 |
{ |
369 |
return mFile.data_fork.total_size; |
370 |
} |
371 |
|
372 |
virtual uint read(void *buf, uint n) |
373 |
{ |
374 |
uint on = n; |
375 |
byte *b = (byte*)buf; |
376 |
while (n) { |
377 |
if (blockfill == 0) { |
378 |
hfsp_os_seek(&vol->fd, blockiter_curr(&it), blocksize_bits); |
379 |
if (hfsp_os_read(&vol->fd, block, 1, blocksize_bits) != 1) break; |
380 |
blockfill = blocksize; |
381 |
blockpos = 0; |
382 |
} else if (blockpos == blockfill) { |
383 |
if (blockiter_next(&it) != 0) break; |
384 |
blockofs++; |
385 |
blockfill = 0; |
386 |
continue; |
387 |
} |
388 |
uint c = blockfill-blockpos; |
389 |
uint t = n; |
390 |
if (t > c) t = c; |
391 |
memcpy(b, block+blockpos, t); |
392 |
blockpos += t; |
393 |
b += t; |
394 |
n -= t; |
395 |
} |
396 |
return on - n; |
397 |
} |
398 |
|
399 |
virtual void seek(FileOfs offset) |
400 |
{ |
401 |
uint boffset = offset / blocksize; |
402 |
blockiter_init(&it, vol, &mFile.data_fork, HFSP_EXTENT_DATA, mFile.id); |
403 |
if (boffset && (blockiter_skip(&it, boffset) != 0)) |
404 |
throw IOException(EIO); |
405 |
blockofs = boffset; |
406 |
hfsp_os_seek(&vol->fd, blockiter_curr(&it), blocksize_bits); |
407 |
if (hfsp_os_read(&vol->fd, block, 1, blocksize_bits) != 1) throw IOException(ENOSYS); |
408 |
blockfill = blocksize; |
409 |
blockpos = offset % blocksize; |
410 |
} |
411 |
|
412 |
virtual FileOfs tell() const |
413 |
{ |
414 |
return blockofs * blocksize + blockpos; |
415 |
} |
416 |
|
417 |
}; |
418 |
|
419 |
/***/ |
420 |
HFSPlusFileSystem::HFSPlusFileSystem(File *device, int partnum) |
421 |
: FileSystem(device) |
422 |
{ |
423 |
dh.mDevice = mDevice; |
424 |
dh.mStart = 0; |
425 |
hfsplushandle = malloc(sizeof (volume)); |
426 |
volume *vol = (volume*)hfsplushandle; |
427 |
if (volume_open(vol, &dh, partnum-1, HFSP_MODE_RDONLY) != 0) |
428 |
throw MsgException("can't open HFS+ volume"); |
429 |
} |
430 |
|
431 |
HFSPlusFileSystem::~HFSPlusFileSystem() |
432 |
{ |
433 |
volume *vol = (volume*)hfsplushandle; |
434 |
volume_close(vol); |
435 |
free(hfsplushandle); |
436 |
} |
437 |
|
438 |
File *HFSPlusFileSystem::open(const String &filename) |
439 |
{ |
440 |
volume *vol = (volume*)hfsplushandle; |
441 |
|
442 |
record dir; |
443 |
record file; |
444 |
record_init_root(&dir, &vol->catalog); |
445 |
|
446 |
IO_PROM_FS_TRACE("opening %s\n", filename.toString()); |
447 |
|
448 |
char *path = filename.toString(); |
449 |
char buffer[128]; |
450 |
if(*path == '/') |
451 |
path++; |
452 |
|
453 |
char *lastPart = path; |
454 |
|
455 |
while(1) { |
456 |
while(*path && *path != '/') |
457 |
path++; |
458 |
|
459 |
strncpy(buffer, lastPart, path-lastPart); |
460 |
buffer[path-lastPart] = 0; |
461 |
|
462 |
if (record_init_string_parent(&file, &dir, buffer) == -1) |
463 |
return NULL; |
464 |
dir = file; |
465 |
|
466 |
if (!*path) |
467 |
break; |
468 |
|
469 |
path++; |
470 |
lastPart = path; |
471 |
} |
472 |
|
473 |
return new HFSPlusFile(vol, file.record.u.file, this, true); |
474 |
} |
475 |
|
476 |
// WARNING: on success this will bind this filesystem to the file (mOwnFS) |
477 |
File *HFSPlusFileSystem::openBootFile() |
478 |
{ |
479 |
volume *vol = (volume*)hfsplushandle; |
480 |
uint id = createHostInt(vol->vol.finder_info, 4, big_endian); |
481 |
record startupFolderRec; |
482 |
if (record_init_cnid(&startupFolderRec, &vol->catalog, id) != 0) return NULL; |
483 |
if (startupFolderRec.record.type != HFSP_FOLDER_THREAD) return NULL; |
484 |
|
485 |
record rec; |
486 |
if (record_init_parent(&rec, &startupFolderRec) == 0) do { |
487 |
switch (rec.record.type) { |
488 |
case HFSP_FOLDER: { |
489 |
// char buf[256]; |
490 |
// unicode_uni2asc(buf, &rec.key.name, sizeof buf); |
491 |
// IO_PROM_FS_TRACE("folder: %s\n", buf); |
492 |
break; |
493 |
} |
494 |
case HFSP_FILE: { |
495 |
char buf[256]; |
496 |
unicode_uni2asc(buf, &rec.key.name, sizeof buf); |
497 |
OSType t = rec.record.u.file.user_info.fdType; |
498 |
char t2[5]; |
499 |
t2[0] = t >> 24; |
500 |
t2[1] = t >> 16; |
501 |
t2[2] = t >> 8; |
502 |
t2[3] = t; |
503 |
t2[4] = 0; |
504 |
/* OSType c = rec.record.u.file.user_info.fdCreator; |
505 |
char c2[5]; |
506 |
c2[0] = c >> 24; |
507 |
c2[1] = c >> 16; |
508 |
c2[2] = c >> 8; |
509 |
c2[3] = c; |
510 |
c2[4] = 0;*/ |
511 |
if (strcmp(t2, "tbxi") == 0) { |
512 |
return new HFSPlusFile(vol, rec.record.u.file, this, true); |
513 |
} |
514 |
// IO_PROM_FS_TRACE("file: %4s/%4s %s\n", t2, c2, buf); |
515 |
break; |
516 |
} |
517 |
case HFSP_FOLDER_THREAD: { |
518 |
// char buf[256]; |
519 |
// unicode_uni2asc(buf, &rec.record.u.thread.nodeName, sizeof buf); |
520 |
// IO_PROM_FS_TRACE("folder thread: %s\n", buf); |
521 |
break; |
522 |
} |
523 |
case HFSP_FILE_THREAD: { |
524 |
// IO_PROM_FS_TRACE("file thread\n"); |
525 |
break; |
526 |
} |
527 |
} |
528 |
} while (record_next(&rec) == 0); |
529 |
|
530 |
return NULL; |
531 |
} |
532 |
|
533 |
bool HFSPlusFileSystem::getBlessedPath(String &blessed) |
534 |
{ |
535 |
volume *vol = (volume*)hfsplushandle; |
536 |
uint startupFolderID = createHostInt(vol->vol.finder_info, 4, big_endian); |
537 |
|
538 |
uint id = startupFolderID; |
539 |
uint maxit = 200; |
540 |
blessed.assign("/"); |
541 |
while ((id != HFSP_ROOT_CNID) && maxit--) { |
542 |
record rec; |
543 |
if (record_init_cnid(&rec, &vol->catalog, id) != 0) return false; |
544 |
if (rec.record.type != HFSP_FOLDER_THREAD) return false; |
545 |
|
546 |
char buf[256]; |
547 |
unicode_uni2asc(buf, &rec.record.u.thread.nodeName, sizeof buf); |
548 |
String p(buf); |
549 |
blessed.prepend(p); |
550 |
blessed.prepend("/"); |
551 |
id = rec.record.u.thread.parentID; |
552 |
} |
553 |
return (id == HFSP_ROOT_CNID); |
554 |
} |