diff options
author | Adrien Schildknecht <adriens@google.com> | 2016-11-29 21:36:43 -0800 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2017-05-23 22:08:44 -0400 |
commit | 974c8483b9f097798a78dbe9cf1c4a10cd1eb9ab (patch) | |
tree | 98e60aef266bf1f643905eeb87b8df0975f3a0a5 /contrib | |
parent | 9d25d462c671f9b5664f6ae6fa76e0010db68b13 (diff) | |
download | e2fsprogs-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.mk | 2 | ||||
-rw-r--r-- | contrib/android/Android.mk | 21 | ||||
-rw-r--r-- | contrib/android/block_list.c | 94 | ||||
-rw-r--r-- | contrib/android/block_list.h | 8 | ||||
-rw-r--r-- | contrib/android/block_range.c | 65 | ||||
-rw-r--r-- | contrib/android/block_range.h | 18 | ||||
-rw-r--r-- | contrib/android/e2fsdroid.c | 91 | ||||
-rw-r--r-- | contrib/android/fsmap.c | 117 | ||||
-rw-r--r-- | contrib/android/fsmap.h | 29 |
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(¶ms->entry.head, ¶ms->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 */ |