void do_dirsearch(int argc, char *argv[]) { ext2_ino_t inode; struct process_block_struct pb; if (check_fs_open(argv[0])) return; if (argc != 3) { com_err(0, 0, "Usage: dirsearch dir filename"); return; } inode = string_to_inode(argv[1]); if (!inode) return; pb.buf = malloc(current_fs->blocksize); if (!pb.buf) { com_err("dirsearch", 0, "Couldn't allocate buffer"); return; } pb.search_name = argv[2]; pb.len = strlen(pb.search_name); ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 0, search_dir_block, &pb); free(pb.buf); }
static int fix_directory(ext2_filsys fs, struct ext2_db_entry2 *db, void *priv_data) { errcode_t retval; empty_dir_info edi = (empty_dir_info) priv_data; edi->logblk = 0; edi->freed_blocks = 0; edi->ino = db->ino; retval = ext2fs_read_inode(fs, db->ino, &edi->inode); if (retval) return 0; retval = ext2fs_block_iterate3(fs, db->ino, 0, edi->block_buf, empty_pass1, edi); if (retval) return 0; if (edi->freed_blocks) { edi->inode.i_size -= edi->freed_blocks * fs->blocksize; ext2fs_iblk_add_blocks(fs, &edi->inode, edi->freed_blocks); retval = ext2fs_write_inode(fs, db->ino, &edi->inode); if (retval) return 0; } return 0; }
/* * This fuction deallocates an inode */ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) { ext2_filsys fs = ctx->fs; struct ext2_inode inode; struct problem_context pctx; __u32 count; struct del_block del_block; e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode"); clear_problem_context(&pctx); pctx.ino = ino; /* * Fix up the bitmaps... */ e2fsck_read_bitmaps(ctx); ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); if (ext2fs_file_acl_block(fs, &inode) && (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { pctx.errcode = ext2fs_adjust_ea_refcount3(fs, ext2fs_file_acl_block(fs, &inode), block_buf, -1, &count, ino); if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { pctx.errcode = 0; count = 1; } if (pctx.errcode) { pctx.blk = ext2fs_file_acl_block(fs, &inode); fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } if (count == 0) { ext2fs_unmark_block_bitmap2(ctx->block_found_map, ext2fs_file_acl_block(fs, &inode)); ext2fs_block_alloc_stats2(fs, ext2fs_file_acl_block(fs, &inode), -1); } ext2fs_file_acl_block_set(fs, &inode, 0); } if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) return; if (LINUX_S_ISREG(inode.i_mode) && EXT2_I_SIZE(&inode) >= 0x80000000UL) ctx->large_files--; del_block.ctx = ctx; del_block.num = 0; pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf, deallocate_inode_block, &del_block); if (pctx.errcode) { fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } }
static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, struct out_dir *outdir, ext2_ino_t ino, int compress) { struct write_dir_struct wd; errcode_t retval; struct ext2_inode inode; retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num); if (retval) return retval; wd.outdir = outdir; wd.err = 0; wd.ctx = ctx; wd.cleared = 0; retval = ext2fs_block_iterate3(fs, ino, 0, 0, write_dir_block, &wd); if (retval) return retval; if (wd.err) return wd.err; e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); if (compress) inode.i_flags &= ~EXT2_INDEX_FL; else inode.i_flags |= EXT2_INDEX_FL; inode.i_size = outdir->num * fs->blocksize; ext2fs_iblk_sub_blocks(fs, &inode, wd.cleared); e2fsck_write_inode(ctx, ino, &inode, "rehash_dir"); return 0; }
errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) { errcode_t retval; struct expand_dir_struct es; struct ext2_inode inode; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (!(fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; if (!fs->block_map) return EXT2_ET_NO_BLOCK_BITMAP; retval = ext2fs_check_directory(fs, dir); if (retval) return retval; es.done = 0; es.err = 0; es.goal = 0; es.newblocks = 0; es.dir = dir; retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND, 0, expand_dir_proc, &es); if (es.err) return es.err; if (!es.done) return EXT2_ET_EXPAND_DIR_ERR; /* * Update the size and block count fields in the inode. */ retval = ext2fs_read_inode(fs, dir, &inode); if (retval) return retval; inode.i_size += fs->blocksize; ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); retval = ext2fs_write_inode(fs, dir, &inode); if (retval) return retval; return 0; }
static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, struct out_dir *outdir, ext2_ino_t ino, struct ext2_inode *inode, int compress) { struct write_dir_struct wd; errcode_t retval; retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num); if (retval) return retval; wd.outdir = outdir; wd.err = 0; wd.ino = ino; wd.ctx = ctx; wd.dir = ino; retval = ext2fs_block_iterate3(fs, ino, 0, NULL, write_dir_block, &wd); if (retval) return retval; if (wd.err) return wd.err; e2fsck_read_inode(ctx, ino, inode, "rehash_dir"); if (compress) inode->i_flags &= ~EXT2_INDEX_FL; else inode->i_flags |= EXT2_INDEX_FL; #ifdef REHASH_DEBUG printf("%u: set inode size to %u blocks = %u bytes\n", ino, outdir->num, outdir->num * fs->blocksize); #endif retval = ext2fs_inode_size_set(fs, inode, (ext2_off64_t)outdir->num * fs->blocksize); if (retval) return retval; /* ext2fs_punch() calls ext2fs_write_inode() which writes the size */ return ext2fs_punch(fs, ino, inode, NULL, outdir->num, ~0ULL); }
/* * This function creates a journal using direct I/O routines. */ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, blk_t num_blocks, int flags) { char *buf; dgrp_t group, start, end, i, log_flex; errcode_t retval; struct ext2_inode inode; unsigned long long inode_size; struct mkjournal_struct es; if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, &buf))) return retval; if ((retval = ext2fs_read_bitmaps(fs))) goto out2; if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto out2; if (inode.i_blocks > 0) { retval = EEXIST; goto out2; } es.num_blocks = num_blocks; es.newblocks = 0; es.buf = buf; es.err = 0; es.flags = flags; es.zero_count = 0; if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { inode.i_flags |= EXT4_EXTENTS_FL; if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) goto out2; } /* * Set the initial goal block to be roughly at the middle of * the filesystem. Pick a group that has the largest number * of free blocks. */ group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) - fs->super->s_first_data_block) / 2); log_flex = 1 << fs->super->s_log_groups_per_flex; if (fs->super->s_log_groups_per_flex && (group > log_flex)) { group = group & ~(log_flex - 1); while ((group < fs->group_desc_count) && ext2fs_bg_free_blocks_count(fs, group) == 0) group++; if (group == fs->group_desc_count) group = 0; start = group; } else start = (group > 0) ? group-1 : group; end = ((group+1) < fs->group_desc_count) ? group+1 : group; group = start; for (i=start+1; i <= end; i++) if (ext2fs_bg_free_blocks_count(fs, i) > ext2fs_bg_free_blocks_count(fs, group)) group = i; es.goal = ext2fs_group_first_block2(fs, group); retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND, 0, mkjournal_proc, &es); if (es.err) { retval = es.err; goto errout; } if (es.zero_count) { retval = ext2fs_zero_blocks2(fs, es.blk_to_zero, es.zero_count, 0, 0); if (retval) goto errout; } if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto errout; inode_size = (unsigned long long)fs->blocksize * num_blocks; inode.i_size = inode_size & 0xFFFFFFFF; inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF; if (ext2fs_needs_large_file_feature(inode_size)) fs->super->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE; ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) goto errout; retval = 0; memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); fs->super->s_jnl_blocks[15] = inode.i_size_high; fs->super->s_jnl_blocks[16] = inode.i_size; fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); errout: ext2fs_zero_blocks2(0, 0, 0, 0, 0); out2: ext2fs_free_mem(&buf); return retval; }
errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, struct problem_context *pctx) { ext2_filsys fs = ctx->fs; errcode_t retval; struct ext2_inode inode; char *dir_buf = 0; struct fill_dir_struct fd; struct out_dir outdir; outdir.max = outdir.num = 0; outdir.buf = 0; outdir.hashes = 0; e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_INLINE_DATA) && (inode.i_flags & EXT4_INLINE_DATA_FL)) return 0; retval = ENOMEM; fd.harray = 0; dir_buf = malloc(inode.i_size); if (!dir_buf) goto errout; fd.max_array = inode.i_size / 32; fd.num_array = 0; fd.harray = malloc(fd.max_array * sizeof(struct hash_entry)); if (!fd.harray) goto errout; fd.ctx = ctx; fd.buf = dir_buf; fd.inode = &inode; fd.ino = ino; fd.err = 0; fd.dir_size = 0; fd.compress = 0; fd.dir = ino; if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) || (inode.i_size / fs->blocksize) < 2) fd.compress = 1; fd.parent = 0; retry_nohash: /* Read in the entire directory into memory */ retval = ext2fs_block_iterate3(fs, ino, 0, 0, fill_dir_block, &fd); if (fd.err) { retval = fd.err; goto errout; } /* * If the entries read are less than a block, then don't index * the directory */ if (!fd.compress && (fd.dir_size < (fs->blocksize - 24))) { fd.compress = 1; fd.dir_size = 0; fd.num_array = 0; goto retry_nohash; } #if 0 printf("%d entries (%d bytes) found in inode %d\n", fd.num_array, fd.dir_size, ino); #endif /* Sort the list */ resort: if (fd.compress && fd.num_array > 1) qsort(fd.harray+2, fd.num_array-2, sizeof(struct hash_entry), hash_cmp); else qsort(fd.harray, fd.num_array, sizeof(struct hash_entry), hash_cmp); /* * Look for duplicates */ if (duplicate_search_and_fix(ctx, fs, ino, &fd)) goto resort; if (ctx->options & E2F_OPT_NO) { retval = 0; goto errout; } /* Sort non-hashed directories by inode number */ if (fd.compress && fd.num_array > 1) qsort(fd.harray+2, fd.num_array-2, sizeof(struct hash_entry), ino_cmp); /* * Copy the directory entries. In a htree directory these * will become the leaf nodes. */ retval = copy_dir_entries(ctx, &fd, &outdir); if (retval) goto errout; free(dir_buf); dir_buf = 0; if (!fd.compress) { /* Calculate the interior nodes */ retval = calculate_tree(fs, &outdir, ino, fd.parent); if (retval) goto errout; } retval = write_directory(ctx, fs, &outdir, ino, &inode, fd.compress); if (retval) goto errout; if (ctx->options & E2F_OPT_CONVERT_BMAP) retval = e2fsck_rebuild_extents_later(ctx, ino); else retval = e2fsck_check_rebuild_extents(ctx, ino, &inode, pctx); errout: free(dir_buf); free(fd.harray); free_out_dir(&outdir); return retval; }
static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal) { struct process_block_struct pb; struct ext2_super_block *sb = ctx->fs->super; struct ext2_super_block jsuper; struct problem_context pctx; struct buffer_head *bh; struct inode *j_inode = NULL; struct kdev_s *dev_fs = NULL, *dev_journal; const char *journal_name = 0; journal_t *journal = NULL; errcode_t retval = 0; io_manager io_ptr = 0; unsigned long long start = 0; int ext_journal = 0; int tried_backup_jnl = 0; clear_problem_context(&pctx); journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal"); if (!journal) { return EXT2_ET_NO_MEMORY; } dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev"); if (!dev_fs) { retval = EXT2_ET_NO_MEMORY; goto errout; } dev_journal = dev_fs+1; dev_fs->k_ctx = dev_journal->k_ctx = ctx; dev_fs->k_dev = K_DEV_FS; dev_journal->k_dev = K_DEV_JOURNAL; journal->j_dev = dev_journal; journal->j_fs_dev = dev_fs; journal->j_inode = NULL; journal->j_blocksize = ctx->fs->blocksize; if (uuid_is_null(sb->s_journal_uuid)) { if (!sb->s_journal_inum) { retval = EXT2_ET_BAD_INODE_NUM; goto errout; } j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode), "journal inode"); if (!j_inode) { retval = EXT2_ET_NO_MEMORY; goto errout; } j_inode->i_ctx = ctx; j_inode->i_ino = sb->s_journal_inum; if ((retval = ext2fs_read_inode(ctx->fs, sb->s_journal_inum, &j_inode->i_ext2))) { try_backup_journal: if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS || tried_backup_jnl) goto errout; memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode)); memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, EXT2_N_BLOCKS*4); j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15]; j_inode->i_ext2.i_size = sb->s_jnl_blocks[16]; j_inode->i_ext2.i_links_count = 1; j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600; e2fsck_use_inode_shortcuts(ctx, 1); ctx->stashed_ino = j_inode->i_ino; ctx->stashed_inode = &j_inode->i_ext2; tried_backup_jnl++; } if (!j_inode->i_ext2.i_links_count || !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { retval = EXT2_ET_NO_JOURNAL; goto try_backup_journal; } if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize < JFS_MIN_JOURNAL_BLOCKS) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } pb.last_block = -1; retval = ext2fs_block_iterate3(ctx->fs, j_inode->i_ino, BLOCK_FLAG_HOLE, 0, process_journal_block, &pb); if ((pb.last_block + 1) * ctx->fs->blocksize < EXT2_I_SIZE(&j_inode->i_ext2)) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } if (tried_backup_jnl && !(ctx->options & E2F_OPT_READONLY)) { retval = ext2fs_write_inode(ctx->fs, sb->s_journal_inum, &j_inode->i_ext2); if (retval) goto errout; } journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize; #ifdef USE_INODE_IO retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum, &j_inode->i_ext2, &journal_name); if (retval) goto errout; io_ptr = inode_io_manager; #else journal->j_inode = j_inode; ctx->journal_io = ctx->fs->io; if ((retval = journal_bmap(journal, 0, &start)) != 0) goto errout; #endif } else { ext_journal = 1; if (!ctx->journal_name) { char uuid[37]; uuid_unparse(sb->s_journal_uuid, uuid); ctx->journal_name = blkid_get_devname(ctx->blkid, "UUID", uuid); if (!ctx->journal_name) ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev); } journal_name = ctx->journal_name; if (!journal_name) { fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx); retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } jfs_debug(1, "Using journal file %s\n", journal_name); io_ptr = unix_io_manager; } #if 0 test_io_backing_manager = io_ptr; io_ptr = test_io_manager; #endif #ifndef USE_INODE_IO if (ext_journal) #endif retval = io_ptr->open(journal_name, IO_FLAG_RW | IO_FLAG_EXCLUSIVE, &ctx->journal_io); if (retval) goto errout; io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize); if (ext_journal) { if (ctx->fs->blocksize == 1024) start = 1; bh = getblk(dev_journal, start, ctx->fs->blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; goto errout; } ll_rw_block(READ, 1, &bh); if ((retval = bh->b_err) != 0) { brelse(bh); goto errout; } memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024, sizeof(jsuper)); brelse(bh); #ifdef WORDS_BIGENDIAN if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ext2fs_swap_super(&jsuper); #endif if (jsuper.s_magic != EXT2_SUPER_MAGIC || !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx); retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } /* Make sure the journal UUID is correct */ if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid, sizeof(jsuper.s_uuid))) { fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx); retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } journal->j_maxlen = ext2fs_blocks_count(&jsuper); start++; } if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) { retval = EXT2_ET_NO_MEMORY; goto errout; } journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; #ifdef USE_INODE_IO if (j_inode) ext2fs_free_mem(&j_inode); #endif *ret_journal = journal; e2fsck_use_inode_shortcuts(ctx, 0); return 0; errout: e2fsck_use_inode_shortcuts(ctx, 0); if (dev_fs) ext2fs_free_mem(&dev_fs); if (j_inode) ext2fs_free_mem(&j_inode); if (journal) ext2fs_free_mem(&journal); return retval; }
/* * This function creates a journal using direct I/O routines. */ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, blk_t num_blocks, blk64_t goal, int flags) { char *buf; errcode_t retval; struct ext2_inode inode; unsigned long long inode_size; struct mkjournal_struct es; if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, &buf))) return retval; if ((retval = ext2fs_read_bitmaps(fs))) goto out2; if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto out2; if (inode.i_blocks > 0) { retval = EEXIST; goto out2; } es.num_blocks = num_blocks; es.newblocks = 0; es.buf = buf; es.err = 0; es.flags = flags; es.zero_count = 0; es.goal = (goal != ~0ULL) ? goal : get_midpoint_journal_block(fs); if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { inode.i_flags |= EXT4_EXTENTS_FL; if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) goto out2; } retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND, 0, mkjournal_proc, &es); if (retval) goto out2; if (es.err) { retval = es.err; goto out2; } if (es.zero_count) { retval = ext2fs_zero_blocks2(fs, es.blk_to_zero, es.zero_count, 0, 0); if (retval) goto out2; } if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto out2; inode_size = (unsigned long long)fs->blocksize * num_blocks; ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; retval = ext2fs_inode_size_set(fs, &inode, inode_size); if (retval) goto out2; if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) goto out2; retval = 0; memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); fs->super->s_jnl_blocks[15] = inode.i_size_high; fs->super->s_jnl_blocks[16] = inode.i_size; fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); out2: ext2fs_free_mem(&buf); return retval; }
errcode_t ext2fs_move_blocks(ext2_filsys fs, ext2fs_block_bitmap reserve, ext2fs_block_bitmap alloc_map, int flags) { ext2_ino_t ino; struct ext2_inode inode; errcode_t retval; struct process_block_struct pb; ext2_inode_scan scan; char *block_buf; retval = ext2fs_open_inode_scan(fs, 0, &scan); if (retval) return retval; pb.reserve = reserve; pb.error = 0; pb.alloc_map = alloc_map ? alloc_map : fs->block_map; pb.flags = flags; retval = ext2fs_get_array(4, fs->blocksize, &block_buf); if (retval) return retval; pb.buf = block_buf + fs->blocksize * 3; /* * If GET_DBLIST is set in the flags field, then we should * gather directory block information while we're doing the * block move. */ if (flags & EXT2_BMOVE_GET_DBLIST) { if (fs->dblist) { ext2fs_free_dblist(fs->dblist); fs->dblist = NULL; } retval = ext2fs_init_dblist(fs, 0); if (retval) return retval; } retval = ext2fs_get_next_inode(scan, &ino, &inode); if (retval) return retval; while (ino) { if ((inode.i_links_count == 0) || !ext2fs_inode_has_valid_blocks2(fs, &inode)) goto next; pb.ino = ino; pb.inode = &inode; pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) && flags & EXT2_BMOVE_GET_DBLIST); retval = ext2fs_block_iterate3(fs, ino, 0, block_buf, process_block, &pb); if (retval) return retval; if (pb.error) return pb.error; next: retval = ext2fs_get_next_inode(scan, &ino, &inode); if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) goto next; } return 0; }
static errcode_t ext2fs_get_journal(ext2_filsys fs, journal_t **ret_journal) { struct process_block_struct pb; struct ext2_super_block *sb = fs->super; struct ext2_super_block jsuper; struct buffer_head *bh; struct inode *j_inode = NULL; struct kdev_s *dev_fs = NULL, *dev_journal; const char *journal_name = 0; journal_t *journal = NULL; errcode_t retval = 0; io_manager io_ptr = 0; unsigned long long start = 0; int ext_journal = 0; int tried_backup_jnl = 0; retval = ext2fs_get_memzero(sizeof(journal_t), &journal); if (retval) return retval; retval = ext2fs_get_memzero(2 * sizeof(struct kdev_s), &dev_fs); if (retval) goto errout; dev_journal = dev_fs+1; dev_fs->k_fs = dev_journal->k_fs = fs; dev_fs->k_dev = K_DEV_FS; dev_journal->k_dev = K_DEV_JOURNAL; journal->j_dev = dev_journal; journal->j_fs_dev = dev_fs; journal->j_inode = NULL; journal->j_blocksize = fs->blocksize; if (uuid_is_null(sb->s_journal_uuid)) { if (!sb->s_journal_inum) { retval = EXT2_ET_BAD_INODE_NUM; goto errout; } retval = ext2fs_get_memzero(sizeof(*j_inode), &j_inode); if (retval) goto errout; j_inode->i_fs = fs; j_inode->i_ino = sb->s_journal_inum; retval = ext2fs_read_inode(fs, sb->s_journal_inum, &j_inode->i_ext2); if (retval) { try_backup_journal: if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS || tried_backup_jnl) goto errout; memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode)); memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, EXT2_N_BLOCKS*4); j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15]; j_inode->i_ext2.i_size = sb->s_jnl_blocks[16]; j_inode->i_ext2.i_links_count = 1; j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600; tried_backup_jnl++; } if (!j_inode->i_ext2.i_links_count || !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { retval = EXT2_ET_NO_JOURNAL; goto try_backup_journal; } if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize < JFS_MIN_JOURNAL_BLOCKS) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } pb.last_block = -1; retval = ext2fs_block_iterate3(fs, j_inode->i_ino, BLOCK_FLAG_HOLE, 0, process_journal_block, &pb); if ((pb.last_block + 1) * fs->blocksize < (int) EXT2_I_SIZE(&j_inode->i_ext2)) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } if (tried_backup_jnl && (fs->flags & EXT2_FLAG_RW)) { retval = ext2fs_write_inode(fs, sb->s_journal_inum, &j_inode->i_ext2); if (retval) goto errout; } journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize; #ifdef USE_INODE_IO retval = ext2fs_inode_io_intern2(fs, sb->s_journal_inum, &j_inode->i_ext2, &journal_name); if (retval) goto errout; io_ptr = inode_io_manager; #else journal->j_inode = j_inode; fs->journal_io = fs->io; retval = (errcode_t)journal_bmap(journal, 0, &start); if (retval) goto errout; #endif } else { ext_journal = 1; if (!fs->journal_name) { char uuid[37]; blkid_cache blkid; blkid_get_cache(&blkid, NULL); uuid_unparse(sb->s_journal_uuid, uuid); fs->journal_name = blkid_get_devname(blkid, "UUID", uuid); if (!fs->journal_name) fs->journal_name = blkid_devno_to_devname(sb->s_journal_dev); blkid_put_cache(blkid); } journal_name = fs->journal_name; if (!journal_name) { retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } jfs_debug(1, "Using journal file %s\n", journal_name); io_ptr = unix_io_manager; } #if 0 test_io_backing_manager = io_ptr; io_ptr = test_io_manager; #endif #ifndef USE_INODE_IO if (ext_journal) #endif { retval = io_ptr->open(journal_name, fs->flags & EXT2_FLAG_RW, &fs->journal_io); } if (retval) goto errout; io_channel_set_blksize(fs->journal_io, fs->blocksize); if (ext_journal) { blk64_t maxlen; start = ext2fs_journal_sb_start(fs->blocksize) - 1; bh = getblk(dev_journal, start, fs->blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; goto errout; } ll_rw_block(READ, 1, &bh); retval = bh->b_err; if (retval) { brelse(bh); goto errout; } memcpy(&jsuper, start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET, sizeof(jsuper)); #ifdef WORDS_BIGENDIAN if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ext2fs_swap_super(&jsuper); #endif if (jsuper.s_magic != EXT2_SUPER_MAGIC || !ext2fs_has_feature_journal_dev(&jsuper)) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } /* Make sure the journal UUID is correct */ if (memcmp(jsuper.s_uuid, fs->super->s_journal_uuid, sizeof(jsuper.s_uuid))) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } /* Check the superblock checksum */ if (ext2fs_has_feature_metadata_csum(&jsuper)) { struct struct_ext2_filsys fsx; struct ext2_super_block superx; void *p; p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET; memcpy(&fsx, fs, sizeof(fsx)); memcpy(&superx, fs->super, sizeof(superx)); fsx.super = &superx; ext2fs_set_feature_metadata_csum(fsx.super); if (!ext2fs_superblock_csum_verify(&fsx, p)) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } } brelse(bh); maxlen = ext2fs_blocks_count(&jsuper); journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : (1ULL << 32) - 1; start++; } bh = getblk(dev_journal, start, journal->j_blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; goto errout; } journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; #ifdef USE_INODE_IO if (j_inode) ext2fs_free_mem(&j_inode); #endif *ret_journal = journal; return 0; errout: if (dev_fs) ext2fs_free_mem(&dev_fs); if (j_inode) ext2fs_free_mem(&j_inode); if (journal) ext2fs_free_mem(&journal); return retval; }