summaryrefslogtreecommitdiffstats
path: root/contrib/android/fsmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/android/fsmap.c')
-rw-r--r--contrib/android/fsmap.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/contrib/android/fsmap.c b/contrib/android/fsmap.c
new file mode 100644
index 0000000..9ee8472
--- /dev/null
+++ b/contrib/android/fsmap.c
@@ -0,0 +1,169 @@
+#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_extents(ext2_filsys fs, ext2_ino_t ino,
+ ext2_extent_handle_t extents,
+ struct walk_ext_priv_data *pdata)
+{
+ blk64_t block;
+ errcode_t retval;
+ blk64_t next_lblk = 0;
+ int op = EXT2_EXTENT_ROOT;
+ struct ext2fs_extent extent;
+ struct fsmap_format *format = pdata->format;
+
+ for (;;) {
+ retval = ext2fs_extent_get(extents, op, &extent);
+ if (retval)
+ break;
+
+ op = EXT2_EXTENT_NEXT;
+
+ if ((extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) ||
+ !(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF))
+ continue;
+
+ for (; next_lblk < extent.e_lblk; next_lblk++)
+ format->add_block(fs, 0, 0, format->private);
+
+ block = extent.e_pblk;
+ for (; next_lblk < extent.e_lblk + extent.e_len; next_lblk++)
+ format->add_block(fs, block++, 0, format->private);
+ }
+
+ if (retval == EXT2_ET_EXTENT_NO_NEXT)
+ retval = 0;
+ if (retval) {
+ com_err(__func__, retval, ("getting extents of ino \"%u\""),
+ ino);
+ }
+ return retval;
+}
+
+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;
+ ext2_extent_handle_t extents;
+ 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_extent_open(fs, ino, &extents);
+ if (retval == EXT2_ET_INODE_NOT_EXTENT) {
+ retval = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY,
+ NULL, walk_block, pdata);
+ if (retval) {
+ com_err(__func__, retval, _("listing blocks of ino \"%u\""),
+ ino);
+ }
+ return retval;
+ }
+
+ retval = ino_iter_extents(fs, ino, extents, pdata);
+
+ ext2fs_extent_free(extents);
+ 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;
+}