Merge branch 'maint' into next
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..a095aea
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,10 @@
+// Copyright 2017 The Android Open Source Project
+
+subdirs = [
+    "contrib",
+    "debugfs",
+    "e2fsck",
+    "lib",
+    "misc",
+    "resize",
+]
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/MCONFIG.in b/MCONFIG.in
index e82963d..22b74eb 100644
--- a/MCONFIG.in
+++ b/MCONFIG.in
@@ -4,6 +4,8 @@
 
 check::
 
+fullcheck::
+
 SHELL = /bin/sh
 
 COMPRESS_EXT = gz bz2 bz Z
diff --git a/Makefile.in b/Makefile.in
index 7da9ad7..37b6069 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -78,8 +78,9 @@
 
 check-recursive: all
 
-TAGS clean-recursive distclean-recursive depend-recursive check-recursive \
-  mostlyclean-recursive realclean-recursive coverage.txt-recursive:
+TAGS clean-recursive distclean-recursive depend-recursive fullcheck-recursive \
+  check-recursive mostlyclean-recursive realclean-recursive \
+  coverage.txt-recursive:
 	@for subdir in $(SUBDIRS); do \
 	  if test -d $$subdir ; then \
 	    target=`echo $@|$(SED) 's/-recursive//'`; \
@@ -151,3 +152,4 @@
 
 check::	all check-recursive
 
+fullcheck:: all fullcheck-recursive
diff --git a/configure b/configure
index 5f7b429..f8e0ce4 100755
--- a/configure
+++ b/configure
@@ -12368,7 +12368,7 @@
 done
 
 fi
-for ac_header in  	dirent.h 	errno.h 	execinfo.h 	getopt.h 	malloc.h 	mntent.h 	paths.h 	semaphore.h 	setjmp.h 	signal.h 	stdarg.h 	stdint.h 	stdlib.h 	termios.h 	termio.h 	unistd.h 	utime.h 	attr/xattr.h 	linux/falloc.h 	linux/fd.h 	linux/major.h 	linux/loop.h 	net/if_dl.h 	netinet/in.h 	sys/acl.h 	sys/disklabel.h 	sys/disk.h 	sys/file.h 	sys/ioctl.h 	sys/key.h 	sys/mkdev.h 	sys/mman.h 	sys/mount.h 	sys/prctl.h 	sys/resource.h 	sys/select.h 	sys/socket.h 	sys/sockio.h 	sys/stat.h 	sys/syscall.h 	sys/sysctl.h 	sys/sysmacros.h 	sys/time.h 	sys/types.h 	sys/un.h 	sys/wait.h
+for ac_header in  	dirent.h 	errno.h 	execinfo.h 	getopt.h 	malloc.h 	mntent.h 	paths.h 	semaphore.h 	setjmp.h 	signal.h 	stdarg.h 	stdint.h 	stdlib.h 	termios.h 	termio.h 	unistd.h 	utime.h 	attr/xattr.h 	linux/falloc.h 	linux/fd.h 	linux/fsmap.h 	linux/major.h 	linux/loop.h 	linux/types.h 	net/if_dl.h 	netinet/in.h 	sys/acl.h 	sys/disklabel.h 	sys/disk.h 	sys/file.h 	sys/ioctl.h 	sys/key.h 	sys/mkdev.h 	sys/mman.h 	sys/mount.h 	sys/prctl.h 	sys/resource.h 	sys/select.h 	sys/socket.h 	sys/sockio.h 	sys/stat.h 	sys/syscall.h 	sys/sysctl.h 	sys/sysmacros.h 	sys/time.h 	sys/types.h 	sys/un.h 	sys/wait.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -13073,7 +13073,7 @@
 if test -n "$DLOPEN_LIB" ; then
    ac_cv_func_dlopen=yes
 fi
-for ac_func in  	__secure_getenv 	add_key 	backtrace 	blkid_probe_get_topology 	blkid_probe_enable_partitions 	chflags 	dlopen 	fadvise64 	fallocate 	fallocate64 	fchown 	fdatasync 	fstat64 	ftruncate64 	futimes 	getcwd 	getdtablesize 	getmntinfo 	getpwuid_r 	getrlimit 	getrusage 	jrand48 	keyctl 	llistxattr 	llseek 	lseek64 	mallinfo 	mbstowcs 	memalign 	mempcpy 	mmap 	msync 	nanosleep 	open64 	pathconf 	posix_fadvise 	posix_fadvise64 	posix_memalign 	prctl 	pread 	pwrite 	pread64 	pwrite64 	secure_getenv 	setmntent 	setresgid 	setresuid 	snprintf 	srandom 	stpcpy 	strcasecmp 	strdup 	strnlen 	strptime 	strtoull 	sync_file_range 	sysconf 	usleep 	utime 	utimes 	valloc
+for ac_func in  	__secure_getenv 	add_key 	backtrace 	blkid_probe_get_topology 	blkid_probe_enable_partitions 	chflags 	dlopen 	fadvise64 	fallocate 	fallocate64 	fchown 	fcntl 	fdatasync 	fstat64 	fsync 	ftruncate64 	futimes 	getcwd 	getdtablesize 	getmntinfo 	getpwuid_r 	getrlimit 	getrusage 	jrand48 	keyctl 	llistxattr 	llseek 	lseek64 	mallinfo 	mbstowcs 	memalign 	mempcpy 	mmap 	msync 	nanosleep 	open64 	pathconf 	posix_fadvise 	posix_fadvise64 	posix_memalign 	prctl 	pread 	pwrite 	pread64 	pwrite64 	secure_getenv 	setmntent 	setresgid 	setresuid 	snprintf 	srandom 	stpcpy 	strcasecmp 	strdup 	strnlen 	strptime 	strtoull 	sync_file_range 	sysconf 	usleep 	utime 	utimes 	valloc
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/configure.ac b/configure.ac
index 9da7b86..0c0c1d6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -918,8 +918,10 @@
 	attr/xattr.h
 	linux/falloc.h
 	linux/fd.h
+	linux/fsmap.h
 	linux/major.h
 	linux/loop.h
+	linux/types.h
 	net/if_dl.h
 	netinet/in.h
 	sys/acl.h
@@ -1094,8 +1096,10 @@
 	fallocate
 	fallocate64
 	fchown
+	fcntl
 	fdatasync
 	fstat64
+	fsync
 	ftruncate64
 	futimes
 	getcwd
