/[pearpc]/src/io/prom/fs/hfsplus/record.c
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/record.c

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 MIME type: text/plain
File size: 37564 byte(s)
import upstream CVS
1 dpavlin 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. This file conatins various methods to read and
6     * write the record related HFS+ structures from/to memory.
7     *
8     * Copyright (C) 2000-2001 Klaus Halfmann <klaus.halfmann@t-online.de>
9     * Original 1996-1998 Robert Leslie <rob@mars.org>
10     * Additional work by Brad Boyer (flar@pants.nu)
11     * Additional work in 2004 by Stefan Weyergraf (stefan@weyergraf.de) for use in PearPC
12     *
13     * This program is free software; you can redistribute it and/or modify
14     * it under the terms of the GNU General Public License as published by
15     * the Free Software Foundation; either version 2 of the License, or
16     * (at your option) any later version.
17     *
18     * This program is distributed in the hope that it will be useful,
19     * but WITHOUT ANY WARRANTY; without even the implied warranty of
20     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21     * GNU General Public License for more details.
22     *
23     * You should have received a copy of the GNU General Public License
24     * along with this program; if not, write to the Free Software
25     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26     *
27     */
28    
29     #ifdef HAVE_CONFIG_H
30     # include "config.h"
31     # endif
32    
33     #include <errno.h>
34     #include <stdio.h>
35     #include <string.h>
36    
37     #include "libhfsp.h"
38     #include "hfstime.h"
39     #include "record.h"
40     #include "volume.h"
41     #include "btree.h"
42     #include "unicode.h"
43     #include "swab.h"
44    
45     /* read a hfsp_cat_key from memory, check for correct length
46     *
47     * @param p buffer in memory to read from
48     * @param buf buffer containing the correctly swapped structure
49     *
50     * @return pointer to next byte after structure, NULL on failure
51     */
52     char* record_readkey(char* p, void* buf)
53     {
54     hfsp_cat_key* key = (hfsp_cat_key*) buf;
55     const char* check;
56     UInt16 key_length, len,i;
57     UInt16* cp;
58    
59     key->key_length = key_length = bswabU16_inc(&p);
60     check = p;
61     key->parent_cnid = bswabU32_inc(&p);
62     key->name.strlen = len = bswabU16_inc(&p);
63     cp = key->name.name;
64     for (i=0; i < len; i++, cp++)
65     *cp = bswabU16_inc(&p);
66     /* check if keylenght was correct */
67     if (key_length != p - check)
68     HFSP_ERROR(EINVAL, "Invalid key length in record_readkey");
69     return p;
70     fail:
71     return NULL;
72     }
73    
74     /* write a hfsp_cat_key back to memory, check for correct length.
75     *
76     * @param p buffer in memory to write to
77     * @param buf memory containing the (swapped) key.
78     *
79     * @return pointer to byte after the structure or NULL on failure.
80     *
81     */
82     char* record_writekey(char* p, void* buf)
83     {
84     hfsp_cat_key* key = (hfsp_cat_key*) buf;
85     UInt16 key_length, len,i;
86     UInt16* cp;
87    
88     key_length = key->key_length;
89     len = key->name.strlen;
90     cp = key->name.name;
91     if (key_length != (6 + len * 2))
92     HFSP_ERROR(EINVAL, "Invalid key length in record_writekey");
93    
94     bstoreU16_inc(&p, key_length);
95     bstoreU32_inc(&p, key->parent_cnid);
96     bstoreU16_inc(&p, len);
97     for (i=0; i < len; i++, cp++)
98     bstoreU16_inc(&p, *cp);
99     return p;
100     fail:
101     return NULL;
102     }
103    
104     /* read a hfsp_extent_key from memory */
105     char* record_extent_readkey(char* p, void* buf)
106     {
107     hfsp_extent_key* key = (hfsp_extent_key*) buf;
108     UInt16 key_length;
109    
110     key->key_length = key_length = bswabU16_inc(&p);
111     key->fork_type = bswabU8_inc(&p);
112     key->filler = bswabU8_inc(&p);
113     if (key_length != 10)
114     HFSP_ERROR(-1, "Invalid key length in record_extent_readkey");
115     key->file_id = bswabU32_inc(&p);
116     key->start_block = bswabU32_inc(&p);
117     return p;
118     fail:
119     return NULL;
120     }
121    
122     /* write a hfsp_extent_key to memory */
123     char* record_extent_writekey(char* p, void* buf)
124     {
125     hfsp_extent_key* key = (hfsp_extent_key*) buf;
126     UInt16 key_length = key->key_length;
127     if (key_length != 10)
128     HFSP_ERROR(-1, "Invalid key length in record_extent_writekey");
129    
130     bstoreU16_inc (&p, key_length);
131     bstoreU8_inc (&p, key->fork_type);
132     bstoreU8_inc (&p, key->filler);
133     bstoreU32_inc (&p, key->file_id);
134     bstoreU32_inc (&p, key->start_block);
135     return p;
136     fail:
137     return NULL;
138     }
139    
140     /* read posix permission from memory */
141     static inline char* record_readperm(char *p, hfsp_perm* perm)
142     {
143     perm->owner= bswabU32_inc(&p);
144     perm->group= bswabU32_inc(&p);
145     perm->mode = bswabU32_inc(&p);
146     perm->dev = bswabU32_inc(&p);
147     return p;
148     }
149    
150     /* write posix permission to memory */
151     static inline char* record_writeperm(char *p, hfsp_perm* perm)
152     {
153     bstoreU32_inc (&p, perm->owner);
154     bstoreU32_inc (&p, perm->group);
155     bstoreU32_inc (&p, perm->mode );
156     bstoreU32_inc (&p, perm->dev );
157     return p;
158     }
159    
160     /* intialize posix permission from memory.
161     *
162     * TODO use current umask, user, group, etc.
163     */
164     static inline void record_initperm(hfsp_perm* perm)
165     {
166     perm->owner= 0;
167     perm->group= 0;
168     perm->mode = 0;
169     perm->dev = 0;
170     }
171    
172    
173     /* read directory info */
174     static inline char* record_readDInfo(char *p, DInfo* info)
175     {
176     info->frRect.top = bswabU16_inc(&p);
177     info->frRect.left = bswabU16_inc(&p);
178     info->frRect.bottom = bswabU16_inc(&p);
179     info->frRect.right = bswabU16_inc(&p);
180     info->frFlags = bswabU16_inc(&p);
181     info->frLocation.v = bswabU16_inc(&p);
182     info->frLocation.h = bswabU16_inc(&p);
183     info->frView = bswabU16_inc(&p);
184     return p;
185     }
186    
187     /* write directory info */
188     static inline char* record_writeDInfo(char *p, DInfo* info)
189     {
190     bstoreU16_inc (&p, info->frRect.top );
191     bstoreU16_inc (&p, info->frRect.left );
192     bstoreU16_inc (&p, info->frRect.bottom);
193     bstoreU16_inc (&p, info->frRect.right);
194     bstoreU16_inc (&p, info->frFlags );
195     bstoreU16_inc (&p, info->frLocation.v);
196     bstoreU16_inc (&p, info->frLocation.h);
197     bstoreU16_inc (&p, info->frView );
198     return p;
199     }
200    
201     /* initialize directory info */
202     static inline void record_initDInfo(DInfo* info)
203     {
204     // Hope the finder will not choke on these values
205     memset(info, 0, sizeof(DInfo));
206     /*
207     info->frRect.top = 0;
208     info->frRect.left = 0;
209     info->frRect.bottom = 0;
210     info->frRect.right = 0;
211     info->frFlags = 0;
212     info->frLocation.v = 0;
213     info->frLocation.h = 0;
214     info->frView = 0;
215     */
216     }
217    
218     /* read extra Directory info */
219     static inline char* record_readDXInfo(char *p, DXInfo* xinfo)
220     {
221     xinfo->frScroll.v = bswabU16_inc(&p);
222     xinfo->frScroll.h = bswabU16_inc(&p);
223     xinfo->frOpenChain = bswabU32_inc(&p);
224     xinfo->frUnused = bswabU16_inc(&p);
225     xinfo->frComment = bswabU16_inc(&p);
226     xinfo->frPutAway = bswabU32_inc(&p);
227     return p;
228     }
229    
230     /* write extra Directory info */
231     static inline char* record_writeDXInfo(char *p, DXInfo* xinfo)
232     {
233     bstoreU16_inc (&p, xinfo->frScroll.v );
234     bstoreU16_inc (&p, xinfo->frScroll.h );
235     bstoreU32_inc (&p, xinfo->frOpenChain);
236     bstoreU16_inc (&p, xinfo->frUnused );
237     bstoreU16_inc (&p, xinfo->frComment );
238     bstoreU32_inc (&p, xinfo->frPutAway );
239     return p;
240     }
241    
242     /* initialize extra Directory info */
243     static inline void record_initDXInfo(DXInfo* xinfo)
244     {
245     // Hope the finder will not choke on these values
246     memset(xinfo, 0, sizeof(DXInfo));
247     /*
248     xinfo->frScroll.v = 0;
249     xinfo->frScroll.h = 0;
250     xinfo->frOpenChain= 0;
251     xinfo->frUnused = 0;
252     xinfo->frComment = 0;
253     xinfo->frPutAway = 0;
254     */
255     }
256    
257    
258     /* read a hfsp_cat_folder from memory */
259     static char* record_readfolder(char *p, hfsp_cat_folder* folder)
260     {
261     folder->flags = bswabU16_inc(&p);
262     folder->valence = bswabU32_inc(&p);
263     folder->id = bswabU32_inc(&p);
264     folder->create_date = bswabU32_inc(&p);
265     folder->content_mod_date = bswabU32_inc(&p);
266     folder->attribute_mod_date = bswabU32_inc(&p);
267     folder->access_date = bswabU32_inc(&p);
268     folder->backup_date = bswabU32_inc(&p);
269     p = record_readperm (p, &folder->permissions);
270     p = record_readDInfo (p, &folder->user_info);
271     p = record_readDXInfo (p, &folder->finder_info);
272     folder->text_encoding = bswabU32_inc(&p);
273     folder->reserved = bswabU32_inc(&p);
274     return p;
275     }
276    
277     /* write a hfsp_cat_folder to memory */
278     static char* record_writefolder(char *p, hfsp_cat_folder* folder)
279     {
280     bstoreU16_inc (&p, folder->flags );
281     bstoreU32_inc (&p, folder->valence );
282     bstoreU32_inc (&p, folder->id );
283     bstoreU32_inc (&p, folder->create_date );
284     bstoreU32_inc (&p, folder->content_mod_date );
285     bstoreU32_inc (&p, folder->attribute_mod_date);
286     bstoreU32_inc (&p, folder->access_date );
287     bstoreU32_inc (&p, folder->backup_date );
288     p = record_writeperm (p, &folder->permissions);
289     p = record_writeDInfo (p, &folder->user_info);
290     p = record_writeDXInfo (p, &folder->finder_info);
291     bstoreU32_inc (&p, folder->text_encoding );
292     bstoreU32_inc (&p, folder->reserved );
293     return p;
294     }
295    
296     /* initialize a hfsp_cat_folder with given values.
297     *
298     * @vol is needed to create a new record Id.
299     * @return 0 on sucess anything else on error.
300     */
301     static int record_initfolder(volume* vol, hfsp_cat_folder* folder)
302     {
303     UInt32 macNow = HFSPTIMEDIFF + time(NULL);
304    
305     folder->flags = 0;
306     folder->valence = 0; // no subfiles/folders yet
307     if (! (folder->id = volume_get_nextid(vol))) // oops possible wrap around overflow
308     return -1;
309     folder->create_date = macNow;
310     folder->content_mod_date = macNow;
311     folder->attribute_mod_date = macNow;
312     folder->access_date = macNow;
313     folder->backup_date = 0;
314     record_initperm (&folder->permissions);
315     record_initDInfo (&folder->user_info);
316     record_initDXInfo (&folder->finder_info);
317     folder->text_encoding = 0; // Not supported, sorry
318     folder->reserved = 0;
319     return 0;
320     }
321    
322     /* read file info */
323     static inline char* record_readFInfo(char *p, FInfo* info)
324     {
325     info->fdType = bswabU32_inc(&p);
326     info->fdCreator = bswabU32_inc(&p);
327     info->fdFlags = bswabU16_inc(&p);
328     info->fdLocation.v = bswabU16_inc(&p);
329     info->fdLocation.h = bswabU16_inc(&p);
330     info->fdFldr = bswabU16_inc(&p);
331     return p;
332     }
333    
334     /* write file info */
335     static inline char* record_writeFInfo(char *p, FInfo* info)
336     {
337     bstoreU32_inc (&p, info->fdType );
338     bstoreU32_inc (&p, info->fdCreator );
339     bstoreU16_inc (&p, info->fdFlags );
340     bstoreU16_inc (&p, info->fdLocation.v);
341     bstoreU16_inc (&p, info->fdLocation.h);
342     bstoreU16_inc (&p, info->fdFldr );
343     return p;
344     }
345    
346     /* initialize file info */
347     static inline void record_initFInfo(FInfo* info)
348     {
349     // should use something better somehow
350     info->fdType = sig('T','E','X','T');
351     info->fdCreator = HPLS_SIGNATURE;
352     info->fdFlags = 0; // dunno any finder flags
353     info->fdLocation.v = 0;
354     info->fdLocation.h = 0;
355     info->fdFldr = 0;
356     }
357    
358     /* read extra File info */
359     static inline char* record_readFXInfo(char *p, FXInfo* xinfo)
360     {
361     xinfo->fdIconID = bswabU16_inc(&p);
362     xinfo->fdUnused[0] = bswabU16_inc(&p);
363     xinfo->fdUnused[1] = bswabU16_inc(&p);
364     xinfo->fdUnused[2] = bswabU16_inc(&p);
365     xinfo->fdUnused[3] = bswabU16_inc(&p);
366     xinfo->fdComment = bswabU16_inc(&p);
367     xinfo->fdPutAway = bswabU32_inc(&p);
368     return p;
369     }
370    
371     /* write extra File info */
372     static inline char* record_writeFXInfo(char *p, FXInfo* xinfo)
373     {
374     bstoreU16_inc (&p, xinfo->fdIconID);
375     bstoreU16_inc (&p, xinfo->fdUnused[0]);
376     bstoreU16_inc (&p, xinfo->fdUnused[1]);
377     bstoreU16_inc (&p, xinfo->fdUnused[2]);
378     bstoreU16_inc (&p, xinfo->fdUnused[3]);
379     bstoreU16_inc (&p, xinfo->fdComment);
380     bstoreU16_inc (&p, xinfo->fdPutAway);
381     return p;
382     }
383    
384     /* initialize extra File info */
385     static inline void record_initFXInfo(FXInfo* xinfo)
386     {
387     // Hope the finder will not choke on these values
388     memset(xinfo, 0, sizeof(FXInfo));
389     /*
390     xinfo->fdIconID = 0;
391     xinfo->fdUnused[0] = 0;
392     xinfo->fdUnused[1] = 0;
393     xinfo->fdUnused[2] = 0;
394     xinfo->fdUnused[3] = 0;
395     xinfo->fdComment = 0;
396     xinfo->fdPutAway = 0;
397     */
398     }
399    
400     /* read a hfsp_cat_file from memory */
401     static char* record_readfile(char *p, hfsp_cat_file* file)
402     {
403     file->flags = bswabU16_inc(&p);
404     file->reserved1 = bswabU32_inc(&p);
405     file->id = bswabU32_inc(&p);
406     file->create_date = bswabU32_inc(&p);
407     file->content_mod_date = bswabU32_inc(&p);
408     file->attribute_mod_date = bswabU32_inc(&p);
409     file->access_date = bswabU32_inc(&p);
410     file->backup_date = bswabU32_inc(&p);
411     p = record_readperm (p, &file->permissions);
412     p = record_readFInfo (p, &file->user_info);
413     p = record_readFXInfo (p, &file->finder_info);
414     file->text_encoding = bswabU32_inc(&p);
415     file->reserved2 = bswabU32_inc(&p);
416     p = volume_readfork (p, &file->data_fork);
417     return volume_readfork (p, &file->res_fork);
418     }
419    
420     /* write a hfsp_cat_file to memory */
421     static char* record_writefile(char *p, hfsp_cat_file* file)
422     {
423     bstoreU16_inc(&p, file->flags);
424     bstoreU16_inc(&p, file->reserved1);
425     bstoreU16_inc(&p, file->id);
426     bstoreU16_inc(&p, file->create_date);
427     bstoreU16_inc(&p, file->content_mod_date);
428     bstoreU16_inc(&p, file->attribute_mod_date);
429     bstoreU16_inc(&p, file->access_date);
430     bstoreU16_inc(&p, file->backup_date);
431     p = record_writeperm (p, &file->permissions);
432     p = record_writeFInfo (p, &file->user_info);
433     p = record_writeFXInfo (p, &file->finder_info);
434     bstoreU16_inc(&p, file->text_encoding);
435     bstoreU16_inc(&p, file->reserved2 );
436     p = volume_writefork (p, &file->data_fork);
437     return volume_writefork (p, &file->res_fork);
438     }
439    
440     /* initialize a hfsp_cat_file with given values.
441     *
442     * vol needed to create new Id
443     */
444     static int record_initfile(volume* vol, hfsp_cat_file* file)
445     {
446     UInt32 macNow = HFSPTIMEDIFF + time(NULL);
447    
448     file->flags = 0;
449     file->reserved1 = 0; // no subfiles/folders yet
450     if (! (file->id = volume_get_nextid(vol))) // oops possible wrap around overflow
451     return -1;
452     file->create_date = macNow;
453     file->content_mod_date = macNow;
454     file->attribute_mod_date = macNow;
455     file->access_date = macNow;
456     file->backup_date = 0;
457     record_initperm (&file->permissions);
458     record_initFInfo (&file->user_info);
459     record_initFXInfo (&file->finder_info);
460     file->text_encoding = 0; // Not supported, sorry
461     file->reserved2 = 0;
462     volume_initfork(vol,&file->data_fork, HFSP_EXTENT_DATA);
463     volume_initfork(vol,&file->res_fork, HFSP_EXTENT_RSRC);
464     return 0;
465     }
466    
467    
468     /* read a hfsp_cat_thread from memory */
469     static char* record_readthread(char *p, hfsp_cat_thread* entry)
470     {
471     int i;
472     UInt16 len;
473     UInt16* cp;
474    
475     entry-> reserved = bswabU16_inc(&p);
476     entry-> parentID = bswabU32_inc(&p);
477     entry->nodeName.strlen = len= bswabU16_inc(&p);
478     cp = entry->nodeName.name;
479     if (len > 255)
480     HFSP_ERROR(-1, "Invalid key length in record_thread");
481     for (i=0; i < len; i++, cp++)
482     *cp = bswabU16_inc(&p);
483     return p;
484     fail:
485     return NULL;
486     }
487    
488     /* write a hfsp_cat_thread to memory */
489     static char* record_writethread(char *p, hfsp_cat_thread* entry)
490     {
491     int i;
492     UInt16 len;
493     UInt16* cp;
494    
495     bstoreU16_inc(&p, entry->reserved);
496     bstoreU32_inc(&p, entry->parentID);
497     /* this is bad style, friends... (SW) */
498     /* bstoreU16_inc(&p, len = entry->nodeName.strlen);*/
499     len = entry->nodeName.strlen;
500     bstoreU16_inc(&p, len);
501     cp = entry->nodeName.name;
502     if (len > 255)
503     HFSP_ERROR(-1, "Invalid key length in record_thread");
504     for (i=0; i < len; i++, cp++)
505     bstoreU16_inc(&p, *cp);
506     return p;
507     fail:
508     return NULL;
509     }
510    
511    
512     /* read a hfsp_cat_entry from memory */
513     char* record_readentry(char *p, void* entry)
514     {
515     UInt16 type = bswabU16_inc(&p);
516     hfsp_cat_entry* e = (hfsp_cat_entry*) entry;
517     e->type = type;
518     switch (type)
519     {
520     case HFSP_FOLDER:
521     return record_readfolder(p, &e->u.folder);
522     case HFSP_FILE:
523     return record_readfile (p, &e->u.file);
524     case HFSP_FOLDER_THREAD:
525     case HFSP_FILE_THREAD:
526     return record_readthread(p, &e->u.thread);
527     default:
528     HFSP_ERROR(-1, "Unexpected record type in record_readentry");
529     } ;
530     fail:
531     return NULL;
532     }
533    
534     /* write a hfsp_cat_entry to memory */
535     char* record_writeentry(char *p, hfsp_cat_entry* entry)
536     {
537     UInt16 type = entry->type;
538     bstoreU16_inc(&p, type);
539     switch (type)
540     {
541     case HFSP_FOLDER:
542     return record_writefolder(p, &entry->u.folder);
543     case HFSP_FILE:
544     return record_writefile (p, &entry->u.file);
545     case HFSP_FOLDER_THREAD:
546     case HFSP_FILE_THREAD:
547     return record_writethread(p, &entry->u.thread);
548     default:
549     HFSP_ERROR(-1, "Unexpected record type in record_writeentry");
550     } ;
551     fail:
552     return NULL;
553     }
554    
555     /* read an extent record from memory */
556     // For dependency reasons this actually is found in volume.h
557     char* record_extent_readrecord(char *p, void* entry)
558     {
559     return volume_readextent(p, (hfsp_extent*) entry);
560     }
561    
562    
563     /* intialize the record with the given index entry in the btree. */
564     int record_init(record* r, btree* bt, node_buf* buf, UInt16 index)
565     {
566     void *p;
567     r-> tree = bt;
568     p = btree_key_by_index(bt,buf,index);
569     if (!p)
570     return -1;
571     p = record_readkey (p, &r->key);
572     if (!p)
573     return -1;
574     /* void *help = p; // se comment below */
575     p = record_readentry(p, &r->record);
576     /* This was for testing write cache only
577     void * help;
578     help = record_writeentry(help, &r->record);
579     if (p != help)
580     HFSP_ERROR(-1, "Error in write entry");
581     */
582     if (!p)
583     return -1;
584     r->node_index = buf->index;
585     r-> keyind = index;
586    
587     return 0;
588     /*
589     fail:
590     return -1;
591     */
592     }
593    
594     /* Update the record using its node- and key-index.
595     *
596     * Only use this function with a write lock, directly
597     * after reading the record, otherwise use update_bykey().
598     */
599     int record_update(record* r)
600     {
601     btree *tree= r->tree;
602     node_buf *buf = btree_node_by_index(tree, r->node_index, NODE_DIRTY);
603     void *p = btree_key_by_index (tree, buf, r->keyind);
604     if (!p)
605     return -1;
606     p = record_writekey (p, &r->key);
607     if (!p)
608     return -1;
609     p = record_writeentry(p, &r->record);
610     if (!p)
611     return -1;
612    
613     return 0;
614     }
615    
616    
617     /* intialize the record with the given index entry in the btree. */
618     static int record_init_extent(extent_record* r, btree* bt, node_buf* buf, UInt16 index)
619     {
620     char *p;
621     r-> tree = bt;
622     p = btree_key_by_index(bt, buf,index);
623     if (!p)
624     return -1;
625     p = record_extent_readkey(p, &r->key);
626     if (!p)
627     return -1;
628     p = volume_readextent(p, r->extent);
629     if (!p)
630     return -1;
631     r->node_index = buf->index;
632     r-> keyind = index;
633    
634     return 0;
635     }
636    
637     /* intialize the record to the first record of the tree
638     * which is (per design) the root node.
639     */
640     int record_init_root(record* r, btree* tree)
641     {
642     // Position to first leaf node ...
643     UInt32 leaf_head = tree->head.leaf_head;
644     node_buf* buf = btree_node_by_index(tree, leaf_head, NODE_CLEAN);
645     if (!buf)
646     return -1;
647     return record_init(r, tree, buf, 0);
648     }
649    
650     /* initialize a (catalog) record with given type and (ascii) name.
651     * parent must be a HFSP_FOLDER or FOLDER_THREAD
652     * You should normally call record_insert afterwards.
653     */
654     int record_init_string(record* r, UInt16 type, char* name, record* parent)
655     {
656     int result = 0;
657     hfsp_cat_key* key = &r->key;
658     hfsp_cat_entry* entry = &r->record;
659     UInt16 ptype = parent->record.type;
660    
661     memset(r, 0, sizeof *r); // **** Debugging only
662    
663     r->tree = parent->tree;
664     r->node_index = 0;
665     r->keyind = 0;
666     key->key_length = 6 + 2 * unicode_asc2uni(&key->name,name);
667     // 6 for minumum size
668     if (ptype == HFSP_FOLDER)
669     key->parent_cnid= parent->record.u.folder.id;
670     else if (ptype == HFSP_FOLDER_THREAD)
671     key->parent_cnid= parent->key.parent_cnid;
672     else // no kind of folder ??
673     {
674     hfsp_error = "parent for record_init_string is not a folder.";
675     return EINVAL;
676     }
677    
678     switch(type)
679     {
680     case HFSP_FOLDER :
681     entry->type = type;
682     record_initfolder(parent->tree->vol, &entry->u.folder);
683     break;
684     case HFSP_FILE :
685     entry->type = type;
686     record_initfile(parent->tree->vol, &entry->u.file);
687     break;
688     // Those are unsupported use the types above instead
689     // record_init will care about the threads
690     case HFSP_FOLDER_THREAD :
691     case HFSP_FILE_THREAD :
692     default:
693     hfsp_error = "Unsupported type for record_init_string()";
694     result = -1;
695     }
696    
697     return result;
698     }
699    
700     /* initialize a (catalog) record thread by its original record
701     * used internally by record_insert.
702     */
703     static int record_init_thread(record* r, record* template)
704     {
705     int result = 0;
706     hfsp_cat_key* key = &r->key;
707     hfsp_cat_entry* entry = &r->record;
708     UInt16 type = template->record.type;
709     hfsp_cat_thread* thread;
710    
711     r->tree = template->tree;
712     r->node_index = 0;
713     r->keyind = 0;
714     key->key_length = 6; // empty name is ok for a thread
715     key->parent_cnid= template->record.u.folder.id;
716    
717     thread = &entry->u.thread;
718     switch(type)
719     {
720     case HFSP_FOLDER :
721     case HFSP_FILE :
722     entry->type = type + HFSP_THREAD_OFFSET;
723     thread->reserved = 0;
724     thread->parentID = template->key.parent_cnid;
725     thread->nodeName = template->key.name;
726     break;
727     case HFSP_FOLDER_THREAD :
728     case HFSP_FILE_THREAD :
729     default:
730     hfsp_error = "Cannot create a thread for a thread";
731     result = -1;
732     }
733    
734     return result;
735     }
736    
737     /* Compare two cat_keys ... */
738     int record_key_compare(void* k1, void* k2)
739     {
740     hfsp_cat_key* key1 = (hfsp_cat_key*) k1;
741     hfsp_cat_key* key2 = (hfsp_cat_key*) k2;
742     int diff = key2->parent_cnid - key1->parent_cnid;
743     if (!diff) // same parent
744     diff = fast_unicode_compare(&key1->name, &key2->name);
745     return diff;
746     }
747    
748     /* Compare two extent_keys ... */
749     int record_extent_key_compare(void* k1, void* k2)
750     {
751     hfsp_extent_key* key1 = (hfsp_extent_key*) k1;
752     hfsp_extent_key* key2 = (hfsp_extent_key*) k2;
753     int diff = key2->fork_type - key1->fork_type;
754     if (!diff) // same type
755     {
756     diff = key2->file_id - key1->file_id;
757     if (!diff) // same file
758     diff = key2->start_block - key1->start_block;
759     }
760     return diff;
761     }
762    
763     /* Position node in btree so that key might be inside */
764     static node_buf* record_find_node(btree* tree, void *key)
765     {
766     int start, end, mid, comp; // components of a binary search
767     char *p = NULL;
768     char curr_key[tree->head.max_key_len];
769     // The current key under examination
770     hfsp_key_read readkey = tree->kread;
771     hfsp_key_compare key_compare = tree->kcomp;
772     UInt32 index;
773     node_buf* node =
774     btree_node_by_index(tree, tree->head.root, NODE_CLEAN);
775     HFSP_SYNC_START(HFSP_READLOCK, node);
776     if (!node)
777     HFSP_ERROR(-1, "record_find_node: Cant position to root node");
778     while (node->desc.kind == HFSP_NODE_NDX)
779     {
780     mid = start = 0;
781     end = node->desc.num_rec;
782     comp = -1;
783     while (start < end)
784     {
785     mid = (start + end) >> 1;
786     p = btree_key_by_index(tree, node, mid);
787     if (!p)
788     HFSP_ERROR(-1, "record_find_node: unexpected error");
789     p = readkey (p, curr_key);
790     if (!p)
791     HFSP_ERROR(-1, "record_find_node: unexpected error");
792     comp = key_compare(curr_key, key);
793     if (comp > 0)
794     start = mid + 1;
795     else if (comp < 0)
796     end = mid;
797     else
798     break;
799     }
800     if (!p) // Empty tree, fascinating ...
801     HFSP_ERROR(-1, "record_find_node: unexpected empty node");
802     if (comp < 0) // mmh interesting key is before this key ...
803     {
804     if (mid == 0)
805     return NULL; // nothing before this key ..
806     p = btree_key_by_index(tree, node, mid-1);
807     if (!p)
808     HFSP_ERROR(-1, "record_find_node: unexpected error");
809     p = readkey (p, curr_key);
810     if (!p)
811     HFSP_ERROR(-1, "record_find_node: unexpected error");
812     }
813    
814     index = bswabU32_inc(&p);
815     node = btree_node_by_index(tree, index, NODE_CLEAN);
816     }
817     HFSP_SYNC_END(HFSP_READLOCK, node);
818     return node; // go on and use the found node
819     fail:
820     HFSP_SYNC_END(HFSP_READLOCK, node);
821     return NULL;
822     }
823    
824     /* search for the given key in the btree.
825     *
826     * returns pointer to memory just after key or NULL.
827     *
828     * *keyind recives the index where the key was found
829     * (or could be inserted.)
830     * *node_index is the index of the node where key was found/might
831     * be inserted before
832     */
833     char* record_find_key(btree* tree, void* key, int* keyind, UInt16* node_index)
834     {
835     node_buf* buf = record_find_node(tree, key);
836     if (buf)
837     {
838     int comp = -1;
839     int start = 0; // components of a binary search
840     int end = buf->desc.num_rec;
841     int mid = -1;
842     char *p = NULL;
843     char curr_key[tree->head.max_key_len];
844     hfsp_key_read readkey = tree->kread;
845     hfsp_key_compare key_compare = tree->kcomp;
846     HFSP_SYNC_START(HFSP_READLOCK, node);
847     while (start < end)
848     {
849     mid = (start + end) >> 1;
850     p = btree_key_by_index(tree, buf, mid);
851     if (!p)
852     HFSP_ERROR(-1, "record_find_key: unexpected error");
853     p = readkey (p, curr_key);
854     if (!p)
855     goto fail;
856     comp = key_compare(curr_key, key);
857     if (comp > 0)
858     start = mid + 1;
859     else if (comp < 0)
860     end = mid;
861     else
862     break;
863     }
864     if (!p) // Empty tree, fascinating ...
865     HFSP_ERROR(ENOENT, "record_find_key: unexpected empty node");
866     *node_index = buf->index;
867     if (!comp) // found something ...
868     {
869     *keyind = mid; // Thats where we found it
870     HFSP_SYNC_END(HFSP_READLOCK, node);
871     return p;
872     }
873     *keyind = end; // Here we can insert a new key
874     }
875     HFSP_ERROR(ENOENT, NULL);
876     fail:
877     HFSP_SYNC_END(HFSP_READLOCK, node);
878     return NULL;
879     }
880    
881     /* intialize the record by searching for the given key in the btree.
882     *
883     * r is umodified on error.
884     */
885     int record_init_key(record* r, btree* tree, hfsp_cat_key* key)
886     {
887     int keyind;
888     UInt16 node_index;
889     char *p = record_find_key(tree, key, &keyind, &node_index);
890    
891     if (p)
892     {
893     r -> tree = tree;
894     r -> node_index= node_index;
895     r -> keyind = keyind;
896     r -> key = *key; // Better use a record_key_copy ...
897     p = record_readentry(p, &r->record);
898     if (!p)
899     HFSP_ERROR(-1, "record_init_key: unexpected error");
900     return 0;
901     }
902     fail:
903     return -1;
904     }
905    
906     /* intialize the extent_record to the extent identified by the
907     * (first) blockindex.
908     *
909     * forktype: either HFSP_EXTEND_DATA or HFSP_EXTEND_RSRC
910     */
911     int record_init_file(extent_record* r, btree* tree,
912     UInt8 forktype, UInt32 fileId, UInt32 blockindex)
913     {
914     int keyind;
915     UInt16 node_index;
916     hfsp_extent_key key = { 10, forktype, 0, fileId, blockindex };
917     char *p = record_find_key(tree, &key, &keyind, &node_index);
918    
919     if (p)
920     {
921     r -> tree = tree;
922     r -> node_index= node_index;
923     r -> keyind = keyind;
924     r -> key = key; // Better use a record_key_copy ...
925     p = volume_readextent(p, r->extent);
926     if (!p)
927     HFSP_ERROR(-1, "record_init_file: unexpected error");
928     return 0;
929     }
930     fail:
931     return -1;
932     }
933    
934     /* intialize the record to the folder identified by cnid
935     */
936     int record_init_cnid(record* r, btree* tree, UInt32 cnid)
937     {
938     hfsp_cat_key thread_key; // the thread is the first record
939    
940     thread_key.key_length = 6; // null name (like '.' in unix )
941     thread_key.parent_cnid = cnid;
942     thread_key.name.strlen = 0;
943    
944     return record_init_key(r, tree, &thread_key);
945     }
946    
947     /* intialize the record to the first record of the parent.
948     */
949     int record_init_parent(record* r, record* parent)
950     {
951     if (parent->record.type == HFSP_FOLDER)
952     return record_init_cnid(r, parent->tree, parent->record.u.folder.id);
953     else if(parent->record.type == HFSP_FOLDER_THREAD)
954     {
955     if (r != parent)
956     *r = *parent; // The folder thread is in fact the first entry, like '.'
957     return 0;
958     }
959     HFSP_ERROR(EINVAL,
960     "record_init_parent: parent is neither folder nor folder thread.");
961    
962     fail:
963     return EINVAL;
964     }
965    
966     /* intialize the record to the parent directory of the given record.
967     */
968     int record_find_parent(record* r, record* from)
969     {
970     UInt16 type = from->record.type;
971     btree* bt = from->tree;
972     hfsp_cat_key parentKey;
973     if (type == HFSP_FOLDER || type == HFSP_FILE)
974     if (record_init_cnid(r, bt, from->key.parent_cnid))
975     goto fail;
976     // r now is the folder thread, position to the real folder
977     parentKey.key_length = 6 + r->record.u.thread.nodeName.strlen * 2;
978     parentKey.parent_cnid = r->record.u.thread.parentID;
979     parentKey.name = r->record.u.thread.nodeName;
980     if (record_init_key(r, bt, &parentKey))
981     goto fail;
982    
983     return 0;
984     fail:
985     return -1;
986    
987     }
988    
989     /* find correct node record for given node and *pindex.
990     *
991     * index of record in this (or next) node
992     */
993     static node_buf* prepare_next(btree* tree, UInt16 node_index, UInt16* pindex)
994     {
995     node_buf* buf = btree_node_by_index(tree, node_index, NODE_CLEAN);
996     btree_node_desc* desc = &buf->desc;
997     UInt32 numrec = desc->num_rec;
998     if (*pindex >= numrec) // move on to next node
999     {
1000     UInt16 next = desc->next;
1001     *pindex = 0;
1002     if (!next /* is there a next node ? */
1003     || !( buf = btree_node_by_index(tree, next, NODE_CLEAN)))
1004     return NULL;
1005     }
1006     return buf;
1007     }
1008     /* move record foreward to next entry.
1009     *
1010     * In case of an error the value of *r is undefined !
1011     */
1012     int record_next(record* r)
1013     {
1014     btree* tree = r->tree;
1015     UInt16 index = r->keyind +1;
1016     UInt32 parent;
1017     node_buf* buf = prepare_next(tree, r->node_index, &index);
1018    
1019     if (!buf)
1020     return ENOENT; // No (more) such file or directory
1021    
1022     parent = r->key.parent_cnid;
1023    
1024     if (record_init(r, tree, buf, index))
1025     return -1;
1026    
1027     if (r->key.parent_cnid != parent || // end of current directory
1028     index != r->keyind) // internal error ?
1029     return ENOENT; // No (more) such file or directory
1030    
1031     return 0;
1032     }
1033    
1034     /* move record foreward to next extent record.
1035     *
1036     * In case of an error the value of *r is undefined !
1037     */
1038     int record_next_extent(extent_record* r)
1039     {
1040     btree* tree = r->tree;
1041     UInt16 index = r->keyind +1;
1042     UInt32 file_id;
1043     UInt8 fork_type;
1044     node_buf* buf = prepare_next(tree, r->node_index, &index);
1045    
1046     if (!buf)
1047     return ENOENT; // No (more) such file or directory
1048    
1049     file_id = r->key.file_id;
1050     fork_type = r->key.fork_type;
1051    
1052     if (record_init_extent(r, tree, buf, index))
1053     return -1;
1054    
1055     if (r->key.file_id != file_id || // end of current file
1056     r->key.fork_type != fork_type || // end of current fork
1057     index != r->keyind) // internal error ?
1058     return ENOENT; // No (more) such file or directory
1059    
1060     return 0;
1061     }
1062    
1063     /* intialize the record by searching for the given string in the given folder.
1064     *
1065     * parent and r may be the same.
1066     */
1067     int record_init_string_parent(record* r, record* parent, char* name)
1068     {
1069     hfsp_cat_key key;
1070    
1071     if (parent->record.type == HFSP_FOLDER)
1072     key.parent_cnid = parent->record.u.folder.id;
1073     else if(parent->record.type == HFSP_FOLDER_THREAD)
1074     key.parent_cnid = parent->key.parent_cnid;
1075     else
1076     HFSP_ERROR(-1, "record_init_string_parent: parent is not a folder.");
1077    
1078     key.key_length = 6 + unicode_asc2uni(&key.name,name); // 6 for minumum size
1079     return record_init_key(r, parent->tree, &key);
1080    
1081     fail:
1082     return -1;
1083     }
1084    
1085     /* move record up in folder hierarchy (if possible) */
1086     int record_up(record* r)
1087     {
1088     if (r->record.type == HFSP_FOLDER)
1089     {
1090     // locate folder thread
1091     if (record_init_cnid(r, r->tree, r->record.u.folder.id))
1092     return -1;
1093     }
1094     else if(r->record.type == HFSP_FOLDER_THREAD)
1095     {
1096     // do nothing were are already where we want to be
1097     }
1098     else
1099     HFSP_ERROR(-1, "record_up: record is neither folder nor folder thread.");
1100    
1101     if(r->record.type != HFSP_FOLDER_THREAD)
1102     HFSP_ERROR(-1, "record_up: unable to locate parent");
1103     return record_init_cnid(r, r->tree, r->record.u.thread.parentID);
1104    
1105     fail:
1106     return -1;
1107     }
1108    
1109     /* Delete the record from the tree but dont care about its type.
1110     * helper function for record_delete */
1111    
1112     static int record_delete_direct(record *r)
1113     {
1114     btree *bt = r->tree;
1115     record parent; // Parent folder of the deleted record
1116     UInt16 type = r->record.type;
1117     hfsp_vh *volheader;
1118    
1119     HFSP_SYNC_START(HFSP_WRITELOCK, bt);
1120    
1121     // Must reload record it may bave become invalid..
1122     if (record_init_key(r, bt, &r->key))
1123     goto fail;
1124    
1125     btree_remove_record(bt, r->node_index, r->keyind);
1126    
1127     // Care about valence only when not using threads ...
1128     if (type <= HFSP_THREAD_OFFSET)
1129     {
1130     if (record_find_parent(&parent, r))
1131     goto fail;
1132     if (parent.record.u.folder.valence == 0) {
1133     // fprintf(stderr, "Deleting item from folder with 0 items !?\n");
1134     } else {
1135     parent.record.u.folder.valence --;
1136     parent.record.u.folder.content_mod_date = HFSPTIMEDIFF + time(NULL);
1137     // write back that folder ...
1138     record_update(&parent);
1139     }
1140     }
1141    
1142     volheader = &bt->vol->vol;
1143     HFSP_SYNC_END(HFSP_WRITELOCK, bt);
1144    
1145     // Update header depending on type
1146     if (type == HFSP_FOLDER_THREAD)
1147     volheader->folder_count--;
1148     else if (type == HFSP_FILE)
1149     volheader->file_count--;
1150    
1151     return 0;
1152     fail:
1153     HFSP_SYNC_END(HFSP_WRITELOCK, bt);
1154     return -1;
1155     }
1156    
1157     /* recursivly remove contents of folder from btree
1158     *
1159     * r must be a folder thread.
1160     */
1161     static int record_delete_recurse(record* r, int flags)
1162     {
1163     record iter = *r; // iterator for entries
1164     int result = 0;
1165     if (r->record.type != HFSP_FOLDER_THREAD)
1166     return -1; // should not happen !
1167    
1168     while (!result && !record_next(&iter))
1169     {
1170     if (flags & RECORD_DELETE_RECURSE)
1171     result = record_delete(&iter, flags);
1172     // Mmh, this will fail as soon as the b*tree is reorganized :(
1173     else
1174     return ENOTEMPTY; // must not delete non-empty directory
1175     iter = *r; // reset iterator
1176     }
1177    
1178     return 0;
1179     }
1180    
1181     /* remove record from btree, It does not care about any
1182     * forks associated with a file (yet) */
1183     int record_delete(record* r, int flags)
1184     {
1185     btree *bt = r->tree;
1186     record parent; // Parent folder of the deleted record
1187     hfsp_cat_key parentKey;
1188     UInt16 type = r->record.type;
1189     int result = 0;
1190    
1191     if (type == HFSP_FOLDER && !(flags & RECORD_DELETE_DIRECT))
1192     {
1193     record thread;
1194     // locate folder thread and delete it
1195     result = record_init_cnid(&thread, bt, r->record.u.folder.id);
1196     if (!result)
1197     result = record_delete(&thread, flags | RECORD_DELETE_DIRECT);
1198     // failing to delete the folder now will leave the
1199     // btree inconsistant, but this should not happen any more
1200     }
1201    
1202     if (type == HFSP_FOLDER_THREAD)
1203     {
1204     // will result in error in case folder is not empty
1205     result = record_delete_recurse(r, flags & ~RECORD_DELETE_DIRECT);
1206    
1207     if (!result && !(flags & RECORD_DELETE_DIRECT))
1208     {
1209     record folder;
1210     hfsp_cat_key folderKey;
1211     // locate folder for thread
1212     folderKey.key_length = 6 + r->record.u.thread.nodeName.strlen * 2;
1213     folderKey.parent_cnid = r->record.u.thread.parentID;
1214     folderKey.name = r->record.u.thread.nodeName;
1215     result = record_init_key(&parent, bt, &parentKey);
1216     if (!result) // shortcut recursive call
1217     result = record_delete_direct(&folder);
1218     // failing to delete the folder thread now will leave the
1219     // btree inconsistant, but this should not happen any more
1220     }
1221     }
1222    
1223     if (!result)
1224     result = record_delete_direct(r);
1225    
1226     return result;
1227     }
1228    
1229     /* insert record into btree, It does not care about any
1230     * forks associated with a file (yet)
1231     * ToDo: Care about parent and header counts
1232     *
1233     */
1234     int record_insert(record* r)
1235     {
1236     btree *bt = r->tree;
1237     record parent; // Parent folder of the new record
1238     UInt16 type = r->record.type;
1239     int result = 0;
1240     char buf[sizeof(record)]; // a bit too long, well
1241     char* p = buf;
1242     int len; // actual len of buffer used
1243     int keyind; // index where key should be inserted
1244     UInt16 nodeind; // node where record should be inserted
1245     hfsp_vh *volheader;
1246    
1247     // now insert thread for file/folder
1248     if (type == HFSP_FOLDER || type == HFSP_FILE)
1249     {
1250     record thread;
1251     // create folder thread and insert it
1252     result = record_init_thread(&thread, r);
1253     if (!result)
1254     result = record_insert(&thread);
1255     }
1256    
1257     HFSP_SYNC_START(HFSP_WRITELOCK, bt);
1258    
1259     // Find out where to insert the record
1260     if (record_find_key(bt, &r->key, &keyind, &nodeind)) {
1261     hfsp_error = "File/Folder already exists";
1262     HFSP_ERROR(EEXIST, hfsp_error);
1263     }
1264    
1265     // Create memory image
1266     p = record_writekey (p, &r->key);
1267     if (!p)
1268     return -1; // ????
1269     p = record_writeentry(p, &r->record);
1270     if (!p)
1271     return -1; // ????
1272     // Insert the buffer
1273     len = p - buf;
1274     if (len > bt->max_rec_size) // Emergency bail out, sorry
1275     {
1276     /* fprintf(stderr,"Unexpected Buffer overflow in record_insert %d > %d",
1277     len, sizeof(bt->max_rec_size));*/
1278     // exit(-1);
1279     goto fail;
1280     }
1281     if (btree_insert_record(bt,nodeind,keyind,buf,len))
1282     HFSP_ERROR(ENOSPC, "Unable to insert record into tree (volume full ?)");
1283    
1284     // Ignore threads for valence and file/folder counts
1285     if (type == HFSP_FOLDER || type == HFSP_FILE)
1286     {
1287     // Update parent valence
1288     if (record_find_parent(&parent, r))
1289     goto fail;
1290    
1291     parent.record.u.folder.valence ++;
1292     parent.record.u.folder.content_mod_date = HFSPTIMEDIFF + time(NULL);
1293     // write back that folder ...
1294     record_update(&parent);
1295    
1296     volheader = &bt->vol->vol;
1297    
1298     // Update header depending on type
1299     if (type == HFSP_FOLDER)
1300     volheader->folder_count++;
1301     else if (type == HFSP_FILE)
1302     volheader->file_count++;
1303     }
1304     HFSP_SYNC_END(HFSP_WRITELOCK, bt);
1305     return result;
1306     fail:
1307     HFSP_SYNC_END(HFSP_WRITELOCK, bt);
1308     return -1;
1309     }

  ViewVC Help
Powered by ViewVC 1.1.26