1 /* 2 * hfsutils - tools for reading and writing Macintosh HFS volumes 3 * Copyright (C) 1996, 1997 Robert Leslie 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20 # include <stdlib.h> 21 # include <string.h> 22 # include <errno.h> 23 24 # include "internal.h" 25 # include "data.h" 26 # include "block.h" 27 # include "file.h" 28 # include "btree.h" 29 # include "node.h" 30 31 /* 32 * NAME: btree->getnode() 33 * DESCRIPTION: retrieve a numbered node from a B*-tree file 34 */ 35 int bt_getnode(node *np) 36 { 37 btree *bt = np->bt; 38 block *bp = &np->data; 39 unsigned char *ptr; 40 int i; 41 42 /* verify the node exists and is marked as in-use */ 43 44 if (np->nnum < 0 || (np->nnum > 0 && np->nnum >= bt->hdr.bthNNodes)) 45 { 46 ERROR(EIO, "read nonexistent b*-tree node"); 47 return -1; 48 } 49 50 if (bt->map && ! BMTST(bt->map, np->nnum)) 51 { 52 ERROR(EIO, "read unallocated b*-tree node"); 53 return -1; 54 } 55 56 if (f_getblock(&bt->f, np->nnum, bp) < 0) 57 return -1; 58 59 ptr = *bp; 60 61 d_fetchl(&ptr, (long *) &np->nd.ndFLink); 62 d_fetchl(&ptr, (long *) &np->nd.ndBLink); 63 d_fetchb(&ptr, (char *) &np->nd.ndType); 64 d_fetchb(&ptr, (char *) &np->nd.ndNHeight); 65 d_fetchw(&ptr, (short *) &np->nd.ndNRecs); 66 d_fetchw(&ptr, &np->nd.ndResv2); 67 68 if (np->nd.ndNRecs > HFS_MAXRECS) 69 { 70 ERROR(EIO, "too many b*-tree node records"); 71 return -1; 72 } 73 74 i = np->nd.ndNRecs + 1; 75 76 ptr = *bp + HFS_BLOCKSZ - (2 * i); 77 78 while (i--) 79 d_fetchw(&ptr, (short *) &np->roff[i]); 80 81 return 0; 82 } 83 84 /* 85 * NAME: btree->putnode() 86 * DESCRIPTION: store a numbered node into a B*-tree file 87 */ 88 int bt_putnode(node *np) 89 { 90 btree *bt = np->bt; 91 block *bp = &np->data; 92 unsigned char *ptr; 93 int i; 94 95 /* verify the node exists and is marked as in-use */ 96 97 if (np->nnum && np->nnum >= bt->hdr.bthNNodes) 98 { 99 ERROR(EIO, "write nonexistent b*-tree node"); 100 return -1; 101 } 102 else if (bt->map && ! BMTST(bt->map, np->nnum)) 103 { 104 ERROR(EIO, "write unallocated b*-tree node"); 105 return -1; 106 } 107 108 ptr = *bp; 109 110 d_storel(&ptr, np->nd.ndFLink); 111 d_storel(&ptr, np->nd.ndBLink); 112 d_storeb(&ptr, np->nd.ndType); 113 d_storeb(&ptr, np->nd.ndNHeight); 114 d_storew(&ptr, np->nd.ndNRecs); 115 d_storew(&ptr, np->nd.ndResv2); 116 117 if (np->nd.ndNRecs > HFS_MAXRECS) 118 { 119 ERROR(EIO, "too many b*-tree node records"); 120 return -1; 121 } 122 123 i = np->nd.ndNRecs + 1; 124 125 ptr = *bp + HFS_BLOCKSZ - (2 * i); 126 127 while (i--) 128 d_storew(&ptr, np->roff[i]); 129 130 if (f_putblock(&bt->f, np->nnum, bp) < 0) 131 return -1; 132 133 return 0; 134 } 135 136 /* 137 * NAME: btree->readhdr() 138 * DESCRIPTION: read the header node of a B*-tree 139 */ 140 int bt_readhdr(btree *bt) 141 { 142 unsigned char *ptr; 143 char *map; 144 int i; 145 unsigned long nnum; 146 147 bt->hdrnd.bt = bt; 148 bt->hdrnd.nnum = 0; 149 150 if (bt_getnode(&bt->hdrnd) < 0) 151 return -1; 152 153 if (bt->hdrnd.nd.ndType != ndHdrNode || 154 bt->hdrnd.nd.ndNRecs != 3 || 155 bt->hdrnd.roff[0] != 0x00e || 156 bt->hdrnd.roff[1] != 0x078 || 157 bt->hdrnd.roff[2] != 0x0f8 || 158 bt->hdrnd.roff[3] != 0x1f8) 159 { 160 ERROR(EIO, "malformed b*-tree header node"); 161 return -1; 162 } 163 164 /* read header record */ 165 166 ptr = HFS_NODEREC(bt->hdrnd, 0); 167 168 d_fetchw(&ptr, (short *) &bt->hdr.bthDepth); 169 d_fetchl(&ptr, (long *) &bt->hdr.bthRoot); 170 d_fetchl(&ptr, (long *) &bt->hdr.bthNRecs); 171 d_fetchl(&ptr, (long *) &bt->hdr.bthFNode); 172 d_fetchl(&ptr, (long *) &bt->hdr.bthLNode); 173 d_fetchw(&ptr, (short *) &bt->hdr.bthNodeSize); 174 d_fetchw(&ptr, (short *) &bt->hdr.bthKeyLen); 175 d_fetchl(&ptr, (long *) &bt->hdr.bthNNodes); 176 d_fetchl(&ptr, (long *) &bt->hdr.bthFree); 177 178 for (i = 0; i < 76; ++i) 179 d_fetchb(&ptr, (char *) &bt->hdr.bthResv[i]); 180 181 if (bt->hdr.bthNodeSize != HFS_BLOCKSZ) 182 { 183 ERROR(EINVAL, "unsupported b*-tree node size"); 184 return -1; 185 } 186 187 /* read map record; construct btree bitmap */ 188 /* don't set bt->map until we're done, since getnode() checks it */ 189 190 map = ALLOC(char, HFS_MAP1SZ); 191 if (map == 0) 192 { 193 ERROR(ENOMEM, 0); 194 return -1; 195 } 196 197 memcpy(map, HFS_NODEREC(bt->hdrnd, 2), HFS_MAP1SZ); 198 bt->mapsz = HFS_MAP1SZ; 199 200 /* read continuation map records, if any */ 201 202 nnum = bt->hdrnd.nd.ndFLink; 203 204 while (nnum) 205 { 206 node n; 207 char *newmap; 208 209 n.bt = bt; 210 n.nnum = nnum; 211 212 if (bt_getnode(&n) < 0) 213 { 214 FREE(map); 215 return -1; 216 } 217 218 if (n.nd.ndType != ndMapNode || 219 n.nd.ndNRecs != 1 || 220 n.roff[0] != 0x00e || 221 n.roff[1] != 0x1fa) 222 { 223 FREE(map); 224 ERROR(EIO, "malformed b*-tree map node"); 225 return -1; 226 } 227 228 newmap = REALLOC(map, char, bt->mapsz + HFS_MAPXSZ); 229 if (newmap == 0) 230 { 231 FREE(map); 232 ERROR(ENOMEM, 0); 233 return -1; 234 } 235 map = newmap; 236 237 memcpy(map + bt->mapsz, HFS_NODEREC(n, 0), HFS_MAPXSZ); 238 bt->mapsz += HFS_MAPXSZ; 239 240 nnum = n.nd.ndFLink; 241 } 242 243 bt->map = map; 244 245 return 0; 246 } 247 248 /* 249 * NAME: btree->writehdr() 250 * DESCRIPTION: write the header node of a B*-tree 251 */ 252 int bt_writehdr(btree *bt) 253 { 254 unsigned char *ptr; 255 char *map; 256 unsigned long mapsz, nnum; 257 int i; 258 259 if (bt->hdrnd.bt != bt || 260 bt->hdrnd.nnum != 0 || 261 bt->hdrnd.nd.ndType != ndHdrNode || 262 bt->hdrnd.nd.ndNRecs != 3) 263 abort(); 264 265 ptr = HFS_NODEREC(bt->hdrnd, 0); 266 267 d_storew(&ptr, bt->hdr.bthDepth); 268 d_storel(&ptr, bt->hdr.bthRoot); 269 d_storel(&ptr, bt->hdr.bthNRecs); 270 d_storel(&ptr, bt->hdr.bthFNode); 271 d_storel(&ptr, bt->hdr.bthLNode); 272 d_storew(&ptr, bt->hdr.bthNodeSize); 273 d_storew(&ptr, bt->hdr.bthKeyLen); 274 d_storel(&ptr, bt->hdr.bthNNodes); 275 d_storel(&ptr, bt->hdr.bthFree); 276 277 for (i = 0; i < 76; ++i) 278 d_storeb(&ptr, bt->hdr.bthResv[i]); 279 280 memcpy(HFS_NODEREC(bt->hdrnd, 2), bt->map, HFS_MAP1SZ); 281 282 if (bt_putnode(&bt->hdrnd) < 0) 283 return -1; 284 285 map = bt->map + HFS_MAP1SZ; 286 mapsz = bt->mapsz - HFS_MAP1SZ; 287 288 nnum = bt->hdrnd.nd.ndFLink; 289 290 while (mapsz) 291 { 292 node n; 293 294 if (nnum == 0) 295 { 296 ERROR(EIO, "truncated b*-tree map"); 297 return -1; 298 } 299 300 n.bt = bt; 301 n.nnum = nnum; 302 303 if (bt_getnode(&n) < 0) 304 return -1; 305 306 if (n.nd.ndType != ndMapNode || 307 n.nd.ndNRecs != 1 || 308 n.roff[0] != 0x00e || 309 n.roff[1] != 0x1fa) 310 { 311 ERROR(EIO, "malformed b*-tree map node"); 312 return -1; 313 } 314 315 memcpy(HFS_NODEREC(n, 0), map, HFS_MAPXSZ); 316 317 if (bt_putnode(&n) < 0) 318 return -1; 319 320 map += HFS_MAPXSZ; 321 mapsz -= HFS_MAPXSZ; 322 323 nnum = n.nd.ndFLink; 324 } 325 326 bt->flags &= ~HFS_UPDATE_BTHDR; 327 328 return 0; 329 } 330 331 /* High-Level B*-Tree Routines ============================================= */ 332 333 /* 334 * NAME: btree->space() 335 * DESCRIPTION: assert space for new records, or extend the file 336 */ 337 int bt_space(btree *bt, unsigned int nrecs) 338 { 339 unsigned int nnodes; 340 int space; 341 342 nnodes = nrecs * (bt->hdr.bthDepth + 1); 343 344 if (nnodes <= bt->hdr.bthFree) 345 return 0; 346 347 /* make sure the extents tree has room too */ 348 349 if (bt != &bt->f.vol->ext) 350 { 351 if (bt_space(&bt->f.vol->ext, 1) < 0) 352 return -1; 353 } 354 355 space = f_alloc(&bt->f); 356 if (space < 0) 357 return -1; 358 359 nnodes = space * (bt->f.vol->mdb.drAlBlkSiz / bt->hdr.bthNodeSize); 360 361 bt->hdr.bthNNodes += nnodes; 362 bt->hdr.bthFree += nnodes; 363 364 bt->flags |= HFS_UPDATE_BTHDR; 365 366 bt->f.vol->flags |= HFS_UPDATE_ALTMDB; 367 368 while (bt->hdr.bthNNodes > bt->mapsz * 8) 369 { 370 char *newmap; 371 node mapnd; 372 373 /* extend tree map */ 374 375 newmap = REALLOC(bt->map, char, bt->mapsz + HFS_MAPXSZ); 376 if (newmap == 0) 377 { 378 ERROR(ENOMEM, 0); 379 return -1; 380 } 381 382 memset(newmap + bt->mapsz, 0, HFS_MAPXSZ); 383 384 bt->map = newmap; 385 bt->mapsz += HFS_MAPXSZ; 386 387 n_init(&mapnd, bt, ndMapNode, 0); 388 if (n_new(&mapnd) < 0) 389 return -1; 390 391 /* link the new map node */ 392 393 if (bt->hdrnd.nd.ndFLink == 0) 394 { 395 bt->hdrnd.nd.ndFLink = mapnd.nnum; 396 mapnd.nd.ndBLink = 0; 397 } 398 else 399 { 400 node n; 401 402 n.bt = bt; 403 n.nnum = bt->hdrnd.nd.ndFLink; 404 405 while (1) 406 { 407 if (bt_getnode(&n) < 0) 408 return -1; 409 410 if (n.nd.ndFLink == 0) 411 break; 412 413 n.nnum = n.nd.ndFLink; 414 } 415 416 n.nd.ndFLink = mapnd.nnum; 417 mapnd.nd.ndBLink = n.nnum; 418 419 if (bt_putnode(&n) < 0) 420 return -1; 421 } 422 423 mapnd.nd.ndNRecs = 1; 424 mapnd.roff[1] = 0x1fa; 425 426 if (bt_putnode(&mapnd) < 0) 427 return -1; 428 } 429 430 return 0; 431 } 432 433 /* 434 * NAME: btree->insertx() 435 * DESCRIPTION: recursively locate a node and insert a record 436 */ 437 int bt_insertx(node *np, unsigned char *record, int *reclen) 438 { 439 node child; 440 unsigned char *rec; 441 442 if (n_search(np, record)) 443 { 444 ERROR(EIO, "b*-tree record already exists"); 445 return -1; 446 } 447 448 switch ((unsigned char) np->nd.ndType) 449 { 450 case ndIndxNode: 451 if (np->rnum < 0) 452 rec = HFS_NODEREC(*np, 0); 453 else 454 rec = HFS_NODEREC(*np, np->rnum); 455 456 child.bt = np->bt; 457 child.nnum = d_getl(HFS_RECDATA(rec)); 458 459 if (bt_getnode(&child) < 0 || 460 bt_insertx(&child, record, reclen) < 0) 461 return -1; 462 463 if (np->rnum < 0) 464 { 465 n_index(np->bt, HFS_NODEREC(child, 0), child.nnum, rec, 0); 466 if (*reclen == 0) 467 return bt_putnode(np); 468 } 469 470 return *reclen ? n_insert(np, record, reclen) : 0; 471 472 case ndLeafNode: 473 return n_insert(np, record, reclen); 474 475 default: 476 ERROR(EIO, "unexpected b*-tree node"); 477 return -1; 478 } 479 } 480 481 /* 482 * NAME: btree->insert() 483 * DESCRIPTION: insert a new node record into a tree 484 */ 485 int bt_insert(btree *bt, unsigned char *record, int reclen) 486 { 487 node root; 488 489 if (bt->hdr.bthRoot == 0) 490 { 491 /* create root node */ 492 493 n_init(&root, bt, ndLeafNode, 1); 494 if (n_new(&root) < 0 || 495 bt_putnode(&root) < 0) 496 return -1; 497 498 bt->hdr.bthDepth = 1; 499 bt->hdr.bthRoot = root.nnum; 500 bt->hdr.bthFNode = root.nnum; 501 bt->hdr.bthLNode = root.nnum; 502 503 bt->flags |= HFS_UPDATE_BTHDR; 504 } 505 else 506 { 507 root.bt = bt; 508 root.nnum = bt->hdr.bthRoot; 509 510 if (bt_getnode(&root) < 0) 511 return -1; 512 } 513 514 if (bt_insertx(&root, record, &reclen) < 0) 515 return -1; 516 517 if (reclen) 518 { 519 unsigned char oroot[HFS_MAXRECLEN]; 520 int orootlen; 521 522 /* root node was split; create a new root */ 523 524 n_index(bt, HFS_NODEREC(root, 0), root.nnum, oroot, &orootlen); 525 526 n_init(&root, bt, ndIndxNode, root.nd.ndNHeight + 1); 527 if (n_new(&root) < 0) 528 return -1; 529 530 ++bt->hdr.bthDepth; 531 bt->hdr.bthRoot = root.nnum; 532 533 bt->flags |= HFS_UPDATE_BTHDR; 534 535 /* insert index records for new root */ 536 537 n_search(&root, oroot); 538 n_insertx(&root, oroot, orootlen); 539 540 n_search(&root, record); 541 n_insertx(&root, record, reclen); 542 543 if (bt_putnode(&root) < 0) 544 return -1; 545 } 546 547 ++bt->hdr.bthNRecs; 548 bt->flags |= HFS_UPDATE_BTHDR; 549 550 return 0; 551 } 552 553 /* 554 * NAME: btree->deletex() 555 * DESCRIPTION: recursively locate a node and delete a record 556 */ 557 int bt_deletex(node *np, unsigned char *key, unsigned char *record, int *flag) 558 { 559 node child; 560 unsigned char *rec; 561 int found; 562 563 found = n_search(np, key); 564 565 switch ((unsigned char) np->nd.ndType) 566 { 567 case ndIndxNode: 568 if (np->rnum < 0) 569 { 570 ERROR(EIO, "b*-tree record not found"); 571 return -1; 572 } 573 574 rec = HFS_NODEREC(*np, np->rnum); 575 576 child.bt = np->bt; 577 child.nnum = d_getl(HFS_RECDATA(rec)); 578 579 if (bt_getnode(&child) < 0 || 580 bt_deletex(&child, key, rec, flag) < 0) 581 return -1; 582 583 if (*flag) 584 { 585 *flag = 0; 586 587 if (HFS_RECKEYLEN(rec) == 0) 588 return n_delete(np, record, flag); 589 590 if (np->rnum == 0) 591 { 592 n_index(np->bt, HFS_NODEREC(*np, 0), np->nnum, record, 0); 593 *flag = 1; 594 } 595 596 return bt_putnode(np); 597 } 598 599 return 0; 600 601 case ndLeafNode: 602 if (found == 0) 603 { 604 ERROR(EIO, "b*-tree record not found"); 605 return -1; 606 } 607 608 return n_delete(np, record, flag); 609 610 default: 611 ERROR(EIO, "unexpected b*-tree node"); 612 return -1; 613 } 614 } 615 616 /* 617 * NAME: btree->delete() 618 * DESCRIPTION: remove a node record from a tree 619 */ 620 int bt_delete(btree *bt, unsigned char *key) 621 { 622 node root; 623 unsigned char record[HFS_MAXRECLEN]; 624 int flag = 0; 625 626 root.bt = bt; 627 root.nnum = bt->hdr.bthRoot; 628 629 if (root.nnum == 0) 630 { 631 ERROR(EIO, "empty b*-tree"); 632 return -1; 633 } 634 635 if (bt_getnode(&root) < 0 || 636 bt_deletex(&root, key, record, &flag) < 0) 637 return -1; 638 639 if (bt->hdr.bthDepth > 1 && root.nd.ndNRecs == 1) 640 { 641 unsigned char *rec; 642 643 /* chop the root */ 644 645 rec = HFS_NODEREC(root, 0); 646 647 --bt->hdr.bthDepth; 648 bt->hdr.bthRoot = d_getl(HFS_RECDATA(rec)); 649 650 n_free(&root); 651 } 652 else if (bt->hdr.bthDepth == 1 && root.nd.ndNRecs == 0) 653 { 654 /* delete the root node */ 655 656 bt->hdr.bthDepth = 0; 657 bt->hdr.bthRoot = 0; 658 bt->hdr.bthFNode = 0; 659 bt->hdr.bthLNode = 0; 660 661 n_free(&root); 662 } 663 664 --bt->hdr.bthNRecs; 665 bt->flags |= HFS_UPDATE_BTHDR; 666 667 return 0; 668 } 669 670 /* 671 * NAME: btree->search() 672 * DESCRIPTION: locate a data record given a search key 673 */ 674 int bt_search(btree *bt, unsigned char *key, node *np) 675 { 676 np->bt = bt; 677 np->nnum = bt->hdr.bthRoot; 678 679 if (np->nnum == 0) 680 { 681 ERROR(ENOENT, 0); 682 return 0; 683 } 684 685 while (1) 686 { 687 int found; 688 unsigned char *rec; 689 690 if (bt_getnode(np) < 0) 691 return -1; 692 693 found = n_search(np, key); 694 695 switch ((unsigned char) np->nd.ndType) 696 { 697 case ndIndxNode: 698 if (np->rnum < 0) 699 { 700 ERROR(ENOENT, 0); 701 return 0; 702 } 703 704 rec = HFS_NODEREC(*np, np->rnum); 705 np->nnum = d_getl(HFS_RECDATA(rec)); 706 break; 707 708 case ndLeafNode: 709 if (! found) 710 ERROR(ENOENT, 0); 711 712 return found; 713 714 default: 715 ERROR(EIO, "unexpected b*-tree node"); 716 return -1; 717 } 718 } 719 } 720