diff --git a/contrib/Android.bp b/contrib/Android.bp
new file mode 100644
index 0000000..c2d5cd9
--- /dev/null
+++ b/contrib/Android.bp
@@ -0,0 +1,37 @@
+// Copyright 2017 The Android Open Source Project
+
+subdirs = ["android"]
+
+//##########################################################################
+// Build fsstress
+
+cc_binary {
+    name: "fsstress",
+    host_supported: true,
+
+    srcs: ["fsstress.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    system_shared_libs: ["libc"],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+//########################################################################
+// Build add_ext4_encrypt
+
+cc_binary {
+    name: "add_ext4_encrypt",
+    host_supported: true,
+
+    srcs: ["add_ext4_encrypt.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+    ],
+    system_shared_libs: ["libc"],
+}
diff --git a/contrib/Android.mk b/contrib/Android.mk
deleted file mode 100644
index f8d74c3..0000000
--- a/contrib/Android.mk
+++ /dev/null
@@ -1,80 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-###########################################################################
-# Build fsstress
-#
-fsstress_src_files := \
-	fsstress.c
-
-fsstress_c_includes := 
-
-fsstress_cflags := -O2 -g -W -Wall
-
-fsstress_shared_libraries := 
-
-fsstress_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(fsstress_src_files)
-mke2fs_c_includesLOCAL_CFLAGS := $(fsstress_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(fsstress_system_shared_libraries)
-LOCAL_MODULE := fsstress
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(fsstress_src_files)
-LOCAL_CFLAGS := $(fsstress_cflags)
-LOCAL_MODULE := fsstress_host
-LOCAL_MODULE_STEM := fsstress
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_HOST_OS := linux
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build add_ext4_encrypt
-#
-include $(CLEAR_VARS)
-
-add_ext4_encrypt_src_files := \
-	add_ext4_encrypt.c
-
-add_ext4_encrypt_c_includes := \
-	external/e2fsprogs/lib
-
-add_ext4_encrypt_cflags := -O2 -g -W -Wall
-
-add_ext4_encrypt_shared_libraries := \
-	libext2fs \
-	libext2_com_err
-
-add_ext4_encrypt_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(add_ext4_encrypt_src_files)
-LOCAL_C_INCLUDES := $(add_ext4_encrypt_c_includes)
-LOCAL_CFLAGS := $(add_ext4_encrypt_cflags)
-LOCAL_SHARED_LIBRARIES := $(add_ext4_encrypt_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(add_ext4_encrypt_system_shared_libraries)
-LOCAL_MODULE := add_ext4_encrypt
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(add_ext4_encrypt_src_files)
-LOCAL_C_INCLUDES := $(add_ext4_encrypt_c_includes)
-LOCAL_CFLAGS := $(add_ext4_encrypt_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(add_ext4_encrypt_shared_libraries))
-LOCAL_MODULE := add_ext4_encrypt_host
-LOCAL_MODULE_STEM := add_ext4_encrypt
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
diff --git a/contrib/android/Android.bp b/contrib/android/Android.bp
new file mode 100644
index 0000000..afa335e
--- /dev/null
+++ b/contrib/android/Android.bp
@@ -0,0 +1,55 @@
+// Copyright 2017 The Android Open Source Project
+
+//##########################################################################
+// Build e2fsdroid
+
+cc_binary {
+    name: "e2fsdroid",
+    host_supported: true,
+
+    srcs: [
+        "e2fsdroid.c",
+        "block_range.c",
+        "fsmap.c",
+        "block_list.c",
+        "base_fs.c",
+        "perms.c",
+        "basefs_allocator.c",
+        "hashmap.c",
+    ],
+    cflags: ["-W", "-Wall"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libext2_misc",
+        "libcutils",
+        "libbase",
+        "libselinux",
+        "libcrypto",
+    ],
+}
+
+//##########################################################################
+// Build ext2simg
+
+cc_binary {
+    name: "ext2simg",
+    host_supported: true,
+
+    srcs: ["ext2simg.c"],
+    cflags: ["-W", "-Wall"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libsparse",
+    ],
+
+    target: {
+        host: {
+            shared_libs: ["libz-host"],
+        },
+        android: {
+            shared_libs: ["libz"],
+        },
+    },
+}
diff --git a/contrib/android/base_fs.c b/contrib/android/base_fs.c
new file mode 100644
index 0000000..2dcb5fe
--- /dev/null
+++ b/contrib/android/base_fs.c
@@ -0,0 +1,207 @@
+#include "base_fs.h"
+#include <stdio.h>
+
+#define BASE_FS_VERSION "Base EXT4 version 1.0"
+
+struct base_fs {
+	FILE *file;
+	const char *mountpoint;
+	struct basefs_entry entry;
+};
+
+static FILE *basefs_open(const char *file)
+{
+	char *line = NULL;
+	size_t len;
+	FILE *f = fopen(file, "r");
+	if (!f)
+		return NULL;
+
+	if (getline(&line, &len, f) == -1 || !line)
+		goto err_getline;
+
+	if (strncmp(line, BASE_FS_VERSION, strlen(BASE_FS_VERSION)))
+		goto err_header;
+
+	free(line);
+	return f;
+
+err_header:
+	free(line);
+err_getline:
+	fclose(f);
+	return NULL;
+}
+
+static struct basefs_entry *basefs_readline(FILE *f, const char *mountpoint,
+					    int *err)
+{
+	char *line = NULL, *saveptr1, *saveptr2, *block_range, *block;
+	int offset;
+	size_t len;
+	struct basefs_entry *entry = NULL;
+	blk64_t range_start, range_end;
+
+	if (getline(&line, &len, f) == -1) {
+		if (feof(f))
+			goto end;
+		goto err_getline;
+	}
+
+	entry = calloc(1, sizeof(*entry));
+	if (!entry)
+		goto err_alloc;
+
+	/*
+	 * With BASEFS version 1.0, a typical line looks like this:
+	 * /bin/mke2fs 5000-5004,8000,9000-9990
+	 */
+	if (sscanf(line, "%ms%n", &entry->path, &offset) != 1)
+		goto err_sscanf;
+	len = strlen(mountpoint);
+	memmove(entry->path, entry->path + len, strlen(entry->path) - len + 1);
+
+	while (line[offset] == ' ')
+		++offset;
+
+	block_range = strtok_r(line + offset, ",\n", &saveptr1);
+	while (block_range) {
+		block = strtok_r(block_range, "-", &saveptr2);
+		if (!block)
+			break;
+		range_start = atoll(block);
+		block = strtok_r(NULL, "-", &saveptr2);
+		range_end = block ? atoll(block) : range_start;
+		add_blocks_to_range(&entry->head, &entry->tail, range_start,
+				    range_end);
+		block_range = strtok_r(NULL, ",\n", &saveptr1);
+	}
+end:
+	*err = 0;
+	free(line);
+	return entry;
+
+err_sscanf:
+	free(entry);
+err_alloc:
+	free(line);
+err_getline:
+	*err = 1;
+	return NULL;
+}
+
+static void free_base_fs_entry(void *e)
+{
+	struct basefs_entry *entry = e;
+	if (entry) {
+		free(entry->path);
+		free(entry);
+	}
+}
+
+struct hashmap *basefs_parse(const char *file, const char *mountpoint)
+{
+	int err;
+	struct hashmap *entries = NULL;
+	struct basefs_entry *entry;
+	FILE *f = basefs_open(file);
+	if (!f)
+		return NULL;
+	entries = hashmap_create(djb2_hash, free_base_fs_entry, 1024);
+	if (!entries)
+		goto end;
+
+	while ((entry = basefs_readline(f, mountpoint, &err)))
+		hashmap_add(entries, entry, entry->path);
+
+	if (err) {
+		fclose(f);
+		hashmap_free(entries);
+		return NULL;
+	}
+end:
+	fclose(f);
+	return entries;
+}
+
+static void *init(const char *file, const char *mountpoint)
+{
+	struct base_fs *params = malloc(sizeof(*params));
+
+	if (!params)
+		return NULL;
+	params->mountpoint = mountpoint;
+	params->file = fopen(file, "w+");
+	if (!params->file) {
+		free(params);
+		return NULL;
+	}
+	if (fwrite(BASE_FS_VERSION"\n", 1, strlen(BASE_FS_VERSION"\n"),
+		   params->file) != strlen(BASE_FS_VERSION"\n")) {
+		fclose(params->file);
+		free(params);
+		return NULL;
+	}
+	return params;
+}
+
+static int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
+			  struct ext2_inode *inode, void *data)
+{
+	struct base_fs *params = data;
+
+	params->entry.head = params->entry.tail = NULL;
+	params->entry.path = 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 base_fs *params = data;
+
+	if (params->entry.path && !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 base_fs *params = data;
+
+	if (!params->entry.path)
+		return 0;
+	if (fprintf(params->file, "%s%s ", params->mountpoint,
+		    params->entry.path) < 0
+	    || write_block_ranges(params->file, params->entry.head, ",")
+	    || fwrite("\n", 1, 1, params->file) != 1)
+		return -1;
+
+	delete_block_ranges(params->entry.head);
+	return 0;
+}
+
+static int cleanup(void *data)
+{
+	struct base_fs *params = data;
+
+	fclose(params->file);
+	free(params);
+	return 0;
+}
+
+struct fsmap_format base_fs_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/base_fs.h b/contrib/android/base_fs.h
new file mode 100644
index 0000000..94bae29
--- /dev/null
+++ b/contrib/android/base_fs.h
@@ -0,0 +1,18 @@
+#ifndef BASE_FS_H
+# define BASE_FS_H
+
+# include "fsmap.h"
+# include "hashmap.h"
+# include "block_range.h"
+
+struct basefs_entry {
+	char *path;
+	struct block_range *head;
+	struct block_range *tail;
+};
+
+extern struct fsmap_format base_fs_format;
+
+struct hashmap *basefs_parse(const char *file, const char *mountpoint);
+
+#endif /* !BASE_FS_H */
diff --git a/contrib/android/basefs_allocator.c b/contrib/android/basefs_allocator.c
new file mode 100644
index 0000000..3d014a2
--- /dev/null
+++ b/contrib/android/basefs_allocator.c
@@ -0,0 +1,147 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "basefs_allocator.h"
+#include "block_range.h"
+#include "hashmap.h"
+#include "base_fs.h"
+
+struct base_fs_allocator {
+	struct hashmap *entries;
+	struct basefs_entry *cur_entry;
+};
+
+static errcode_t basefs_block_allocator(ext2_filsys, blk64_t, blk64_t *,
+					struct blk_alloc_ctx *ctx);
+
+static void fs_free_blocks_range(ext2_filsys fs, struct block_range *blocks)
+{
+	while (blocks) {
+		ext2fs_unmark_block_bitmap_range2(fs->block_map, blocks->start,
+			blocks->end - blocks->start + 1);
+		blocks = blocks->next;
+	}
+}
+
+static void fs_reserve_blocks_range(ext2_filsys fs, struct block_range *blocks)
+{
+	while (blocks) {
+		ext2fs_mark_block_bitmap_range2(fs->block_map,
+			blocks->start, blocks->end - blocks->start + 1);
+		blocks = blocks->next;
+	}
+}
+
+errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
+			     const char *mountpoint)
+{
+	errcode_t retval;
+	struct basefs_entry *e;
+	struct hashmap_entry *it = NULL;
+	struct base_fs_allocator *allocator;
+	struct hashmap *entries = basefs_parse(file, mountpoint);
+	if (!entries)
+		return -1;
+
+	allocator = malloc(sizeof(*allocator));
+	if (!allocator)
+		goto err_alloc;
+
+	retval = ext2fs_read_bitmaps(fs);
+	if (retval)
+		goto err_bitmap;
+	while ((e = hashmap_iter_in_order(entries, &it)))
+		fs_reserve_blocks_range(fs, e->head);
+
+	allocator->cur_entry = NULL;
+	allocator->entries = entries;
+
+	/* Overhide the default allocator */
+	fs->get_alloc_block2 = basefs_block_allocator;
+	fs->priv_data = allocator;
+
+	return 0;
+
+err_bitmap:
+	free(allocator);
+err_alloc:
+	hashmap_free(entries);
+	return EXIT_FAILURE;
+}
+
+static errcode_t basefs_block_allocator(ext2_filsys fs, blk64_t goal,
+					blk64_t *ret, struct blk_alloc_ctx *ctx)
+{
+	errcode_t retval;
+	struct block_range *next_range;
+	struct base_fs_allocator *allocator = fs->priv_data;
+	struct basefs_entry *e = allocator->cur_entry;
+
+	/* Try to get a block from the base_fs */
+	if (e && e->head && ctx && (ctx->flags & BLOCK_ALLOC_DATA)) {
+		*ret = e->head->start;
+		e->head->start += 1;
+		if (e->head->start > e->head->end) {
+			next_range = e->head->next;
+			free(e->head);
+			e->head = next_range;
+		}
+	} else { /* Allocate a new block */
+		retval = ext2fs_new_block2(fs, goal, fs->block_map, ret);
+		if (retval)
+			return retval;
+		ext2fs_mark_block_bitmap2(fs->block_map, *ret);
+	}
+	return 0;
+}
+
+void base_fs_alloc_cleanup(ext2_filsys fs)
+{
+	struct basefs_entry *e;
+	struct hashmap_entry *it = NULL;
+	struct base_fs_allocator *allocator = fs->priv_data;
+
+	while ((e = hashmap_iter_in_order(allocator->entries, &it))) {
+		fs_free_blocks_range(fs, e->head);
+		delete_block_ranges(e->head);
+		e->head = e->tail = NULL;
+	}
+
+	fs->priv_data = NULL;
+	fs->get_alloc_block2 = NULL;
+	hashmap_free(allocator->entries);
+	free(allocator);
+}
+
+errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
+	const char *name EXT2FS_ATTR((unused)),
+	ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
+	ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
+{
+	struct base_fs_allocator *allocator = fs->priv_data;
+
+	if (mode != S_IFREG)
+		return 0;
+
+	if (allocator)
+		allocator->cur_entry = hashmap_lookup(allocator->entries,
+						      target_path);
+	return 0;
+}
+
+errcode_t base_fs_alloc_unset_target(ext2_filsys fs,
+        const char *target_path EXT2FS_ATTR((unused)),
+	const char *name EXT2FS_ATTR((unused)),
+	ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
+	ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
+{
+	struct base_fs_allocator *allocator = fs->priv_data;
+
+	if (!allocator || !allocator->cur_entry || mode != S_IFREG)
+		return 0;
+
+	fs_free_blocks_range(fs, allocator->cur_entry->head);
+	delete_block_ranges(allocator->cur_entry->head);
+	allocator->cur_entry->head = allocator->cur_entry->tail = NULL;
+	allocator->cur_entry = NULL;
+	return 0;
+}
diff --git a/contrib/android/basefs_allocator.h b/contrib/android/basefs_allocator.h
new file mode 100644
index 0000000..f1109cd
--- /dev/null
+++ b/contrib/android/basefs_allocator.h
@@ -0,0 +1,16 @@
+#ifndef BASE_FS_ALLOCATOR_H
+# define BASE_FS_ALLOCATOR_H
+
+# include <time.h>
+# include <ext2fs/ext2fs.h>
+
+errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
+			     const char *mountpoint);
+void base_fs_alloc_cleanup(ext2_filsys fs);
+
+errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
+	const char *name, ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
+errcode_t base_fs_alloc_unset_target(ext2_filsys fs, const char *target_path,
+	const char *name, ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
+
+#endif /* !BASE_FS_ALLOCATOR_H */
diff --git a/contrib/android/block_list.c b/contrib/android/block_list.c
new file mode 100644
index 0000000..25dcc51
--- /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 || !params->entry.head)
+		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 0000000..47041e4
--- /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 0000000..2f951c7
--- /dev/null
+++ b/contrib/android/block_range.c
@@ -0,0 +1,64 @@
+#define _GNU_SOURCE
+
+#include "block_range.h"
+#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 0000000..31e3c23
--- /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 0000000..1ae133d
--- /dev/null
+++ b/contrib/android/e2fsdroid.c
@@ -0,0 +1,194 @@
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <ext2fs/ext2fs.h>
+
+#include "perms.h"
+#include "base_fs.h"
+#include "block_list.h"
+#include "basefs_allocator.h"
+#include "create_inode.h"
+
+static char *prog_name = "e2fsdroid";
+static char *in_file;
+static char *block_list;
+static char *basefs_out;
+static char *basefs_in;
+static char *mountpoint = "";
+static time_t fixed_time = -1;
+static char *fs_config_file;
+static struct selinux_opt seopt_file[8];
+static int max_nr_opt = (int)sizeof(seopt_file) / sizeof(seopt_file[0]);
+static char *product_out;
+static char *src_dir;
+static int android_configure;
+static int android_sparse_file = 1;
+
+static void usage(int ret)
+{
+	fprintf(stderr, "%s [-B block_list] [-D basefs_out] [-T timestamp]\n"
+			"\t[-C fs_config] [-S file_contexts] [-p product_out]\n"
+			"\t[-a mountpoint] [-d basefs_in] [-f src_dir] [-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;
+	char *p;
+	int flags = EXT2_FLAG_RW;
+	errcode_t retval;
+	io_manager io_mgr;
+	ext2_filsys fs = NULL;
+	struct fs_ops_callbacks fs_callbacks = { NULL, NULL };
+	char *token;
+	int nr_opt = 0;
+
+	add_error_table(&et_ext2_error_table);
+
+	while ((c = getopt (argc, argv, "T:C:S:p:a:D:d:B:f:e")) != EOF) {
+		switch (c) {
+		case 'T':
+			fixed_time = strtoul(optarg, &p, 0);
+			android_configure = 1;
+			break;
+		case 'C':
+			fs_config_file = absolute_path(optarg);
+			android_configure = 1;
+			break;
+		case 'S':
+			token = strtok(optarg, ",");
+			while (token) {
+				if (nr_opt == max_nr_opt) {
+					fprintf(stderr, "Expected at most %d selinux opts\n",
+						max_nr_opt);
+					exit(EXIT_FAILURE);
+				}
+				seopt_file[nr_opt].type = SELABEL_OPT_PATH;
+				seopt_file[nr_opt].value = absolute_path(token);
+				nr_opt++;
+				token = strtok(NULL, ",");
+			}
+			android_configure = 1;
+			break;
+		case 'p':
+			product_out = absolute_path(optarg);
+			break;
+		case 'a':
+			mountpoint = strdup(optarg);
+			break;
+		case 'D':
+			basefs_out = absolute_path(optarg);
+			break;
+		case 'd':
+			basefs_in = absolute_path(optarg);
+			break;
+		case 'B':
+			block_list = absolute_path(optarg);
+			break;
+		case 'f':
+			src_dir = 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 (src_dir) {
+		ext2fs_read_bitmaps(fs);
+		if (basefs_in) {
+			retval = base_fs_alloc_load(fs, basefs_in, mountpoint);
+			if (retval) {
+				com_err(prog_name, retval, "%s",
+				"while reading base_fs file");
+			    exit(1);
+			}
+			fs_callbacks.create_new_inode =
+				base_fs_alloc_set_target;
+			fs_callbacks.end_create_new_inode =
+				base_fs_alloc_unset_target;
+		}
+		retval = populate_fs2(fs, EXT2_ROOT_INO, src_dir,
+				      EXT2_ROOT_INO, &fs_callbacks);
+		if (retval) {
+			com_err(prog_name, retval, "%s",
+			"while populating file system");
+		    exit(1);
+		}
+		if (basefs_in)
+			base_fs_alloc_cleanup(fs);
+	}
+
+	if (android_configure) {
+		retval = android_configure_fs(fs, src_dir, product_out, mountpoint,
+			seopt_file, nr_opt, fs_config_file, fixed_time);
+		if (retval) {
+			com_err(prog_name, retval, "%s",
+				"while configuring the file system");
+			exit(1);
+		}
+	}
+
+	if (block_list) {
+		retval = fsmap_iter_filsys(fs, &block_list_format, block_list,
+					   mountpoint);
+		if (retval) {
+			com_err(prog_name, retval, "%s",
+				"while creating the block_list");
+			exit(1);
+		}
+	}
+
+	if (basefs_out) {
+		retval = fsmap_iter_filsys(fs, &base_fs_format,
+					   basefs_out, mountpoint);
+		if (retval) {
+			com_err(prog_name, retval, "%s",
+				"while creating the basefs file");
+			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/ext2simg.c b/contrib/android/ext2simg.c
new file mode 100644
index 0000000..fcefe1d
--- /dev/null
+++ b/contrib/android/ext2simg.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ext2fs/ext2fs.h>
+#include <et/com_err.h>
+#include <sparse/sparse.h>
+
+struct {
+	int	crc;
+	int	sparse;
+	int	gzip;
+	char	*in_file;
+	char	*out_file;
+	bool	overwrite_input;
+} params = {
+	.crc	    = 0,
+	.sparse	    = 1,
+	.gzip	    = 0,
+};
+
+#define ext2fs_fatal(Retval, Format, ...) \
+	do { \
+		com_err("error", Retval, Format, __VA_ARGS__); \
+		exit(EXIT_FAILURE); \
+	} while(0)
+
+#define sparse_fatal(Format) \
+	do { \
+		fprintf(stderr, "sparse: "Format); \
+		exit(EXIT_FAILURE); \
+	} while(0)
+
+static void usage(char *path)
+{
+	char *progname = basename(path);
+
+	fprintf(stderr, "%s [ options ] <image or block device> <output image>\n"
+			"  -c include CRC block\n"
+			"  -z gzip output\n"
+			"  -S don't use sparse output format\n", progname);
+}
+
+static struct buf_item {
+	struct buf_item	    *next;
+	void		    *buf[0];
+} *buf_list;
+
+static void add_chunk(ext2_filsys fs, struct sparse_file *s, blk_t chunk_start, blk_t chunk_end)
+{
+	int retval;
+	unsigned int nb_blk = chunk_end - chunk_start;
+	size_t len = nb_blk * fs->blocksize;
+	int64_t offset = (int64_t)chunk_start * (int64_t)fs->blocksize;
+
+	if (params.overwrite_input == false) {
+		if (sparse_file_add_file(s, params.in_file, offset, len, chunk_start) < 0)
+			sparse_fatal("adding data to the sparse file");
+	} else {
+		/*
+		 * The input file will be overwritten, make a copy of
+		 * the blocks
+		 */
+		struct buf_item *bi = calloc(1, sizeof(struct buf_item) + len);
+		if (buf_list == NULL)
+			buf_list = bi;
+		else {
+			bi->next = buf_list;
+			buf_list = bi;
+		}
+
+		retval = io_channel_read_blk64(fs->io, chunk_start, nb_blk, bi->buf);
+		if (retval < 0)
+			ext2fs_fatal(retval, "reading block %u - %u", chunk_start, chunk_end);
+
+		if (sparse_file_add_data(s, bi->buf, len, chunk_start) < 0)
+			sparse_fatal("adding data to the sparse file");
+	}
+}
+
+static void free_chunks(void)
+{
+	struct buf_item *bi;
+
+	while (buf_list) {
+		bi = buf_list->next;
+		free(buf_list);
+		buf_list = bi;
+	}
+}
+
+static struct sparse_file *ext_to_sparse(const char *in_file)
+{
+	errcode_t retval;
+	ext2_filsys fs;
+	struct sparse_file *s;
+	int64_t chunk_start = -1;
+	blk_t first_blk, last_blk, nb_blk, cur_blk;
+
+	retval = ext2fs_open(in_file, 0, 0, 0, unix_io_manager, &fs);
+	if (retval)
+		ext2fs_fatal(retval, "while reading %s", in_file);
+
+	retval = ext2fs_read_block_bitmap(fs);
+	if (retval)
+		ext2fs_fatal(retval, "while reading block bitmap of %s", in_file);
+
+	first_blk = ext2fs_get_block_bitmap_start2(fs->block_map);
+	last_blk = ext2fs_get_block_bitmap_end2(fs->block_map);
+	nb_blk = last_blk - first_blk + 1;
+
+	s = sparse_file_new(fs->blocksize, (uint64_t)fs->blocksize * (uint64_t)nb_blk);
+	if (!s)
+		sparse_fatal("creating sparse file");
+
+	/*
+	 * The sparse format encodes the size of a chunk (and its header) in a
+	 * 32-bit unsigned integer (UINT32_MAX)
+	 * When writing the chunk, the library uses a single call to write().
+	 * Linux's implementation of the 'write' syscall does not allow transfers
+	 * larger than INT32_MAX (32-bit _and_ 64-bit systems).
+	 * Make sure we do not create chunks larger than this limit.
+	 */
+	int64_t max_blk_per_chunk = (INT32_MAX - 12) / fs->blocksize;
+
+	/* Iter on the blocks to merge contiguous chunk */
+	for (cur_blk = first_blk; cur_blk <= last_blk; ++cur_blk) {
+		if (ext2fs_test_block_bitmap2(fs->block_map, cur_blk)) {
+			if (chunk_start == -1) {
+				chunk_start = cur_blk;
+			} else if (cur_blk - chunk_start + 1 == max_blk_per_chunk) {
+				add_chunk(fs, s, chunk_start, cur_blk);
+				chunk_start = -1;
+			}
+		} else if (chunk_start != -1) {
+			add_chunk(fs, s, chunk_start, cur_blk);
+			chunk_start = -1;
+		}
+	}
+	if (chunk_start != -1)
+		add_chunk(fs, s, chunk_start, cur_blk - 1);
+
+	ext2fs_free(fs);
+	return s;
+}
+
+static bool same_file(const char *in, const char *out)
+{
+	struct stat st1, st2;
+
+	if (access(out, F_OK) == -1)
+		return false;
+
+	if (lstat(in, &st1) == -1)
+		ext2fs_fatal(errno, "stat %s\n", in);
+	if (lstat(out, &st2) == -1)
+		ext2fs_fatal(errno, "stat %s\n", out);
+	return st1.st_ino == st2.st_ino;
+}
+
+int main(int argc, char *argv[])
+{
+	int opt;
+	int out_fd;
+	errcode_t retval;
+	struct sparse_file *s;
+
+	while ((opt = getopt(argc, argv, "czS")) != -1) {
+		switch(opt) {
+		case 'c':
+			params.crc = 1;
+			break;
+		case 'z':
+			params.gzip = 1;
+			break;
+		case 'S':
+			params.sparse = 0;
+			break;
+		default:
+			usage(argv[0]);
+			exit(EXIT_FAILURE);
+		}
+	}
+	if (optind + 1 >= argc) {
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+	params.in_file = strdup(argv[optind++]);
+	params.out_file = strdup(argv[optind]);
+	params.overwrite_input = same_file(params.in_file, params.out_file);
+
+	s = ext_to_sparse(params.in_file);
+
+	out_fd = open(params.out_file, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+	if (out_fd == -1)
+		ext2fs_fatal(errno, "opening %s\n", params.out_file);
+	if (sparse_file_write(s, out_fd, params.gzip, params.sparse, params.crc) < 0)
+		sparse_fatal("writing sparse file");
+
+	sparse_file_destroy(s);
+
+	free(params.in_file);
+	free(params.out_file);
+	free_chunks();
+	close(out_fd);
+
+	return 0;
+}
diff --git a/contrib/android/fsmap.c b/contrib/android/fsmap.c
new file mode 100644
index 0000000..36adb7f
--- /dev/null
+++ b/contrib/android/fsmap.c
@@ -0,0 +1,119 @@
+#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;
+}
diff --git a/contrib/android/fsmap.h b/contrib/android/fsmap.h
new file mode 100644
index 0000000..9f84a71
--- /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 */
diff --git a/contrib/android/hashmap.c b/contrib/android/hashmap.c
new file mode 100644
index 0000000..eee0071
--- /dev/null
+++ b/contrib/android/hashmap.c
@@ -0,0 +1,76 @@
+#include "hashmap.h"
+#include <string.h>
+
+uint32_t djb2_hash(const void *str)
+{
+	int c;
+	const char *s = str;
+	uint32_t hash = 5381;
+
+	while ((c = *s++))
+		hash = ((hash << 5) + hash) + c;
+	return hash;
+}
+
+struct hashmap *hashmap_create(uint32_t(*hash_fct)(const void*),
+			       void(*free_fct)(void*), size_t size)
+{
+	struct hashmap *h = calloc(sizeof(struct hashmap) +
+				      sizeof(struct hashmap_entry) * size, 1);
+	h->size = size;
+	h->free = free_fct;
+	h->hash = hash_fct;
+	h->first = h->last = NULL;
+	return h;
+}
+
+void hashmap_add(struct hashmap *h, void *data, const void *key)
+{
+	uint32_t hash = h->hash(key) % h->size;
+	struct hashmap_entry *e = malloc(sizeof(*e));
+
+	e->data = data;
+	e->key = key;
+	e->next = h->entries[hash];
+	h->entries[hash] = e;
+
+	e->list_prev = NULL;
+	e->list_next = h->first;
+	if (h->first)
+		h->first->list_prev = e;
+	h->first = e;
+	if (!h->last)
+		h->last = e;
+}
+
+void *hashmap_lookup(struct hashmap *h, const void *key)
+{
+	struct hashmap_entry *iter;
+	uint32_t hash = h->hash(key) % h->size;
+
+	for (iter = h->entries[hash]; iter; iter = iter->next)
+		if (!strcmp(iter->key, key))
+			return iter->data;
+	return NULL;
+}
+
+void *hashmap_iter_in_order(struct hashmap *h, struct hashmap_entry **it)
+{
+	*it = *it ? (*it)->list_next : h->first;
+	return *it ? (*it)->data : NULL;
+}
+
+void hashmap_free(struct hashmap *h)
+{
+	for (size_t i = 0; i < h->size; ++i) {
+		struct hashmap_entry *it = h->entries[i];
+		while (it) {
+			struct hashmap_entry *tmp = it->next;
+			if (h->free)
+				h->free(it->data);
+			free(it);
+			it = tmp;
+		}
+	}
+	free(h);
+}
diff --git a/contrib/android/hashmap.h b/contrib/android/hashmap.h
new file mode 100644
index 0000000..70d0ed1
--- /dev/null
+++ b/contrib/android/hashmap.h
@@ -0,0 +1,32 @@
+#ifndef HASHMAP_H
+# define HASHMAP_H
+
+# include <stdlib.h>
+# include <stdint.h>
+
+struct hashmap {
+	uint32_t size;
+	uint32_t(*hash)(const void *key);
+	void(*free)(void*);
+	struct hashmap_entry *first;
+	struct hashmap_entry *last;
+	struct hashmap_entry {
+		void *data;
+		const void *key;
+		struct hashmap_entry *next;
+		struct hashmap_entry *list_next;
+		struct hashmap_entry *list_prev;
+	} *entries[0];
+};
+
+struct hashmap *hashmap_create(uint32_t(*hash_fct)(const void*),
+			       void(*free_fct)(void*), size_t size);
+void hashmap_add(struct hashmap *h, void *data, const void *key);
+void *hashmap_lookup(struct hashmap *h, const void *key);
+void *hashmap_iter_in_order(struct hashmap *h, struct hashmap_entry **it);
+void hashmap_del(struct hashmap *h, struct hashmap_entry *e);
+void hashmap_free(struct hashmap *h);
+
+uint32_t djb2_hash(const void *str);
+
+#endif /* !HASHMAP_H */
diff --git a/contrib/android/perms.c b/contrib/android/perms.c
new file mode 100644
index 0000000..9a7a93f
--- /dev/null
+++ b/contrib/android/perms.c
@@ -0,0 +1,325 @@
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE //asprintf
+#endif
+#include "perms.h"
+#include "support/nls-enable.h"
+#include <time.h>
+#include <sys/stat.h>
+
+#ifndef XATTR_SELINUX_SUFFIX
+# define XATTR_SELINUX_SUFFIX  "selinux"
+#endif
+#ifndef XATTR_CAPS_SUFFIX
+# define XATTR_CAPS_SUFFIX     "capability"
+#endif
+
+struct inode_params {
+	ext2_filsys fs;
+	char *path;
+	char *filename;
+	char *src_dir;
+	char *target_out;
+	char *mountpoint;
+	fs_config_f fs_config_func;
+	struct selabel_handle *sehnd;
+	time_t fixed_time;
+};
+
+static errcode_t ino_add_xattr(ext2_filsys fs, ext2_ino_t ino, const char *name,
+			       const void *value, int value_len)
+{
+	errcode_t retval, close_retval;
+	struct ext2_xattr_handle *xhandle;
+
+	retval = ext2fs_xattrs_open(fs, ino, &xhandle);
+	if (retval) {
+		com_err(__func__, retval, _("while opening inode %u"), ino);
+		return retval;
+	}
+	retval = ext2fs_xattrs_read(xhandle);
+	if (retval) {
+		com_err(__func__, retval,
+			_("while reading xattrs of inode %u"), ino);
+		goto xattrs_close;
+	}
+	retval = ext2fs_xattr_set(xhandle, name, value, value_len);
+	if (retval) {
+		com_err(__func__, retval,
+			_("while setting xattrs of inode %u"), ino);
+		goto xattrs_close;
+	}
+	retval = ext2fs_xattrs_write(xhandle);
+	if (retval) {
+		com_err(__func__, retval,
+			_("while writting xattrs of inode %u"), ino);
+		goto xattrs_close;
+	}
+xattrs_close:
+	close_retval = ext2fs_xattrs_close(&xhandle);
+	if (close_retval) {
+		com_err(__func__, close_retval,
+			_("while closing xattrs of inode %u"), ino);
+		return retval ? retval : close_retval;
+	}
+	return retval;
+}
+
+static errcode_t set_selinux_xattr(ext2_filsys fs, ext2_ino_t ino,
+				   struct inode_params *params)
+{
+	errcode_t retval;
+	char *secontext = NULL;
+	struct ext2_inode inode;
+
+	if (params->sehnd == NULL)
+		return 0;
+
+	retval = ext2fs_read_inode(fs, ino, &inode);
+	if (retval) {
+		com_err(__func__, retval,
+			_("while reading inode %u"), ino);
+		return retval;
+	}
+
+	retval = selabel_lookup(params->sehnd, &secontext, params->filename,
+				inode.i_mode);
+	if (retval < 0) {
+		com_err(__func__, retval,
+			_("searching for label \"%s\""), params->filename);
+		exit(1);
+	}
+
+	retval = ino_add_xattr(fs, ino,  "security." XATTR_SELINUX_SUFFIX,
+			       secontext, strlen(secontext) + 1);
+
+	freecon(secontext);
+	return retval;
+}
+
+static errcode_t set_perms_and_caps(ext2_filsys fs, ext2_ino_t ino,
+				    struct inode_params *params)
+{
+	errcode_t retval;
+	uint64_t capabilities = 0;
+	struct ext2_inode inode;
+	struct vfs_cap_data cap_data;
+	unsigned int uid = 0, gid = 0, imode = 0;
+
+	retval = ext2fs_read_inode(fs, ino, &inode);
+	if (retval) {
+		com_err(__func__, retval, _("while reading inode %u"), ino);
+		return retval;
+	}
+
+	/* Permissions */
+	if (params->fs_config_func != NULL) {
+		params->fs_config_func(params->filename, S_ISDIR(inode.i_mode),
+				       params->target_out, &uid, &gid, &imode,
+				       &capabilities);
+		inode.i_uid = uid & 0xffff;
+		inode.i_gid = gid & 0xffff;
+		inode.i_mode = (inode.i_mode & S_IFMT) | (imode & 0xffff);
+		retval = ext2fs_write_inode(fs, ino, &inode);
+		if (retval) {
+			com_err(__func__, retval,
+				_("while writting inode %u"), ino);
+			return retval;
+		}
+	}
+
+	/* Capabilities */
+	if (!capabilities)
+		return 0;
+	memset(&cap_data, 0, sizeof(cap_data));
+	cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+	cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff);
+	cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
+	return ino_add_xattr(fs, ino,  "security." XATTR_CAPS_SUFFIX,
+			     &cap_data, sizeof(cap_data));
+}
+
+static errcode_t set_timestamp(ext2_filsys fs, ext2_ino_t ino,
+			       struct inode_params *params)
+{
+	errcode_t retval;
+	struct ext2_inode inode;
+	struct stat stat;
+	char *src_filename = NULL;
+
+	retval = ext2fs_read_inode(fs, ino, &inode);
+	if (retval) {
+		com_err(__func__, retval,
+			_("while reading inode %u"), ino);
+		return retval;
+	}
+
+	if (params->fixed_time == -1 && params->src_dir) {
+		/* replace mountpoint from filename with src_dir */
+		if (asprintf(&src_filename, "%s/%s", params->src_dir,
+			params->filename + strlen(params->mountpoint)) < 0) {
+			return -ENOMEM;
+		}
+		retval = lstat(src_filename, &stat);
+		if (retval < 0) {
+			com_err(__func__, retval,
+				_("while lstat file %s"), src_filename);
+			goto end;
+		}
+		inode.i_atime = inode.i_ctime = inode.i_mtime = stat.st_mtime;
+	} else {
+		inode.i_atime = inode.i_ctime = inode.i_mtime = params->fixed_time;
+	}
+
+	retval = ext2fs_write_inode(fs, ino, &inode);
+	if (retval) {
+		com_err(__func__, retval,
+			_("while writting inode %u"), ino);
+		goto end;
+	}
+
+end:
+	free(src_filename);
+	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 errcode_t androidify_inode(ext2_filsys fs, ext2_ino_t ino,
+				  struct inode_params *params)
+{
+	errcode_t retval;
+
+	retval = set_timestamp(fs, ino, params);
+	if (retval)
+		return retval;
+
+	retval = set_selinux_xattr(fs, ino, params);
+	if (retval)
+		return retval;
+
+	return set_perms_and_caps(fs, ino, params);
+}
+
+static int walk_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)
+{
+	__u16 name_len;
+	errcode_t retval;
+	struct inode_params *params = (struct inode_params *)priv_data;
+
+	name_len = de->name_len & 0xff;
+	if (!strncmp(de->name, ".", name_len)
+	    || (!strncmp(de->name, "..", name_len)))
+		return 0;
+
+	if (asprintf(&params->filename, "%s/%.*s", params->path, name_len,
+		     de->name) < 0)
+		return -ENOMEM;
+
+	if (!strncmp(de->name, "lost+found", 10)) {
+		retval = set_selinux_xattr(params->fs, de->inode, params);
+		if (retval)
+			goto end;
+	} else {
+		retval = androidify_inode(params->fs, de->inode, params);
+		if (retval)
+			goto end;
+		if (is_dir(params->fs, de->inode)) {
+			char *cur_path = params->path;
+			char *cur_filename = params->filename;
+			params->path = params->filename;
+			ext2fs_dir_iterate2(params->fs, de->inode, 0, NULL,
+					    walk_dir, params);
+			params->path = cur_path;
+			params->filename = cur_filename;
+		}
+	}
+
+end:
+	free(params->filename);
+	return retval;
+}
+
+errcode_t __android_configure_fs(ext2_filsys fs, char *src_dir,
+				 char *target_out,
+				 char *mountpoint,
+				 fs_config_f fs_config_func,
+				 struct selabel_handle *sehnd,
+				 time_t fixed_time)
+{
+	errcode_t retval;
+	struct inode_params params = {
+		.fs = fs,
+		.src_dir = src_dir,
+		.target_out = target_out,
+		.fs_config_func = fs_config_func,
+		.sehnd = sehnd,
+		.fixed_time = fixed_time,
+		.path = mountpoint,
+		.filename = mountpoint,
+		.mountpoint = mountpoint,
+	};
+
+	/* walk_dir will add the "/". Don't add it twice. */
+	if (strlen(mountpoint) == 1 && mountpoint[0] == '/')
+		params.path = "";
+
+	retval = set_selinux_xattr(fs, EXT2_ROOT_INO, &params);
+	if (retval)
+		return retval;
+	retval = set_timestamp(fs, EXT2_ROOT_INO, &params);
+	if (retval)
+		return retval;
+
+	return ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir,
+				   &params);
+}
+
+errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out,
+			       char *mountpoint,
+			       struct selinux_opt *seopts,
+			       unsigned int nopt,
+			       char *fs_config_file, time_t fixed_time)
+{
+	errcode_t retval;
+	fs_config_f fs_config_func = NULL;
+	struct selabel_handle *sehnd = NULL;
+
+	/* Retrieve file contexts */
+	if (nopt > 0) {
+		sehnd = selabel_open(SELABEL_CTX_FILE, seopts, nopt);
+		if (!sehnd) {
+			com_err(__func__, -EINVAL,
+				_("while opening file contexts \"%s\""),
+				seopts[0].value);
+			return -EINVAL;
+		}
+	}
+
+	/* Load the FS config */
+	if (fs_config_file) {
+		retval = load_canned_fs_config(fs_config_file);
+		if (retval < 0) {
+			com_err(__func__, retval,
+				_("while loading fs_config \"%s\""),
+				fs_config_file);
+			return retval;
+		}
+		fs_config_func = canned_fs_config;
+	} else if (mountpoint)
+		fs_config_func = fs_config;
+
+	return __android_configure_fs(fs, src_dir, target_out, mountpoint,
+				      fs_config_func, sehnd, fixed_time);
+}
diff --git a/contrib/android/perms.h b/contrib/android/perms.h
new file mode 100644
index 0000000..9955bb5
--- /dev/null
+++ b/contrib/android/perms.h
@@ -0,0 +1,42 @@
+#ifndef ANDROID_PERMS_H
+# define ANDROID_PERMS_H
+
+# include "config.h"
+# include <ext2fs/ext2fs.h>
+
+typedef void (*fs_config_f)(const char *path, int dir,
+			    const char *target_out_path,
+			    unsigned *uid, unsigned *gid,
+			    unsigned *mode, uint64_t *capabilities);
+
+# ifdef _WIN32
+struct selabel_handle;
+static inline errcode_t android_configure_fs(ext2_filsys fs,
+					     char *src_dir,
+					     char *target_out,
+					     char *mountpoint,
+					     void *seopts,
+					     unsigned int nopt,
+					     char *fs_config_file,
+					     time_t fixed_time)
+{
+	return 0;
+}
+# else
+#  include <selinux/selinux.h>
+#  include <selinux/label.h>
+#  if !defined(HOST)
+#   include <selinux/android.h>
+#  endif
+#  include <private/android_filesystem_config.h>
+#  include <private/canned_fs_config.h>
+
+errcode_t android_configure_fs(ext2_filsys fs, char *src_dir,
+			       char *target_out,
+			       char *mountpoint,
+			       struct selinux_opt *seopts,
+			       unsigned int nopt,
+			       char *fs_config_file, time_t fixed_time);
+
+# endif
+#endif /* !ANDROID_PERMS_H */
diff --git a/debugfs/Android.bp b/debugfs/Android.bp
new file mode 100644
index 0000000..7dfc7d3
--- /dev/null
+++ b/debugfs/Android.bp
@@ -0,0 +1,72 @@
+// Copyright 2017 The Android Open Source Project
+
+//########################
+// Build the debugfs binary
+
+cc_defaults {
+    name: "debugfs-defaults",
+    srcs: [
+        "debug_cmds.c",
+        "debugfs.c",
+        "util.c",
+        "ncheck.c",
+        "icheck.c",
+        "ls.c",
+        "lsdel.c",
+        "dump.c",
+        "set_fields.c",
+        "logdump.c",
+        "htree.c",
+        "unused.c",
+        "e2freefrag.c",
+        "filefrag.c",
+        "extent_cmds.c",
+        "extent_inode.c",
+        "zap.c",
+        "quota.c",
+        "xattrs.c",
+        "journal.c",
+        "revoke.c",
+        "recovery.c",
+        "do_journal.c",
+    ],
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-macro-redefined",
+        "-fno-strict-aliasing",
+        "-DDEBUGFS",
+    ],
+    include_dirs: [
+        "external/e2fsprogs/misc",
+        "external/e2fsprogs/e2fsck"
+    ],
+}
+
+debugfs_libs = [
+    "libext2_misc",
+    "libext2fs",
+    "libext2_blkid",
+    "libext2_uuid",
+    "libext2_ss",
+    "libext2_quota",
+    "libext2_com_err",
+    "libext2_e2p",
+]
+
+cc_binary {
+    name: "debugfs",
+    host_supported: true,
+    defaults: ["debugfs-defaults"],
+
+    shared_libs: debugfs_libs,
+    system_shared_libs: ["libc"],
+}
+
+cc_binary {
+    name: "debugfs_static",
+    static_executable: true,
+    defaults: ["debugfs-defaults"],
+
+    static_libs: debugfs_libs + ["libc"],
+}
diff --git a/debugfs/Android.mk b/debugfs/Android.mk
deleted file mode 100644
index 91dc8c3..0000000
--- a/debugfs/Android.mk
+++ /dev/null
@@ -1,93 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-#########################
-# Build the debugfs binary
-
-debugfs_src_files :=  \
-	debug_cmds.c \
-	debugfs.c \
-	util.c \
-	ncheck.c\
-	icheck.c \
-	ls.c \
-	lsdel.c \
-	dump.c \
-	set_fields.c \
-	logdump.c \
-	htree.c \
-	unused.c \
-	e2freefrag.c \
-	filefrag.c \
-	extent_cmds.c \
-	extent_inode.c \
-	zap.c \
-	create_inode.c \
-	quota.c \
-	xattrs.c \
-	journal.c \
-	revoke.c \
-	recovery.c \
-	do_journal.c
-
-debugfs_shared_libraries := \
-	libext2fs \
-	libext2_blkid \
-	libext2_uuid \
-	libext2_ss \
-	libext2_quota \
-	libext2_com_err \
-	libext2_e2p
-
-debugfs_system_shared_libraries := libc
-
-debugfs_static_libraries := \
-	libext2fs \
-	libext2_blkid \
-	libext2_uuid_static \
-	libext2_ss \
-	libext2_quota \
-	libext2_com_err \
-	libext2_e2p
-
-debugfs_system_static_libraries := libc
-
-debugfs_c_includes := \
-	external/e2fsprogs/e2fsck \
-	external/e2fsprogs/misc \
-	external/e2fsprogs/lib
-
-debugfs_cflags := -O2 -g -W -Wall -fno-strict-aliasing -DDEBUGFS
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(debugfs_src_files)
-LOCAL_C_INCLUDES := $(debugfs_c_includes)
-LOCAL_CFLAGS := $(debugfs_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(debugfs_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(debugfs_shared_libraries)
-LOCAL_MODULE := debugfs
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(debugfs_src_files)
-LOCAL_C_INCLUDES := $(debugfs_c_includes)
-LOCAL_CFLAGS := $(debugfs_cflags)
-LOCAL_STATIC_LIBRARIES := $(debugfs_static_libraries) $(debugfs_system_static_libraries)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE := debugfs_static
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(debugfs_src_files)
-LOCAL_C_INCLUDES := $(debugfs_c_includes)
-LOCAL_CFLAGS := $(debugfs_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(debugfs_shared_libraries))
-LOCAL_MODULE := debugfs_host
-LOCAL_MODULE_STEM := debugfs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/debugfs/Makefile.in b/debugfs/Makefile.in
index 3ac80d9..408a323 100644
--- a/debugfs/Makefile.in
+++ b/debugfs/Makefile.in
@@ -164,7 +164,7 @@
 	$(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(SYSLIBS) -DUNITTEST \
 		-o tst_set_fields $(srcdir)/set_fields.c $(srcdir)/util.c $(LIBS)
 
-check:: tst_set_fields
+fullcheck check:: tst_set_fields
 	$(TESTENV) ./tst_set_fields
 
 # +++ Dependency line eater +++
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 453f5b5..cef4ec2 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -861,16 +861,15 @@
 		fprintf(out, "%d\n", inode->i_size);
 	if (os == EXT2_OS_HURD)
 		fprintf(out,
-			"%sFile ACL: %d    Directory ACL: %d Translator: %d\n",
+			"%sFile ACL: %d Translator: %d\n",
 			prefix,
-			inode->i_file_acl, LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0,
+			inode->i_file_acl,
 			inode->osd1.hurd1.h_i_translator);
 	else
-		fprintf(out, "%sFile ACL: %llu    Directory ACL: %d\n",
+		fprintf(out, "%sFile ACL: %llu\n",
 			prefix,
 			inode->i_file_acl | ((long long)
-				(inode->osd2.linux2.l_i_file_acl_high) << 32),
-			LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0);
+				(inode->osd2.linux2.l_i_file_acl_high) << 32));
 	if (os != EXT2_OS_HURD)
 		fprintf(out, "%sLinks: %d   Blockcount: %llu\n",
 			prefix, inode->i_links_count,
@@ -1367,10 +1366,9 @@
 	modify_u32(argv[0], "Reserved1", decimal_format, &inode.i_reserved1);
 #endif
 	modify_u32(argv[0], "File acl", decimal_format, &inode.i_file_acl);
-	if (LINUX_S_ISDIR(inode.i_mode))
-		modify_u32(argv[0], "Directory acl", decimal_format, &inode.i_dir_acl);
-	else
-		modify_u32(argv[0], "High 32bits of size", decimal_format, &inode.i_size_high);
+
+	modify_u32(argv[0], "High 32bits of size", decimal_format,
+		   &inode.i_size_high);
 
 	if (os == EXT2_OS_HURD)
 		modify_u32(argv[0], "Translator Block",
diff --git a/debugfs/htree.c b/debugfs/htree.c
index 54e55e2..8c18666 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -287,7 +287,8 @@
 	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);
+	ent = (struct ext2_dx_entry *)
+		((char *)rootnode + rootnode->info_length);
 
 	htree_dump_int_node(current_fs, ino, &inode, rootnode, ent,
 			    buf + current_fs->blocksize,
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index ff9b7b6..ca68862 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -212,7 +212,6 @@
 	/* Special case: i_file_acl_high is 2 bytes */
 	{ "file_acl", &set_inode.i_file_acl, 
 		&set_inode.osd2.linux2.l_i_file_acl_high, 6, parse_uint },
-	{ "dir_acl", &set_inode.i_dir_acl, NULL, 4, parse_uint, FLAG_ALIAS },
 	{ "faddr", &set_inode.i_faddr, NULL, 4, parse_uint },
 	{ "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint, FLAG_ALIAS },
 	{ "fsize", &set_inode.osd2.hurd2.h_i_fsize, NULL, 1, parse_uint },
diff --git a/e2fsck/Android.bp b/e2fsck/Android.bp
new file mode 100644
index 0000000..1cabe86
--- /dev/null
+++ b/e2fsck/Android.bp
@@ -0,0 +1,64 @@
+// Copyright 2017 The Android Open Source Project
+
+//########################
+// Build the e2fsck binary
+
+cc_defaults {
+    name: "e2fsck-defaults",
+    srcs: [
+        "e2fsck.c",
+        "super.c",
+        "pass1.c",
+        "pass1b.c",
+        "pass2.c",
+        "pass3.c",
+        "pass4.c",
+        "pass5.c",
+        "logfile.c",
+        "journal.c",
+        "recovery.c",
+        "revoke.c",
+        "badblocks.c",
+        "util.c",
+        "unix.c",
+        "dirinfo.c",
+        "dx_dirinfo.c",
+        "ehandler.c",
+        "problem.c",
+        "message.c",
+        "ea_refcount.c",
+        "quota.c",
+        "rehash.c",
+        "region.c",
+        "sigcatcher.c",
+        "readahead.c",
+        "extents.c",
+    ],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined", "-fno-strict-aliasing"],
+}
+
+e2fsck_libs = [
+    "libext2fs",
+    "libext2_blkid",
+    "libext2_uuid",
+    "libext2_quota",
+    "libext2_com_err",
+    "libext2_e2p",
+]
+
+cc_binary {
+    name: "e2fsck",
+    host_supported: true,
+    defaults: ["e2fsck-defaults"],
+
+    shared_libs: e2fsck_libs,
+    system_shared_libs: ["libc"],
+}
+
+cc_binary {
+    name: "e2fsck_static",
+    static_executable: true,
+    defaults: ["e2fsck-defaults"],
+
+    static_libs: e2fsck_libs + ["libc"],
+}
diff --git a/e2fsck/Android.mk b/e2fsck/Android.mk
deleted file mode 100644
index 604eaa1..0000000
--- a/e2fsck/Android.mk
+++ /dev/null
@@ -1,92 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-#########################
-# Build the e2fsck binary
-
-e2fsck_src_files :=  \
-	e2fsck.c \
-	super.c \
-	pass1.c \
-	pass1b.c \
-	pass2.c \
-	pass3.c \
-	pass4.c \
-	pass5.c \
-	logfile.c \
-	journal.c \
-	recovery.c \
-	revoke.c \
-	badblocks.c \
-	util.c \
-	unix.c \
-	dirinfo.c \
-	dx_dirinfo.c \
-	ehandler.c \
-	problem.c \
-	message.c \
-	ea_refcount.c \
-	quota.c \
-	rehash.c \
-	region.c \
-	sigcatcher.c \
-	readahead.c \
-	extents.c
-
-e2fsck_shared_libraries := \
-	libext2fs \
-	libext2_blkid \
-	libext2_uuid \
-	libext2_quota \
-	libext2_com_err \
-	libext2_e2p
-
-e2fsck_system_shared_libraries := libc
-
-e2fsck_static_libraries := \
-	libext2fs \
-	libext2_blkid \
-	libext2_uuid_static \
-	libext2_quota \
-	libext2_com_err \
-	libext2_e2p
-
-e2fsck_system_static_libraries := libc
-
-e2fsck_c_includes :=
-
-e2fsck_cflags := -O2 -g -W -Wall -fno-strict-aliasing
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2fsck_src_files)
-LOCAL_C_INCLUDES := $(e2fsck_c_includes)
-LOCAL_CFLAGS := $(e2fsck_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(e2fsck_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(e2fsck_shared_libraries)
-LOCAL_MODULE := e2fsck
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2fsck_src_files)
-LOCAL_C_INCLUDES := $(e2fsck_c_includes)
-LOCAL_CFLAGS := $(e2fsck_cflags)
-LOCAL_STATIC_LIBRARIES := $(e2fsck_static_libraries) $(e2fsck_system_static_libraries)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE := e2fsck_static
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2fsck_src_files)
-LOCAL_C_INCLUDES := $(e2fsck_c_includes)
-LOCAL_CFLAGS := $(e2fsck_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(e2fsck_shared_libraries))
-LOCAL_MODULE := e2fsck_host
-LOCAL_MODULE_STEM := e2fsck
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in
index cee6a42..e43d340 100644
--- a/e2fsck/Makefile.in
+++ b/e2fsck/Makefile.in
@@ -150,7 +150,7 @@
 		$(ALL_CFLAGS) $(ALL_LDFLAGS) -DTEST_PROGRAM \
 		$(LIBCOM_ERR) $(SYSLIBS)
 
-check:: tst_refcount tst_region tst_problem
+fullcheck check:: tst_refcount tst_region tst_problem
 	$(TESTENV) ./tst_refcount
 	$(TESTENV) ./tst_region
 	$(TESTENV) ./tst_problem
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 6ab4f9c..fd12024 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -122,6 +122,7 @@
 	blk64_t		phys;
 	int		flags;
 	blk64_t		parent;
+	blk64_t		previous;
 	ext2_dirhash_t	min_hash;
 	ext2_dirhash_t	max_hash;
 	ext2_dirhash_t	node_min_hash;
@@ -647,4 +648,7 @@
 extern void e2fsck_clear_progbar(e2fsck_t ctx);
 extern int e2fsck_simple_progress(e2fsck_t ctx, const char *label,
 				  float percent, unsigned int dpynum);
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
 #endif /* _E2FSCK_H */
diff --git a/e2fsck/message.c b/e2fsck/message.c
index 1c3fcd8..34201a3 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -32,7 +32,7 @@
  * 	%IM	<inode> -> i_mtime
  * 	%IF	<inode> -> i_faddr
  * 	%If	<inode> -> i_file_acl
- * 	%Id	<inode> -> i_dir_acl
+ * 	%Id	<inode> -> i_size_high
  * 	%Iu	<inode> -> i_uid
  * 	%Ig	<inode> -> i_gid
  *	%It	<inode type>
@@ -320,7 +320,7 @@
 		break;
 	case 'd':
 		fprintf(f, "%u", (LINUX_S_ISDIR(inode->i_mode) ?
-				  inode->i_dir_acl : 0));
+			inode->i_size_high : 0));
 		break;
 	case 'u':
 		fprintf(f, "%d", inode_uid(*inode));
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 7983ffd..422a3d6 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -1715,7 +1715,8 @@
 		}
 
 		if (inode->i_faddr || frag || fsize ||
-		    (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
+		    (!ext2fs_has_feature_largedir(fs->super) &&
+		    (LINUX_S_ISDIR(inode->i_mode) && inode->i_size_high)))
 			mark_inode_bad(ctx, ino);
 		if ((fs->super->s_creator_os != EXT2_OS_HURD) &&
 		    !ext2fs_has_feature_64bit(fs->super) &&
@@ -2154,14 +2155,20 @@
 	}
 }
 
+/*
+ * When cluster size is greater than one block, it is caller's responsibility
+ * to make sure block parameter starts at a cluster boundary.
+ */
 static _INLINE_ void mark_blocks_used(e2fsck_t ctx, blk64_t block,
 				      unsigned int num)
 {
 	if (ext2fs_test_block_bitmap_range2(ctx->block_found_map, block, num))
 		ext2fs_mark_block_bitmap_range2(ctx->block_found_map, block, num);
-	else
-		while (num--)
-			mark_block_used(ctx, block++);
+	else {
+		int i;
+		for (i = 0; i < num; i += EXT2FS_CLUSTER_RATIO(ctx->fs))
+			mark_block_used(ctx, block + i);
+	}
 }
 
 /*
@@ -2473,7 +2480,7 @@
 		return 1;
 
 	pctx->num = root->indirect_levels;
-	if ((root->indirect_levels > 1) &&
+	if ((root->indirect_levels > ext2_dir_htree_level(fs)) &&
 	    fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
 		return 1;
 
@@ -2561,8 +2568,7 @@
 {
 	struct ext2fs_extent	extent;
 	blk64_t			blk, last_lblk;
-	e2_blkcnt_t		blockcnt;
-	unsigned int		i;
+	unsigned int		i, n;
 	int			is_dir, is_leaf;
 	problem_t		problem;
 	struct ext2_extent_info	info;
@@ -2827,50 +2833,29 @@
 			}
 		}
 alloc_later:
-		while (is_dir && (++pb->last_db_block <
-				  (e2_blkcnt_t) extent.e_lblk)) {
-			pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist,
-							      pb->ino, 0,
-							      pb->last_db_block);
-			if (pctx->errcode) {
-				pctx->blk = 0;
-				pctx->num = pb->last_db_block;
-				goto failed_add_dir_block;
-			}
-		}
-		if (!ctx->fs->cluster_ratio_bits) {
-			mark_blocks_used(ctx, extent.e_pblk, extent.e_len);
-			pb->num_blocks += extent.e_len;
-		}
-		for (blk = extent.e_pblk, blockcnt = extent.e_lblk, i = 0;
-		     i < extent.e_len;
-		     blk++, blockcnt++, i++) {
-			if (ctx->fs->cluster_ratio_bits &&
-			    !(pb->previous_block &&
-			      (EXT2FS_B2C(ctx->fs, blk) ==
-			       EXT2FS_B2C(ctx->fs, pb->previous_block)) &&
-			      (blk & EXT2FS_CLUSTER_MASK(ctx->fs)) ==
-			      ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) {
-				mark_block_used(ctx, blk);
-				pb->num_blocks++;
-			}
-			if (has_unaligned_cluster_map(ctx, pb->previous_block,
-						      pb->last_block, blk,
-						      blockcnt)) {
-				pctx->blk = blockcnt;
-				pctx->blk2 = blk;
-				fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
-				mark_block_used(ctx, blk);
-				mark_block_used(ctx, blk);
-			}
-			pb->last_block = blockcnt;
-			pb->previous_block = blk;
-
-			if (is_dir) {
-				pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pctx->ino, blk, blockcnt);
+		if (is_dir) {
+			while (++pb->last_db_block <
+			       (e2_blkcnt_t) extent.e_lblk) {
+				pctx->errcode = ext2fs_add_dir_block2(
+							ctx->fs->dblist,
+							pb->ino, 0,
+							pb->last_db_block);
 				if (pctx->errcode) {
-					pctx->blk = blk;
-					pctx->num = blockcnt;
+					pctx->blk = 0;
+					pctx->num = pb->last_db_block;
+					goto failed_add_dir_block;
+				}
+			}
+
+			for (i = 0; i < extent.e_len; i++) {
+				pctx->errcode = ext2fs_add_dir_block2(
+							ctx->fs->dblist,
+							pctx->ino,
+							extent.e_pblk + i,
+							extent.e_lblk + i);
+				if (pctx->errcode) {
+					pctx->blk = extent.e_pblk + i;
+					pctx->num = extent.e_lblk + i;
 				failed_add_dir_block:
 					fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
 					/* Should never get here */
@@ -2878,9 +2863,46 @@
 					return;
 				}
 			}
+			if (extent.e_len > 0)
+				pb->last_db_block = extent.e_lblk + extent.e_len - 1;
 		}
-		if (is_dir && extent.e_len > 0)
-			pb->last_db_block = blockcnt - 1;
+		if (has_unaligned_cluster_map(ctx, pb->previous_block,
+					      pb->last_block,
+					      extent.e_pblk,
+					      extent.e_lblk)) {
+			for (i = 0; i < extent.e_len; i++) {
+				pctx->blk = extent.e_lblk + i;
+				pctx->blk2 = extent.e_pblk + i;
+				fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
+				mark_block_used(ctx, extent.e_pblk + i);
+				mark_block_used(ctx, extent.e_pblk + i);
+			}
+		}
+
+		/*
+		 * Check whether first cluster got marked in previous iteration.
+		 */
+		if (ctx->fs->cluster_ratio_bits &&
+		    pb->previous_block &&
+		    (EXT2FS_B2C(ctx->fs, extent.e_pblk) ==
+		     EXT2FS_B2C(ctx->fs, pb->previous_block)))
+			/* Set blk to the beginning of next cluster. */
+			blk = EXT2FS_C2B(
+				ctx->fs,
+				EXT2FS_B2C(ctx->fs, extent.e_pblk) + 1);
+		else
+			/* Set blk to the beginning of current cluster. */
+			blk = EXT2FS_C2B(ctx->fs,
+					 EXT2FS_B2C(ctx->fs, extent.e_pblk));
+
+		if (blk < extent.e_pblk + extent.e_len) {
+			mark_blocks_used(ctx, blk,
+					 extent.e_pblk + extent.e_len - blk);
+			n = DIV_ROUND_UP(extent.e_pblk + extent.e_len - blk,
+					 EXT2FS_CLUSTER_RATIO(ctx->fs));
+			pb->num_blocks += n;
+		}
+		pb->last_block = extent.e_lblk + extent.e_len - 1;
 		pb->previous_block = extent.e_pblk + extent.e_len - 1;
 		start_block = pb->last_block = last_lblk;
 		if (is_leaf && !is_dir &&
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 170878c..09b79c3 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -85,6 +85,39 @@
 	unsigned long long next_ra_off;
 };
 
+static void update_parents(struct dx_dir_info *dx_dir, int type)
+{
+	struct dx_dirblock_info *dx_db, *dx_parent, *dx_previous;
+	int b;
+
+	for (b = 0, dx_db = dx_dir->dx_block;
+	     b < dx_dir->numblocks;
+	     b++, dx_db++) {
+		dx_parent = &dx_dir->dx_block[dx_db->parent];
+		if (dx_db->type != type)
+			continue;
+
+		/*
+		 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
+		*/
+		if (dx_db->flags & DX_FLAG_FIRST) {
+			dx_parent->min_hash = dx_db->min_hash;
+			if (dx_parent->previous) {
+				dx_previous =
+					&dx_dir->dx_block[dx_parent->previous];
+				dx_previous->node_max_hash =
+					dx_parent->min_hash;
+			}
+		}
+		/*
+		 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
+		 */
+		if (dx_db->flags & DX_FLAG_LAST) {
+			dx_parent->max_hash = dx_db->max_hash;
+		}
+	}
+}
+
 void e2fsck_pass2(e2fsck_t ctx)
 {
 	struct ext2_super_block *sb = ctx->fs->super;
@@ -182,24 +215,11 @@
 		 * Find all of the first and last leaf blocks, and
 		 * update their parent's min and max hash values
 		 */
-		for (b=0, dx_db = dx_dir->dx_block;
-		     b < dx_dir->numblocks;
-		     b++, dx_db++) {
-			if ((dx_db->type != DX_DIRBLOCK_LEAF) ||
-			    !(dx_db->flags & (DX_FLAG_FIRST | DX_FLAG_LAST)))
-				continue;
-			dx_parent = &dx_dir->dx_block[dx_db->parent];
-			/*
-			 * XXX Make sure dx_parent->min_hash > dx_db->min_hash
-			 */
-			if (dx_db->flags & DX_FLAG_FIRST)
-				dx_parent->min_hash = dx_db->min_hash;
-			/*
-			 * XXX Make sure dx_parent->max_hash < dx_db->max_hash
-			 */
-			if (dx_db->flags & DX_FLAG_LAST)
-				dx_parent->max_hash = dx_db->max_hash;
-		}
+		update_parents(dx_dir, DX_DIRBLOCK_LEAF);
+
+		/* for 3 level htree: update 2 level parent's min
+		 * and max hash values */
+		update_parents(dx_dir, DX_DIRBLOCK_NODE);
 
 		for (b=0, dx_db = dx_dir->dx_block;
 		     b < dx_dir->numblocks;
@@ -642,6 +662,10 @@
 			dx_db->flags |= DX_FLAG_REFERENCED;
 			dx_db->parent = db->blockcnt;
 		}
+
+		dx_db->previous =
+			i ? ext2fs_le32_to_cpu(ent[i-1].block & 0x0ffffff) : 0;
+
 		if (hash < min_hash)
 			min_hash = hash;
 		if (hash > max_hash)
@@ -949,6 +973,14 @@
 			return DIRENT_ABORT;
 	}
 
+	/* This will allow (at some point in the future) to punch out empty
+	 * directory blocks and reduce the space used by a directory that grows
+	 * very large and then the files are deleted. For now, all that is
+	 * needed is to avoid e2fsck filling in these holes as part of
+	 * feature flag. */
+	if (db->blk == 0 && ext2fs_has_feature_largedir(fs->super))
+		return 0;
+
 	if (db->blk == 0 && !inline_data_size) {
 		if (allocate_dir_block(ctx, db, buf, &cd->pctx))
 			return 0;
@@ -1058,7 +1090,8 @@
 			dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
 			if ((root->reserved_zero ||
 			     root->info_length < 8 ||
-			     root->indirect_levels > 1) &&
+			     root->indirect_levels >=
+			     ext2_dir_htree_level(fs)) &&
 			    fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
 				clear_htree(ctx, ino);
 				dx_dir->numblocks = 0;
@@ -1811,10 +1844,10 @@
 		} else
 			not_fixed++;
 	}
-	if (inode.i_dir_acl &&
+	if (inode.i_size_high && !ext2fs_has_feature_largedir(fs->super) &&
 	    LINUX_S_ISDIR(inode.i_mode)) {
-		if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
-			inode.i_dir_acl = 0;
+		if (fix_problem(ctx, PR_2_DIR_SIZE_HIGH_ZERO, &pctx)) {
+			inode.i_size_high = 0;
 			inode_modified++;
 		} else
 			not_fixed++;
diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c
index fb55b7e..ab73649 100644
--- a/e2fsck/pass5.c
+++ b/e2fsck/pass5.c
@@ -21,8 +21,6 @@
 #include "e2fsck.h"
 #include "problem.h"
 
-#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-
 static void check_block_bitmaps(e2fsck_t ctx);
 static void check_inode_bitmaps(e2fsck_t ctx);
 static void check_inode_end(e2fsck_t ctx);
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index c3e4f6a..206a8a0 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1361,9 +1361,9 @@
 	  N_("i_file_acl @F %If, @s zero.\n"),
 	  PROMPT_CLEAR, 0 },
 
-	/* i_dir_acl should be zero */
-	{ PR_2_DIR_ACL_ZERO,
-	  N_("i_dir_acl @F %Id, @s zero.\n"),
+	/* i_size_high should be zero */
+	{ PR_2_DIR_SIZE_HIGH_ZERO,
+	  N_("i_size_high @F %Id, @s zero.\n"),
 	  PROMPT_CLEAR, 0 },
 
 	/* i_frag should be zero */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index d291e26..f8650b9 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -813,8 +813,8 @@
 /* i_file_acl should be zero */
 #define PR_2_FILE_ACL_ZERO	0x02000E
 
-/* i_dir_acl should be zero */
-#define PR_2_DIR_ACL_ZERO	0x02000F
+/* i_size_high should be zero */
+#define PR_2_DIR_SIZE_HIGH_ZERO	0x02000F
 
 /* i_frag should be zero */
 #define PR_2_FRAG_ZERO		0x020010
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 22a58f3..7dcb386 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -603,6 +603,43 @@
 	return (struct ext2_dx_entry *) limits;
 }
 
+static int alloc_blocks(ext2_filsys fs,
+			struct ext2_dx_countlimit **limit,
+			struct ext2_dx_entry **prev_ent,
+			struct ext2_dx_entry **next_ent,
+			int *prev_offset, int *next_offset,
+			struct out_dir *outdir, int i,
+			int *prev_count, int *next_count)
+{
+	errcode_t	retval;
+	char		*block_start;
+
+	if (*limit)
+		(*limit)->limit = (*limit)->count =
+			ext2fs_cpu_to_le16((*limit)->limit);
+	*prev_ent = (struct ext2_dx_entry *) (outdir->buf + *prev_offset);
+	(*prev_ent)->block = ext2fs_cpu_to_le32(outdir->num);
+
+	if (i != 1)
+		(*prev_ent)->hash =
+			ext2fs_cpu_to_le32(outdir->hashes[i]);
+
+	retval = get_next_block(fs, outdir, &block_start);
+	if (retval)
+		return retval;
+
+	*next_ent = set_int_node(fs, block_start);
+	*limit = (struct ext2_dx_countlimit *)(*next_ent);
+	if (next_offset)
+		*next_offset = ((char *) *next_ent - outdir->buf);
+
+	*next_count = (*limit)->limit;
+	(*prev_offset) += sizeof(struct ext2_dx_entry);
+	(*prev_count)--;
+
+	return 0;
+}
+
 /*
  * This function takes the leaf nodes which have been written in
  * outdir, and populates the root node and any necessary interior nodes.
@@ -612,13 +649,13 @@
 				ext2_ino_t ino,
 				ext2_ino_t parent)
 {
-	struct ext2_dx_root_info  	*root_info;
-	struct ext2_dx_entry 		*root, *dx_ent = 0;
-	struct ext2_dx_countlimit	*root_limit, *limit;
+	struct ext2_dx_root_info	*root_info;
+	struct ext2_dx_entry		*root, *int_ent, *dx_ent = 0;
+	struct ext2_dx_countlimit	*root_limit, *int_limit, *limit;
 	errcode_t			retval;
 	char				* block_start;
-	int				i, c1, c2, nblks;
-	int				limit_offset, root_offset;
+	int				i, c1, c2, c3, nblks;
+	int				limit_offset, int_offset, root_offset;
 
 	root_info = set_root_node(fs, outdir->buf, ino, parent);
 	root_offset = limit_offset = ((char *) root_info - outdir->buf) +
@@ -628,7 +665,7 @@
 	nblks = outdir->num;
 
 	/* Write out the pointer blocks */
-	if (nblks-1 <= c1) {
+	if (nblks - 1 <= c1) {
 		/* Just write out the root block, and we're done */
 		root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
 		for (i=1; i < nblks; i++) {
@@ -639,31 +676,20 @@
 			root++;
 			c1--;
 		}
-	} else {
+	} else if (nblks - 1 <= ext2fs_htree_intnode_maxrecs(fs, c1)) {
 		c2 = 0;
-		limit = 0;
+		limit = NULL;
 		root_info->indirect_levels = 1;
 		for (i=1; i < nblks; i++) {
-			if (c1 == 0)
+			if (c2 == 0 && c1 == 0)
 				return ENOSPC;
 			if (c2 == 0) {
-				if (limit)
-					limit->limit = limit->count =
-		ext2fs_cpu_to_le16(limit->limit);
-				root = (struct ext2_dx_entry *)
-					(outdir->buf + root_offset);
-				root->block = ext2fs_cpu_to_le32(outdir->num);
-				if (i != 1)
-					root->hash =
-			ext2fs_cpu_to_le32(outdir->hashes[i]);
-				if ((retval =  get_next_block(fs, outdir,
-							      &block_start)))
+				retval = alloc_blocks(fs, &limit, &root,
+						      &dx_ent, &root_offset,
+						      NULL, outdir, i, &c1,
+						      &c2);
+				if (retval)
 					return retval;
-				dx_ent = set_int_node(fs, block_start);
-				limit = (struct ext2_dx_countlimit *) dx_ent;
-				c2 = limit->limit;
-				root_offset += sizeof(struct ext2_dx_entry);
-				c1--;
 			}
 			dx_ent->block = ext2fs_cpu_to_le32(i);
 			if (c2 != limit->limit)
@@ -674,6 +700,45 @@
 		}
 		limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
 		limit->limit = ext2fs_cpu_to_le16(limit->limit);
+	} else {
+		c2 = 0;
+		c3 = 0;
+		limit = NULL;
+		int_limit = 0;
+		root_info->indirect_levels = 2;
+		for (i = 1; i < nblks; i++) {
+			if (c3 == 0 && c2 == 0 && c1 == 0)
+				return ENOSPC;
+			if (c3 == 0 && c2 == 0) {
+				retval = alloc_blocks(fs, &int_limit, &root,
+						      &int_ent, &root_offset,
+						      &int_offset, outdir, i,
+						      &c1, &c2);
+				if (retval)
+					return retval;
+			}
+			if (c3 == 0) {
+				retval = alloc_blocks(fs, &limit, &int_ent,
+						      &dx_ent, &int_offset,
+						      NULL, outdir, i, &c2,
+						      &c3);
+				if (retval)
+					return retval;
+
+			}
+			dx_ent->block = ext2fs_cpu_to_le32(i);
+			if (c3 != limit->limit)
+				dx_ent->hash =
+					ext2fs_cpu_to_le32(outdir->hashes[i]);
+			dx_ent++;
+			c3--;
+		}
+		int_limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
+		int_limit->limit = ext2fs_cpu_to_le16(limit->limit);
+
+		limit->count = ext2fs_cpu_to_le16(limit->limit - c3);
+		limit->limit = ext2fs_cpu_to_le16(limit->limit);
+
 	}
 	root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
 	root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
diff --git a/ext2ed/doc/ext2ed-design.sgml b/ext2ed/doc/ext2ed-design.sgml
index ad2df96..7841358 100644
--- a/ext2ed/doc/ext2ed-design.sgml
+++ b/ext2ed/doc/ext2ed-design.sgml
@@ -2726,7 +2726,7 @@
 	__u32	i_block[EXT2_N_BLOCKS];	/* Pointers to blocks */
 	__u32	i_version;		/* File version (for NFS) */
 	__u32	i_file_acl;		/* File ACL */
-	__u32	i_dir_acl;		/* Directory ACL */
+	__u32	i_size_high;		/* High 32bits of size */
 	__u32	i_faddr;		/* Fragment address */
 	union {
 		struct {
diff --git a/ext2ed/doc/ext2fs-overview.sgml b/ext2ed/doc/ext2fs-overview.sgml
index a6ebf5a..900c393 100644
--- a/ext2ed/doc/ext2fs-overview.sgml
+++ b/ext2ed/doc/ext2fs-overview.sgml
@@ -487,7 +487,7 @@
 	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
 	__u32	i_version;	/* File version (for NFS) */
 	__u32	i_file_acl;	/* File ACL */
-	__u32	i_dir_acl;	/* Directory ACL */
+	__u32	i_size_high;	/* High 32bits of size */
 	__u32	i_faddr;	/* Fragment address */
 	union {
 		struct {
diff --git a/ext2ed/ext2.descriptors b/ext2ed/ext2.descriptors
index bf927b0..b1ac4c4 100644
--- a/ext2ed/ext2.descriptors
+++ b/ext2ed/ext2.descriptors
@@ -102,7 +102,7 @@
 	__u32  i_block[14]; /* Pointers to blocks */
 	__u32  i_version;	/* File version (for NFS) */
 	__u32  i_file_acl;	/* File ACL */
-	__u32  i_dir_acl;	/* Directory ACL */
+	__u32  i_size_high;	/* High 32bits of size */
 	__u32  i_faddr;		/* Fragment address */
 	__u8   l_i_frag;	/* Fragment number */
 	__u8   l_i_fsize;	/* Fragment size */
diff --git a/include/nonunix/linux/types.h b/include/nonunix/linux/types.h
index 8e5bc90..eb87011 100644
--- a/include/nonunix/linux/types.h
+++ b/include/nonunix/linux/types.h
@@ -1,10 +1,11 @@
 #ifndef _LINUX_TYPES_H
 #define _LINUX_TYPES_H
 
-#ifndef _MSC_VER
-#error  _MSC_VER not defined
-#endif
+//#ifndef _MSC_VER
+//#error  _MSC_VER not defined
+//#endif
 
+#include <sys/types.h>
 
 typedef unsigned __int8 __u8;
 typedef signed __int8 __s8;
@@ -22,7 +23,11 @@
 typedef	unsigned __int64	__u64;
 
 
-typedef __u32 ino_t;
+//typedef __u32 ino_t;
+typedef __u32 dev_t;
+typedef __u32 uid_t;
+typedef __u32 gid_t;
 
+#include <stdint.h>
 
 #endif /* LINUX_TYPES_H */
diff --git a/intl/Makefile.in b/intl/Makefile.in
index db6d7d7..66d7512 100644
--- a/intl/Makefile.in
+++ b/intl/Makefile.in
@@ -293,7 +293,7 @@
 	$(Q) $(SHELL) $(srcdir)/config.charset '@host@' > t-$@
 	$(Q) mv t-$@ $@
 
-check: all
+fullcheck check: all
 
 # We must not install the libintl.h/libintl.a files if we are on a
 # system which has the GNU gettext() function in its C library or in a
diff --git a/lib/Android.bp b/lib/Android.bp
new file mode 100644
index 0000000..b38d8b1
--- /dev/null
+++ b/lib/Android.bp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Android Open Source Project
+
+// All the libraries under this directory export their headers as relative
+// paths to this directory (external/e2fsprogs/lib). This is a helper headers
+// only library to allow exporting
+cc_library_headers {
+    name: "libext2-headers",
+    host_supported: true,
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+    export_include_dirs: ["."],
+}
+
+
+subdirs = [
+    "*",
+]
diff --git a/lib/Android.mk b/lib/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/lib/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/lib/blkid/Android.bp b/lib/blkid/Android.bp
new file mode 100644
index 0000000..9b385f9
--- /dev/null
+++ b/lib/blkid/Android.bp
@@ -0,0 +1,33 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_blkid",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "cache.c",
+        "dev.c",
+        "devname.c",
+        "devno.c",
+        "getsize.c",
+        "llseek.c",
+        "probe.c",
+        "read.c",
+        "resolve.c",
+        "save.c",
+        "tag.c",
+        "version.c",
+    ],
+    shared_libs: ["libext2_uuid"],
+
+    cflags: [
+        "-W",
+        "-Wall",
+        "-fno-strict-aliasing",
+        "-Wno-macro-redefined",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/blkid/Android.mk b/lib/blkid/Android.mk
deleted file mode 100644
index 857c4f9..0000000
--- a/lib/blkid/Android.mk
+++ /dev/null
@@ -1,62 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_blkid_src_files := \
-	cache.c \
-	dev.c \
-	devname.c \
-	devno.c \
-	getsize.c \
-	llseek.c \
-	probe.c \
-	read.c \
-	resolve.c \
-	save.c \
-	tag.c \
-	version.c \
-
-
-libext2_blkid_shared_libraries := libext2_uuid
-
-libext2_blkid_system_shared_libraries := libc
-
-libext2_blkid_static_libraries := libext2_uuid_static
-
-libext2_blkid_system_static_libraries := libc
-
-libext2_blkid_c_includes := external/e2fsprogs/lib
-
-libext2_blkid_cflags := -O2 -g -W -Wall -fno-strict-aliasing
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_blkid_src_files)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_blkid_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(libext2_blkid_shared_libraries)
-LOCAL_C_INCLUDES := $(libext2_blkid_c_includes)
-LOCAL_CFLAGS := $(libext2_blkid_cflags)
-LOCAL_MODULE := libext2_blkid
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_blkid_src_files)
-LOCAL_STATIC_LIBRARIES := $(libext2_blkid_static_libraries) $(libext2_blkid_system_static_libraries)
-LOCAL_C_INCLUDES := $(libext2_blkid_c_includes)
-LOCAL_CFLAGS := $(libext2_blkid_cflags) $(libext2_blkid_cflags_linux) -fno-strict-aliasing
-LOCAL_MODULE := libext2_blkid
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_blkid_src_files)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2_blkid_shared_libraries))
-LOCAL_C_INCLUDES := $(libext2_blkid_c_includes)
-LOCAL_CFLAGS := $(libext2_blkid_cflags)
-LOCAL_MODULE := libext2_blkid-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/lib/blkid/Makefile.in b/lib/blkid/Makefile.in
index 7f38452..0be2da5 100644
--- a/lib/blkid/Makefile.in
+++ b/lib/blkid/Makefile.in
@@ -135,8 +135,9 @@
 	$(Q) cat $(srcdir)/test_probe.in >> test_probe
 	$(Q) chmod +x test_probe
 
-check:: all tst_cache tst_dev tst_devname tst_devno tst_getsize tst_probe \
- tst_read tst_resolve tst_save tst_tag test_probe tst_types
+fullcheck check:: all tst_cache tst_dev tst_devname tst_devno \
+ tst_getsize tst_probe tst_read tst_resolve tst_save tst_tag \
+ test_probe tst_types
 	./test_probe
 	./tst_types
 
diff --git a/lib/blkid/devname.c b/lib/blkid/devname.c
index 671e781..444afdc 100644
--- a/lib/blkid/devname.c
+++ b/lib/blkid/devname.c
@@ -397,7 +397,7 @@
 {
 	FILE *proc;
 	char line[1024];
-	char ptname0[128], ptname1[128], *ptname = 0;
+	char ptname0[129], ptname1[129], *ptname = 0;
 	char *ptnames[2];
 	dev_t devs[2];
 	int ma, mi;
diff --git a/lib/config.h.in b/lib/config.h.in
index bc006de..91e869e 100644
--- a/lib/config.h.in
+++ b/lib/config.h.in
@@ -244,6 +244,9 @@
 /* Define to 1 if you have the <linux/fd.h> header file. */
 #undef HAVE_LINUX_FD_H
 
+/* Define to 1 if you have the <linux/fsmap.h> header file. */
+#undef HAVE_LINUX_FSMAP_H
+
 /* Define to 1 if you have the <linux/loop.h> header file. */
 #undef HAVE_LINUX_LOOP_H
 
@@ -467,6 +470,9 @@
 /* Define to 1 if you have the `sync_file_range' function. */
 #undef HAVE_SYNC_FILE_RANGE
 
+/* Define to 1 if you have the 'fsync' function. */
+#undef HAVE_FSYNC
+
 /* Define to 1 if you have the `sysconf' function. */
 #undef HAVE_SYSCONF
 
diff --git a/lib/e2p/Android.bp b/lib/e2p/Android.bp
new file mode 100644
index 0000000..db51670
--- /dev/null
+++ b/lib/e2p/Android.bp
@@ -0,0 +1,41 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_e2p",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "feature.c",
+        "fgetflags.c",
+        "fsetflags.c",
+        "fgetproject.c",
+        "fsetproject.c",
+        "fgetversion.c",
+        "fsetversion.c",
+        "getflags.c",
+        "getversion.c",
+        "hashstr.c",
+        "iod.c",
+        "ls.c",
+        "mntopts.c",
+        "parse_num.c",
+        "pe.c",
+        "pf.c",
+        "ps.c",
+        "setflags.c",
+        "setversion.c",
+        "uuid.c",
+        "ostype.c",
+        "percent.c",
+    ],
+
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-macro-redefined",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/e2p/Android.mk b/lib/e2p/Android.mk
deleted file mode 100644
index 8a732c3..0000000
--- a/lib/e2p/Android.mk
+++ /dev/null
@@ -1,65 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_e2p_src_files := \
-	feature.c \
-	fgetflags.c \
-	fsetflags.c \
-	fgetproject.c \
-	fsetproject.c \
-	fgetversion.c \
-	fsetversion.c \
-	getflags.c \
-	getversion.c \
-	hashstr.c \
-	iod.c \
-	ls.c \
-	mntopts.c \
-	parse_num.c \
-	pe.c \
-	pf.c \
-	ps.c \
-	setflags.c \
-	setversion.c \
-	uuid.c \
-	ostype.c \
-	percent.c
-
-libext2_e2p_c_includes := external/e2fsprogs/lib
-
-libext2_e2p_cflags := -O2 -g -W -Wall
-
-libext2_e2p_system_shared_libraries := libc
-
-libext2_e2p_system_static_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_e2p_src_files)
-LOCAL_C_INCLUDES := $(libext2_e2p_c_includes)
-LOCAL_CFLAGS := $(libext2_e2p_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_e2p_system_shared_libraries)
-LOCAL_MODULE := libext2_e2p
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_e2p_src_files)
-LOCAL_C_INCLUDES := $(libext2_e2p_c_includes)
-LOCAL_CFLAGS := $(libext2_e2p_cflags)
-LOCAL_STATIC_LIBRARIES := $(libext2_e2p_system_static_libraries)
-LOCAL_MODULE := libext2_e2p
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_e2p_src_files)
-LOCAL_C_INCLUDES := $(libext2_e2p_c_includes)
-LOCAL_CFLAGS := $(libext2_e2p_cflags)
-LOCAL_MODULE := libext2_e2p-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/lib/e2p/Makefile.in b/lib/e2p/Makefile.in
index 6fd2cec..d266d68 100644
--- a/lib/e2p/Makefile.in
+++ b/lib/e2p/Makefile.in
@@ -75,7 +75,7 @@
 	$(Q) $(CC) -DTEST_PROGRAM -I$(top_srcdir)/lib -o tst_feature \
 		$(srcdir)/feature.c $(ALL_CFLAGS) $(ALL_LDFLAGS)
 
-check::	tst_ostype tst_feature
+fullcheck check::	tst_ostype tst_feature
 	./tst_ostype
 	./tst_feature
 
diff --git a/lib/et/Android.bp b/lib/et/Android.bp
new file mode 100644
index 0000000..f6ad416
--- /dev/null
+++ b/lib/et/Android.bp
@@ -0,0 +1,28 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_com_err",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "error_message.c",
+        "et_name.c",
+        "init_et.c",
+        "com_err.c",
+        "com_right.c",
+    ],
+
+    cflags: [
+        "-W",
+        "-Wall",
+    ],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/et/Android.mk b/lib/et/Android.mk
deleted file mode 100644
index 8704f4c..0000000
--- a/lib/et/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_com_err_src_files := \
-	error_message.c \
-	et_name.c \
-	init_et.c \
-	com_err.c \
-	com_right.c
-
-libext2_com_err_c_includes := external/e2fsprogs/lib
-
-libext2_com_err_cflags := -O2 -g -W -Wall
-
-libext2_com_err_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_com_err_src_files)
-LOCAL_C_INCLUDES := $(libext2_com_err_c_includes)
-LOCAL_CFLAGS := $(libext2_com_err_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := libc
-LOCAL_MODULE := libext2_com_err
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_com_err_src_files)
-LOCAL_C_INCLUDES := $(libext2_com_err_c_includes)
-LOCAL_CFLAGS := $(libext2_com_err_cflags)
-LOCAL_STATIC_LIBRARIES := libc
-LOCAL_MODULE := libext2_com_err
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_com_err_src_files)
-LOCAL_C_INCLUDES := $(libext2_com_err_c_includes)
-LOCAL_CFLAGS := $(libext2_com_err_cflags)
-LOCAL_MODULE := libext2_com_err-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/lib/et/Makefile.in b/lib/et/Makefile.in
index 476f189..0344679 100644
--- a/lib/et/Makefile.in
+++ b/lib/et/Makefile.in
@@ -137,7 +137,7 @@
 		$(DESTDIR)$(pkgconfigdir)/com_err.pc
 	$(RM) -rf $(DESTDIR)$(includedir)/et $(DESTDIR)$(datadir)/et
 
