📄 extent.c
字号:
build_key(&key, fork, ablock); error = hfs_binsert(fork->entry->mdb->ext_tree, HFS_BKEY(&key), &raw, sizeof(raw)); if (error) { ext->prev->next = NULL; HFS_DELETE(ext); return NULL; } set_cache(fork, ext); return ext;}/* * update_ext() * * Given a (struct hfs_fork) write an extent record back to disk. */static void update_ext(struct hfs_fork *fork, struct hfs_extent *ext){ struct hfs_ext_key target; struct hfs_brec brec; if (ext->start) { build_key(&target, fork, ext->start); if (!hfs_bfind(&brec, fork->entry->mdb->ext_tree, HFS_BKEY(&target), HFS_BFIND_WRITE)) { write_extent(brec.data, ext); hfs_brec_relse(&brec, NULL); } }}/* * zero_blocks() * * Zeros-out 'num' allocation blocks beginning with 'start'. */static int zero_blocks(struct hfs_mdb *mdb, int start, int num) { hfs_buffer buf; int end; int j; start = mdb->fs_start + start * mdb->alloc_blksz; end = start + num * mdb->alloc_blksz; for (j=start; j<end; ++j) { if (hfs_buffer_ok(buf = hfs_buffer_get(mdb->sys_mdb, j, 0))) { memset(hfs_buffer_data(buf), 0, HFS_SECTOR_SIZE); hfs_buffer_dirty(buf); hfs_buffer_put(buf); } } return 0;}/* * shrink_fork() * * Try to remove enough allocation blocks from 'fork' * so that it is 'ablocks' allocation blocks long. */static void shrink_fork(struct hfs_fork *fork, int ablocks){ struct hfs_mdb *mdb = fork->entry->mdb; struct hfs_extent *ext; int i, error, next, count; hfs_u32 ablksz = mdb->alloc_blksz; next = (fork->psize / ablksz) - 1; ext = find_ext(fork, next); while (ext && ext->start && (ext->start >= ablocks)) { next = ext->start - 1; delete_extent(fork, ext); ext = find_ext(fork, next); } if (!ext) { fork->psize = (next + 1) * ablksz; return; } if ((count = next + 1 - ablocks) > 0) { for (i=2; (i>=0) && !ext->length[i]; --i) {}; lock_bitmap(mdb); while (count && (ext->length[i] <= count)) { ext->end -= ext->length[i]; count -= ext->length[i]; error = hfs_clear_vbm_bits(mdb, ext->block[i], ext->length[i]); if (error) { hfs_warn("hfs_truncate: error %d freeing " "blocks.\n", error); } ext->block[i] = ext->length[i] = 0; --i; } if (count) { ext->end -= count; ext->length[i] -= count; error = hfs_clear_vbm_bits(mdb, ext->block[i] + ext->length[i], count); if (error) { hfs_warn("hfs_truncate: error %d freeing " "blocks.\n", error); } } unlock_bitmap(mdb); update_ext(fork, ext); } fork->psize = ablocks * ablksz;}/* * grow_fork() * * Try to add enough allocation blocks to 'fork' * so that it is 'ablock' allocation blocks long. */static int grow_fork(struct hfs_fork *fork, int ablocks){ struct hfs_cat_entry *entry = fork->entry; struct hfs_mdb *mdb = entry->mdb; struct hfs_extent *ext; int i, start, err; hfs_u16 need, len=0; hfs_u32 ablksz = mdb->alloc_blksz; hfs_u32 blocks, clumpablks; blocks = fork->psize; need = ablocks - blocks/ablksz; if (need < 1) { /* no need to grow the fork */ return 0; } /* round up to clumpsize */ if (entry->u.file.clumpablks) { clumpablks = entry->u.file.clumpablks; } else { clumpablks = mdb->clumpablks; } need = ((need + clumpablks - 1) / clumpablks) * clumpablks; /* find last extent record and try to extend it */ if (!(ext = find_ext(fork, blocks/ablksz - 1))) { /* somehow we couldn't find the end of the file! */ return -1; } /* determine which is the last used extent in the record */ /* then try to allocate the blocks immediately following it */ for (i=2; (i>=0) && !ext->length[i]; --i) {}; if (i>=0) { /* try to extend the last extent */ start = ext->block[i] + ext->length[i]; err = 0; lock_bitmap(mdb); len = hfs_vbm_count_free(mdb, start); if (!len) { unlock_bitmap(mdb); goto more_extents; } if (need < len) { len = need; } err = hfs_set_vbm_bits(mdb, start, len); unlock_bitmap(mdb); if (err) { relse_ext(ext); return -1; } zero_blocks(mdb, start, len); ext->length[i] += len; ext->end += len; blocks = (fork->psize += len * ablksz); need -= len; update_ext(fork, ext); }more_extents: /* add some more extents */ while (need) { len = need; err = 0; lock_bitmap(mdb); start = hfs_vbm_search_free(mdb, &len); if (need < len) { len = need; } err = hfs_set_vbm_bits(mdb, start, len); unlock_bitmap(mdb); if (!len || err) { relse_ext(ext); return -1; } zero_blocks(mdb, start, len); /* determine which is the first free extent in the record */ for (i=0; (i<3) && ext->length[i]; ++i) {}; if (i < 3) { ext->block[i] = start; ext->length[i] = len; ext->end += len; update_ext(fork, ext); } else { if (!(ext = new_extent(fork, ext, blocks/ablksz, start, len, ablksz))) { lock_bitmap(mdb); hfs_clear_vbm_bits(mdb, start, len); unlock_bitmap(mdb); return -1; } } blocks = (fork->psize += len * ablksz); need -= len; } set_cache(fork, ext); relse_ext(ext); return 0;}/*================ Global functions ================*//* * hfs_ext_compare() * * Description: * This is the comparison function used for the extents B-tree. In * comparing extent B-tree entries, the file id is the most * significant field (compared as unsigned ints); the fork type is * the second most significant field (compared as unsigned chars); * and the allocation block number field is the least significant * (compared as unsigned ints). * Input Variable(s): * struct hfs_ext_key *key1: pointer to the first key to compare * struct hfs_ext_key *key2: pointer to the second key to compare * Output Variable(s): * NONE * Returns: * int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2 * Preconditions: * key1 and key2 point to "valid" (struct hfs_ext_key)s. * Postconditions: * This function has no side-effects */int hfs_ext_compare(const struct hfs_ext_key *key1, const struct hfs_ext_key *key2){ unsigned int tmp; int retval; tmp = hfs_get_hl(key1->FNum) - hfs_get_hl(key2->FNum); if (tmp != 0) { retval = (int)tmp; } else { tmp = (unsigned char)key1->FkType - (unsigned char)key2->FkType; if (tmp != 0) { retval = (int)tmp; } else { retval = (int)(hfs_get_hs(key1->FABN) - hfs_get_hs(key2->FABN)); } } return retval;}/* * hfs_extent_adj() * * Given an hfs_fork shrink or grow the fork to hold the * forks logical size. */void hfs_extent_adj(struct hfs_fork *fork){ if (fork) { hfs_u32 blks, ablocks, ablksz; if (fork->lsize > HFS_FORK_MAX) { fork->lsize = HFS_FORK_MAX; } blks = (fork->lsize+HFS_SECTOR_SIZE-1) >> HFS_SECTOR_SIZE_BITS; ablksz = fork->entry->mdb->alloc_blksz; ablocks = (blks + ablksz - 1) / ablksz; if (blks > fork->psize) { grow_fork(fork, ablocks); if (blks > fork->psize) { fork->lsize = fork->psize >> HFS_SECTOR_SIZE_BITS; } } else if (blks < fork->psize) { shrink_fork(fork, ablocks); } }}/* * hfs_extent_map() * * Given an hfs_fork and a block number within the fork, return the * number of the corresponding physical block on disk, or zero on * error. */int hfs_extent_map(struct hfs_fork *fork, int block, int create) { int ablksz, ablock, offset, tmp; struct hfs_extent *ext; if (!fork || !fork->entry || !fork->entry->mdb) { return 0; }#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL) hfs_warn("hfs_extent_map: ablock %d of file %d, fork %d\n", block, fork->entry->cnid, fork->fork);#endif if (block < 0) { hfs_warn("hfs_extent_map: block < 0\n"); return 0; } if (block > (HFS_FORK_MAX >> HFS_SECTOR_SIZE_BITS)) { hfs_warn("hfs_extent_map: block(0x%08x) > big; cnid=%d " "fork=%d\n", block, fork->entry->cnid, fork->fork); return 0; } ablksz = fork->entry->mdb->alloc_blksz; offset = fork->entry->mdb->fs_start + (block % ablksz); ablock = block / ablksz; if (block >= fork->psize) { if (!create || (grow_fork(fork, ablock + 1) < 0)) return 0; }#if defined(DEBUG_EXTENTS) || defined(DEBUG_ALL) hfs_warn("(lblock %d offset %d)\n", ablock, offset);#endif if ((ext = find_ext(fork, ablock))) { dump_ext("trying new: ", ext); tmp = decode_extent(ext, ablock); relse_ext(ext); if (tmp >= 0) { return tmp*ablksz + offset; } } return 0;}/* * hfs_extent_out() * * Copy the first extent record from a (struct hfs_fork) to a (struct * raw_extent), record (normally the one in the catalog entry). */void hfs_extent_out(const struct hfs_fork *fork, hfs_byte_t dummy[12]){ struct hfs_raw_extent *ext = (struct hfs_raw_extent *)dummy; if (fork && ext) { write_extent(ext, &fork->first); dump_ext("extent out: ", &fork->first); }}/* * hfs_extent_in() * * Copy an raw_extent to the 'first' and 'cache' fields of an hfs_fork. */void hfs_extent_in(struct hfs_fork *fork, const hfs_byte_t dummy[12]){ const struct hfs_raw_extent *ext = (const struct hfs_raw_extent *)dummy; if (fork && ext) { read_extent(&fork->first, ext, 0); fork->cache = &fork->first; fork->first.count = 2; dump_ext("extent in: ", &fork->first); }}/* * hfs_extent_free() * * Removes from memory all extents associated with 'fil'. */void hfs_extent_free(struct hfs_fork *fork){ if (fork) { set_cache(fork, &fork->first); if (fork->first.next) { hfs_warn("hfs_extent_free: extents in use!\n"); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -