static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir, char ** ret) { errcode_t retval; if (outdir->num >= outdir->max) { retval = alloc_size_dir(fs, outdir, outdir->max + 50); if (retval) return retval; } *ret = outdir->buf + (outdir->num++ * fs->blocksize); memset(*ret, 0, fs->blocksize); return 0; }
static errcode_t copy_dir_entries(e2fsck_t ctx, struct fill_dir_struct *fd, struct out_dir *outdir) { ext2_filsys fs = ctx->fs; errcode_t retval; char *block_start; struct hash_entry *ent; struct ext2_dir_entry *dirent; unsigned int rec_len, prev_rec_len, left, slack, offset; int i; ext2_dirhash_t prev_hash; int csum_size = 0; struct ext2_dir_entry_tail *t; if (ctx->htree_slack_percentage == 255) { profile_get_uint(ctx->profile, "options", "indexed_dir_slack_percentage", 0, 20, &ctx->htree_slack_percentage); if (ctx->htree_slack_percentage > 100) ctx->htree_slack_percentage = 20; } if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) csum_size = sizeof(struct ext2_dir_entry_tail); outdir->max = 0; retval = alloc_size_dir(fs, outdir, (fd->dir_size / fs->blocksize) + 2); if (retval) return retval; outdir->num = fd->compress ? 0 : 1; offset = 0; outdir->hashes[0] = 0; prev_hash = 1; if ((retval = get_next_block(fs, outdir, &block_start))) return retval; dirent = (struct ext2_dir_entry *) block_start; prev_rec_len = 0; rec_len = 0; left = fs->blocksize - csum_size; slack = fd->compress ? 12 : ((fs->blocksize - csum_size) * ctx->htree_slack_percentage)/100; if (slack < 12) slack = 12; for (i = 0; i < fd->num_array; i++) { ent = fd->harray + i; if (ent->dir->inode == 0) continue; rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(ent->dir)); if (rec_len > left) { if (left) { left += prev_rec_len; retval = ext2fs_set_rec_len(fs, left, dirent); if (retval) return retval; } if (csum_size) { t = EXT2_DIRENT_TAIL(block_start, fs->blocksize); ext2fs_initialize_dirent_tail(fs, t); } if ((retval = get_next_block(fs, outdir, &block_start))) return retval; offset = 0; } left = (fs->blocksize - csum_size) - offset; dirent = (struct ext2_dir_entry *) (block_start + offset); if (offset == 0) { if (ent->hash == prev_hash) outdir->hashes[outdir->num-1] = ent->hash | 1; else outdir->hashes[outdir->num-1] = ent->hash; } dirent->inode = ent->dir->inode; ext2fs_dirent_set_name_len(dirent, ext2fs_dirent_name_len(ent->dir)); ext2fs_dirent_set_file_type(dirent, ext2fs_dirent_file_type(ent->dir)); retval = ext2fs_set_rec_len(fs, rec_len, dirent); if (retval) return retval; prev_rec_len = rec_len; memcpy(dirent->name, ent->dir->name, ext2fs_dirent_name_len(dirent)); offset += rec_len; left -= rec_len; if (left < slack) { prev_rec_len += left; retval = ext2fs_set_rec_len(fs, prev_rec_len, dirent); if (retval) return retval; offset += left; left = 0; } prev_hash = ent->hash; } if (left) retval = ext2fs_set_rec_len(fs, rec_len + left, dirent); if (csum_size) { t = EXT2_DIRENT_TAIL(block_start, fs->blocksize); ext2fs_initialize_dirent_tail(fs, t); } return retval; }
static errcode_t copy_dir_entries(e2fsck_t ctx, struct fill_dir_struct *fd, struct out_dir *outdir) { ext2_filsys fs = ctx->fs; errcode_t retval; char *block_start; struct hash_entry *ent; struct ext2_dir_entry *dirent; unsigned int rec_len, prev_rec_len; int i, left; ext2_dirhash_t prev_hash; int offset, slack; if (ctx->htree_slack_percentage == 255) { profile_get_uint(ctx->profile, "options", "indexed_dir_slack_percentage", 0, 20, &ctx->htree_slack_percentage); if (ctx->htree_slack_percentage > 100) ctx->htree_slack_percentage = 20; } outdir->max = 0; retval = alloc_size_dir(fs, outdir, (fd->dir_size / fs->blocksize) + 2); if (retval) return retval; outdir->num = fd->compress ? 0 : 1; offset = 0; outdir->hashes[0] = 0; prev_hash = 1; if ((retval = get_next_block(fs, outdir, &block_start))) return retval; dirent = (struct ext2_dir_entry *) block_start; prev_rec_len = 0; left = fs->blocksize; slack = fd->compress ? 12 : (fs->blocksize * ctx->htree_slack_percentage)/100; if (slack < 12) slack = 12; for (i=0; i < fd->num_array; i++) { ent = fd->harray + i; if (ent->dir->inode == 0) continue; rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF); if (rec_len > left) { if (left) { left += prev_rec_len; retval = ext2fs_set_rec_len(fs, left, dirent); if (retval) return retval; } if ((retval = get_next_block(fs, outdir, &block_start))) return retval; offset = 0; } left = fs->blocksize - offset; dirent = (struct ext2_dir_entry *) (block_start + offset); if (offset == 0) { if (ent->hash == prev_hash) outdir->hashes[outdir->num-1] = ent->hash | 1; else outdir->hashes[outdir->num-1] = ent->hash; } dirent->inode = ent->dir->inode; dirent->name_len = ent->dir->name_len; retval = ext2fs_set_rec_len(fs, rec_len, dirent); if (retval) return retval; prev_rec_len = rec_len; memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF); offset += rec_len; left -= rec_len; if (left < slack) { prev_rec_len += left; retval = ext2fs_set_rec_len(fs, prev_rec_len, dirent); if (retval) return retval; offset += left; left = 0; } prev_hash = ent->hash; } if (left) retval = ext2fs_set_rec_len(fs, rec_len + left, dirent); return retval; }
static errcode_t copy_dir_entries(ext2_filsys fs, struct fill_dir_struct *fd, struct out_dir *outdir) { errcode_t retval; char *block_start; struct hash_entry *ent; struct ext2_dir_entry *dirent; int i, rec_len, left; ext2_dirhash_t prev_hash; int offset; outdir->max = 0; retval = alloc_size_dir(fs, outdir, (fd->dir_size / fs->blocksize) + 2); if (retval) return retval; outdir->num = fd->compress ? 0 : 1; offset = 0; outdir->hashes[0] = 0; prev_hash = 1; if ((retval = get_next_block(fs, outdir, &block_start))) return retval; dirent = (struct ext2_dir_entry *) block_start; left = fs->blocksize; for (i=0; i < fd->num_array; i++) { ent = fd->harray + i; if (ent->dir->inode == 0) continue; rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF); if (rec_len > left) { if (left) dirent->rec_len += left; if ((retval = get_next_block(fs, outdir, &block_start))) return retval; offset = 0; } left = fs->blocksize - offset; dirent = (struct ext2_dir_entry *) (block_start + offset); if (offset == 0) { if (ent->hash == prev_hash) outdir->hashes[outdir->num-1] = ent->hash | 1; else outdir->hashes[outdir->num-1] = ent->hash; } dirent->inode = ent->dir->inode; dirent->name_len = ent->dir->name_len; dirent->rec_len = rec_len; memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF); offset += rec_len; left -= rec_len; if (left < 12) { dirent->rec_len += left; offset += left; left = 0; } prev_hash = ent->hash; } if (left) dirent->rec_len += left; return 0; }