-check:: compile_et
+fullcheck check:: compile_et
 	for i in $(srcdir)/test_cases/*.et ; do \
 		t=`basename $$i | sed -e 's/.et//'`; \
 		_ET_DIR_OVERRIDE=$(srcdir) ./compile_et $$i ; \
diff --git a/lib/et/error_message.c b/lib/et/error_message.c
index fe79122..5dd8aa6 100644
--- a/lib/et/error_message.c
+++ b/lib/et/error_message.c
@@ -35,7 +35,9 @@
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#if HAVE_FCNTL
 #include <fcntl.h>
+#endif
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -196,8 +198,10 @@
  */
 static char *safe_getenv(const char *arg)
 {
+#if !defined(_WIN32)
 	if ((getuid() != geteuid()) || (getgid() != getegid()))
 		return NULL;
+#endif
 #if HAVE_PRCTL
 	if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
 		return NULL;
@@ -249,11 +253,13 @@
 		debug_f = fopen("/dev/tty", "a");
 	if (debug_f) {
 		fd = fileno(debug_f);
+#if defined(HAVE_FCNTL)
 		if (fd >= 0) {
 			flags = fcntl(fd, F_GETFD);
 			if (flags >= 0)
 				fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
 		}
+#endif
 	} else
 		debug_mask = DEBUG_INIT;
 
diff --git a/lib/ext2fs/Android.bp b/lib/ext2fs/Android.bp
new file mode 100644
index 0000000..df07a9b
--- /dev/null
+++ b/lib/ext2fs/Android.bp
@@ -0,0 +1,134 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2fs",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "ext2_err.c",
+        "alloc.c",
+        "alloc_sb.c",
+        "alloc_stats.c",
+        "alloc_tables.c",
+        "atexit.c",
+        "badblocks.c",
+        "bb_inode.c",
+        "bitmaps.c",
+        "bitops.c",
+        "blkmap64_ba.c",
+        "blkmap64_rb.c",
+        "blknum.c",
+        "block.c",
+        "bmap.c",
+        "check_desc.c",
+        "crc16.c",
+        "crc32c.c",
+        "csum.c",
+        "closefs.c",
+        "dblist.c",
+        "dblist_dir.c",
+        "digest_encode.c",
+        "dirblock.c",
+        "dirhash.c",
+        "dir_iterate.c",
+        "dupfs.c",
+        "expanddir.c",
+        "ext_attr.c",
+        "extent.c",
+        "fallocate.c",
+        "fileio.c",
+        "finddev.c",
+        "flushb.c",
+        "freefs.c",
+        "gen_bitmap.c",
+        "gen_bitmap64.c",
+        "get_num_dirs.c",
+        "get_pathname.c",
+        "getsize.c",
+        "getsectsize.c",
+        "i_block.c",
+        "icount.c",
+        "imager.c",
+        "ind_block.c",
+        "initialize.c",
+        "inline.c",
+        "inline_data.c",
+        "inode.c",
+        "io_manager.c",
+        "ismounted.c",
+        "link.c",
+        "llseek.c",
+        "lookup.c",
+        "mmp.c",
+        "mkdir.c",
+        "mkjournal.c",
+        "namei.c",
+        "native.c",
+        "newdir.c",
+        "openfs.c",
+        "progress.c",
+        "punch.c",
+        "qcow2.c",
+        "rbtree.c",
+        "read_bb.c",
+        "read_bb_file.c",
+        "res_gdt.c",
+        "rw_bitmaps.c",
+        "sha256.c",
+        "sha512.c",
+        "swapfs.c",
+        "symlink.c",
+        "undo_io.c",
+        "unix_io.c",
+        "sparse_io.c",
+        "unlink.c",
+        "valid_blk.c",
+        "version.c",
+        // get rid of this?!
+        "test_io.c",
+    ],
+    shared_libs: [
+        "libsparse",
+    ],
+    whole_static_libs: [
+        "libext2_com_err"
+    ],
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-unused-parameter",
+        "-Wno-macro-redefined",
+    ],
+    target: {
+        host: {
+            shared_libs: ["libz-host"],
+            // Consider removing this library as a whole for the host. It is not
+            // in the android side.
+            whole_static_libs: ["libext2_com_err"],
+        },
+        android: {
+            shared_libs: [
+                "libext2_com_err",
+                "libext2_uuid",
+                "libz"
+            ],
+        },
+        windows: {
+            // include/nonunix is used as an overlay on top of the system
+            // include directory. Some empty header files in include/nonunix
+            // hide the ones in the system include path. This setup doesn't work
+            // unless we pass the include/nonunix as an -isystem flag.
+            // TODO(deymo): Enable windows
+            enabled: false,
+            cflags: [
+                "-Wno-format",
+            //    "-isystem external/e2fsprogs/include/nonunix",
+            ],
+            host_ldlibs: ["-lws2_32"],
+        },
+    },
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/ext2fs/Android.mk b/lib/ext2fs/Android.mk
deleted file mode 100644
index 356232f..0000000
--- a/lib/ext2fs/Android.mk
+++ /dev/null
@@ -1,141 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2fs_src_files := \
-	ext2_err.c \
-	alloc.c \
-	alloc_sb.c \
-	alloc_stats.c \
-	alloc_tables.c \
-	atexit.c \
-	badblocks.c \
-	bb_inode.c \
-	bitmaps.c \
-	bitops.c \
-	blkmap64_ba.c \
-	blkmap64_rb.c \
-	blknum.c \
-	block.c \
-	bmap.c \
-	check_desc.c \
-	crc16.c \
-	crc32c.c \
-	csum.c \
-	closefs.c \
-	dblist.c \
-	dblist_dir.c \
-	digest_encode.c \
-	dirblock.c \
-	dirhash.c \
-	dir_iterate.c \
-	dupfs.c \
-	expanddir.c \
-	ext_attr.c \
-	extent.c \
-	fallocate.c \
-	fileio.c \
-	finddev.c \
-	flushb.c \
-	freefs.c \
-	gen_bitmap.c \
-	gen_bitmap64.c \
-	get_num_dirs.c \
-	get_pathname.c \
-	getsize.c \
-	getsectsize.c \
-	i_block.c \
-	icount.c \
-	imager.c \
-	ind_block.c \
-	initialize.c \
-	inline.c \
-	inline_data.c \
-	inode.c \
-	io_manager.c \
-	ismounted.c \
-	link.c \
-	llseek.c \
-	lookup.c \
-	mmp.c \
-	mkdir.c \
-	mkjournal.c \
-	namei.c \
-	native.c \
-	newdir.c \
-	openfs.c \
-	progress.c \
-	punch.c \
-	qcow2.c \
-	rbtree.c \
-	read_bb.c \
-	read_bb_file.c \
-	res_gdt.c \
-	rw_bitmaps.c \
-	sha256.c \
-	sha512.c \
-	swapfs.c \
-	symlink.c \
-	undo_io.c \
-	unix_io.c \
-	unlink.c \
-	valid_blk.c \
-	version.c
-
-# get rid of this?!
-libext2fs_src_files += test_io.c
-
-libext2fs_shared_libraries := \
-	libext2_com_err \
-	libext2_uuid \
-	libext2_blkid \
-	libext2_e2p
-
-libext2fs_system_shared_libraries := libc
-
-libext2fs_static_libraries := \
-	libext2_com_err \
-	libext2_uuid_static \
-	libext2_blkid \
-	libext2_e2p
-
-libext2fs_system_static_libraries := libc
-
-libext2fs_c_includes := external/e2fsprogs/lib
-
-libext2fs_cflags := -O2 -g -W -Wall
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2fs_src_files)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2fs_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(libext2fs_shared_libraries)
-LOCAL_C_INCLUDES := $(libext2fs_c_includes)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(libext2fs_c_includes)
-LOCAL_CFLAGS := $(libext2fs_cflags)
-LOCAL_MODULE := libext2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2fs_src_files)
-LOCAL_STATIC_LIBRARIES := $(libext2fs_static_libraries) $(libext2fs_system_static_libraries)
-LOCAL_C_INCLUDES := $(libext2fs_c_includes)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(libext2fs_c_includes)
-LOCAL_CFLAGS := $(libext2fs_cflags) $(libext2fs_cflags_linux)
-LOCAL_MODULE := libext2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2fs_src_files)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2fs_shared_libraries))
-LOCAL_C_INCLUDES := $(libext2fs_c_includes)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(libext2fs_c_includes)
-LOCAL_CFLAGS := $(libext2fs_cflags)
-LOCAL_MODULE := libext2fs-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 425b856..b6b0f85 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -125,6 +125,7 @@
 	$(TDB_OBJ) \
 	undo_io.o \
 	unix_io.o \
+	sparse_io.o \
 	unlink.o \
 	valid_blk.o \
 	version.o \
@@ -212,6 +213,7 @@
 	$(srcdir)/tst_iscan.c \
 	$(srcdir)/undo_io.c \
 	$(srcdir)/unix_io.c \
+	$(srcdir)/sparse_io.c \
 	$(srcdir)/unlink.c \
 	$(srcdir)/valid_blk.c \
 	$(srcdir)/version.c \
@@ -521,7 +523,7 @@
 	$(Q) $(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG \
 		$(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS) $(SYSLIBS)
 
-check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
+fullcheck check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
     tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \
     tst_inline tst_inline_data tst_libext2fs tst_sha256 tst_sha512 \
     tst_digest_encode tst_getsize tst_getsectsize
@@ -1108,6 +1110,12 @@
  $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
  $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+sparse_io.o: $(srcdir)/sparse_io.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
 unlink.o: $(srcdir)/unlink.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c
index f96ac4b..af21410 100644
--- a/lib/ext2fs/alloc.c
+++ b/lib/ext2fs/alloc.c
@@ -144,27 +144,38 @@
  * Stupid algorithm --- we now just search forward starting from the
  * goal.  Should put in a smarter one someday....
  */
-errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
-			   ext2fs_block_bitmap map, blk64_t *ret)
+errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal,
+			    ext2fs_block_bitmap map, blk64_t *ret,
+			    struct blk_alloc_ctx *ctx)
 {
 	errcode_t retval;
 	blk64_t	b = 0;
 	errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret);
