/* * hfs_btree_commit() * * Called to write a possibly dirty btree back to disk. */ void hfs_btree_commit(struct hfs_btree *bt, hfs_byte_t ext[12], hfs_lword_t size) { if (bt->dirt) { struct BTHdrRec *th; th = (struct BTHdrRec *)((char *)hfs_buffer_data(bt->head.buf) + sizeof(struct NodeDescriptor)); hfs_put_hs(bt->bthDepth, th->bthDepth); hfs_put_hl(bt->bthRoot, th->bthRoot); hfs_put_hl(bt->bthNRecs, th->bthNRecs); hfs_put_hl(bt->bthFNode, th->bthFNode); hfs_put_hl(bt->bthLNode, th->bthLNode); hfs_put_hl(bt->bthNNodes, th->bthNNodes); hfs_put_hl(bt->bthFree, th->bthFree); hfs_buffer_dirty(bt->head.buf); /* * Commit the bnodes which are not cached. * The map nodes don't need to be committed here because * they are committed every time they are changed. */ hfs_bnode_commit(&bt->head); if (bt->root) { hfs_bnode_commit(bt->root); } hfs_put_hl(bt->bthNNodes << HFS_SECTOR_SIZE_BITS, size); hfs_extent_out(&bt->entry.u.file.data_fork, ext); /* hfs_buffer_dirty(mdb->buf); (Done by caller) */ bt->dirt = 0; } }
/* * build_key */ static inline void build_key(struct hfs_ext_key *key, const struct hfs_fork *fork, hfs_u16 block) { key->KeyLen = 7; key->FkType = fork->fork; hfs_put_nl(fork->entry->cnid, key->FNum); hfs_put_hs(block, key->FABN); }
/* * hfs_bnode_shift_right() * * Description: * Shifts some records from a node to its right neighbor. * Input Variable(s): * struct hfs_bnode* left: the node to shift records from * struct hfs_bnode* right: the node to shift records to * hfs_u16 first: the number of the first record in 'left' to move to 'right' * Output Variable(s): * NONE * Returns: * void * Preconditions: * 'left' and 'right' point to valid (struct hfs_bnode)s. * 'left' contains at least 'first' records. * 'right' has enough free space to hold the records to be moved from 'left' * Postconditions: * The record numbered 'first' and all records after it in 'left' are * placed at the beginning of 'right'. * The key corresponding to 'right' in its parent is NOT updated. */ void hfs_bnode_shift_right(struct hfs_bnode *left, struct hfs_bnode *right, int first) { int i, adjust, nrecs; unsigned size; hfs_u16 *to, *from; if ((first <= 0) || (first > left->ndNRecs)) { hfs_warn("bad argument to shift_right: first=%d, nrecs=%d\n", first, left->ndNRecs); return; } /* initialize variables */ nrecs = left->ndNRecs + 1 - first; size = bnode_end(left) - bnode_offset(left, first); /* move (possibly empty) contents of right node forward */ memmove(bnode_datastart(right) + size, bnode_datastart(right), bnode_end(right) - sizeof(struct NodeDescriptor)); /* copy in new records */ memcpy(bnode_datastart(right), bnode_key(left,first), size); /* fix up offsets in right node */ i = right->ndNRecs + 1; from = RECTBL(right, i); to = from - nrecs; while (i--) { hfs_put_hs(hfs_get_hs(from++) + size, to++); } adjust = sizeof(struct NodeDescriptor) - bnode_offset(left, first); i = nrecs-1; from = RECTBL(left, first+i); while (i--) { hfs_put_hs(hfs_get_hs(from++) + adjust, to++); } /* fix record counts */ left->ndNRecs -= nrecs; right->ndNRecs += nrecs; }
/* * hfs_bnode_shift_left() * * Description: * Shifts some records from a node to its left neighbor. * Input Variable(s): * struct hfs_bnode* left: the node to shift records to * struct hfs_bnode* right: the node to shift records from * hfs_u16 last: the number of the last record in 'right' to move to 'left' * Output Variable(s): * NONE * Returns: * void * Preconditions: * 'left' and 'right' point to valid (struct hfs_bnode)s. * 'right' contains at least 'last' records. * 'left' has enough free space to hold the records to be moved from 'right' * Postconditions: * The record numbered 'last' and all records before it in 'right' are * placed at the end of 'left'. * The key corresponding to 'right' in its parent is NOT updated. */ void hfs_bnode_shift_left(struct hfs_bnode *left, struct hfs_bnode *right, int last) { int i, adjust, nrecs; unsigned size; hfs_u16 *to, *from; if ((last <= 0) || (last > right->ndNRecs)) { hfs_warn("bad argument to shift_left: last=%d, nrecs=%d\n", last, right->ndNRecs); return; } /* initialize variables */ size = bnode_offset(right, last + 1) - sizeof(struct NodeDescriptor); /* copy records to left node */ memcpy(bnode_dataend(left), bnode_datastart(right), size); /* move (possibly empty) remainder of right node backward */ memmove(bnode_datastart(right), bnode_datastart(right) + size, bnode_end(right) - bnode_offset(right, last + 1)); /* fix up offsets */ nrecs = left->ndNRecs; i = last; from = RECTBL(right, 2); to = RECTBL(left, nrecs + 2); adjust = bnode_offset(left, nrecs + 1) - sizeof(struct NodeDescriptor); while (i--) { hfs_put_hs(hfs_get_hs(from--) + adjust, to--); } i = right->ndNRecs + 1 - last; ++from; to = RECTBL(right, 1); while (i--) { hfs_put_hs(hfs_get_hs(from--) - size, to--); } /* fix record counts */ left->ndNRecs += last; right->ndNRecs -= last; }
/* * write_extent() * * Initializes a (struct hfs_raw_extent) from a (struct hfs_extent). * * Note that the callers must check that to,from != NULL */ static void write_extent(struct hfs_raw_extent *to, const struct hfs_extent *from) { hfs_put_hs(from->block[0], to->block1); hfs_put_hs(from->length[0], to->length1); hfs_put_hs(from->block[1], to->block2); hfs_put_hs(from->length[1], to->length2); hfs_put_hs(from->block[2], to->block3); hfs_put_hs(from->length[2], to->length3); }
/* * cap_build_meta() * * Build the metadata structure. */ static void cap_build_meta(struct hfs_cap_info *meta, struct hfs_cat_entry *entry) { memset(meta, 0, sizeof(*meta)); memcpy(meta->fi_fndr, &entry->info, 32); if ((entry->type == HFS_CDR_FIL) && (entry->u.file.flags & HFS_FIL_LOCK)) { /* Couple the locked bit of the file to the AFP {write,rename,delete} inhibit bits. */ hfs_put_hs(HFS_AFP_RDONLY, meta->fi_attr); } meta->fi_magic1 = HFS_CAP_MAGIC1; meta->fi_version = HFS_CAP_VERSION; meta->fi_magic = HFS_CAP_MAGIC; meta->fi_bitmap = HFS_CAP_LONGNAME; memcpy(meta->fi_macfilename, entry->key.CName.Name, entry->key.CName.Len); meta->fi_datemagic = HFS_CAP_DMAGIC; meta->fi_datevalid = HFS_CAP_MDATE | HFS_CAP_CDATE; hfs_put_nl(hfs_m_to_htime(entry->create_date), meta->fi_ctime); hfs_put_nl(hfs_m_to_htime(entry->modify_date), meta->fi_mtime); hfs_put_nl(CURRENT_TIME, meta->fi_utime); }
/* * bdelete_nonempty() * * Description: * Deletes a record from a given bnode without regard to it becoming empty. * Input Variable(s): * struct hfs_brec* brec: pointer to the brec for the deletion * struct hfs_belem* belem: which node in 'brec' to delete from * Output Variable(s): * NONE * Returns: * void * Preconditions: * 'brec' points to a valid (struct hfs_brec). * 'belem' points to a valid (struct hfs_belem) in 'brec'. * Postconditions: * The record has been inserted in the position indicated by 'brec'. */ static void bdelete_nonempty(struct hfs_brec *brec, struct hfs_belem *belem) { int i, rec, nrecs, tomove; hfs_u16 size; hfs_u8 *start; struct hfs_bnode *bnode = belem->bnr.bn; rec = belem->record; nrecs = bnode->ndNRecs; size = bnode_rsize(bnode, rec); tomove = bnode_offset(bnode, nrecs+1) - bnode_offset(bnode, rec+1); /* adjust the record table */ for (i = rec+1; i <= nrecs; ++i) { hfs_put_hs(bnode_offset(bnode,i+1) - size, RECTBL(bnode,i)); } /* move it down */ start = bnode_key(bnode, rec); memmove(start, start + size, tomove); /* update record count */ --bnode->ndNRecs; }