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

Contents of /src/io/prom/fs/hfsplus/record.c

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 MIME type: text/plain
File size: 37564 byte(s)
import upstream CVS
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