+	errcode_t (*gab2)(ext2_filsys, blk64_t, blk64_t *,
+			  struct blk_alloc_ctx *);
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
-	if (!map && fs->get_alloc_block) {
+	if (!map) {
 		/*
 		 * In case there are clients out there whose get_alloc_block
 		 * handlers call ext2fs_new_block2 with a NULL block map,
 		 * temporarily swap out the function pointer so that we don't
 		 * end up in an infinite loop.
 		 */
-		gab = fs->get_alloc_block;
-		fs->get_alloc_block = NULL;
-		retval = gab(fs, goal, &b);
-		fs->get_alloc_block = gab;
-		goto allocated;
+		if (fs->get_alloc_block2) {
+			gab2 = fs->get_alloc_block2;
+			fs->get_alloc_block2 = NULL;
+			retval = gab2(fs, goal, &b, ctx);
+			fs->get_alloc_block2 = gab2;
+			goto allocated;
+		} else if (fs->get_alloc_block) {
+			gab = fs->get_alloc_block;
+			fs->get_alloc_block = NULL;
+			retval = gab(fs, goal, &b);
+			fs->get_alloc_block = gab;
+			goto allocated;
+		}
 	}
 	if (!map)
 		map = fs->block_map;
@@ -190,6 +201,12 @@
 	return 0;
 }
 
+errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
+			   ext2fs_block_bitmap map, blk64_t *ret)
+{
+	return ext2fs_new_block3(fs, goal, map, ret, NULL);
+}
+
 errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
 			   ext2fs_block_bitmap map, blk_t *ret)
 {
@@ -205,13 +222,17 @@
  * This function zeros out the allocated block, and updates all of the
  * appropriate filesystem records.
  */
-errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
-			     char *block_buf, blk64_t *ret)
+errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, char *block_buf,
+			      blk64_t *ret, struct blk_alloc_ctx *ctx)
 {
 	errcode_t	retval;
 	blk64_t		block;
 
-	if (fs->get_alloc_block) {
+	if (fs->get_alloc_block2) {
+		retval = (fs->get_alloc_block2)(fs, goal, &block, ctx);
+		if (retval)
+			goto fail;
+	} else if (fs->get_alloc_block) {
 		retval = (fs->get_alloc_block)(fs, goal, &block);
 		if (retval)
 			goto fail;
@@ -222,7 +243,7 @@
 				goto fail;
 		}
 
-		retval = ext2fs_new_block2(fs, goal, 0, &block);
+		retval = ext2fs_new_block3(fs, goal, 0, &block, ctx);
 		if (retval)
 			goto fail;
 	}
@@ -242,15 +263,21 @@
 	return retval;
 }
 
+errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
+			     char *block_buf, blk64_t *ret)
+{
+	return ext2fs_alloc_block3(fs, goal, block_buf, ret, NULL);
+}
+
 errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
 			     char *block_buf, blk_t *ret)
 {
 	errcode_t retval;
-	blk64_t	val;
-	retval = ext2fs_alloc_block2(fs, goal, block_buf, &val);
+	blk64_t ret64, goal64 = goal;
+	retval = ext2fs_alloc_block3(fs, goal64, block_buf, &ret64, NULL);
 	if (!retval)
-		*ret = (blk_t) val;
-	return retval;
+		*ret = (blk_t)ret64;
+        return retval;
 }
 
 errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish,
diff --git a/lib/ext2fs/bitops.h b/lib/ext2fs/bitops.h
index bc59608..505b3c9 100644
--- a/lib/ext2fs/bitops.h
+++ b/lib/ext2fs/bitops.h
@@ -108,7 +108,7 @@
 extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
 					  blk_t block, int num);
 extern int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap,
-					  ino_t inode, int num);
+					  ext2_ino_t inode, int num);
 extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
 					 __u32 bitno);
 extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
diff --git a/lib/ext2fs/blkmap64_rb.c b/lib/ext2fs/blkmap64_rb.c
index 7e7e29d..8d5ddd3 100644
--- a/lib/ext2fs/blkmap64_rb.c
+++ b/lib/ext2fs/blkmap64_rb.c
@@ -9,6 +9,7 @@
  * %End-Header%
  */
 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
 #if HAVE_UNISTD_H
@@ -22,6 +23,9 @@
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
+#if HAVE_LINUX_TYPES_H
+#include <linux/types.h>
+#endif
 
 #include "ext2_fs.h"
 #include "ext2fsP.h"
diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 29da4ef..1ed98aa 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -207,6 +207,7 @@
 			     int *ret_flags, int *blocks_alloc,
 			     blk64_t *phys_blk)
 {
+	struct blk_alloc_ctx	alloc_ctx;
 	struct ext2fs_extent	extent;
 	unsigned int		offset;
 	errcode_t		retval = 0;
@@ -246,8 +247,12 @@
 				     0, block-1, 0, blocks_alloc, &blk64);
 		if (retval)
 			blk64 = ext2fs_find_inode_goal(fs, ino, inode, block);
-		retval = ext2fs_alloc_block2(fs, blk64, block_buf,
-					     &blk64);
+		alloc_ctx.ino = ino;
+		alloc_ctx.inode = inode;
+		alloc_ctx.lblk = extent.e_lblk;
+		alloc_ctx.flags = BLOCK_ALLOC_DATA;
+		retval = ext2fs_alloc_block3(fs, blk64, block_buf, &blk64,
+					     &alloc_ctx);
 		if (retval)
 			return retval;
 		blk64 &= ~EXT2FS_CLUSTER_MASK(fs);
@@ -300,9 +305,16 @@
 	ext2_extent_handle_t handle = 0;
 	blk_t addr_per_block;
 	blk_t	b, blk32;
+	blk64_t b64;
 	char	*buf = 0;
 	errcode_t	retval = 0;
 	int		blocks_alloc = 0, inode_dirty = 0;
+	struct blk_alloc_ctx alloc_ctx = {
+		.ino	= ino,
+		.inode	= inode,
+		.lblk	= 0,
+		.flags	= BLOCK_ALLOC_DATA,
+	};
 
 	if (!(bmap_flags & BMAP_SET))
 		*phys_blk = 0;
@@ -359,7 +371,10 @@
 			    ext2fs_find_inode_goal(fs, ino, inode, block);
 
 		if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
-			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+			b64 = b;
+			retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
+						     &alloc_ctx);
+			b = b64;
 			if (retval)
 				goto done;
 			inode_bmap(inode, block) = b;
@@ -382,7 +397,10 @@
 			}
 
 			b = inode_bmap(inode, EXT2_IND_BLOCK-1);
- 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+			b64 = b;
+			retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
+						     &alloc_ctx);
+			b = b64;
 			if (retval)
 				goto done;
 			inode_bmap(inode, EXT2_IND_BLOCK) = b;
@@ -407,7 +425,10 @@
 			}
 
 			b = inode_bmap(inode, EXT2_IND_BLOCK);
- 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+			b64 = b;
+			retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
+						     &alloc_ctx);
+			b = b64;
 			if (retval)
 				goto done;
 			inode_bmap(inode, EXT2_DIND_BLOCK) = b;
@@ -431,7 +452,10 @@
 		}
 
 		b = inode_bmap(inode, EXT2_DIND_BLOCK);
-		retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+		b64 = b;
+		retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
+					     &alloc_ctx);
+		b = b64;
 		if (retval)
 			goto done;
 		inode_bmap(inode, EXT2_TIND_BLOCK) = b;
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 27a7d3a..66b7058 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -398,7 +398,7 @@
 	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
 	__u32	i_generation;	/* File version (for NFS) */
 	__u32	i_file_acl;	/* File ACL */
