| #include "fsmap.h" |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include "support/nls-enable.h" |
| |
| struct walk_ext_priv_data { |
| char *path; |
| ext2_filsys fs; |
| struct fsmap_format *format; |
| }; |
| |
| static int walk_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t *blocknr, |
| e2_blkcnt_t blockcnt, |
| blk64_t ref64_blk EXT2FS_ATTR((unused)), |
| int ref_offset EXT2FS_ATTR((unused)), |
| void *priv) |
| { |
| struct walk_ext_priv_data *pdata = priv; |
| struct fsmap_format *format = pdata->format; |
| |
| return format->add_block(fs, *blocknr, blockcnt < 0, format->private); |
| } |
| |
| static errcode_t ino_iter_blocks(ext2_filsys fs, ext2_ino_t ino, |
| struct walk_ext_priv_data *pdata) |
| { |
| errcode_t retval; |
| struct ext2_inode inode; |
| struct fsmap_format *format = pdata->format; |
| |
| retval = ext2fs_read_inode(fs, ino, &inode); |
| if (retval) |
| return retval; |
| |
| if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) |
| return format->inline_data(&(inode.i_block[0]), |
| format->private); |
| |
| retval = ext2fs_block_iterate3(fs, ino, 0, NULL, walk_block, pdata); |
| if (retval) |
| com_err(__func__, retval, _("listing blocks of ino \"%u\""), |
| ino); |
| return retval; |
| } |
| |
| static int is_dir(ext2_filsys fs, ext2_ino_t ino) |
| { |
| struct ext2_inode inode; |
| |
| if (ext2fs_read_inode(fs, ino, &inode)) |
| return 0; |
| return S_ISDIR(inode.i_mode); |
| } |
| |
| static int walk_ext_dir(ext2_ino_t dir EXT2FS_ATTR((unused)), |
| int flags EXT2FS_ATTR((unused)), |
| struct ext2_dir_entry *de, |
| int offset EXT2FS_ATTR((unused)), |
| int blocksize EXT2FS_ATTR((unused)), |
| char *buf EXT2FS_ATTR((unused)), void *priv_data) |
| { |
| errcode_t retval; |
| struct ext2_inode inode; |
| char *filename, *cur_path, *name = de->name; |
| int name_len = de->name_len & 0xff; |
| struct walk_ext_priv_data *pdata = priv_data; |
| struct fsmap_format *format = pdata->format; |
| |
| if (!strncmp(name, ".", name_len) |
| || !strncmp(name, "..", name_len) |
| || !strncmp(name, "lost+found", 10)) |
| return 0; |
| |
| if (asprintf(&filename, "%s/%.*s", pdata->path, name_len, name) < 0) |
| return -ENOMEM; |
| |
| retval = ext2fs_read_inode(pdata->fs, de->inode, &inode); |
| if (retval) { |
| com_err(__func__, retval, _("reading ino \"%u\""), de->inode); |
| goto end; |
| } |
| format->start_new_file(filename, de->inode, &inode, format->private); |
| retval = ino_iter_blocks(pdata->fs, de->inode, pdata); |
| if (retval) |
| return retval; |
| format->end_new_file(format->private); |
| |
| retval = 0; |
| if (is_dir(pdata->fs, de->inode)) { |
| cur_path = pdata->path; |
| pdata->path = filename; |
| retval = ext2fs_dir_iterate2(pdata->fs, de->inode, 0, NULL, |
| walk_ext_dir, pdata); |
| pdata->path = cur_path; |
| } |
| |
| end: |
| free(filename); |
| return retval; |
| } |
| |
| errcode_t fsmap_iter_filsys(ext2_filsys fs, struct fsmap_format *format, |
| const char *file, const char *mountpoint) |
| { |
| struct walk_ext_priv_data pdata; |
| errcode_t retval; |
| |
| format->private = format->init(file, mountpoint); |
| pdata.fs = fs; |
| pdata.path = ""; |
| pdata.format = format; |
| |
| retval = ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_ext_dir, &pdata); |
| |
| format->cleanup(format->private); |
| return retval; |
| } |