/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


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