Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / fs / hfsplus / hfsp_record.c
1 /*
2  * libhfsp - library for reading and writing Macintosh HFS+ volumes.
3  *
4  * a record contains a key and a folder or file and is part
5  * of a btree.
6  *
7  * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
8  * Original 1996-1998 Robert Leslie <rob@mars.org>
9  * Additional work by  Brad Boyer (flar@pants.nu)
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
24  * MA 02110-1301, USA.
25  *
26  * $Id: record.c,v 1.24 2000/10/17 05:58:46 hasi Exp $
27  */
28
29 #include "config.h"
30 #include "libhfsp.h"
31 #include "hfstime.h"
32 #include "record.h"
33 #include "volume.h"
34 #include "btree.h"
35 #include "unicode.h"
36 #include "swab.h"
37
38 /* read a hfsp_cat_key from memory */
39 void* record_readkey(void* p, void* buf)
40 {
41     hfsp_cat_key*   key = (hfsp_cat_key*) buf;
42     const void*     check;
43     UInt16          key_length, len,i;
44     UInt16*         cp;
45
46     key->key_length = key_length    = bswabU16_inc(p);
47     check = p;
48     key->parent_cnid                = bswabU32_inc(p);
49     key->name.strlen = len          = bswabU16_inc(p);
50     cp = key->name.name;
51     for (i=0; i < len; i++, cp++)
52         *cp                         = bswabU16_inc(p);
53         /* check if keylenght was correct */
54     if (key_length != ((char*) p) - ((char*) check))
55          HFSP_ERROR(EINVAL, "Invalid key length in record_readkey");
56     return p;
57   fail:
58     return NULL;
59 }
60
61 /* read a hfsp_extent_key from memory */
62 void* record_extent_readkey(void* p, void* buf)
63 {
64     hfsp_extent_key* key = (hfsp_extent_key*) buf;
65     UInt16  key_length;
66
67     key->key_length = key_length    = bswabU16_inc(p);
68     key->fork_type                  = bswabU8_inc(p);
69     key->filler                     = bswabU8_inc(p);
70     if (key_length != 10)
71         HFSP_ERROR(-1, "Invalid key length in record_extent_readkey");
72     key->file_id                    = bswabU32_inc(p);
73     key->start_block                = bswabU32_inc(p);
74     return p;
75   fail:
76     return NULL;
77 }
78
79
80 /* read posix permission from memory */
81 static inline void* record_readperm(void *p, hfsp_perm* perm)
82 {
83     perm->owner= bswabU32_inc(p);
84     perm->group= bswabU32_inc(p);
85     perm->mode = bswabU32_inc(p);
86     perm->dev  = bswabU32_inc(p);
87     return p;
88 }
89
90 /* read directory info */
91 static inline void* record_readDInfo(void *p, DInfo* info)
92 {
93     info->frRect.top    = bswabU16_inc(p);
94     info->frRect.left   = bswabU16_inc(p);
95     info->frRect.bottom = bswabU16_inc(p);
96     info->frRect.right  = bswabU16_inc(p);
97     info->frFlags       = bswabU16_inc(p);
98     info->frLocation.v  = bswabU16_inc(p);
99     info->frLocation.h  = bswabU16_inc(p);
100     info->frView        = bswabU16_inc(p);
101     return p;
102 }
103
104 /* read extra Directory info */
105 static inline void* record_readDXInfo(void *p, DXInfo* xinfo)
106 {
107     xinfo->frScroll.v  = bswabU16_inc(p);
108     xinfo->frScroll.h  = bswabU16_inc(p);
109     xinfo->frOpenChain = bswabU32_inc(p);
110     xinfo->frUnused    = bswabU16_inc(p);
111     xinfo->frComment   = bswabU16_inc(p);
112     xinfo->frPutAway   = bswabU32_inc(p);
113     return p;
114 }
115
116 /* read a hfsp_cat_folder from memory */
117 static void* record_readfolder(void *p, hfsp_cat_folder* folder)
118 {
119     folder->flags               = bswabU16_inc(p);
120     folder->valence             = bswabU32_inc(p);
121     folder->id                  = bswabU32_inc(p);
122     folder->create_date         = bswabU32_inc(p);
123     folder->content_mod_date    = bswabU32_inc(p);
124     folder->attribute_mod_date  = bswabU32_inc(p);
125     folder->access_date         = bswabU32_inc(p);
126     folder->backup_date         = bswabU32_inc(p);
127     p = record_readperm     (p, &folder->permissions);
128     p = record_readDInfo    (p, &folder->user_info);
129     p = record_readDXInfo   (p, &folder->finder_info);
130     folder->text_encoding       = bswabU32_inc(p);
131     folder->reserved            = bswabU32_inc(p);
132     return p;
133 }
134
135 /* read file info */
136 static inline void* record_readFInfo(void *p, FInfo* info)
137 {
138     info->fdType        = bswabU32_inc(p);
139     info->fdCreator     = bswabU32_inc(p);
140     info->fdFlags       = bswabU16_inc(p);
141     info->fdLocation.v  = bswabU16_inc(p);
142     info->fdLocation.h  = bswabU16_inc(p);
143     info->fdFldr        = bswabU16_inc(p);
144     return p;
145 }
146
147 /* read extra File info */
148 static inline void* record_readFXInfo(void *p, FXInfo* xinfo)
149 {
150     SInt16 *q;
151     xinfo->fdIconID     = bswabU16_inc(p);
152     q=(SInt16*) p;
153     q+=4; // skip unused
154     p=(void *)q;
155     xinfo->fdComment    = bswabU16_inc(p);
156     xinfo->fdPutAway    = bswabU32_inc(p);
157     return p;
158 }
159
160 /* read a hfsp_cat_file from memory */
161 static void* record_readfile(void *p, hfsp_cat_file* file)
162 {
163     file->flags                 = bswabU16_inc(p);
164     file->reserved1             = bswabU32_inc(p);
165     file->id                    = bswabU32_inc(p);
166     file->create_date           = bswabU32_inc(p);
167     file->content_mod_date      = bswabU32_inc(p);
168     file->attribute_mod_date    = bswabU32_inc(p);
169     file->access_date           = bswabU32_inc(p);
170     file->backup_date           = bswabU32_inc(p);
171     p = record_readperm     (p, &file->permissions);
172     p = record_readFInfo    (p, &file->user_info);
173     p = record_readFXInfo   (p, &file->finder_info);
174     file->text_encoding         = bswabU32_inc(p);
175     file->reserved2             = bswabU32_inc(p);
176     p =     volume_readfork (p, &file->data_fork);
177     return  volume_readfork (p, &file->res_fork);
178 }
179
180 /* read a hfsp_cat_thread from memory */
181 static void* record_readthread(void *p, hfsp_cat_thread* entry)
182 {
183     int     i;
184     UInt16  len;
185     UInt16* cp;
186
187     entry->         reserved    = bswabU16_inc(p);
188     entry->         parentID    = bswabU32_inc(p);
189     entry->nodeName.strlen = len= bswabU16_inc(p);
190     cp = entry->nodeName.name;
191     if (len > 255)
192         HFSP_ERROR(-1, "Invalid key length in record thread");
193     for (i=0; i < len; i++, cp++)
194         *cp                      = bswabU16_inc(p);
195     return p;
196  fail:
197     return NULL;
198 }
199
200 /* read a hfsp_cat_entry from memory */
201 static void* record_readentry(void *p, hfsp_cat_entry* entry)
202 {
203     UInt16 type = bswabU16_inc(p);
204     entry->type = type;
205     switch (type)
206     {
207         case HFSP_FOLDER:
208             return record_readfolder(p, &entry->u.folder);
209         case HFSP_FILE:
210             return record_readfile  (p, &entry->u.file);
211         case HFSP_FOLDER_THREAD:
212         case HFSP_FILE_THREAD:
213             return record_readthread(p, &entry->u.thread);
214         default:
215             HFSP_ERROR(-1, "Unexpected record type in record_readentry");
216     } ;
217   fail:
218     return NULL;
219 }
220
221
222 /* Most of the functions here will not change the node in the btree,
223    But this must be changed in the future ... */
224
225
226 /* intialize the record with the given index entry in the btree. */
227 static int record_init(record* r, btree* bt, node_buf* buf, UInt16 index)
228 {
229     void *p;
230     r-> tree   = bt;
231     p = btree_key_by_index(bt,buf,index);
232     if (!p)
233         return -1;
234     p = record_readkey  (p, &r->key);
235     if (!p)
236         return -1;
237     p = record_readentry(p, &r->record);
238     if (!p)
239         return -1;
240     r->node_index = buf->index;
241     r-> keyind    = index;
242
243     return 0;
244 }
245
246 /* intialize the record with the given index entry in the btree. */
247 static int record_init_extent(extent_record* r, btree* bt, node_buf* buf, UInt16 index)
248 {
249     void *p;
250     r-> tree   = bt;
251     p = btree_key_by_index(bt, buf,index);
252     if (!p)
253         return -1;
254     p = record_extent_readkey(p, &r->key);
255     if (!p)
256         return -1;
257     p = volume_readextent(p, r->extent);
258     if (!p)
259         return -1;
260     r->node_index = buf->index;
261     r-> keyind    = index;
262
263     return 0;
264 }
265
266 /* intialize the record to the first record of the tree
267  * which is (per design) the root node.
268  */
269 int record_init_root(record* r, btree* tree)
270 {
271     // Position to first leaf node ...
272     UInt32 leaf_head = tree->head.leaf_head;
273     node_buf* buf = btree_node_by_index(tree, leaf_head);
274     if (!buf)
275         return -1;
276     return record_init(r, tree, buf, 0);
277 }
278
279 /* Compare two cat_keys ... */
280 int record_key_compare(void* k1, void* k2)
281 {
282     hfsp_cat_key* key1 = (hfsp_cat_key*) k1;
283     hfsp_cat_key* key2 = (hfsp_cat_key*) k2;
284     int diff = key2->parent_cnid - key1->parent_cnid;
285     if (!diff) // same parent
286         diff = fast_unicode_compare(&key1->name, &key2->name);
287     return diff;
288 }
289
290 /* Compare two extent_keys ... */
291 int record_extent_key_compare(void* k1, void* k2)
292 {
293     hfsp_extent_key* key1 = (hfsp_extent_key*) k1;
294     hfsp_extent_key* key2 = (hfsp_extent_key*) k2;
295     int diff = key2->fork_type - key1->fork_type;
296     if (!diff) // same type
297     {
298         diff = key2->file_id - key1->file_id;
299         if (!diff) // same file
300             diff = key2->start_block - key1->start_block;
301     }
302     return diff;
303 }
304
305 /* Position node in btree so that key might be inside */
306 static node_buf* record_find_node(btree* tree, void *key)
307 {
308     int                 start, end, mid, comp;  // components of a binary search
309     void                *p = NULL;
310     char                curr_key[tree->head.max_key_len];
311                     // The current key under examination
312     hfsp_key_read       readkey     = tree->kread;
313     hfsp_key_compare    key_compare = tree->kcomp;
314     UInt32              index;
315     node_buf*           node = btree_node_by_index(tree, tree->head.root);
316     if (!node)
317         HFSP_ERROR(-1, "record_find_node: Cant position to root node");
318     while (node->desc.kind == HFSP_NODE_NDX)
319     {
320         mid = start = 0;
321         end  = node->desc.num_rec;
322         comp = -1;
323         while (start < end)
324         {
325             mid = (start + end) >> 1;
326             p = btree_key_by_index(tree, node, mid);
327             if (!p)
328                 HFSP_ERROR(-1, "record_find_node: unexpected error");
329             p = readkey  (p, curr_key);
330             if (!p)
331                 HFSP_ERROR(-1, "record_find_node: unexpected error");
332             comp = key_compare(curr_key, key);
333             if (comp > 0)
334                 start = mid + 1;
335             else if (comp < 0)
336                 end = mid;
337             else
338                 break;
339         }
340         if (!p) // Empty tree, fascinating ...
341             HFSP_ERROR(-1, "record_find_node: unexpected empty node");
342         if (comp < 0)   // mmh interesting key is before this key ...
343         {
344             if (mid == 0)
345                 return NULL;  // nothing before this key ..
346             p = btree_key_by_index(tree, node, mid-1);
347             if (!p)
348                 HFSP_ERROR(-1, "record_find_node: unexpected error");
349             p = readkey  (p, curr_key);
350             if (!p)
351                 HFSP_ERROR(-1, "record_find_node: unexpected error");
352         }
353
354         index = bswabU32_inc(p);
355         node = btree_node_by_index(tree, index);
356     }
357     return node;        // go on and use the found node
358   fail:
359     return NULL;
360 }
361
362 /* search for the given key in the btree.
363  *
364  * returns pointer to memory just after key or NULL
365  * In any case *keyind recives the index where the
366  * key was found (or could be inserted.)
367  */
368 static void *
369 record_find_key(btree* tree, void* key, int* keyind, UInt16* node_index)
370 {
371     node_buf* buf = record_find_node(tree, key);
372     if (buf)
373     {
374         int                 comp  = -1;
375         int                 start = 0; // components of a binary search
376         int                 end   = buf->desc.num_rec;
377         int                 mid   = -1;
378         void                *p    = NULL;
379         char                curr_key[tree->head.max_key_len];
380         hfsp_key_read       readkey     = tree->kread;
381         hfsp_key_compare    key_compare = tree->kcomp;
382         while (start < end)
383         {
384             mid = (start + end) >> 1;
385             p = btree_key_by_index(tree, buf, mid);
386             if (!p)
387                 HFSP_ERROR(-1, "record_init_key: unexpected error");
388             p = readkey  (p, curr_key);
389             if (!p)
390                 HFSP_ERROR(-1, "record_init_cat_key: unexpected error");
391             comp = key_compare(curr_key, key);
392             if (comp > 0)
393                 start = mid + 1;
394             else if (comp < 0)
395                 end = mid;
396             else
397                 break;
398         }
399         if (!p) // Empty tree, fascinating ...
400             HFSP_ERROR(ENOENT, "record_init_key: unexpected empty node");
401         *keyind = mid;
402         *node_index = buf->index;
403         if (!comp)      // found something ...
404             return p;
405     }
406     HFSP_ERROR(ENOENT, NULL);
407   fail:
408     return NULL;
409 }
410
411 /* intialize the record by searching for the given key in the btree.
412  *
413  * r is umodified on error.
414  */
415 static int
416 record_init_key(record* r, btree* tree, hfsp_cat_key* key)
417 {
418     int     keyind;
419     UInt16  node_index;
420     void    *p = record_find_key(tree, key, &keyind, &node_index);
421
422     if (p)
423     {
424         r -> tree      = tree;
425         r -> node_index= node_index;
426         r -> keyind    = keyind;
427         r -> key       = *key; // Better use a record_key_copy ...
428         p = record_readentry(p, &r->record);
429         if (!p)
430             HFSP_ERROR(-1, "record_init_key: unexpected error");
431         return 0;
432     }
433   fail:
434     return -1;
435 }
436
437 /* intialize the extent_record to the extent identified by the
438  * (first) blockindex.
439  *
440  * forktype: either HFSP_EXTEND_DATA or HFSP_EXTEND_RSRC
441  */
442 int record_init_file(extent_record* r, btree* tree,
443                     UInt8 forktype, UInt32 fileId, UInt32 blockindex)
444 {
445     int             keyind;
446     UInt16          node_index;
447     hfsp_extent_key key = { 10, forktype, 0, fileId, blockindex };
448     void            *p = record_find_key(tree, &key, &keyind, &node_index);
449
450     if (p)
451     {
452         r -> tree      = tree;
453         r -> node_index= node_index;
454         r -> keyind    = keyind;
455         r -> key       = key; // Better use a record_key_copy ...
456         p =  volume_readextent(p, r->extent);
457         if (!p)
458             HFSP_ERROR(-1, "record_init_file: unexpected error");
459         return 0;
460     }
461   fail:
462     return -1;
463 }
464
465 /* intialize the record to the folder identified by cnid
466  */
467 int record_init_cnid(record* r, btree* tree, UInt32 cnid)
468 {
469     hfsp_cat_key    thread_key;     // the thread is the first record
470
471     thread_key.key_length = 6;      // null name (like '.' in unix )
472     thread_key.parent_cnid = cnid;
473     thread_key.name.strlen = 0;
474
475     return record_init_key(r, tree, &thread_key);
476 }
477
478 /* intialize the record to the first record of the parent.
479  */
480 int record_init_parent(record* r, record* parent)
481 {
482     if (parent->record.type == HFSP_FOLDER)
483         return record_init_cnid(r, parent->tree, parent->record.u.folder.id);
484     else if(parent->record.type == HFSP_FOLDER_THREAD)
485     {
486         if (r != parent)
487             *r = *parent; // The folder thread is in fact the first entry, like '.'
488         return 0;
489     }
490     HFSP_ERROR(EINVAL,
491         "record_init_parent: parent is neither folder nor folder thread.");
492
493   fail:
494     return EINVAL;
495 }
496
497
498 /* find correct node record for given node and *pindex.
499  *
500  * index of record in this (or next) node
501  * */
502 static node_buf* prepare_next(btree* tree, UInt16 node_index, UInt16* pindex)
503 {
504     node_buf*        buf    = btree_node_by_index(tree, node_index);
505     btree_node_desc* desc   = &buf->desc;
506     UInt32           numrec = desc->num_rec;
507     if (*pindex >= numrec) // move on to next node
508     {
509         UInt16 next = desc->next;
510         *pindex = 0;
511         if (!next   /* is there a next node ? */
512         ||  !( buf = btree_node_by_index(tree, next)))
513             return NULL;
514     }
515     return buf;
516 }
517 /* move record foreward to next entry.
518  *
519  * In case of an error the value of *r is undefined !
520  */
521 int record_next(record* r)
522 {
523     btree*      tree    = r->tree;
524     UInt16      index   = r->keyind +1;
525     UInt32      parent;
526     node_buf*   buf     = prepare_next(tree, r->node_index, &index);
527
528     if (!buf)
529         return ENOENT;  // No (more) such file or directory
530
531     parent = r->key.parent_cnid;
532
533     if (record_init(r, tree, buf, index))
534         return -1;
535
536     if (r->key.parent_cnid != parent || // end of current directory
537         index != r->keyind)             // internal error ?
538         return ENOENT;  // No (more) such file or directory
539
540     return 0;
541 }
542
543 /* move record foreward to next extent record.
544  *
545  * In case of an error the value of *r is undefined !
546  */
547 int record_next_extent(extent_record* r)
548 {
549     btree*      tree   = r->tree;
550     UInt16      index  = r->keyind +1;
551     UInt32      file_id;
552     UInt8       fork_type;
553     node_buf*   buf     = prepare_next(tree, r->node_index, &index);
554
555     if (!buf)
556         return ENOENT;  // No (more) such file or directory
557
558     file_id     = r->key.file_id;
559     fork_type   = r->key.fork_type;
560
561     if (record_init_extent(r, tree, buf, index))
562         return -1;
563
564     if (r->key.file_id   != file_id ||      // end of current file
565         r->key.fork_type != fork_type ||    // end of current fork
566         index != r->keyind)                 // internal error ?
567         return ENOENT;  // No (more) such file or directory
568
569     return 0;
570 }
571
572 /* intialize the record by searching for the given string in the given folder.
573  *
574  * parent and r may be the same.
575  */
576 int record_init_string_parent(record* r, record* parent, char* name)
577 {
578     hfsp_cat_key key;
579
580     if (parent->record.type == HFSP_FOLDER)
581         key.parent_cnid = parent->record.u.folder.id;
582     else if(parent->record.type == HFSP_FOLDER_THREAD)
583         key.parent_cnid = parent->key.parent_cnid;
584     else
585         HFSP_ERROR(-1, "record_init_string_parent: parent is not a folder.");
586
587     key.key_length = 6 + unicode_asc2uni(&key.name,name); // 6 for minumum size
588     return record_init_key(r, parent->tree, &key);
589
590   fail:
591     return -1;
592 }
593
594 /* move record up in folder hierarchy (if possible) */
595 int record_up(record* r)
596 {
597     if (r->record.type == HFSP_FOLDER)
598     {
599         // locate folder thread
600         if (record_init_cnid(r, r->tree, r->record.u.folder.id))
601             return -1;
602     }
603     else if(r->record.type == HFSP_FOLDER_THREAD)
604     {
605         // do nothing were are already where we want to be
606     }
607     else
608         HFSP_ERROR(-1, "record_up: record is neither folder nor folder thread.");
609
610     if(r->record.type != HFSP_FOLDER_THREAD)
611         HFSP_ERROR(-1, "record_up: unable to locate parent");
612     return record_init_cnid(r, r->tree, r->record.u.thread.parentID);
613
614   fail:
615     return -1;
616 }
617
618 #ifdef DEBUG
619
620 /* print Quickdraw Point */
621 static void record_print_Point(Point* p)
622 {
623     printf("[ v=%d, h=%d ]", p->v, p->h);
624 }
625
626 /* print Quickdraw Rect */
627 static void record_print_Rect(Rect* r)
628 {
629     printf("[ top=%d, left=%d, bottom=%d, right=%d  ]",
630              r->top, r->left, r->bottom, r->right);
631 }
632
633 /* print the key of a record */
634 static void record_print_key(hfsp_cat_key* key)
635 {
636     char buf[255]; // mh this _might_ overflow
637     unicode_uni2asc(buf, &key->name, 255);
638     printf("parent cnid :    %ld\n",   key->parent_cnid);
639     printf("name        :    %s\n", buf);
640 }
641
642 /* print permissions */
643 static void record_print_perm(hfsp_perm* perm)
644 {
645     printf("owner               :\t%ld\n",  perm->owner);
646     printf("group               :\t%ld\n",  perm->group);
647     printf("perm                :\t0x%lX\n",perm->mode);
648     printf("dev                 :\t%ld\n",  perm->dev);
649 }
650
651 /* print Directory info */
652 static void record_print_DInfo(DInfo* dinfo)
653 {
654     printf(  "frRect              :\t");    record_print_Rect(&dinfo->frRect);
655     printf("\nfrFlags             :\t0X%X\n",    dinfo->frFlags);
656     printf(  "frLocation          :\t");    record_print_Point(&dinfo->frLocation);
657     printf("\nfrView              :\t0X%X\n",    dinfo->frView);
658 }
659
660 /* print extended Directory info */
661 static void record_print_DXInfo(DXInfo* xinfo)
662 {
663     printf(  "frScroll            :\t");    record_print_Point(&xinfo->frScroll);
664     printf("\nfrOpenChain         :\t%ld\n",  xinfo->frOpenChain);
665     printf(  "frUnused            :\t%d\n",   xinfo->frUnused);
666     printf(  "frComment           :\t%d\n",   xinfo->frComment);
667     printf(  "frPutAway           :\t%ld\n",  xinfo->frPutAway);
668 }
669
670 static void record_print_folder(hfsp_cat_folder* folder)
671 {
672     printf("flags               :\t0x%X\n",     folder->flags);
673     printf("valence             :\t0x%lX\n",    folder->valence);
674     printf("id                  :\t%ld\n",      folder->id);
675     record_print_perm   (&folder->permissions);
676     record_print_DInfo  (&folder->user_info);
677     record_print_DXInfo (&folder->finder_info);
678     printf("text_encoding       :\t0x%lX\n",    folder->text_encoding);
679     printf("reserved            :\t0x%lX\n",    folder->reserved);
680 }
681
682 /* print File info */
683 static void record_print_FInfo(FInfo* finfo)
684 {
685     printf(  "fdType              :\t%4.4s\n", (char*) &finfo->fdType);
686     printf(  "fdCreator           :\t%4.4s\n", (char*) &finfo->fdCreator);
687     printf(  "fdFlags             :\t0X%X\n", finfo->fdFlags);
688     printf(  "fdLocation          :\t");     record_print_Point(&finfo->fdLocation);
689     printf("\nfdFldr              :\t%d\n",  finfo->fdFldr);
690 }
691
692 /* print extended File info */
693 static void record_print_FXInfo(FXInfo* xinfo)
694 {
695     printf(  "fdIconID            :\t%d\n",   xinfo->fdIconID);
696     // xinfo -> fdUnused;
697     printf(  "fdComment           :\t%d\n",   xinfo->fdComment);
698     printf(  "fdPutAway           :\t%ld\n",  xinfo->fdPutAway);
699 }
700
701 /* print folder entry */
702
703 /* print file entry */
704 static void record_print_file(hfsp_cat_file* file)
705 {
706     printf("flags               :\t0x%X\n",     file->flags);
707     printf("reserved1           :\t0x%lX\n",    file->reserved1);
708     printf("id                  :\t%ld\n",      file->id);
709     record_print_perm   (&file->permissions);
710     record_print_FInfo  (&file->user_info);
711     record_print_FXInfo (&file->finder_info);
712     printf("text_encoding       :\t0x%lX\n",    file->text_encoding);
713     printf("reserved            :\t0x%lX\n",    file->reserved2);
714     printf("Datafork:\n");
715     volume_print_fork (&file->data_fork);
716     printf("Rsrcfork:\n");
717     volume_print_fork (&file->res_fork);
718 }
719
720 /* print info for a file or folder thread */
721 static void record_print_thread(hfsp_cat_thread* entry)
722 {
723     char buf[255]; // mh this _might_ overflow
724     unicode_uni2asc(buf, &entry->nodeName, 255);
725     printf("parent cnid :\t%ld\n", entry->parentID);
726     printf("name        :\t%s\n" , buf);
727 }
728
729 /* print the information for a record */
730 static void record_print_entry(hfsp_cat_entry* entry)
731 {
732     switch (entry->type)
733     {
734         case HFSP_FOLDER:
735             printf("=== Folder ===\n");
736             return record_print_folder(&entry->u.folder);
737         case HFSP_FILE:
738             printf("=== File ===\n");
739             return record_print_file  (&entry->u.file);
740         case HFSP_FOLDER_THREAD:
741             printf("=== Folder Thread ===\n");
742             return record_print_thread(&entry->u.thread);
743         case HFSP_FILE_THREAD:
744             printf("=== File Thread ==\n");
745             return record_print_thread(&entry->u.thread);
746         default:
747             printf("=== Unknown Record Type ===\n");
748     } ;
749 }
750
751     /* Dump all the record information to stdout */
752 void record_print(record* r)
753 {
754     printf ("keyind      :    %u\n", r->keyind);
755     record_print_key  (&r->key);
756     record_print_entry(&r->record);
757 }
758
759 #endif