-	__u32	i_size_high;	/* Formerly i_dir_acl, directory ACL */
+	__u32	i_size_high;
 	__u32	i_faddr;	/* Fragment address */
 	union {
 		struct {
@@ -446,7 +446,7 @@
 	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
 	__u32	i_generation;	/* File version (for NFS) */
 	__u32	i_file_acl;	/* File ACL */
-	__u32	i_size_high;	/* Formerly i_dir_acl, directory ACL */
+	__u32	i_size_high;
 	__u32	i_faddr;	/* Fragment address */
 	union {
 		struct {
@@ -484,8 +484,6 @@
 #define EXT4_EPOCH_BITS 2
 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
 
-#define i_dir_acl	i_size_high
-
 #define i_checksum_lo	osd2.linux2.l_i_checksum_lo
 
 #define inode_includes(size, field)			\
@@ -923,7 +921,8 @@
 
 #define EXT2_FEATURE_COMPAT_SUPP	0
 #define EXT2_FEATURE_INCOMPAT_SUPP    (EXT2_FEATURE_INCOMPAT_FILETYPE| \
-				       EXT4_FEATURE_INCOMPAT_MMP)
+				       EXT4_FEATURE_INCOMPAT_MMP| \
+				       EXT4_FEATURE_INCOMPAT_LARGEDIR)
 #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
 					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h
index 6b7e977..5540900 100644
--- a/lib/ext2fs/ext2_io.h
+++ b/lib/ext2fs/ext2_io.h
@@ -12,6 +12,8 @@
 #ifndef _EXT2FS_EXT2_IO_H
 #define _EXT2FS_EXT2_IO_H
 
+#include <ext2fs/ext2_types.h>
+
 /*
  * ext2_loff_t is defined here since unix_io.c needs it.
  */
@@ -141,6 +143,10 @@
 extern io_manager unix_io_manager;
 extern io_manager unixfd_io_manager;
 
+/* sparse_io.c */
+extern io_manager sparse_io_manager;
+extern io_manager sparsefd_io_manager;
+
 /* undo_io.c */
 extern io_manager undo_io_manager;
 extern errcode_t set_undo_io_backing_manager(io_manager manager);
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 8ff49ca..c18ea5f 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -209,6 +209,7 @@
 #define EXT2_MKJOURNAL_LAZYINIT	0x0000002 /* don't zero journal inode before use*/
 #define EXT2_MKJOURNAL_NO_MNT_CHECK 0x0000004 /* don't check mount status */
 
+struct blk_alloc_ctx;
 struct opaque_ext2_group_desc;
 
 struct struct_ext2_filsys {
@@ -264,6 +265,8 @@
 	 */
 	errcode_t (*get_alloc_block)(ext2_filsys fs, blk64_t goal,
 				     blk64_t *ret);
+	errcode_t (*get_alloc_block2)(ext2_filsys fs, blk64_t goal,
+				      blk64_t *ret, struct blk_alloc_ctx *ctx);
 	void (*block_alloc_stats)(ext2_filsys fs, blk64_t blk, int inuse);
 
 	/*
@@ -355,6 +358,17 @@
 #define BLOCK_COUNT_TIND	(-3)
 #define BLOCK_COUNT_TRANSLATOR	(-4)
 
+#define BLOCK_ALLOC_UNKNOWN	0
+#define BLOCK_ALLOC_DATA	1
+#define BLOCK_ALLOC_METADATA	2
+
+struct blk_alloc_ctx {
+	ext2_ino_t		ino;
+	struct ext2_inode	*inode;
+	blk64_t			lblk;
+	int			flags;
+};
+
 #if 0
 /*
  * Flags for ext2fs_move_blocks
@@ -588,7 +602,8 @@
 					 EXT4_FEATURE_INCOMPAT_64BIT|\
 					 EXT4_FEATURE_INCOMPAT_INLINE_DATA|\
 					 EXT4_FEATURE_INCOMPAT_ENCRYPT|\
-					 EXT4_FEATURE_INCOMPAT_CSUM_SEED)
+					 EXT4_FEATURE_INCOMPAT_CSUM_SEED|\
+					 EXT4_FEATURE_INCOMPAT_LARGEDIR)
 
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
 					 EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
@@ -662,6 +677,9 @@
 				  ext2fs_block_bitmap map, blk_t *ret);
 extern errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
 				   ext2fs_block_bitmap map, blk64_t *ret);
+extern errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal,
+				   ext2fs_block_bitmap map, blk64_t *ret,
+				   struct blk_alloc_ctx *ctx);
 extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start,
 					blk_t finish, int num,
 					ext2fs_block_bitmap map,
@@ -674,6 +692,10 @@
 				    char *block_buf, blk_t *ret);
 extern errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
 				     char *block_buf, blk64_t *ret);
+extern errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal,
+				     char *block_buf, blk64_t *ret,
+				     struct blk_alloc_ctx *ctx);
+
 extern void ext2fs_set_alloc_block_callback(ext2_filsys fs,
 					    errcode_t (*func)(ext2_filsys fs,
 							      blk64_t goal,
@@ -1927,6 +1949,23 @@
 	return (blk_t) ext2fs_inode_data_blocks2(fs, inode);
 }
 
+/* htree levels for ext4 */
+#define EXT4_HTREE_LEVEL_COMPAT 2
+#define EXT4_HTREE_LEVEL	3
+
+static inline unsigned int ext2_dir_htree_level(ext2_filsys fs)
+{
+	if (ext2fs_has_feature_largedir(fs->super))
+		return EXT4_HTREE_LEVEL;
+
+	return EXT4_HTREE_LEVEL_COMPAT;
+}
+
+_INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks)
+{
+	return blocks * ((fs->blocksize - 8) / sizeof(struct ext2_dx_entry));
+}
+
 /*
  * This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b)
  */
diff --git a/lib/ext2fs/flushb.c b/lib/ext2fs/flushb.c
index 98821fc..fe1d3e7 100644
--- a/lib/ext2fs/flushb.c
+++ b/lib/ext2fs/flushb.c
@@ -58,8 +58,10 @@
 	 * still is a race condition for those kernels, but this
 	 * reduces it greatly.)
 	 */
+#if defined(HAVE_FSYNC)
 	if (fsync (fd) == -1)
 		return errno;
+#endif
 
 	if (flushb) {
 
diff --git a/lib/ext2fs/gen_bitmap.c b/lib/ext2fs/gen_bitmap.c
index 6cd6fe6..d0061b8 100644
--- a/lib/ext2fs/gen_bitmap.c
+++ b/lib/ext2fs/gen_bitmap.c
@@ -564,7 +564,7 @@
 }
 
 int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap,
-				   ino_t inode, int num)
+				   ext2_ino_t inode, int num)
 {
 	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
 	if ((inode < bitmap->start) || (inode+num-1 > bitmap->real_end)) {
diff --git a/lib/ext2fs/jfs_compat.h b/lib/ext2fs/jfs_compat.h
index 75a0596..9137367 100644
--- a/lib/ext2fs/jfs_compat.h
+++ b/lib/ext2fs/jfs_compat.h
@@ -7,7 +7,11 @@
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
+#ifdef HAVE_WINSOCK_H
+#include <winsock.h>
+#else
 #include <arpa/inet.h>
+#endif
 
 #define printk printf
 #define KERN_ERR ""
diff --git a/lib/ext2fs/sparse_io.c b/lib/ext2fs/sparse_io.c
new file mode 100644
index 0000000..a307859
--- /dev/null
+++ b/lib/ext2fs/sparse_io.c
@@ -0,0 +1,541 @@
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#if !defined(ENABLE_LIBSPARSE)
+static errcode_t sparse_open(const char *name EXT2FS_ATTR((unused)),
+			     int flags EXT2FS_ATTR((unused)),
+			     io_channel *channel EXT2FS_ATTR((unused)))
+{
+	return EXT2_ET_UNIMPLEMENTED;
+}
+static errcode_t sparse_close(io_channel channel EXT2FS_ATTR((unused)))
+{
+	return EXT2_ET_UNIMPLEMENTED;
+}
+static struct struct_io_manager struct_sparse_manager = {
+	.magic			= EXT2_ET_MAGIC_IO_MANAGER,
+	.name			= "Android sparse I/O Manager",
+	.open			= sparse_open,
+	.close			= sparse_close,
+};
+static struct struct_io_manager struct_sparsefd_manager = {
+	.magic			= EXT2_ET_MAGIC_IO_MANAGER,
+	.name			= "Android sparse fd I/O Manager",
+	.open			= sparse_open,
+	.close			= sparse_close,
+};
+#else
+#include <sparse/sparse.h>
+
+struct sparse_map {
+	int			fd;
+	char			**blocks;
+	int			block_size;
+	uint64_t		blocks_count;
+	char			*file;
+	struct sparse_file	*sparse_file;
+	io_channel		channel;
+};
+
+struct sparse_io_params {
+	int			fd;
+	char			*file;
+	uint64_t		blocks_count;
+	unsigned int		block_size;
+};
+
+static errcode_t sparse_write_blk(io_channel channel, unsigned long block,
+				  int count, const void *buf);
+
+static void free_sparse_blocks(struct sparse_map *sm)
+{
+	uint64_t i;
+
+	for (i = 0; i < sm->blocks_count; ++i)
+		free(sm->blocks[i]);
+	free(sm->blocks);
+	sm->blocks = NULL;
+}
+
+static int sparse_import_segment(void *priv, const void *data, int len,
+				 unsigned int block, unsigned int nr_blocks)
+{
+	struct sparse_map *sm = priv;
+
+	/* Ignore chunk headers, only write the data */
+	if (!nr_blocks || len % sm->block_size)
+		return 0;
+
+	return sparse_write_blk(sm->channel, block, nr_blocks, data);
+}
+
+static errcode_t io_manager_import_sparse(struct sparse_io_params *params,
+					  struct sparse_map *sm, io_channel io)
+{
+	int fd;
+	errcode_t retval;
+	struct sparse_file *sparse_file;
+
+	if (params->fd < 0) {
+		fd = open(params->file, O_RDONLY);
+		if (fd < 0) {
+			retval = -1;
+			goto err_open;
+		}
+	} else
+		fd = params->fd;
+	sparse_file = sparse_file_import(fd, false, false);
+	if (!sparse_file) {
+		retval = -1;
+		goto err_sparse;
+	}
+
+	sm->block_size = sparse_file_block_size(sparse_file);
+	sm->blocks_count = (sparse_file_len(sparse_file, 0, 0) - 1)
+				/ sm->block_size + 1;
+	sm->blocks = calloc(sm->blocks_count, sizeof(char*));
+	if (!sm->blocks) {
+		retval = -1;
+		goto err_alloc;
+	}
+	io->block_size = sm->block_size;
+
+	retval = sparse_file_foreach_chunk(sparse_file, true, false,
+					   sparse_import_segment, sm);
+
+	if (retval)
+		free_sparse_blocks(sm);
+err_alloc:
+	sparse_file_destroy(sparse_file);
+err_sparse:
+	close(fd);
+err_open:
+	return retval;
+}
+
+static errcode_t io_manager_configure(struct sparse_io_params *params,
+				      int flags, io_channel io)
+{
+	errcode_t retval;
+	uint64_t img_size;
+	struct sparse_map *sm = calloc(1, sizeof(*sm));
+	if (!sm)
+		return EXT2_ET_NO_MEMORY;
+
+	sm->file = params->file;
+	sm->channel = io;
+	io->private_data = sm;
+	retval = io_manager_import_sparse(params, sm, io);
+	if (retval) {
+		if (!params->block_size || !params->blocks_count) {
+			retval = -EINVAL;
+			goto err_params;
+		}
+		sm->block_size = params->block_size;
+		sm->blocks_count = params->blocks_count;
+		sm->blocks = calloc(params->blocks_count, sizeof(void*));
+		if (!sm->blocks) {
+			retval = EXT2_ET_NO_MEMORY;
+			goto err_alloc;
+		}
+	}
+	io->block_size = sm->block_size;
+	img_size = (uint64_t)sm->block_size * sm->blocks_count;
+
+	if (flags & IO_FLAG_RW) {
+		sm->sparse_file = sparse_file_new(sm->block_size, img_size);
+		if (!sm->sparse_file) {
+			retval = EXT2_ET_NO_MEMORY;
+			goto err_alloc;
+		}
+		if (params->fd < 0) {
+			sm->fd = open(params->file, O_CREAT | O_RDWR | O_TRUNC,
+				      0644);
+			if (sm->fd < 0) {
+				retval = errno;
+				goto err_open;
+			}
+		} else
+			sm->fd = params->fd;
+	} else {
+		sm->fd = -1;
+		sm->sparse_file = NULL;
+	}
+	return 0;
+
+err_open:
+	sparse_file_destroy(sm->sparse_file);
+err_alloc:
+	free_sparse_blocks(sm);
+err_params:
+	free(sm);
+	return retval;
+}
+
+static errcode_t sparse_open_channel(struct sparse_io_params *sparse_params,
+				     int flags, io_channel *channel)
+{
+	io_channel io;
+
+	io = calloc(1, sizeof(struct struct_io_channel));
+	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+	io->block_size = 0;
+	io->refcount = 1;
+	*channel = io;
+	return io_manager_configure(sparse_params, flags, io);
+}
+
+static errcode_t read_sparse_argv(const char *name, bool is_fd,
+				  struct sparse_io_params *sparse_params)
+{
+	int ret;
+	sparse_params->fd = -1;
+	sparse_params->block_size = 0;
+	sparse_params->blocks_count = 0;
+
+	sparse_params->file = malloc(strlen(name) + 1);
+	if (!sparse_params->file) {
+		fprintf(stderr, "failed to alloc %zu\n", strlen(name) + 1);
+		return EXT2_ET_NO_MEMORY;
+	}
+
+	if (is_fd) {
+		ret = sscanf(name, "%d:%llu:%u", &sparse_params->fd,
+			     (unsigned long long *)&sparse_params->blocks_count,
+			     &sparse_params->block_size);
+	} else {
+		ret = sscanf(name, "%[^:]%*[:]%llu%*[:]%u", sparse_params->file,
+			     (unsigned long long *)&sparse_params->blocks_count,
+			     &sparse_params->block_size);
+	}
+
+	if (ret < 1) {
+		free(sparse_params->file);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static errcode_t sparse_open(const char *name, int flags, io_channel *channel)
+{
+	errcode_t retval;
+	struct sparse_io_params sparse_params;
+
+	retval = read_sparse_argv(name, false, &sparse_params);
+	if (retval)
+		return EXT2_ET_BAD_DEVICE_NAME;
+
+	retval = sparse_open_channel(&sparse_params, flags, channel);
+	if (retval)
+		return retval;
+	(*channel)->manager = sparse_io_manager;
+
+	return retval;
+}
+
+static errcode_t sparsefd_open(const char *name, int flags, io_channel *channel)
+{
+	errcode_t retval;
+	struct sparse_io_params sparse_params;
+
+	retval = read_sparse_argv(name, true, &sparse_params);
+	if (retval)
+		return EXT2_ET_BAD_DEVICE_NAME;
+
+	retval = sparse_open_channel(&sparse_params, flags, channel);
+	if (retval)
+		return retval;
+	(*channel)->manager = sparsefd_io_manager;
+
+	return retval;
+}
+
+static errcode_t sparse_merge_blocks(struct sparse_map *sm, uint64_t start,
+					uint64_t num)
+{
+	char *buf;
+	uint64_t i;
+	unsigned int block_size = sm->block_size;
+	errcode_t retval = 0;
+
+	buf = calloc(num, block_size);
+	if (!buf) {
+		fprintf(stderr, "failed to alloc %lu\n", num * block_size);
+		return EXT2_ET_NO_MEMORY;
+	}
+
+	for (i = 0; i < num; i++) {
+		memcpy(buf + i * block_size, sm->blocks[start + i] , block_size);
+		free(sm->blocks[start + i]);
+		sm->blocks[start + i] = NULL;
+	}
+
+	/* free_sparse_blocks will release this buf. */
+	sm->blocks[start] = buf;
+
+	retval = sparse_file_add_data(sm->sparse_file, sm->blocks[start],
+					block_size * num, start);
+
+	return retval;
+}
+
+static errcode_t sparse_close_channel(io_channel channel)
+{
+	uint64_t i;
+	errcode_t retval = 0;
+	struct sparse_map *sm = channel->private_data;
+
+	if (sm->sparse_file) {
+		int64_t chunk_start = (sm->blocks[0] == NULL) ? -1 : 0;
+		for (i = 0; i < sm->blocks_count; ++i) {
+			if (!sm->blocks[i] && chunk_start != -1) {
+				retval = sparse_merge_blocks(sm, chunk_start, i - chunk_start);
+				chunk_start = -1;
+			} else if (sm->blocks[i] && chunk_start == -1) {
+				chunk_start = i;
+			}
+			if (retval)
+				goto ret;
+		}
+		if (chunk_start != -1) {
+			retval = sparse_merge_blocks(sm, chunk_start,
+							sm->blocks_count - chunk_start);
+			if (retval)
+				goto ret;
+		}
+		retval = sparse_file_write(sm->sparse_file, sm->fd,
+					   /*gzip*/0, /*sparse*/1, /*crc*/0);
+	}
+
+ret:
+	if (sm->sparse_file)
+		sparse_file_destroy(sm->sparse_file);
+	free_sparse_blocks(sm);
+	free(sm->file);
+	free(sm);
+	free(channel);
+	return retval;
+}
+
+static errcode_t sparse_close(io_channel channel)
+{
+	errcode_t retval;
+	struct sparse_map *sm = channel->private_data;
+	int fd = sm->fd;
+
+	retval = sparse_close_channel(channel);
+	if (fd >= 0)
+		close(fd);
+
+	return retval;
+}
+
+static errcode_t sparse_set_blksize(io_channel channel, int blksize)
+{
+	channel->block_size = blksize;
+	return 0;
+}
+
+static blk64_t block_to_sparse_block(blk64_t block, blk64_t *offset,
+			       io_channel channel, struct sparse_map *sm)
+{
+	int ratio;
+	blk64_t ret = block;
+
+	ratio = sm->block_size / channel->block_size;
+	ret /= ratio;
+	*offset = (block % ratio) * channel->block_size;
+
+	return ret;
+}
+
+static errcode_t check_block_size(io_channel channel, struct sparse_map *sm)
+{
+	if (sm->block_size >= channel->block_size)
+		return 0;
+	return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+}
+
+static errcode_t sparse_read_blk64(io_channel channel, blk64_t block,
+				   int count, void *buf)
+{
+	int i;
+	char *out = buf;
+	blk64_t offset = 0, cur_block;
+	struct sparse_map *sm = channel->private_data;
+
+	if (check_block_size(channel, sm))
+		return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+
+	if (count < 0) { //partial read
+		count = -count;
+		cur_block = block_to_sparse_block(block, &offset, channel, sm);
+		if (sm->blocks[cur_block])
+			memcpy(out, (sm->blocks[cur_block]) + offset, count);
+		else
+			memset(out, 0, count);
+	} else {
+		for (i = 0; i < count; ++i) {
+			cur_block = block_to_sparse_block(block + i, &offset,
+						    channel, sm);
+			if (sm->blocks[cur_block])
+				memcpy(out + (i * channel->block_size),
+				       sm->blocks[cur_block] + offset,
+				       channel->block_size);
+			else if (sm->blocks)
+				memset(out + (i * channel->block_size), 0,
+				       channel->block_size);
+		}
+	}
+	return 0;
+}
+
+static errcode_t sparse_read_blk(io_channel channel, unsigned long block,
+				 int count, void *buf)
+{
+	return sparse_read_blk64(channel, block, count, buf);
+}
+
+static errcode_t sparse_write_blk64(io_channel channel, blk64_t block,
+				    int count, const void *buf)
+{
+	int i;
+	blk64_t offset = 0, cur_block;
+	const char *in = buf;
+	struct sparse_map *sm = channel->private_data;
+
+	if (check_block_size(channel, sm))
+		return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+
+	if (count < 0) { //partial write
+		count = -count;
+		cur_block = block_to_sparse_block(block, &offset, channel,
+						  sm);
+		if (!sm->blocks[cur_block]) {
+			sm->blocks[cur_block] = calloc(1, sm->block_size);
+			if (!sm->blocks[cur_block])
+				return EXT2_ET_NO_MEMORY;
+		}
+		memcpy(sm->blocks[cur_block] + offset, in, count);
+	} else {
+		for (i = 0; i < count; ++i) {
+			if (block + i >= sm->blocks_count)
+				return 0;
+			cur_block = block_to_sparse_block(block + i, &offset,
+						    channel, sm);
+			if (!sm->blocks[cur_block]) {
+				sm->blocks[cur_block] =
+					calloc(1, sm->block_size);
+				if (!sm->blocks[cur_block])
+					return EXT2_ET_NO_MEMORY;
+			}
+			memcpy(sm->blocks[cur_block] + offset,
+			       in + (i * channel->block_size),
+			       channel->block_size);
+		}
+	}
+	return 0;
+}
+
+static errcode_t sparse_write_blk(io_channel channel, unsigned long block,
+				  int count, const void *buf)
+{
+	return sparse_write_blk64(channel, block, count, buf);
+}
+
+static errcode_t sparse_discard(io_channel channel __attribute__((unused)),
+				blk64_t blk, unsigned long long count)
+{
+	blk64_t cur_block, offset;
+	struct sparse_map *sm = channel->private_data;
+
+	if (check_block_size(channel, sm))
+		return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+
+	for (unsigned long long i = 0; i < count; ++i) {
+		if (blk + i >= sm->blocks_count)
+			return 0;
+		cur_block = block_to_sparse_block(blk + i, &offset, channel,
+						  sm);
+		if (!sm->blocks[cur_block])
+			continue;
+		free(sm->blocks[cur_block]);
+		sm->blocks[cur_block] = NULL;
+	}
+	return 0;
+}
+
+static errcode_t sparse_zeroout(io_channel channel, blk64_t blk,
+				unsigned long long count)
+{
+	return sparse_discard(channel, blk, count);
+}
+
+static errcode_t sparse_flush(io_channel channel __attribute__((unused)))
+{
+	return 0;
+}
+
+static errcode_t sparse_set_option(io_channel channel __attribute__((unused)),
+                                   const char *option __attribute__((unused)),
+                                   const char *arg __attribute__((unused)))
+{
+	return 0;
+}
+
+static errcode_t sparse_cache_readahead(
+			io_channel channel __attribute__((unused)),
+			blk64_t blk __attribute__((unused)),
+			unsigned long long count __attribute__((unused)))
+{
+	return 0;
+}
+
+static struct struct_io_manager struct_sparse_manager = {
+	.magic			= EXT2_ET_MAGIC_IO_MANAGER,
+	.name			= "Android sparse I/O Manager",
+	.open			= sparse_open,
+	.close			= sparse_close,
+	.set_blksize		= sparse_set_blksize,
+	.read_blk		= sparse_read_blk,
+	.write_blk		= sparse_write_blk,
+	.flush			= sparse_flush,
+	.write_byte		= NULL,
+	.set_option		= sparse_set_option,
+	.get_stats		= NULL,
+	.read_blk64		= sparse_read_blk64,
+	.write_blk64		= sparse_write_blk64,
+	.discard		= sparse_discard,
+	.cache_readahead	= sparse_cache_readahead,
+	.zeroout		= sparse_zeroout,
+};
+
+static struct struct_io_manager struct_sparsefd_manager = {
+	.magic			= EXT2_ET_MAGIC_IO_MANAGER,
+	.name			= "Android sparse fd I/O Manager",
+	.open			= sparsefd_open,
+	.close			= sparse_close,
+	.set_blksize		= sparse_set_blksize,
+	.read_blk		= sparse_read_blk,
+	.write_blk		= sparse_write_blk,
+	.flush			= sparse_flush,
+	.write_byte		= NULL,
+	.set_option		= sparse_set_option,
+	.get_stats		= NULL,
+	.read_blk64		= sparse_read_blk64,
+	.write_blk64		= sparse_write_blk64,
+	.discard		= sparse_discard,
+	.cache_readahead	= sparse_cache_readahead,
+	.zeroout		= sparse_zeroout,
+};
+
+#endif
+
+io_manager sparse_io_manager = &struct_sparse_manager;
+io_manager sparsefd_io_manager = &struct_sparsefd_manager;
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index d63fc55..2d05ee7 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -247,7 +247,7 @@
 		has_extents = 1;
 	if (!hostorder && (t->i_flags & EXT4_INLINE_DATA_FL))
 		has_inline_data = 1;
-	t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
+	t->i_size_high = ext2fs_swab32(f->i_size_high);
 	/*
 	 * Extent data and inline data are swapped on access, not here
 	 */
diff --git a/lib/ext2fs/test_io.c b/lib/ext2fs/test_io.c
index f7c50d1..ee828be 100644
--- a/lib/ext2fs/test_io.c
+++ b/lib/ext2fs/test_io.c
@@ -146,8 +146,10 @@
 
 static char *safe_getenv(const char *arg)
 {
+#if !defined(_WIN32)
 	if ((getuid() != geteuid()) || (getgid() != getegid()))
 		return NULL;
+#endif
 #if HAVE_PRCTL
 	if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
 		return NULL;
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index f4e6148..dc2a2e9 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -718,6 +718,7 @@
 	int fd_flags;
 
 	fd = atoi(str_fd);
+#if defined(HAVE_FCNTL)
 	fd_flags = fcntl(fd, F_GETFD);
 	if (fd_flags == -1)
 		return -EBADF;
@@ -731,6 +732,7 @@
 	if (fd_flags & O_DIRECT)
 		flags |= IO_FLAG_DIRECT_IO;
 #endif
+#endif  /* HAVE_FCNTL */
 
 	return unix_open_channel(str_fd, fd, flags, channel, unixfd_io_manager);
 }
@@ -1030,8 +1032,10 @@
 #ifndef NO_IO_CACHE
 	retval = flush_cached_blocks(channel, data, 0);
 #endif
+#ifdef HAVE_FSYNC
 	if (!retval && fsync(data->dev) != 0)
 		return errno;
+#endif
 	return retval;
 }
 
diff --git a/lib/ss/Android.bp b/lib/ss/Android.bp
new file mode 100644
index 0000000..06925d7
--- /dev/null
+++ b/lib/ss/Android.bp
@@ -0,0 +1,33 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_ss",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "ss_err.c",
+        "std_rqs.c",
+        "invocation.c",
+        "help.c",
+        "execute_cmd.c",
+        "listen.c",
+        "parse.c",
+        "error.c",
+        "prompt.c",
+        "request_tbl.c",
+        "list_rqs.c",
+        "pager.c",
+        "requests.c",
+        "data.c",
+        "get_readline.c",
+    ],
+    shared_libs: ["libext2_com_err"],
+    cflags: [
+        "-W",
+        "-Wall",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/ss/Android.mk b/lib/ss/Android.mk
deleted file mode 100644
index c19accc..0000000
--- a/lib/ss/Android.mk
+++ /dev/null
@@ -1,60 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_ss_src_files := \
-	ss_err.c \
-	std_rqs.c \
-	invocation.c help.c \
-	execute_cmd.c \
-	listen.c \
-	parse.c \
-	error.c \
-	prompt.c \
-	request_tbl.c \
-	list_rqs.c \
-	pager.c \
-	requests.c \
-	data.c \
-	get_readline.c
-
-libext2_ss_c_includes := external/e2fsprogs/lib
-
-libext2_ss_cflags := -O2 -g -W -Wall
-
-libext2_ss_shared_libraries := \
-	libext2_com_err
-
-libext2_ss_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_ss_src_files)
-LOCAL_C_INCLUDES := $(libext2_ss_c_includes)
-LOCAL_CFLAGS := $(libext2_ss_cflags)
-LOCAL_SHARED_LIBRARIES := $(libext2_ss_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_ss_system_shared_libraries)
-LOCAL_MODULE := libext2_ss
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_ss_src_files)
-LOCAL_C_INCLUDES := $(libext2_ss_c_includes)
-LOCAL_CFLAGS := $(libext2_ss_cflags)
-LOCAL_STATIC_LIBRARIES := libc
-LOCAL_MODULE := libext2_ss
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_ss_src_files)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2_ss_shared_libraries))
-LOCAL_C_INCLUDES := $(libext2_ss_c_includes)
-LOCAL_CFLAGS := $(libext2_ss_cflags)
-LOCAL_MODULE := libext2_ss-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/lib/ss/Makefile.in b/lib/ss/Makefile.in
index f4953f0..ee18dc8 100644
--- a/lib/ss/Makefile.in
+++ b/lib/ss/Makefile.in
@@ -163,7 +163,7 @@
 	$(Q) $(CC) -o $@ test_ss.o test_cmd.o $(ALL_CFLAGS) $(ALL_LDFLAGS) \
 		$(LIBSS) $(LIBCOM_ERR) $(SYSLIBS)
 
-check:: all test_ss
+fullcheck check:: all test_ss
 	$(E) "	RUN TEST test_ss"
 	-@($(TESTENV) ./test_ss -f $(srcdir)/test_script > test_out 2>&1; exit 0)
 	$(Q) if diff test_out $(srcdir)/test_script_expected > test.diff; then \
diff --git a/lib/support/Android.bp b/lib/support/Android.bp
new file mode 100644
index 0000000..24414a4
--- /dev/null
+++ b/lib/support/Android.bp
@@ -0,0 +1,54 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_quota",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "dict.c",
+        "mkquota.c",
+        "parse_qtype.c",
+        "plausible.c",
+        "profile.c",
+        "profile_helpers.c",
+        "prof_err.c",
+        "quotaio.c",
+        "quotaio_tree.c",
+        "quotaio_v2.c",
+    ],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libext2_blkid",
+    ],
+
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-macro-redefined",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
+
+cc_library_shared {
+    name: "libext2_profile",
+    host_supported: true,
+    unique_host_soname: true,
+
+    srcs: [
+        "prof_err.c",
+        "profile.c",
+    ],
+    cflags = [
+        "-W",
+        "-Wall",
+    ],
+    shared_libs: ["libext2_com_err"],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/support/Android.mk b/lib/support/Android.mk
deleted file mode 100644
index fefd058..0000000
--- a/lib/support/Android.mk
+++ /dev/null
@@ -1,95 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_quota_src_files := \
-	dict.c \
-	mkquota.c \
-	parse_qtype.c \
-	plausible.c \
-	profile.c \
-	profile_helpers.c \
-	prof_err.c \
-	quotaio.c \
-	quotaio_tree.c \
-	quotaio_v2.c
-
-libext2_quota_c_includes := external/e2fsprogs/lib
-
-libext2_quota_cflags := -O2 -g -W -Wall
-
-libext2_quota_shared_libraries := libext2fs libext2_com_err libext2_blkid
-
-libext2_quota_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_quota_src_files)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_quota_system_shared_libraries)
-LOCAL_C_INCLUDES := $(libext2_quota_c_includes)
-LOCAL_CFLAGS := $(libext2_quota_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := libc $(libext2_quota_shared_libraries)
-LOCAL_MODULE := libext2_quota
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-libext2_quota_static_libraries := libext2fs libext2_com_err
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_quota_src_files)
-LOCAL_C_INCLUDES := $(libext2_quota_c_includes)
-LOCAL_CFLAGS := $(libext2_quota_cflags)
-LOCAL_STATIC_LIBRARIES := libc $(libext2_quota_static_libraries)
-LOCAL_MODULE := libext2_quota
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_quota_src_files)
-LOCAL_C_INCLUDES := $(libext2_quota_c_includes)
-LOCAL_CFLAGS := $(libext2_quota_cflags)
-LOCAL_MODULE := libext2_quota-host
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2_quota_shared_libraries))
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-libext2_profile_src_files :=  \
-       prof_err.c \
-       profile.c
-
-libext2_profile_shared_libraries := \
-       libext2_com_err
-
-libext2_profile_system_shared_libraries := libc
-
-libext2_profile_c_includes := external/e2fsprogs/lib
-
-libext2_profile_cflags := -O2 -g -W -Wall
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_profile_src_files)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_profile_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(libext2_profile_shared_libraries)
-LOCAL_C_INCLUDES := $(libext2_profile_c_includes)
-LOCAL_CFLAGS := $(libext2_profile_cflags)
-LOCAL_MODULE := libext2_profile
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_profile_src_files)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(libext2_profile_shared_libraries))
-LOCAL_C_INCLUDES := $(libext2_profile_c_includes)
-LOCAL_CFLAGS := $(libext2_profile_cflags)
-LOCAL_MODULE := libext2_profile-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/lib/support/Makefile.in b/lib/support/Makefile.in
index d5a6f26..40206b7 100644
--- a/lib/support/Makefile.in
+++ b/lib/support/Makefile.in
@@ -79,7 +79,7 @@
 		../libsupport.a ../libsupport_p.a $(SMANPAGES) \
 		prof_err.c prof_err.h test_profile test_cstring
 
-#check:: tst_uuid
+#fullcheck check:: tst_uuid
 #	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid
 
 mostlyclean:: clean
