/[pearpc]/src/io/prom/fs/hfsplus.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/io/prom/fs/hfsplus.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 6 months ago) by dpavlin
File size: 15643 byte(s)
import upstream CVS
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 }

  ViewVC Help
Powered by ViewVC 1.1.26