summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorAdrien Schildknecht <adriens@google.com>2016-11-29 21:36:43 -0800
committerTheodore Ts'o <tytso@mit.edu>2017-05-23 22:08:44 -0400
commit974c8483b9f097798a78dbe9cf1c4a10cd1eb9ab (patch)
tree98e60aef266bf1f643905eeb87b8df0975f3a0a5 /contrib
parent9d25d462c671f9b5664f6ae6fa76e0010db68b13 (diff)
downloade2fsprogs-974c8483b9f097798a78dbe9cf1c4a10cd1eb9ab.tar.gz
AOSP: e2fsdroid: a tool to create android compatible image
Add an option to generate a block_list file from an existing ext4 or sparse image. Test: make_ext4 and e2fsdroid both generate the same list of file. Change-Id: I5ecc6521797397102904bf510c283dfd50a72721 From AOSP commit: fdc29bee07aef3a379f3ec3ccbaa551ff6500bff Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'contrib')
-rw-r--r--contrib/Android.mk2
-rw-r--r--contrib/android/Android.mk21
-rw-r--r--contrib/android/block_list.c94
-rw-r--r--contrib/android/block_list.h8
-rw-r--r--contrib/android/block_range.c65
-rw-r--r--contrib/android/block_range.h18
-rw-r--r--contrib/android/e2fsdroid.c91
-rw-r--r--contrib/android/fsmap.c117
-rw-r--r--contrib/android/fsmap.h29
9 files changed, 445 insertions, 0 deletions
diff --git a/contrib/Android.mk b/contrib/Android.mk
index f8d74c30..9f57daa8 100644
--- a/contrib/Android.mk
+++ b/contrib/Android.mk
@@ -78,3 +78,5 @@ LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_EXECUTABLE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/contrib/android/Android.mk b/contrib/android/Android.mk
new file mode 100644
index 00000000..8199037f
--- /dev/null
+++ b/contrib/android/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+
+e2fsdroid_src := e2fsdroid.c \
+ block_range.c \
+ fsmap.c \
+ block_list.c
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(e2fsdroid_src)
+LOCAL_MODULE := e2fsdroid
+LOCAL_SHARED_LIBRARIES := libext2fs-host \
+ libext2_com_err-host
+include $(BUILD_HOST_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(e2fsdroid_src)
+LOCAL_MODULE := e2fsdroid
+LOCAL_SHARED_LIBRARIES := libext2fs \
+ libext2_com_err
+include $(BUILD_EXECUTABLE)
diff --git a/contrib/android/block_list.c b/contrib/android/block_list.c
new file mode 100644
index 00000000..fec9dec8
--- /dev/null
+++ b/contrib/android/block_list.c
@@ -0,0 +1,94 @@
+#include "block_list.h"
+#include "block_range.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+struct block_list {
+ FILE *f;
+ const char *mountpoint;
+
+ struct {
+ const char *filename;
+ struct block_range *head;
+ struct block_range *tail;
+ } entry;
+};
+
+static void *init(const char *file, const char *mountpoint)
+{
+ struct block_list *params = malloc(sizeof(*params));
+
+ if (!params)
+ return NULL;
+ params->mountpoint = mountpoint;
+ params->f = fopen(file, "w+");
+ if (!params->f) {
+ free(params);
+ return NULL;
+ }
+ return params;
+}
+
+static int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
+ struct ext2_inode *inode EXT2FS_ATTR((unused)),
+ void *data)
+{
+ struct block_list *params = data;
+
+ params->entry.head = params->entry.tail = NULL;
+ params->entry.filename = LINUX_S_ISREG(inode->i_mode) ? path : NULL;
+ return 0;
+}
+
+static int add_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t blocknr,
+ int metadata, void *data)
+{
+ struct block_list *params = data;
+
+ if (params->entry.filename && !metadata)
+ add_blocks_to_range(&params->entry.head, &params->entry.tail,
+ blocknr, blocknr);
+ return 0;
+}
+
+static int inline_data(void *inline_data EXT2FS_ATTR((unused)),
+ void *data EXT2FS_ATTR((unused)))
+{
+ return 0;
+}
+
+static int end_new_file(void *data)
+{
+ struct block_list *params = data;
+
+ if (!params->entry.filename)
+ return 0;
+ if (fprintf(params->f, "%s%s ", params->mountpoint,
+ params->entry.filename) < 0
+ || write_block_ranges(params->f, params->entry.head, " ")
+ || fwrite("\n", 1, 1, params->f) != 1)
+ return -1;
+
+ delete_block_ranges(params->entry.head);
+ return 0;
+}
+
+static int cleanup(void *data)
+{
+ struct block_list *params = data;
+
+ fclose(params->f);
+ free(params);
+ return 0;
+}
+
+struct fsmap_format block_list_format = {
+ .init = init,
+ .start_new_file = start_new_file,
+ .add_block = add_block,
+ .inline_data = inline_data,
+ .end_new_file = end_new_file,
+ .cleanup = cleanup,
+};
diff --git a/contrib/android/block_list.h b/contrib/android/block_list.h
new file mode 100644
index 00000000..47041e40
--- /dev/null
+++ b/contrib/android/block_list.h
@@ -0,0 +1,8 @@
+#ifndef BLOCK_LIST_H
+# define BLOCK_LIST_H
+
+# include "fsmap.h"
+
+extern struct fsmap_format block_list_format;
+
+#endif /* !BLOCK_LIST_H */
diff --git a/contrib/android/block_range.c b/contrib/android/block_range.c
new file mode 100644
index 00000000..d054123a
--- /dev/null
+++ b/contrib/android/block_range.c
@@ -0,0 +1,65 @@
+#include "block_range.h"
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <stdio.h>
+
+struct block_range *new_block_range(blk64_t start, blk64_t end)
+{
+ struct block_range *range = malloc(sizeof(*range));
+ range->start = start;
+ range->end = end;
+ range->next = NULL;
+ return range;
+}
+
+void add_blocks_to_range(struct block_range **head, struct block_range **tail,
+ blk64_t blk_start, blk64_t blk_end)
+{
+ if (*head == NULL)
+ *head = *tail = new_block_range(blk_start, blk_end);
+ else if ((*tail)->end + 1 == blk_start)
+ (*tail)->end += (blk_end - blk_start + 1);
+ else {
+ struct block_range *range = new_block_range(blk_start, blk_end);
+ (*tail)->next = range;
+ *tail = range;
+ }
+}
+
+void delete_block_ranges(struct block_range *head)
+{
+ struct block_range *tmp;
+
+ while (head) {
+ tmp = head->next;
+ free(head);
+ head = tmp;
+ }
+}
+
+int write_block_ranges(FILE *f, struct block_range *range,
+ char *sep)
+{
+ int len;
+ char *buf;
+
+ while (range) {
+ if (range->start == range->end)
+ len = asprintf(&buf, "%llu%s", range->start, sep);
+ else
+ len = asprintf(&buf, "%llu-%llu%s", range->start,
+ range->end, sep);
+ if (fwrite(buf, 1, len, f) != (size_t)len) {
+ free(buf);
+ return -1;
+ }
+ free(buf);
+ range = range->next;
+ }
+
+ len = strlen(sep);
+ if (fseek(f, -len, SEEK_CUR) == -len)
+ return -1;
+ return 0;
+}
diff --git a/contrib/android/block_range.h b/contrib/android/block_range.h
new file mode 100644
index 00000000..31e3c23f
--- /dev/null
+++ b/contrib/android/block_range.h
@@ -0,0 +1,18 @@
+#ifndef BLOCK_RANGE_H
+# define BLOCK_RANGE_H
+
+# include <sys/types.h>
+# include <ext2fs/ext2fs.h>
+
+struct block_range {
+ blk64_t start;
+ blk64_t end;
+ struct block_range *next;
+};
+
+void add_blocks_to_range(struct block_range **head, struct block_range **tail,
+ blk64_t blk_start, blk64_t blk_end);
+void delete_block_ranges(struct block_range *head);
+int write_block_ranges(FILE *f, struct block_range *range, char *sep);
+
+#endif /* !BLOCK_RANGE_H */
diff --git a/contrib/android/e2fsdroid.c b/contrib/android/e2fsdroid.c
new file mode 100644
index 00000000..816104f8
--- /dev/null
+++ b/contrib/android/e2fsdroid.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <ext2fs/ext2fs.h>
+
+#include "block_list.h"
+
+const char *prog_name = "e2fsdroid";
+const char *in_file;
+const char *block_list;
+const char *mountpoint = "";
+int android_sparse_file = 1;
+
+static void usage(int ret)
+{
+ fprintf(stderr, "%s [-B block_list] [-e] image\n", prog_name);
+ exit(ret);
+}
+
+static char *absolute_path(const char *file)
+{
+ char *ret;
+ char cwd[PATH_MAX];
+
+ if (file[0] != '/') {
+ getcwd(cwd, PATH_MAX);
+ ret = malloc(strlen(cwd) + 1 + strlen(file) + 1);
+ if (ret)
+ sprintf(ret, "%s/%s", cwd, file);
+ } else
+ ret = strdup(file);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int flags = EXT2_FLAG_RW;
+ errcode_t retval;
+ io_manager io_mgr;
+ ext2_filsys fs = NULL;
+
+ add_error_table(&et_ext2_error_table);
+
+ while ((c = getopt (argc, argv, "B:e")) != EOF) {
+ switch (c) {
+ case 'B':
+ block_list = absolute_path(optarg);
+ break;
+ case 'e':
+ android_sparse_file = 0;
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ }
+ }
+ if (optind >= argc) {
+ fprintf(stderr, "Expected filename after options\n");
+ exit(EXIT_FAILURE);
+ }
+ in_file = strdup(argv[optind]);
+
+ io_mgr = android_sparse_file ? sparse_io_manager: unix_io_manager;
+ retval = ext2fs_open(in_file, flags, 0, 0, io_mgr, &fs);
+ if (retval) {
+ com_err(prog_name, retval, "while opening file %s\n", in_file);
+ return retval;
+ }
+
+ if (block_list) {
+ retval = fsmap_iter_filsys(fs, &block_list_format, block_list,
+ mountpoint);
+ if (retval) {
+ com_err(prog_name, retval, "%s",
+ "while creating block_list");
+ exit(1);
+ }
+ }
+
+ retval = ext2fs_close_free(&fs);
+ if (retval) {
+ com_err(prog_name, retval, "%s",
+ "while writing superblocks");
+ exit(1);
+ }
+
+ remove_error_table(&et_ext2_error_table);
+ return 0;
+}
diff --git a/contrib/android/fsmap.c b/contrib/android/fsmap.c
new file mode 100644
index 00000000..0a4867bf
--- /dev/null
+++ b/contrib/android/fsmap.c
@@ -0,0 +1,117 @@
+#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);
+
+ if (is_dir(pdata->fs, de->inode)) {
+ cur_path = pdata->path;
+ pdata->path = filename;
+ ext2fs_dir_iterate2(pdata->fs, de->inode, 0, NULL,
+ walk_ext_dir, pdata);
+ pdata->path = cur_path;
+ }
+
+end:
+ free(filename);
+ return 0;
+}
+
+errcode_t fsmap_iter_filsys(ext2_filsys fs, struct fsmap_format *format,
+ const char *file, const char *mountpoint)
+{
+ struct walk_ext_priv_data pdata;
+
+ format->private = format->init(file, mountpoint);
+ pdata.fs = fs;
+ pdata.path = "";
+ pdata.format = format;
+
+ ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_ext_dir, &pdata);
+
+ format->cleanup(format->private);
+ return 0;
+}
diff --git a/contrib/android/fsmap.h b/contrib/android/fsmap.h
new file mode 100644
index 00000000..9f84a718
--- /dev/null
+++ b/contrib/android/fsmap.h
@@ -0,0 +1,29 @@
+#ifndef FSMAP_H
+# define FSMAP_H
+
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE // asprintf
+# endif
+# include <stdio.h>
+# include <stdint.h>
+# include <stdbool.h>
+# include <sys/types.h>
+# include <ext2fs/ext2fs.h>
+
+struct fsmap_format {
+ void* (* init)(const char *file, const char *mountpoint);
+ int (* start_new_file)(char *path, ext2_ino_t ino,
+ struct ext2_inode *inode, void *data);
+ int (* add_block)(ext2_filsys fs, blk64_t blocknr, int metadata,
+ void *data);
+ int (* inline_data)(void *inline_data, void *data);
+ int (* end_new_file)(void *data);
+ int (* cleanup)(void *data);
+
+ void *private;
+};
+
+errcode_t fsmap_iter_filsys(ext2_filsys fs, struct fsmap_format *format,
+ const char *file, const char *mountpoint);
+
+#endif /* !FSMAP_H */