/* * Helper function used by fix_directory. * * XXX need to finish this. General approach is to use bmap to * iterate over all of the logical blocks using the bmap function, and * copy the block reference as necessary. Big question --- what do * about error recovery? * * Also question --- how to free the indirect blocks. */ int empty_pass1(ext2_filsys fs, blk64_t *block_nr, e2_blkcnt_t blockcnt, blk64_t ref_block, int ref_offset, void *priv_data) { empty_dir_info edi = (empty_dir_info) priv_data; blk64_t block, new_block; errcode_t retval; if (blockcnt < 0) return 0; block = *block_nr; do { retval = ext2fs_bmap2(fs, edi->ino, &edi->inode, edi->block_buf, 0, edi->logblk, 0, &new_block); if (retval) return DIRENT_ABORT; /* XXX what to do? */ if (new_block == 0) break; edi->logblk++; } while (ext2fs_test_block_bitmap2(edi->empty_dir_blocks, new_block)); if (new_block == block) return 0; if (new_block == 0) edi->freed_blocks++; *block_nr = new_block; return BLOCK_CHANGED; }
static void htree_dump_int_block(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, struct ext2_dx_root_info * rootnode, blk64_t blk, char *buf, int level) { char *cbuf; errcode_t errcode; blk64_t pblk; cbuf = malloc(fs->blocksize); if (!cbuf) { fprintf(pager, "Couldn't allocate child block.\n"); return; } errcode = ext2fs_bmap2(fs, ino, inode, buf, 0, blk, 0, &pblk); if (errcode) { com_err("htree_dump_int_block", errcode, "while mapping logical block %llu\n", blk); goto errout; } errcode = io_channel_read_blk64(current_fs->io, pblk, 1, buf); if (errcode) { com_err("htree_dump_int_block", errcode, "while reading block %llu\n", blk); goto errout; } htree_dump_int_node(fs, ino, inode, rootnode, (struct ext2_dx_entry *) (buf+8), cbuf, level); errout: free(cbuf); }
static errcode_t ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, char *buf, size_t size) { errcode_t retval; blk64_t blk; char *blk_buf; retval = ext2fs_get_memzero(fs->blocksize, &blk_buf); if (retval) return retval; #ifdef WORDS_BIGENDIAN retval = ext2fs_dirent_swab_in2(fs, buf + EXT4_INLINE_DATA_DOTDOT_SIZE, size, 0); if (retval) goto errout; #endif /* Adjust the rec_len */ retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size); if (retval) goto errout; /* Allocate a new block */ retval = ext2fs_new_block2(fs, 0, 0, &blk); if (retval) goto errout; retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino); if (retval) goto errout; /* Update inode */ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT3_FEATURE_INCOMPAT_EXTENTS)) inode->i_flags |= EXT4_EXTENTS_FL; inode->i_flags &= ~EXT4_INLINE_DATA_FL; retval = ext2fs_iblk_add_blocks(fs, inode, 1); if (retval) goto errout; inode->i_size = fs->blocksize; retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk); if (retval) goto errout; retval = ext2fs_write_inode(fs, ino, inode); if (retval) goto errout; ext2fs_block_alloc_stats(fs, blk, +1); errout: ext2fs_free_mem(&blk_buf); return retval; }
static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir, ext2_ino_t inode, int link_count, char *buf, ext2_ino_t *res_inode) { char *pathname; char *buffer = 0; errcode_t retval; struct ext2_inode ei; blk64_t blk; #ifdef NAMEI_DEBUG printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n", root, dir, inode, link_count); #endif retval = ext2fs_read_inode (fs, inode, &ei); if (retval) return retval; if (!LINUX_S_ISLNK (ei.i_mode)) { *res_inode = inode; return 0; } if (link_count++ >= EXT2FS_MAX_NESTED_LINKS) return EXT2_ET_SYMLINK_LOOP; if (ext2fs_inode_data_blocks(fs,&ei)) { retval = ext2fs_bmap2(fs, inode, &ei, NULL, 0, 0, NULL, &blk); if (retval) return retval; retval = ext2fs_get_mem(fs->blocksize, &buffer); if (retval) return retval; retval = io_channel_read_blk64(fs->io, blk, 1, buffer); if (retval) { ext2fs_free_mem(&buffer); return retval; } pathname = buffer; } else pathname = (char *)&(ei.i_block[0]); retval = open_namei(fs, root, dir, pathname, ei.i_size, 1, link_count, buf, res_inode); if (buffer) ext2fs_free_mem(&buffer); return retval; }
/* Kernel compatibility functions for handling the journal. These allow us * to use the recovery.c file virtually unchanged from the kernel, so we * don't have to do much to keep kernel and user recovery in sync. */ int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys) { #ifdef USE_INODE_IO *phys = block; return 0; #else struct inode *inode = journal->j_inode; errcode_t retval; blk64_t pblk; if (!inode) { *phys = block; return 0; } retval= ext2fs_bmap2(inode->i_ctx->fs, inode->i_ino, &inode->i_ext2, NULL, 0, block, 0, &pblk); *phys = pblk; return (retval); #endif }
errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, const char *name, char *target) { ext2_extent_handle_t handle; errcode_t retval; struct ext2_inode inode; ext2_ino_t scratch_ino; blk64_t blk; int fastlink; unsigned int target_len; char *block_buf = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* The Linux kernel doesn't allow for links longer than a block */ target_len = strlen(target); if (target_len > fs->blocksize) { retval = EXT2_ET_INVALID_ARGUMENT; goto cleanup; } /* * Allocate a data block for slow links */ fastlink = (target_len < sizeof(inode.i_block)); if (!fastlink) { retval = ext2fs_new_block2(fs, 0, 0, &blk); if (retval) goto cleanup; retval = ext2fs_get_mem(fs->blocksize, &block_buf); if (retval) goto cleanup; } /* * Allocate an inode, if necessary */ if (!ino) { retval = ext2fs_new_inode(fs, parent, LINUX_S_IFLNK | 0755, 0, &ino); if (retval) goto cleanup; } /* * Create the inode structure.... */ memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFLNK | 0777; inode.i_uid = inode.i_gid = 0; ext2fs_iblk_set(fs, &inode, fastlink ? 0 : 1); inode.i_links_count = 1; inode.i_size = target_len; /* The time fields are set by ext2fs_write_new_inode() */ if (fastlink) { /* Fast symlinks, target stored in inode */ strcpy((char *)&inode.i_block, target); } else { /* Slow symlinks, target stored in the first block */ memset(block_buf, 0, fs->blocksize); strcpy(block_buf, target); if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { /* * The extent bmap is setup after the inode and block * have been written out below. */ inode.i_flags |= EXT4_EXTENTS_FL; } } /* * Write out the inode and inode data block. The inode generation * number is assigned by write_new_inode, which means that the * operations using ino must come after it. */ retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; if (!fastlink) { retval = ext2fs_bmap2(fs, ino, &inode, NULL, BMAP_SET, 0, NULL, &blk); if (retval) goto cleanup; retval = io_channel_write_blk64(fs->io, blk, 1, block_buf); if (retval) goto cleanup; } /* * Link the symlink into the filesystem hierarchy */ if (name) { retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { retval = EXT2_ET_FILE_EXISTS; goto cleanup; } if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_SYMLINK); if (retval) goto cleanup; } /* * Update accounting.... */ if (!fastlink) ext2fs_block_alloc_stats2(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 0); cleanup: if (block_buf) ext2fs_free_mem(&block_buf); return retval; }
static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, struct ext2_dx_root_info * rootnode, blk64_t blk, char *buf) { errcode_t errcode; struct ext2_dir_entry *dirent; int thislen, col = 0; unsigned int offset = 0; char name[EXT2_NAME_LEN + 1]; char tmp[EXT2_NAME_LEN + 64]; blk64_t pblk; ext2_dirhash_t hash, minor_hash; unsigned int rec_len; int hash_alg; errcode = ext2fs_bmap2(fs, ino, inode, buf, 0, blk, 0, &pblk); if (errcode) { com_err("htree_dump_leaf_node", errcode, "while mapping logical block %llu\n", blk); return; } fprintf(pager, "Reading directory block %llu, phys %llu\n", blk, pblk); errcode = ext2fs_read_dir_block2(current_fs, pblk, buf, 0); if (errcode) { com_err("htree_dump_leaf_node", errcode, "while reading block %llu (%llu)\n", blk, pblk); return; } hash_alg = rootnode->hash_version; if ((hash_alg <= EXT2_HASH_TEA) && (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH)) hash_alg += 3; while (offset < fs->blocksize) { dirent = (struct ext2_dir_entry *) (buf + offset); errcode = ext2fs_get_rec_len(fs, dirent, &rec_len); if (errcode) { com_err("htree_dump_leaf_inode", errcode, "while getting rec_len for block %lu", (unsigned long) blk); return; } if (((offset + rec_len) > fs->blocksize) || (rec_len < 8) || ((rec_len % 4) != 0) || ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len)) { fprintf(pager, "Corrupted directory block (%llu)!\n", blk); break; } thislen = dirent->name_len & 0xFF; strncpy(name, dirent->name, thislen); name[thislen] = '\0'; errcode = ext2fs_dirhash(hash_alg, name, thislen, fs->super->s_hash_seed, &hash, &minor_hash); if (errcode) com_err("htree_dump_leaf_node", errcode, "while calculating hash"); snprintf(tmp, EXT2_NAME_LEN + 64, "%u 0x%08x-%08x (%d) %s ", dirent->inode, hash, minor_hash, rec_len, name); thislen = strlen(tmp); if (col + thislen > 80) { fprintf(pager, "\n"); col = 0; } fprintf(pager, "%s", tmp); col += thislen; offset += rec_len; } fprintf(pager, "\n"); }
void do_htree_dump(int argc, char *argv[]) { ext2_ino_t ino; struct ext2_inode inode; blk64_t blk; char *buf = NULL; struct ext2_dx_root_info *rootnode; struct ext2_dx_entry *ent; errcode_t errcode; if (check_fs_open(argv[0])) return; pager = open_pager(); if (common_inode_args_process(argc, argv, &ino, 0)) goto errout; if (debugfs_read_inode(ino, &inode, argv[1])) goto errout; if (!LINUX_S_ISDIR(inode.i_mode)) { com_err(argv[0], 0, "Not a directory"); goto errout; } if ((inode.i_flags & EXT2_BTREE_FL) == 0) { com_err(argv[0], 0, "Not a hash-indexed directory"); goto errout; } buf = malloc(2*current_fs->blocksize); if (!buf) { com_err(argv[0], 0, "Couldn't allocate htree buffer"); goto errout; } errcode = ext2fs_bmap2(current_fs, ino, &inode, buf, 0, 0, 0, &blk); if (errcode) { com_err("do_htree_block", errcode, "while mapping logical block 0\n"); goto errout; } errcode = io_channel_read_blk64(current_fs->io, blk, 1, buf); if (errcode) { com_err(argv[0], errcode, "Error reading root node"); goto errout; } rootnode = (struct ext2_dx_root_info *) (buf + 24); fprintf(pager, "Root node dump:\n"); fprintf(pager, "\t Reserved zero: %u\n", rootnode->reserved_zero); fprintf(pager, "\t Hash Version: %d\n", rootnode->hash_version); fprintf(pager, "\t Info length: %d\n", rootnode->info_length); fprintf(pager, "\t Indirect levels: %d\n", rootnode->indirect_levels); fprintf(pager, "\t Flags: %d\n", rootnode->unused_flags); ent = (struct ext2_dx_entry *) (buf + 24 + rootnode->info_length); htree_dump_int_node(current_fs, ino, &inode, rootnode, ent, buf + current_fs->blocksize, rootnode->indirect_levels); errout: free(buf); close_pager(pager); }
/* * 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; int falloc_flags = EXT2_FALLOCATE_FORCE_INIT; blk64_t zblk; 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; } if (goal == ~0ULL) goal = get_midpoint_journal_block(fs); if (ext2fs_has_feature_extents(fs->super)) inode.i_flags |= EXT4_EXTENTS_FL; if (!(flags & EXT2_MKJOURNAL_LAZYINIT)) falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS; inode_size = (unsigned long long)fs->blocksize * num_blocks; 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; retval = ext2fs_fallocate(fs, falloc_flags, journal_ino, &inode, goal, 0, num_blocks); if (retval) goto out2; if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) goto out2; retval = ext2fs_bmap2(fs, journal_ino, &inode, NULL, 0, 0, NULL, &zblk); if (retval) goto out2; retval = io_channel_write_blk64(fs->io, zblk, 1, buf); if (retval) goto out2; 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; }