diff --git a/lib/uuid/Android.bp b/lib/uuid/Android.bp
new file mode 100644
index 0000000..d173788
--- /dev/null
+++ b/lib/uuid/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library {
+    name: "libext2_uuid",
+    host_supported: true,
+    unique_host_soname: true,
+    srcs: [
+        "clear.c",
+        "compare.c",
+        "copy.c",
+        "gen_uuid.c",
+        "isnull.c",
+        "pack.c",
+        "parse.c",
+        "unpack.c",
+        "unparse.c",
+        "uuid_time.c",
+    ],
+    cflags: [
+        "-W",
+        "-Wall",
+        "-Wno-unused-function",
+        "-Wno-unused-parameter",
+    ],
+
+    header_libs: ["libext2-headers"],
+    export_include_dirs: ["."],
+    export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/uuid/Android.mk b/lib/uuid/Android.mk
deleted file mode 100644
index 91d6836..0000000
--- a/lib/uuid/Android.mk
+++ /dev/null
@@ -1,70 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-libext2_uuid_src_files := \
-	clear.c \
-	compare.c \
-	copy.c \
-	gen_uuid.c \
-	isnull.c \
-	pack.c \
-	parse.c \
-	unpack.c \
-	unparse.c \
-	uuid_time.c
-
-
-libext2_uuid_c_includes := external/e2fsprogs/lib
-
-libext2_uuid_cflags := -O2 -g -W -Wall \
-	-Wno-unused-function \
-	-Wno-unused-parameter
-
-libext2_uuid_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_uuid_src_files)
-LOCAL_C_INCLUDES := $(libext2_uuid_c_includes)
-LOCAL_CFLAGS := $(libext2_uuid_cflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) $(LOCAL_PATH)/..
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_uuid_system_shared_libraries)
-LOCAL_MODULE := libext2_uuid
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_uuid_src_files)
-LOCAL_C_INCLUDES := $(libext2_uuid_c_includes)
-LOCAL_CFLAGS := $(libext2_uuid_cflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_MODULE := libext2_uuid-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_uuid_src_files)
-LOCAL_C_INCLUDES := $(libext2_uuid_c_includes)
-LOCAL_CFLAGS := $(libext2_uuid_cflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_STATIC_LIBRARIES := libc
-LOCAL_MODULE := libext2_uuid_static
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(libext2_uuid_src_files)
-LOCAL_C_INCLUDES := $(libext2_uuid_c_includes)
-LOCAL_CFLAGS := $(libext2_uuid_cflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_MODULE := libext2_uuid-host
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/lib/uuid/Makefile.in b/lib/uuid/Makefile.in
index a298144..4b44418 100644
--- a/lib/uuid/Makefile.in
+++ b/lib/uuid/Makefile.in
@@ -171,7 +171,7 @@
 		../libuuid.a ../libuuid_p.a tst_uuid uuid_time \
 		uuid.pc uuid_types.h $(SMANPAGES)
 
-check:: tst_uuid
+fullcheck check:: tst_uuid
 	LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid
 
 mostlyclean:: clean
diff --git a/misc/Android.bp b/misc/Android.bp
new file mode 100644
index 0000000..ae7d9b6
--- /dev/null
+++ b/misc/Android.bp
@@ -0,0 +1,221 @@
+// Copyright 2017 The Android Open Source Project
+
+// Library used to export files from this directory to other programs in this
+// project.
+cc_library {
+    name: "libext2_misc",
+    host_supported: true,
+
+    srcs: [
+        "create_inode.c",
+    ],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2_quota",
+        "libext2fs",
+    ],
+    system_shared_libs: ["libc"],
+    export_include_dirs: ["."],
+}
+
+//########################################################################
+// Build mke2fs
+
+cc_binary {
+    name: "mke2fs",
+    host_supported: true,
+
+    srcs: [
+        "mke2fs.c",
+        "util.c",
+        "mk_hugefiles.c",
+        "default_profile.c",
+    ],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_blkid",
+        "libext2_misc",
+        "libext2_uuid",
+        "libext2_quota",
+        "libext2_com_err",
+        "libext2_e2p",
+    ],
+    system_shared_libs: ["libc"],
+    include_dirs: ["external/e2fsprogs/e2fsck"],
+}
+
+//##########################################################################
+// Build tune2fs
+
+cc_defaults {
+    name: "tune2fs-defaults",
+    srcs: [
+        "tune2fs.c",
+        "util.c",
+    ],
+    cflags: [
+        "-W",
+        "-Wall",
+        "-DNO_RECOVERY",
+        "-Wno-macro-redefined",
+    ],
+    include_dirs: ["external/e2fsprogs/e2fsck"],
+}
+
+tune2fs_libs = [
+    "libext2_com_err",
+    "libext2_blkid",
+    "libext2_quota",
+    "libext2_uuid",
+    "libext2_e2p",
+    "libext2fs",
+]
+
+cc_binary {
+    name: "tune2fs",
+    host_supported: true,
+    defaults: ["tune2fs-defaults"],
+
+    shared_libs: tune2fs_libs,
+    system_shared_libs: ["libc"],
+}
+
+cc_binary {
+    name: "tune2fs_static",
+    static_executable: true,
+    defaults: ["tune2fs-defaults"],
+
+    static_libs: tune2fs_libs + ["libc"],
+}
+
+cc_library_static {
+    name: "libtune2fs",
+    defaults: ["tune2fs-defaults"],
+
+    cflags: ["-DBUILD_AS_LIB"],
+    static_libs: tune2fs_libs,
+}
+
+//########################################################################
+// Build badblocks
+
+cc_binary {
+    name: "badblocks",
+    host_supported: true,
+
+    srcs: ["badblocks.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libext2_uuid",
+        "libext2_blkid",
+        "libext2_e2p",
+    ],
+    system_shared_libs: ["libc"],
+}
+
+//########################################################################
+// Build chattr
+
+cc_binary {
+    name: "chattr",
+    host_supported: true,
+
+    srcs: ["chattr.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2_com_err",
+        "libext2_e2p",
+    ],
+    system_shared_libs: ["libc"],
+}
+
+//########################################################################
+// Build lsattr
+
+cc_defaults {
+    name: "lsattr-defaults",
+    srcs: ["lsattr.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+}
+
+lsattr_libs = [
+    "libext2_com_err",
+    "libext2_e2p",
+]
+
+cc_binary {
+    name: "lsattr",
+    host_supported: true,
+    defaults: ["lsattr-defaults"],
+
+    shared_libs: lsattr_libs,
+    system_shared_libs: ["libc"],
+}
+
+cc_binary {
+    name: "lsattr_static",
+    static_executable: true,
+    defaults: ["lsattr-defaults"],
+
+    static_libs: lsattr_libs + ["libc"],
+}
+
+//########################################################################
+// Build blkid
+
+cc_binary {
+    name: "blkid",
+
+    srcs: ["blkid.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_blkid",
+        "libext2_com_err",
+        "libext2_e2p",
+    ],
+    system_shared_libs: ["libc"],
+}
+
+//########################################################################
+// Build e4crypt
+
+cc_binary {
+    name: "e4crypt",
+    host_supported: true,
+
+    srcs: ["e4crypt.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_uuid",
+    ],
+    system_shared_libs: ["libc"],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+//##########################################################################
+// Build e2image
+
+cc_binary {
+    name: "e2image",
+    host_supported: true,
+
+    srcs: ["e2image.c"],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_blkid",
+        "libext2_com_err",
+        "libext2_quota",
+    ],
+    system_shared_libs: ["libc"],
+}
diff --git a/misc/Android.mk b/misc/Android.mk
deleted file mode 100644
index d960737..0000000
--- a/misc/Android.mk
+++ /dev/null
@@ -1,390 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-#########################################################################
-# Build mke2fs
-mke2fs_src_files := \
-	mke2fs.c \
-	util.c \
-	mk_hugefiles.c \
-	default_profile.c \
-	create_inode.c
-
-mke2fs_c_includes := \
-	external/e2fsprogs/e2fsck
-
-mke2fs_cflags := -O2 -g -W -Wall
-
-mke2fs_shared_libraries := \
-	libext2fs \
-	libext2_blkid \
-	libext2_uuid \
-	libext2_quota \
-	libext2_com_err \
-	libext2_e2p
-
-mke2fs_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(mke2fs_src_files)
-LOCAL_C_INCLUDES := $(mke2fs_c_includes)
-LOCAL_CFLAGS := $(mke2fs_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(mke2fs_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(mke2fs_shared_libraries)
-LOCAL_MODULE := mke2fs
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(mke2fs_src_files)
-LOCAL_C_INCLUDES := $(mke2fs_c_includes)
-LOCAL_CFLAGS := $(mke2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(mke2fs_shared_libraries))
-LOCAL_MODULE := mke2fs_host
-LOCAL_MODULE_STEM := mke2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-###########################################################################
-# Build tune2fs
-#
-tune2fs_src_files := \
-	tune2fs.c \
-	util.c
-
-tune2fs_c_includes := \
-	external/e2fsprogs/e2fsck
-
-tune2fs_cflags := -O2 -g -W -Wall -DNO_RECOVERY
-
-tune2fs_shared_libraries := \
-	libext2fs \
-	libext2_com_err \
-	libext2_blkid \
-	libext2_quota \
-	libext2_uuid \
-	libext2_e2p
-
-tune2fs_system_shared_libraries := libc
-
-
-tune2fs_static_libraries := \
-	libext2_com_err \
-	libext2_blkid \
-	libext2_quota \
-	libext2_uuid_static \
-	libext2_e2p \
-	libext2fs
-
-tune2fs_system_static_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(tune2fs_src_files)
-LOCAL_C_INCLUDES := $(tune2fs_c_includes)
-LOCAL_CFLAGS := $(tune2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(tune2fs_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(tune2fs_system_shared_libraries)
-LOCAL_MODULE := tune2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(tune2fs_src_files)
-LOCAL_C_INCLUDES := $(tune2fs_c_includes)
-LOCAL_CFLAGS := $(tune2fs_cflags)
-LOCAL_STATIC_LIBRARIES := $(tune2fs_static_libraries) $(tune2fs_system_static_libraries)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE := tune2fs_static
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(tune2fs_src_files)
-LOCAL_C_INCLUDES := $(tune2fs_c_includes)
-LOCAL_CFLAGS := $(tune2fs_cflags) -DBUILD_AS_LIB
-LOCAL_STATIC_LIBRARIES := $(tune2fs_static_libraries) $(tune2fs_system_static_libraries)
-LOCAL_MODULE := libtune2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(tune2fs_src_files)
-LOCAL_C_INCLUDES := $(tune2fs_c_includes)
-LOCAL_CFLAGS := $(tune2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(tune2fs_shared_libraries))
-LOCAL_MODULE := tune2fs_host
-LOCAL_MODULE_STEM := tune2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build badblocks
-#
-include $(CLEAR_VARS)
-
-badblocks_src_files := \
-	badblocks.c
-
-badblocks_c_includes :=
-
-badblocks_cflags := -O2 -g -W -Wall
-
-badblocks_shared_libraries := \
-	libext2fs \
-	libext2_com_err \
-	libext2_uuid \
-	libext2_blkid \
-	libext2_e2p
-
-badblocks_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(badblocks_src_files)
-LOCAL_C_INCLUDES := $(badblocks_c_includes)
-LOCAL_CFLAGS := $(badblocks_cflags)
-LOCAL_SHARED_LIBRARIES := $(badblocks_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(badblocks_system_shared_libraries)
-LOCAL_MODULE := badblocks
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(badblocks_src_files)
-LOCAL_C_INCLUDES := $(badblocks_c_includes)
-LOCAL_CFLAGS := $(badblocks_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(badblocks_shared_libraries))
-LOCAL_MODULE := badblocks_host
-LOCAL_MODULE_STEM := badblocks
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build chattr
-#
-include $(CLEAR_VARS)
-
-chattr_src_files := \
-	chattr.c
-
-chattr_c_includes := \
-	external/e2fsprogs/lib
-
-chattr_cflags := -O2 -g -W -Wall
-
-chattr_shared_libraries := \
-	libext2_com_err \
-	libext2_e2p
-
-chattr_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(chattr_src_files)
-LOCAL_C_INCLUDES := $(chattr_c_includes)
-LOCAL_CFLAGS := $(chattr_cflags)
-LOCAL_SHARED_LIBRARIES := $(chattr_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(chattr_system_shared_libraries)
-LOCAL_MODULE := chattr
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(chattr_src_files)
-LOCAL_C_INCLUDES := $(chattr_c_includes)
-LOCAL_CFLAGS := $(chattr_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(chattr_shared_libraries))
-LOCAL_MODULE := chattr_host
-LOCAL_MODULE_STEM := chattr
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build lsattr
-#
-include $(CLEAR_VARS)
-
-lsattr_src_files := \
-	lsattr.c
-
-lsattr_c_includes := \
-	external/e2fsprogs/lib
-
-lsattr_cflags := -O2 -g -W -Wall
-
-lsattr_shared_libraries := \
-	libext2_com_err \
-	libext2_e2p
-
-lsattr_system_shared_libraries := libc
-
-lsattr_static_libraries := \
-	libext2_com_err \
-	libext2_e2p
-
-lsattr_system_static_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(lsattr_src_files)
-LOCAL_C_INCLUDES := $(lsattr_c_includes)
-LOCAL_CFLAGS := $(lsattr_cflags)
-LOCAL_SHARED_LIBRARIES := $(lsattr_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(lsattr_system_shared_libraries)
-LOCAL_MODULE := lsattr
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(lsattr_src_files)
-LOCAL_C_INCLUDES := $(lsattr_c_includes)
-LOCAL_CFLAGS := $(lsattr_cflags)
-LOCAL_STATIC_LIBRARIES := $(lsattr_static_libraries) $(lsattr_system_static_libraries)
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE := lsattr_static
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(lsattr_src_files)
-LOCAL_C_INCLUDES := $(lsattr_c_includes)
-LOCAL_CFLAGS := $(lsattr_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(lsattr_shared_libraries))
-LOCAL_MODULE := lsattr_host
-LOCAL_MODULE_STEM := lsattr
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
-#########################################################################
-# Build blkid
-#
-include $(CLEAR_VARS)
-
-blkid_src_files := \
-    blkid.c
-
-blkid_c_includes :=
-
-blkid_cflags := -O2 -g -W -Wall
-
-blkid_shared_libraries := \
-    libext2fs \
-    libext2_blkid \
-    libext2_com_err \
-    libext2_e2p
-
-blkid_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(blkid_src_files)
-LOCAL_C_INCLUDES := $(blkid_c_includes)
-LOCAL_CFLAGS := $(blkid_cflags)
-LOCAL_SHARED_LIBRARIES := $(blkid_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(blkid_system_shared_libraries)
-LOCAL_MODULE := blkid
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-#########################################################################
-# Build e4crypt
-e4crypt_src_files := e4crypt.c
-
-e4crypt_c_includes := \
-	external/e2fsprogs/lib
-
-e4crypt_cflags := -O2 -g -W -Wall
-
-e4crypt_shared_libraries := libext2fs libext2_uuid
-
-e4crypt_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e4crypt_src_files)
-LOCAL_C_INCLUDES := $(e4crypt_c_includes)
-LOCAL_CFLAGS := $(e4crypt_cflags)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(e4crypt_system_shared_libraries)
-LOCAL_SHARED_LIBRARIES := $(e4crypt_shared_libraries)
-LOCAL_MODULE := e4crypt
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e4crypt_src_files)
-LOCAL_C_INCLUDES := $(e4crypt_c_includes)
-LOCAL_CFLAGS := $(e4crypt_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(e4crypt_shared_libraries))
-LOCAL_MODULE := e4crypt_host
-LOCAL_MODULE_STEM := e4crypt
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_HOST_OS := linux
-
-include $(BUILD_HOST_EXECUTABLE)
-
-###########################################################################
-# Build e2image
-#
-e2image_src_files := \
-	e2image.c
-
-e2image_c_includes := \
-	external/e2fsprogs/lib
-
-e2image_cflags := -O2 -g -W -Wall
-
-e2image_shared_libraries := \
-	libext2fs \
-	libext2_blkid \
-	libext2_com_err \
-	libext2_quota
-
-e2image_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2image_src_files)
-LOCAL_C_INCLUDES := $(e2image_c_includes)
-mke2fs_c_includesLOCAL_CFLAGS := $(e2image_cflags)
-LOCAL_SHARED_LIBRARIES := $(e2image_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(e2image_system_shared_libraries)
-LOCAL_MODULE := e2image
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(e2image_src_files)
-LOCAL_C_INCLUDES := $(e2image_c_includes)
-LOCAL_CFLAGS := $(e2image_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(e2image_shared_libraries))
-LOCAL_MODULE := e2image_host
-LOCAL_MODULE_STEM := e2image
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
-
diff --git a/misc/Makefile.in b/misc/Makefile.in
index 467c15d..d08859d 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -252,7 +252,7 @@
 	$(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(srcdir)/base_device.c \
 		-DDEBUG -o base_device $(SYSLIBS)
 
-check:: base_device
+fullcheck check:: base_device
 	./base_device < $(srcdir)/base_device.tst > base_device.out
 	cmp $(srcdir)/base_device.tst base_device.out
 
diff --git a/misc/create_inode.c b/misc/create_inode.c
index 8ce3faf..8f7445d 100644
--- a/misc/create_inode.c
+++ b/misc/create_inode.c
@@ -683,10 +683,31 @@
 	return retval;
 }
 
+struct file_info {
+	char *path;
+	size_t path_len;
+	size_t path_max_len;
+};
+
+static errcode_t path_append(struct file_info *target, const char *file)
+{
+	if (strlen(file) + target->path_len + 1 > target->path_max_len) {
+		target->path_max_len *= 2;
+		target->path = realloc(target->path, target->path_max_len);
+		if (!target->path)
+			return EXT2_ET_NO_MEMORY;
+	}
+	target->path_len += sprintf(target->path + target->path_len, "/%s",
+				    file);
+	return 0;
+}
+
 /* Copy files from source_dir to fs */
 static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 			       const char *source_dir, ext2_ino_t root,
-			       struct hdlinks_s *hdlinks)
+			       struct hdlinks_s *hdlinks,
+			       struct file_info *target,
+			       struct fs_ops_callbacks *fs_callbacks)
 {
 	const char	*name;
 	DIR		*dh;
@@ -698,6 +719,7 @@
 	errcode_t	retval = 0;
 	int		read_cnt;
 	int		hdlink;
+	size_t		cur_dir_path_len;
 
 	if (chdir(source_dir) < 0) {
 		retval = errno;
@@ -745,6 +767,19 @@
 				save_inode = 1;
 		}
 
+		cur_dir_path_len = target->path_len;
+		retval = path_append(target, name);
+		if (retval)
+			return retval;
+
+		if (fs_callbacks && fs_callbacks->create_new_inode) {
+			retval = fs_callbacks->create_new_inode(fs,
+				target->path, name, parent_ino, root,
+				st.st_mode & S_IFMT);
+			if (retval)
+				goto out;
+		}
+
 		switch(st.st_mode & S_IFMT) {
 		case S_IFCHR:
 		case S_IFBLK:
@@ -822,7 +857,8 @@
 					goto out;
 			}
 			/* Populate the dir recursively*/
-			retval = __populate_fs(fs, ino, name, root, hdlinks);
+			retval = __populate_fs(fs, ino, name, root, hdlinks,
+					       target, fs_callbacks);
 			if (retval)
 				goto out;
 			if (chdir("..")) {
@@ -858,6 +894,14 @@
 			goto out;
 		}
 
+		if (fs_callbacks && fs_callbacks->end_create_new_inode) {
+			retval = fs_callbacks->end_create_new_inode(fs,
+				target->path, name, parent_ino, root,
+				st.st_mode & S_IFMT);
+			if (retval)
+				goto out;
+		}
+
 		/* Save the hardlink ino */
 		if (save_inode) {
 			/*
@@ -883,6 +927,8 @@
 			hdlinks->hdl[hdlinks->count].dst_ino = ino;
 			hdlinks->count++;
 		}
+		target->path_len = cur_dir_path_len;
+		target->path[target->path_len] = 0;
 	}
 
 out:
@@ -890,9 +936,11 @@
 	return retval;
 }
 
-errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
-		      const char *source_dir, ext2_ino_t root)
+errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
+		       const char *source_dir, ext2_ino_t root,
+		       struct fs_ops_callbacks *fs_callbacks)
 {
+	struct file_info file_info;
 	struct hdlinks_s hdlinks;
 	errcode_t retval;
 
@@ -910,8 +958,20 @@
 		return retval;
 	}
 
-	retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks);
+	file_info.path_len = 0;
+	file_info.path_max_len = 255;
+	file_info.path = calloc(file_info.path_max_len, 1);
 
+	retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks,
+			       &file_info, fs_callbacks);
+
+	free(file_info.path);
 	free(hdlinks.hdl);
 	return retval;
 }
+
+errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
+		      const char *source_dir, ext2_ino_t root)
+{
+	return populate_fs2(fs, parent_ino, source_dir, root, NULL);
+}
diff --git a/misc/create_inode.h b/misc/create_inode.h
index cf49df2..17309c6 100644
--- a/misc/create_inode.h
+++ b/misc/create_inode.h
@@ -24,9 +24,21 @@
 
 #define HDLINK_CNT	(4)
 
+struct fs_ops_callbacks {
+	errcode_t (* create_new_inode)(ext2_filsys fs, const char *target_path,
+		const char *name, ext2_ino_t parent_ino, ext2_ino_t root,
+		mode_t mode);
+	errcode_t (* end_create_new_inode)(ext2_filsys fs,
+		const char *target_path, const char *name,
+		ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
+};
+
 /* For populating the filesystem */
 extern errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
 			     const char *source_dir, ext2_ino_t root);
+extern errcode_t populate_fs2(ext2_filsys fs, ext2_ino_t parent_ino,
+			      const char *source_dir, ext2_ino_t root,
+			      struct fs_ops_callbacks *fs_callbacks);
 extern errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd,
 				   const char *name, struct stat *st);
 extern errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd,
diff --git a/misc/e2freefrag.c b/misc/e2freefrag.c
index 90acb7e..b315263 100644
--- a/misc/e2freefrag.c
+++ b/misc/e2freefrag.c
@@ -25,11 +25,25 @@
 extern char *optarg;
 extern int optind;
 #endif
+#if defined(HAVE_EXT2_IOCTLS) && !defined(DEBUGFS)
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <limits.h>
+#endif
 
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fs.h"
 #include "e2freefrag.h"
 
+#if defined(HAVE_EXT2_IOCTLS) && !defined(DEBUGFS)
+# ifdef HAVE_LINUX_FSMAP_H
+#  include <linux/fsmap.h>
+# endif
+# include "fsmap.h"
+#endif
+
 static void usage(const char *prog)
 {
 	fprintf(stderr, "usage: %s [-c chunksize in kb] [-h] "
@@ -143,8 +157,97 @@
 		update_chunk_stats(info, last_chunk_size);
 }
 
-static errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info,
-				FILE *f)
+#if defined(HAVE_EXT2_IOCTLS) && !defined(DEBUGFS)
+# define FSMAP_EXTENTS	1024
+static int scan_online(ext2_filsys fs, struct chunk_info *info)
+{
+	struct fsmap_head *fsmap;
+	struct fsmap *extent;
+	struct fsmap *p;
+	char mntpoint[PATH_MAX + 1];
+	errcode_t retval;
+	int mount_flags;
+	int fd;
+	int ret;
+	int i;
+
+	/* Try to open the mountpoint for a live query. */
+	retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
+					  mntpoint, PATH_MAX);
+	if (retval) {
+		com_err(fs->device_name, retval, "while checking mount status");
+		return 0;
+	}
+	if (!mount_flags & EXT2_MF_MOUNTED)
+		return 0;
+	fd = open(mntpoint, O_RDONLY);
+	if (fd < 0) {
+		com_err(mntpoint, errno, "while opening mount point");
+		return 0;
+	}
+
+	fsmap = malloc(fsmap_sizeof(FSMAP_EXTENTS));
+	if (!fsmap) {
+		com_err(fs->device_name, errno, "while allocating memory");
+		return 0;
+	}
+
+	memset(fsmap, 0, sizeof(*fsmap));
+	fsmap->fmh_count = FSMAP_EXTENTS;
+	fsmap->fmh_keys[1].fmr_device = UINT_MAX;
+	fsmap->fmh_keys[1].fmr_physical = ULLONG_MAX;
+	fsmap->fmh_keys[1].fmr_owner = ULLONG_MAX;
+	fsmap->fmh_keys[1].fmr_offset = ULLONG_MAX;
+	fsmap->fmh_keys[1].fmr_flags = UINT_MAX;
+
+	/* Fill the extent histogram with live data */
+	while (1) {
+		ret = ioctl(fd, FS_IOC_GETFSMAP, fsmap);
+		if (ret < 0) {
+			com_err(fs->device_name, errno, "while calling fsmap");
+			free(fsmap);
+			return 0;
+		}
+
+		/* No more extents to map, exit */
+		if (!fsmap->fmh_entries)
+			break;
+
+		for (i = 0, extent = fsmap->fmh_recs;
+		     i < fsmap->fmh_entries;
+		     i++, extent++) {
+			if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
+			    extent->fmr_owner != FMR_OWN_FREE)
+				continue;
+			update_chunk_stats(info,
+					   extent->fmr_length / fs->blocksize);
+		}
+
+		p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
+		if (p->fmr_flags & FMR_OF_LAST)
+			break;
+		fsmap_advance(fsmap);
+	}
+
+	return 1;
+}
+#else
+# define scan_online(fs, info)	(0)
+#endif /* HAVE_EXT2_IOCTLS */
+
+static errcode_t scan_offline(ext2_filsys fs, struct chunk_info *info)
+{
+	errcode_t retval;
+
+	retval = ext2fs_read_block_bitmap(fs);
+	if (retval)
+		return retval;
+	scan_block_bitmap(fs, info);
+	return 0;
+}
+
+static errcode_t dump_chunk_info(ext2_filsys fs, struct chunk_info *info,
+				 FILE *f)
 {
 	unsigned long total_chunks;
 	const char *unitp = "KMGTPEZY";
@@ -152,8 +255,6 @@
 	unsigned long start = 0, end;
 	int i, retval = 0;
 
-	scan_block_bitmap(fs, info);
-
 	fprintf(f, "Total blocks: %llu\nFree blocks: %u (%0.1f%%)\n",
 		ext2fs_blocks_count(fs->super), fs->super->s_free_blocks_count,
 		(double)fs->super->s_free_blocks_count * 100 /
@@ -228,18 +329,20 @@
 	fprintf(f, "Device: %s\n", fs->device_name);
 	fprintf(f, "Blocksize: %u bytes\n", fs->blocksize);
 
-	retval = ext2fs_read_block_bitmap(fs);
+	init_chunk_info(fs, chunk_info);
+	if (!scan_online(fs, chunk_info)) {
+		init_chunk_info(fs, chunk_info);
+		retval = scan_offline(fs, chunk_info);
+	}
 	if (retval) {
 		com_err(fs->device_name, retval, "while reading block bitmap");
 		close_device(fs->device_name, fs);
 		exit(1);
 	}
 
-	init_chunk_info(fs, chunk_info);
-
-	retval = get_chunk_info(fs, chunk_info, f);
+	retval = dump_chunk_info(fs, chunk_info, f);
 	if (retval) {
-		com_err(fs->device_name, retval, "while collecting chunk info");
+		com_err(fs->device_name, retval, "while dumping chunk info");
                 close_device(fs->device_name, fs);
 		exit(1);
 	}
diff --git a/misc/fsmap.h b/misc/fsmap.h
new file mode 100644
index 0000000..e9590aa
--- /dev/null
+++ b/misc/fsmap.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 Oracle.
+ * All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#ifndef FSMAP_H_
+#define FSMAP_H_
+
+/* FS_IOC_GETFSMAP ioctl definitions */
+#ifndef FS_IOC_GETFSMAP
+struct fsmap {
+	__u32		fmr_device;	/* device id */
+	__u32		fmr_flags;	/* mapping flags */
+	__u64		fmr_physical;	/* device offset of segment */
+	__u64		fmr_owner;	/* owner id */
+	__u64		fmr_offset;	/* file offset of segment */
+	__u64		fmr_length;	/* length of segment */
+	__u64		fmr_reserved[3];	/* must be zero */
+};
+
+struct fsmap_head {
+	__u32		fmh_iflags;	/* control flags */
+	__u32		fmh_oflags;	/* output flags */
+	__u32		fmh_count;	/* # of entries in array incl. input */
+	__u32		fmh_entries;	/* # of entries filled in (output). */
+	__u64		fmh_reserved[6];	/* must be zero */
+
+	struct fsmap	fmh_keys[2];	/* low and high keys for the mapping search */
+	struct fsmap	fmh_recs[];	/* returned records */
+};
+
+/* Size of an fsmap_head with room for nr records. */
+static inline size_t
+fsmap_sizeof(
+	unsigned int	nr)
+{
+	return sizeof(struct fsmap_head) + nr * sizeof(struct fsmap);
+}
+
+/* Start the next fsmap query at the end of the current query results. */
+static inline void
+fsmap_advance(
+	struct fsmap_head	*head)
+{
+	head->fmh_keys[0] = head->fmh_recs[head->fmh_entries - 1];
+}
+
+/*	fmh_iflags values - set by FS_IOC_GETFSMAP caller in the header. */
+/* no flags defined yet */
+#define FMH_IF_VALID		0
+
+/*	fmh_oflags values - returned in the header segment only. */
+#define FMH_OF_DEV_T		0x1	/* fmr_device values will be dev_t */
+
+/*	fmr_flags values - returned for each non-header segment */
+#define FMR_OF_PREALLOC		0x1	/* segment = unwritten pre-allocation */
+#define FMR_OF_ATTR_FORK	0x2	/* segment = attribute fork */
+#define FMR_OF_EXTENT_MAP	0x4	/* segment = extent map */
+#define FMR_OF_SHARED		0x8	/* segment = shared with another file */
+#define FMR_OF_SPECIAL_OWNER	0x10	/* owner is a special value */
+#define FMR_OF_LAST		0x20	/* segment is the last in the FS */
+
+/* Each FS gets to define its own special owner codes. */
+#define FMR_OWNER(type, code)	(((__u64)type << 32) | \
+				 ((__u64)code & 0xFFFFFFFFULL))
+#define FMR_OWNER_TYPE(owner)	((__u32)((__u64)owner >> 32))
+#define FMR_OWNER_CODE(owner)	((__u32)(((__u64)owner & 0xFFFFFFFFULL)))
+#define FMR_OWN_FREE		FMR_OWNER(0, 1) /* free space */
+#define FMR_OWN_UNKNOWN		FMR_OWNER(0, 2) /* unknown owner */
+#define FMR_OWN_METADATA	FMR_OWNER(0, 3) /* metadata */
+
+#define FS_IOC_GETFSMAP		_IOWR('X', 59, struct fsmap_head)
+#endif /* FS_IOC_GETFSMAP */
+
+#endif
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index b8d078a..6cbba33 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -113,6 +113,9 @@
 const char *src_root_dir;  /* Copy files from the specified directory */
 static char *undo_file;
 
+static int android_sparse_file; /* -E android_sparse */
+static char *android_sparse_params;
+
 static profile_t	profile;
 
 static int sys_page_size = 4096;
@@ -553,7 +556,7 @@
 	int retval;
 	unsigned int *magic;
 
-	buf = malloc(512*nsect);
+	buf = calloc(512, nsect);
 	if (!buf) {
 		printf(_("Out of memory erasing sectors %d-%d\n"),
 		       sect, sect + nsect - 1);
@@ -1026,6 +1029,8 @@
 				badopt = token;
 				continue;
 			}
+		} else if (!strcmp(token, "android_sparse")) {
+			android_sparse_file = 1;
 		} else {
 			r_usage++;
 			badopt = token;
@@ -1081,7 +1086,8 @@
 		EXT4_FEATURE_INCOMPAT_64BIT|
 		EXT4_FEATURE_INCOMPAT_INLINE_DATA|
 		EXT4_FEATURE_INCOMPAT_ENCRYPT |
-		EXT4_FEATURE_INCOMPAT_CSUM_SEED,
+		EXT4_FEATURE_INCOMPAT_CSUM_SEED |
+		EXT4_FEATURE_INCOMPAT_LARGEDIR,
 	/* R/O compat */
 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -2827,7 +2833,21 @@
 	 */
 	if (!quiet)
 		flags |= EXT2_FLAG_PRINT_PROGRESS;
-	retval = ext2fs_initialize(device_name, flags, &fs_param, io_ptr, &fs);
+	if (android_sparse_file) {
+		android_sparse_params = malloc(PATH_MAX + 32);
+		if (!android_sparse_params) {
+			com_err(program_name, ENOMEM, "%s",
+				_("in malloc for android_sparse_params"));
+			exit(1);
+		}
+		snprintf(android_sparse_params, PATH_MAX + 32, "%s:%u:%u",
+			 device_name, fs_param.s_blocks_count,
+			 1024 << fs_param.s_log_block_size);
+		retval = ext2fs_initialize(android_sparse_params, flags,
+					   &fs_param, sparse_io_manager, &fs);
+	} else
+		retval = ext2fs_initialize(device_name, flags, &fs_param,
+					   io_ptr, &fs);
 	if (retval) {
 		com_err(device_name, retval, "%s",
 			_("while setting up superblock"));
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 8543567..dc58729 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -156,7 +156,8 @@
 		EXT4_FEATURE_INCOMPAT_MMP |
 		EXT4_FEATURE_INCOMPAT_64BIT |
 		EXT4_FEATURE_INCOMPAT_ENCRYPT |
-		EXT4_FEATURE_INCOMPAT_CSUM_SEED,
+		EXT4_FEATURE_INCOMPAT_CSUM_SEED |
+		EXT4_FEATURE_INCOMPAT_LARGEDIR,
 	/* R/O compat */
 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
index 2ae2f2a..eff37d3 100644
--- a/po/Makefile.in.in
+++ b/po/Makefile.in.in
@@ -270,7 +270,7 @@
 	  done; \
 	done
 
-check: all
+fullcheck check: all
 
 info dvi ps pdf html tags TAGS ctags CTAGS ID:
 
diff --git a/po/at-expand.pl b/po/at-expand.pl
index bc1a744..47e4ebd 100644
--- a/po/at-expand.pl
+++ b/po/at-expand.pl
@@ -45,7 +45,7 @@
  "#.	%IM	<inode> -> i_mtime\n",
  "#.	%IF	<inode> -> i_faddr\n",
  "#.	%If	<inode> -> i_file_acl\n",
- "#.	%Id	<inode> -> i_dir_acl\n",
+ "#.	%Id	<inode> -> i_size_high\n",
  "#.	%Iu	<inode> -> i_uid\n",
  "#.	%Ig	<inode> -> i_gid\n",
  "#.	%It	<str>			file type\n",
diff --git a/resize/Android.bp b/resize/Android.bp
new file mode 100644
index 0000000..6d3d321
--- /dev/null
+++ b/resize/Android.bp
@@ -0,0 +1,24 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_binary {
+    name: "resize2fs",
+    host_supported: true,
+
+    srcs: [
+        "extent.c",
+        "resize2fs.c",
+        "main.c",
+        "online.c",
+        "sim_progress.c",
+        "resource_track.c",
+    ],
+    cflags: ["-W", "-Wall", "-Wno-macro-redefined"],
+    shared_libs: [
+        "libext2fs",
+        "libext2_com_err",
+        "libext2_e2p",
+        "libext2_uuid",
+        "libext2_blkid",
+    ],
+    system_shared_libs: ["libc"],
+}
diff --git a/resize/Android.mk b/resize/Android.mk
deleted file mode 100644
index 12d6ab5..0000000
--- a/resize/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-resize2fs_src_files := \
-	extent.c \
-	resize2fs.c \
-	main.c \
-	online.c \
-	sim_progress.c \
-	resource_track.c
-
-resize2fs_c_includes := external/e2fsprogs/lib
-
-resize2fs_cflags := -O2 -g -W -Wall
-
-resize2fs_shared_libraries := \
-	libext2fs \
-	libext2_com_err \
-	libext2_e2p \
-	libext2_uuid \
-	libext2_blkid
-
-resize2fs_system_shared_libraries := libc
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(resize2fs_src_files)
-LOCAL_C_INCLUDES := $(resize2fs_c_includes)
-LOCAL_CFLAGS := $(resize2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(resize2fs_shared_libraries)
-LOCAL_SYSTEM_SHARED_LIBRARIES := $(resize2fs_system_shared_libraries)
-LOCAL_MODULE := resize2fs
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(resize2fs_src_files)
-LOCAL_C_INCLUDES := $(resize2fs_c_includes)
-LOCAL_CFLAGS := $(resize2fs_cflags)
-LOCAL_SHARED_LIBRARIES := $(addsuffix -host, $(resize2fs_shared_libraries))
-LOCAL_MODULE := resize2fs_host
-LOCAL_MODULE_STEM := resize2fs
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/resize/Makefile.in b/resize/Makefile.in
index 6014bdd..cb9f553 100644
--- a/resize/Makefile.in
+++ b/resize/Makefile.in
@@ -94,7 +94,7 @@
 test_extent.out: test_extent $(srcdir)/test_extent.in
 	$(TESTENV) ./test_extent < $(srcdir)/test_extent.in > test_extent.out
 
-check:: test_extent.out
+fullcheck check:: test_extent.out
 	$(Q) if cmp -s test_extent.out $(srcdir)/test_extent.in ; then \
 		echo "Test succeeded." ; \
 	else \
diff --git a/tests/Makefile.in b/tests/Makefile.in
index c130f4a..57117ac 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -41,8 +41,10 @@
 @ifGNUmake@TESTS=$(wildcard $(srcdir)/[a-z]_*)
 @ifNotGNUmake@TESTS != echo $(srcdir)/[a-z]_*
 
+SKIP_SLOW_TESTS=--skip-slow-tests
+
 $(TESTS):: test_one always_run
-	@./test_one $@
+	@./test_one $(SKIP_SLOW_TESTS) $@
 
 foo:
 	echo $(TESTS)
@@ -57,6 +59,9 @@
 
 check:: test_pre test_post test_script
 
+fullcheck::
+	$(MAKE) SKIP_SLOW_TESTS= check
+
 check-failed: $(basename $(wildcard *.failed))
 	@$(srcdir)/test_post
 
diff --git a/tests/d_fallocate_blkmap/expect b/tests/d_fallocate_blkmap/expect
index 8ce79ff..f588511 100644
--- a/tests/d_fallocate_blkmap/expect
+++ b/tests/d_fallocate_blkmap/expect
@@ -18,7 +18,7 @@
 Inode: 12   Type: regular    Mode:  0666   Flags: 0x0
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 40960
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 82
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
@@ -30,7 +30,7 @@
 Inode: 13   Type: regular    Mode:  0666   Flags: 0x0
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 10240000
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 20082
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
diff --git a/tests/d_inline_dump/expect b/tests/d_inline_dump/expect
index b685135..db9d522 100644
--- a/tests/d_inline_dump/expect
+++ b/tests/d_inline_dump/expect
@@ -2,7 +2,7 @@
 Inode: 13   Type: regular    Mode:  0644   Flags: 0x10000000
 Generation: 3289262644    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 80
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec6b4:c72e3c00 -- Tue Jul 22 20:16:52 2014
@@ -18,7 +18,7 @@
 Inode: 18   Type: regular    Mode:  0644   Flags: 0x10000000
 Generation: 3842229473    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 20
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec6b4:cafecc00 -- Tue Jul 22 20:16:52 2014
@@ -35,7 +35,7 @@
 Inode: 16   Type: directory    Mode:  0755   Flags: 0x10000000
 Generation: 3842229469    Version: 0x00000000:00000004
 User:     0   Group:     0   Size: 132
-File ACL: 7    Directory ACL: 0
+File ACL: 7
 Links: 2   Blockcount: 8
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec6e3:27eac000 -- Tue Jul 22 20:17:39 2014
@@ -51,7 +51,7 @@
 Inode: 20   Type: directory    Mode:  0755   Flags: 0x10000000
 Generation: 3710818931    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 60
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 2   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec6b4:ca0aa800 -- Tue Jul 22 20:16:52 2014
@@ -68,7 +68,7 @@
 Inode: 12   Type: symlink    Mode:  0777   Flags: 0x10000000
 Generation: 3289262643    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 80
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec47f:724db800 -- Tue Jul 22 20:07:27 2014
@@ -83,7 +83,7 @@
 Inode: 19   Type: symlink    Mode:  0777   Flags: 0x0
 Generation: 3842229474    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 20
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x53cec44c:a1fcc000 -- Tue Jul 22 20:06:36 2014
diff --git a/tests/d_special_files/expect b/tests/d_special_files/expect
index f729b0f..c825932 100644
--- a/tests/d_special_files/expect
+++ b/tests/d_special_files/expect
@@ -5,7 +5,7 @@
 Inode: 12   Type: symlink    Mode:  0777   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 3
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
@@ -17,7 +17,7 @@
 Inode: 13   Type: symlink    Mode:  0777   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 80
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 2
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
@@ -42,7 +42,7 @@
 Inode: 14   Type: FIFO    Mode:  0000   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 0
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
@@ -55,7 +55,7 @@
 Inode: 15   Type: block special    Mode:  0000   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 0
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
@@ -67,7 +67,7 @@
 Inode: 16   Type: character special    Mode:  0000   Flags: 0x0
 Generation: 0    Version: 0x00000000
 User:     0   Group:     0   Size: 0
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
diff --git a/tests/f_badcluster/expect b/tests/f_badcluster/expect
index 65a1641..b44e65d 100644
--- a/tests/f_badcluster/expect
+++ b/tests/f_badcluster/expect
@@ -13,8 +13,6 @@
 Will fix in pass 1B.
 Inode 17 logical block 2 (physical block 1184) violates cluster allocation rules.
 Will fix in pass 1B.
-Inode 17, i_blocks is 32, should be 64.  Fix? yes
-
 Inode 18 logical block 3 (physical block 1201) violates cluster allocation rules.
 Will fix in pass 1B.
 Inode 18, i_blocks is 32, should be 64.  Fix? yes
@@ -86,8 +84,6 @@
 
 Inode 16, i_blocks is 64, should be 32.  Fix? yes
 
-Inode 17, i_blocks is 64, should be 32.  Fix? yes
-
 Inode 18, i_blocks is 64, should be 32.  Fix? yes
 
 Pass 2: Checking directory structure
@@ -116,7 +112,7 @@
 Inode: 12   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152157    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -128,7 +124,7 @@
 Inode: 13   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152158    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -140,7 +136,7 @@
 Inode: 14   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152159    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -152,7 +148,7 @@
 Inode: 15   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152160    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -163,7 +159,7 @@
 Inode: 16   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152161    Version: 0x00000001
 User:     0   Group:     0   Size: 6144
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -175,7 +171,7 @@
 Inode: 17   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152162    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
@@ -187,7 +183,7 @@
 Inode: 18   Type: regular    Mode:  0644   Flags: 0x80000
 Generation: 1117152163    Version: 0x00000001
 User:     0   Group:     0   Size: 3072
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 32
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
diff --git a/tests/f_convert_bmap/expect.1 b/tests/f_convert_bmap/expect.1
index c387962..716dbcb 100644
--- a/tests/f_convert_bmap/expect.1
+++ b/tests/f_convert_bmap/expect.1
@@ -2,7 +2,7 @@
 Inode: 12   Type: regular    Mode:  0644   Flags: 0x0
 Generation: 1573716129    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 524288
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 1030
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x5457f87a:62ae2980 -- Mon Nov  3 21:49:46 2014
diff --git a/tests/f_convert_bmap_and_extent/expect.1 b/tests/f_convert_bmap_and_extent/expect.1
index c86c571..eafd64a 100644
--- a/tests/f_convert_bmap_and_extent/expect.1
+++ b/tests/f_convert_bmap_and_extent/expect.1
@@ -2,7 +2,7 @@
 Inode: 12   Type: regular    Mode:  0644   Flags: 0x0
 Generation: 1573716129    Version: 0x00000000:00000001
 User:     0   Group:     0   Size: 524288
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 1030
 Fragment:  Address: 0    Number: 0    Size: 0
  ctime: 0x5457f87a:62ae2980 -- Mon Nov  3 21:49:46 2014
diff --git a/tests/f_convert_bmap_sparse/expect.1 b/tests/f_convert_bmap_sparse/expect.1
index 74a8034..095fb2b 100644
--- a/tests/f_convert_bmap_sparse/expect.1
+++ b/tests/f_convert_bmap_sparse/expect.1
@@ -2,7 +2,7 @@
 Inode: 12   Type: regular    Mode:  0775   Flags: 0x0
 Generation: 2022334337    Version: 0x00000001
 User:  1000   Group:  1000   Size: 21080
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 16
 Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x5924849d -- Tue May 23 18:51:09 2017
diff --git a/tests/f_create_symlinks/expect b/tests/f_create_symlinks/expect
index dca6e92..4409385 100644
--- a/tests/f_create_symlinks/expect
+++ b/tests/f_create_symlinks/expect
@@ -20,7 +20,7 @@
 Inode: 12   Type: symlink    Mode:  0777   Flags: 0x0
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 31
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
@@ -29,7 +29,7 @@
 Inode: 13   Type: symlink    Mode:  0777   Flags: 0x10000000
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 71
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 0
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
@@ -40,7 +40,7 @@
 Inode: 14   Type: symlink    Mode:  0777   Flags: 0x80000
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 501
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 2
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
@@ -50,7 +50,7 @@
 Inode: 15   Type: symlink    Mode:  0777   Flags: 0x80000
 Generation: 0    Version: 0x00000000:00000000
 User:     0   Group:     0   Project:     0   Size: 1024
-File ACL: 0    Directory ACL: 0
+File ACL: 0
 Links: 1   Blockcount: 2
 Fragment:  Address: 0    Number: 0    Size: 0
 Size of extra inode fields: 32
diff --git a/tests/f_large_dir/expect b/tests/f_large_dir/expect
new file mode 100644
index 0000000..b099460
--- /dev/null
+++ b/tests/f_large_dir/expect
@@ -0,0 +1,12 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 3A: Optimizing directories
+Pass 4: Checking reference counts
+Inode 13 ref count is 1, should be 47245.  Fix? yes
+
+Pass 5: Checking group summary information
+
+test.img: ***** FILE SYSTEM WAS MODIFIED *****
+test.img: 13/115368 files (0.0% non-contiguous), 32817/460800 blocks
+Exit status is 1
diff --git a/tests/f_large_dir/is_slow_test b/tests/f_large_dir/is_slow_test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/f_large_dir/is_slow_test
diff --git a/tests/f_large_dir/name b/tests/f_large_dir/name
new file mode 100644
index 0000000..4b96890
--- /dev/null
+++ b/tests/f_large_dir/name
@@ -0,0 +1 @@
+optimize 3 level htree directories
diff --git a/tests/f_large_dir/script b/tests/f_large_dir/script
new file mode 100644
index 0000000..0b5fdff
--- /dev/null
+++ b/tests/f_large_dir/script
@@ -0,0 +1,51 @@
+OUT=$test_name.log
+EXP=$test_dir/expect
+E2FSCK=../e2fsck/e2fsck
+
+NAMELEN=255
+DIRENT_SZ=8
+BLOCKSZ=1024
+DIRENT_PER_LEAF=$((BLOCKSZ / (NAMELEN + DIRENT_SZ)))
+HEADER=32
+INDEX_SZ=8
+INDEX_L1=$(((BLOCKSZ - HEADER) / INDEX_SZ))
+INDEX_L2=$(((BLOCKSZ - DIRENT_SZ) / INDEX_SZ))
+ENTRIES=$((INDEX_L1 * INDEX_L2 * DIRENT_PER_LEAF))
+
+cp /dev/null $OUT
+$MKE2FS -b 1024 -O large_dir,uninit_bg,dir_nlink -F $TMPFILE 460800 \
+	> /dev/null 2>&1
+{
+	echo "feature large_dir"
+	echo "mkdir /foo"
+	echo "cd /foo"
+	touch foofile
+	echo "write foofile foofile"
+	i=0
+	while test $i  -lt $ENTRIES ; do
+	    if test $(( i % DIRENT_PER_LEAF )) -eq 0 ; then
+		echo "expand ./"
+	    fi
+	    if test $(( i % 5000 )) -eq 0 -a $i -gt 0 ; then
+		>&2 echo "$test_name: $i processed"
+	    fi
+	    printf "ln foofile %0255X\n" $i
+	    i=$(($i + 1))
+	done
+} | $DEBUGFS -w -f /dev/stdin $TMPFILE > /dev/null 2>&1
+
+$E2FSCK -yfD $TMPFILE > $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT
+rm -f $OUT.new
+
+cmp -s $OUT $EXP
+RC=$?
+if [ $RC -eq 0 ]; then
+	echo "$test_name: $test_description: ok"
+	touch $test_name.ok
+else
+	echo "$test_name: $test_description: failed"
+	diff -u $EXP $OUT > $test_name.failed
+fi
diff --git a/tests/f_mmp/is_slow_test b/tests/f_mmp/is_slow_test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/f_mmp/is_slow_test
diff --git a/tests/f_mmp_garbage/is_slow_test b/tests/f_mmp_garbage/is_slow_test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/f_mmp_garbage/is_slow_test
diff --git a/tests/f_recnect_bad/expect.1 b/tests/f_recnect_bad/expect.1
index 8ba81e6..d4f72a1 100644
--- a/tests/f_recnect_bad/expect.1
+++ b/tests/f_recnect_bad/expect.1
@@ -3,7 +3,7 @@
 i_faddr for inode 15 (/test/quux) is 23, should be zero.
 Clear? yes
 
-i_dir_acl for inode 15 (/test/quux) is 12, should be zero.
+i_size_high for inode 15 (/test/quux) is 12, should be zero.
 Clear? yes
 
 i_file_acl for inode 13 (/test/???) is 12, should be zero.
diff --git a/tests/r_64bit_big_expand/is_slow_test b/tests/r_64bit_big_expand/is_slow_test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/r_64bit_big_expand/is_slow_test
diff --git a/tests/r_ext4_big_expand/is_slow_test b/tests/r_ext4_big_expand/is_slow_test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/r_ext4_big_expand/is_slow_test
diff --git a/tests/test_one.in b/tests/test_one.in
index fb30e57..35465b6 100644
--- a/tests/test_one.in
+++ b/tests/test_one.in
@@ -13,6 +13,10 @@
     	export USE_VALGRIND="valgrind --sim-hints=lax-ioctls --leak-check=full --show-reachable=yes --log-file=/tmp/valgrind-%p.log"
 	shift;
 	;;
+    --skip-slow-tests)
+	SKIP_SLOW_TESTS=yes
+	shift;
+	;;
 esac
 
 case "$1" in
@@ -49,6 +53,11 @@
 	test_description=
 fi
 
+if [ -n "$SKIP_SLOW_TESTS" -a -f $test_dir/is_slow_test ]; then
+    echo "$test_name: $test_description: skipped (slow test)"
+    exit 0
+fi
+
 rm -f $test_name.ok $test_name.failed
 #echo -e -n "$test_name: $test_description:\r"
 
diff --git a/util/android_config.h b/util/android_config.h
index b3c12a7..e6b25fa 100644
--- a/util/android_config.h
+++ b/util/android_config.h
@@ -1,33 +1,23 @@
-/* work around bug in AndroidConfig.h */
-#ifdef HAVE_MALLOC_H
-#undef HAVE_MALLOC_H
+#ifndef __APPLE__
 #define HAVE_MALLOC_H 1
 #endif
 
 #define ROOT_SYSCONFDIR "/etc"
 
+#define ENABLE_LIBSPARSE 1
+
 #define DISABLE_BACKTRACE 1
 #define HAVE_DIRENT_H 1
 #define HAVE_ERRNO_H 1
-#define HAVE_EXT2_IOCTLS 1
-#define HAVE_FALLOCATE 1
 #define HAVE_GETOPT_H 1
-#define HAVE_GETPAGESIZE 1
 #define HAVE_GETPWUID_R 1
 #define HAVE_INTPTR_T 1
 #define HAVE_INTTYPES_H 1
-#define HAVE_LINUX_FD_H 1
-#define HAVE_LSEEK64 1
-#define HAVE_LSEEK64_PROTOTYPE 1
 #define HAVE_MMAP 1
-#define HAVE_NETINET_IN_H 1
-#define HAVE_NET_IF_H 1
-#define HAVE_POSIX_MEMALIGN 1
-#define HAVE_PREAD 1
-#define HAVE_PREAD64 1
-#define HAVE_PWRITE 1
-#define HAVE_PWRITE64 1
 #define HAVE_SETJMP_H 1
+#ifdef __linux__
+#define HAVE_SETMNTENT 1
+#endif
 #define HAVE_SNPRINTF 1
 #define HAVE_STDLIB_H 1
 #define HAVE_STRCASECMP 1
@@ -36,17 +26,44 @@
 #define HAVE_STRNLEN 1
 #define HAVE_STRPTIME 1
 #define HAVE_SYSCONF 1
-#define HAVE_SYS_IOCTL_H 1
-#define HAVE_SYS_MMAN_H 1
-#define HAVE_SYS_MOUNT_H 1
-#define HAVE_SYS_PARAM_H 1
-#define HAVE_SYS_PRCTL_H 1
-#define HAVE_SYS_RESOURCE_H 1
-#define HAVE_SYS_SELECT_H 1
-#define HAVE_SYS_STAT_H 1
-#define HAVE_SYS_TIME_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_SYS_WAIT_H 1
 #define HAVE_TYPE_SSIZE_T 1
 #define HAVE_UNISTD_H 1
 #define HAVE_UTIME_H 1
+
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+
+#if defined(_WIN32)
+# define HAVE_LINUX_TYPES_H 1
+# define HAVE_WINSOCK_H 1
+#endif
+#if defined(__APPLE__) || defined(__linux__)
+# define HAVE_FCNTL 1
+# define HAVE_FSYNC 1
+# define HAVE_GETPAGESIZE 1
+# define HAVE_NET_IF_H 1
+# define HAVE_NETINET_IN_H 1
+# define HAVE_PREAD 1
+# define HAVE_PWRITE 1
+# define HAVE_POSIX_MEMALIGN 1
+# define HAVE_SYS_IOCTL_H 1
+# define HAVE_SYS_MMAN_H 1
+# define HAVE_SYS_MOUNT_H 1
+# define HAVE_SYS_PARAM_H 1
+# define HAVE_SYS_RESOURCE_H 1
+# define HAVE_SYS_SELECT_H 1
+# define HAVE_SYS_WAIT_H 1
+#endif
+#if defined(__linux__)
+# define HAVE_EXT2_IOCTLS 1
+# define HAVE_FALLOCATE 1
+# define HAVE_LINUX_FD_H 1
+# define HAVE_LINUX_TYPES_H 1
+# define HAVE_LSEEK64 1
+# define HAVE_LSEEK64_PROTOTYPE 1
+# define HAVE_PREAD64 1
+# define HAVE_PWRITE64 1
+# define HAVE_SYS_PRCTL_H 1
+# define HAVE_SYS_SYSMACROS_H 1
+#endif
diff --git a/util/gen-android-files b/util/gen-android-files
index ebd8778..937496b 100755
--- a/util/gen-android-files
+++ b/util/gen-android-files
@@ -7,7 +7,7 @@
 	lib/ext2fs/ext2_types.h lib/config.h lib/blkid/blkid.h \
 	lib/uuid/uuid.h lib/ext2fs/crc32c_table.h misc/default_profile.c \
 	lib/ss/std_rqs.c debugfs/debug_cmds.c debugfs/ro_debug_cmds.c \
-	debugfs/extent_cmds.c debugfs/e2freefrag.c debugfs/create_inode.c \
+	debugfs/extent_cmds.c debugfs/e2freefrag.c \
 	debugfs/recovery.c debugfs/revoke.c \
 	MODULE_LICENSE_GPL README.version"
 
@@ -41,7 +41,7 @@
 cp util/android_types.h lib/blkid/blkid_types.h
 cp util/android_types.h lib/uuid/uuid_types.h
 cp util/android_config.h lib/config.h
-cp misc/e2freefrag.c misc/create_inode.c debugfs/
+cp misc/e2freefrag.c debugfs/
 cp e2fsck/recovery.c e2fsck/revoke.c debugfs/
 
 gcc -o gen_crc32ctable lib/ext2fs/gen_crc32ctable.c